TForm: Add a message handler and call inherited - c++builder

Let´s say I need to create a Windows message handler in my C++ Builder cpp file.
I'll write a handler for WM_SIZE like this:
h file:
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_SIZE, TWMSize, OnWMSize)
END_MESSAGE_MAP(TControl)
void __fastcall OnWMSize(TWMSize &msg);
cpp file:
void __fastcall TForm1::OnWMSize(TWMSize &msg)
{
if (msg.SizeType == SIZE_MAXIMIZED)
Caption = "Maximized";
// This is a Delphi call and won't work in C++:
// inherited;
// Cpp call. Won't compile due to method visibility (private)
// TForm::WMSize(msg);
// Cpp call. Compiles but doesn't get expected behavior
DefaultHandler((void*)&msg);
}
As shown in the example, using Delphi this is pretty straightforward, just call inherited.
But using C++, how do I call the base class in C++ Builder? WMSize method is declared as private in TScrollingWinControl.
In this example, not calling the base class breaks Anchors functionality. Using DefaultHandler won't solve the problem, either.
Am I missing something obvious?

First off, you are passing the wrong class type to END_MESSAGE_MAP(). You need to specify the immediate parent class, which in this case is TForm, not TControl:
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_SIZE, TWMSize, OnWMSize)
END_MESSAGE_MAP(TForm) // <-- here
Now, that being said, a MESSAGE_MAP is just a fancy way of overriding the virtual Dispatch() method:
#define BEGIN_MESSAGE_MAP virtual void __fastcall Dispatch(void *Message) \
{ \
switch (((PMessage)Message)->Msg) \
{
#define VCL_MESSAGE_HANDLER(msg,type,meth) \
case msg: \
meth(*((type *)Message)); \
break;
// NOTE: ATL defines a MESSAGE_HANDLER macro which conflicts with VCL's macro. The
// VCL macro has been renamed to VCL_MESSAGE_HANDLER. If you are not using ATL,
// MESSAGE_HANDLER is defined as in previous versions of BCB.
//
#if !defined(USING_ATL) && !defined(USING_ATLVCL) && !defined(INC_ATL_HEADERS)
#define MESSAGE_HANDLER VCL_MESSAGE_HANDLER
#endif // ATL_COMPAT
#define END_MESSAGE_MAP(base) default: \
base::Dispatch(Message); \
break; \
} \
}
So, your MESSAGE_MAP resolves to the following code logic:
virtual void __fastcall Dispatch(void *Message)
{
switch (((PMessage)Message)->Msg)
{
case WM_SIZE:
OnWMSize(*((TWMSize *)Message));
break;
default:
TForm::Dispatch(Message);
break;
}
}
As you can see, END_MESSAGE_MAP() simply passes unhandled messages to the base class TForm::Dispatch() method. You must do the same in your message handlers, eg:
void __fastcall TForm1::OnWMSize(TWMSize &msg)
{
if (msg.SizeType == SIZE_MAXIMIZED)
Caption = "Maximized";
TForm::Dispatch(&msg);
}

Related

Convert a snippet of Delphi code to C++Builder

I am working with the EurekaLog bug catcher for Delphi/C++Builder. All of their examples are in Delphi and I am using C++Builder. The Delphi code below is one of their examples that causes a software exception. I tried to convert this into C++ below but my code is wrong. Can you show me the correct C++ Code to make this work.
Delphi code from EurekaLog
type
EMyException = class(Exception);
Procedure TForm. ButtonClick(Sender: TObject);
begin
raise EMyException.Create('Error Message');
end;
end.
My C++Builder code that does not work
typedef class{
Exception;
}EMyException;
void __fastcall TForm1::ButtonClick(TObject *Sender)
{
throw new EMyException("Error Message");
}
You need to derive a new class, not use a typedef. And don't use new when calling throw (this is the only area in C++Builder where a TObject descendant must not be constructed with new).
class EMyException : public Exception
{
public:
__fastcall EMyException(const String Msg) : Exception(Msg) {}
};
void __fastcall TForm::ButtonClick(TObject *Sender)
{
throw EMyException("Error Message");
}

C++Builder Console application: linking to a __closure based method

First off, forgive me on the title. Not really sure how to ask this question:
I have an application that I need to convert to a console application (note the application runs fine as a VCL style windows app). The app uses a few 3rd party widgets that have callback functions. However, when I attempt to compile it, I get 'cannot convert ...' errors, like this:
Cannot convert 'void(Tobject *, TErrorEventParams *)' to 'TErrorEvent'
TErrorEvent is defined as:
typedef void __fastcall (__closure* TErrorEvent)(System::TObject* Sender, TErrorEventParams *e);
The line causing the error is:
handler->OnError = errorHandler;
The code for errorHandler is:
void __fastcall errorHandler(System::TObject* Sender, TErrorEventParams *e)
{
memoLine = e->Description;
updateLog();
}
A __closure type is a pointer to a non-static class method. The compiler does not allow you to assign a standalone non-class function where a __closure is expected. It requires a pointer to a method of a class object. Karem's answer shows you one way to accomplish that.
However, there IS a way to use a non-class function, using the helper TMethod struct (which is how a __closure is implemented behind the scenes).
First, add an explicit 'this' parameter to your event handler:
void __fastcall errorHandler(void *This, TObject* Sender, TErrorEventParams *e)
{
memoLine = e->Description;
updateLog();
}
And then assign the event handler like this:
TMethod m;
m.Code = &errorHandler
m.Data = NULL; // any value you want to pass to the 'This' parameter...
handler->OnError = reinterpret_cast<TErrorEvent&>(m);
Have a look at this documentation:
http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Closure
In short:
TErrorEvent is defined as a pointer to a class member function. So errorHandler has to be declared as a class member function.
The implementation could look somewhat like this:
class TMyClass
{
private:
TMyHandler* handler;
void __fastcall errorHandler(System::TObject* Sender, TErrorEventParams *e);
public:
__fastcall TMyClass();
} my_dummy_class;
__fastcall TMyClass::MyClass()
{
//handler has to be created
handler->OnError = errorHandler;
}
void __fastcall TMyClass::errorHandler(System::TObject* Sender, TErrorEventParams *e)
{
memoLine = e->Description;
updateLog();
}

Registering a custom CodeInsight manager to C++Builder without initialization/finalization sections

I'm trying to register a custom CodeInsight manager into C++Builder 10.1.2 Berlin.
Because there's nothing like Objects Pascal's initialization and finalization sections in C++, e.g.
var
codeManagerIndex: Integer;
{...}
initialization
codeManagerIndex := (BorlandIDEServices as IOTACodeInsightServices).AddCodeInsightManager(TMyCodeInsightManager.Create);
finalization
(borlandIDEServices as IOTACodeInsightServices).RemoveCodeInsightManager(codeManagerIndex);
end.
I tried reproducing their behavior with a custom runner class with constructor/destructor:
class Runner
{
public:
int FCodeManagerIndex;
_di_IOTACodeInsightServices CIS;
Runner() {
if (BorlandIDEServices->Supports(CIS))
FCodeManagerIndex = CIS->AddCodeInsightManager(new TMyCodeInsightManager);
}
~Runner() {
if (BorlandIDEServices->Supports(CIS))
CIS->RemoveCodeInsightManager(FCodeManagerIndex);
}
};
#pragma argsused
extern "C" int _libmain(unsigned long reason)
{
Runner Run;
return 1;
}
I can compile my simple implementation but when I try to install the package the following things are happening:
1st try: Error message: Can't load package ... mypackage.bpl - A dynamic link library (DLL) initialization routine failed.
2nd try: An exception (C0000005) occured during DllEntryPoint or DllMain in module: ... mypackage.bpl ... then the IDE crashes.
Is this a wrong way to register?
What am I doing wrong here?
P.S. I get a [TLIB Warning] Warning: library was too large for page size, rebuilt with page size 32 warning when compiling, but I'm quite sure that this can't be the reason for my errors. (?)
there's nothing like Objects Pascal's initialization and finalization sections in C++
Actually, there is. In C++Builder, you can use #pragma startup and #pragma exit to execute user-defined functions:
static int FCodeManagerIndex = -1;
void DoRegister() {
_di_IOTACodeInsightServices CIS;
if (BorlandIDEServices->Supports(CIS)) {
FCodeManagerIndex = CIS->AddCodeInsightManager(new TMyCodeInsightManager);
}
}
#pragma startup DoRegister
void DoUnregister() {
_di_IOTACodeInsightServices CIS;
if ((FCodeManagerIndex != -1) && BorlandIDEServices->Supports(CIS)) {
CIS->RemoveCodeInsightManager(FCodeManagerIndex);
}
}
#pragma exit DoUnregister
#pragma argsused
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
Alternatively, since you ready declared a class to handle your registration, you can simply move your class variable into global static memory so its constructor runs at startup and destructor runs at shutdown:
class Runner
{
public:
int FCodeManagerIndex;
Runner() : FCodeManagerIndex(-1) {
_di_IOTACodeInsightServices CIS;
if (BorlandIDEServices->Supports(CIS)) {
FCodeManagerIndex = CIS->AddCodeInsightManager(new TMyCodeInsightManager);
}
}
~Runner() {
_di_IOTACodeInsightServices CIS;
if ((FCodeManagerIndex != -1) && BorlandIDEServices->Supports(CIS)) {
CIS->RemoveCodeInsightManager(FCodeManagerIndex);
}
}
};
static Runner Run;
#pragma argsused
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
Declaring the class variable inside of _libmain() is useless since the destructor will be called when the variable goes out of scope when _libmain() exits, thus unregistering the manager immediately after registering it. So the variable has to survive for as long as the package is loaded in memory.

Problems with property editor in Embarcadero XE6

As usual, every new release of c++ builder takes days of changes...
I'm having trouble fixing a property editor, the code is:
***************** THE H FILE ****************************
//---------------------------------------------------------------------------
#ifndef ufrmLabelEditorH
#define ufrmLabelEditorH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.Buttons.hpp>
#include <Vcl.ExtCtrls.hpp>
#include <DesignIntf.hpp>
#include <TypInfo.hpp>
#include <DesignEditors.hpp>
#include <Classes.hpp>
// Add DesignIDE.bpi to your package's Requires list in the Project Manager
#pragma comment(lib, "DesignIDE.bpi")
//---------------------------------------------------------------------------
class TfrmLabelEditor : public TForm
{
__published: // IDE-managed Components
TPanel *Panel1;
TMemo *Memo1;
TBitBtn *BitBtn1;
TBitBtn *BitBtn2;
private: // User declarations
public: // User declarations
__fastcall TfrmLabelEditor(TComponent* Owner);
};
class PACKAGE TLabelProperty : public TStringProperty
{
public:
virtual Designintf::TPropertyAttributes __fastcall GetAttributes() {
return TStringProperty::GetAttributes()<<paDialog;
}
virtual void __fastcall Edit(void) {
TfrmLabelEditor *frmEditor = new TfrmLabelEditor(Application);
frmEditor->Memo1->Lines->Text = GetStrValue();
try {
if (frmEditor->ShowModal()==mrOk) {
int i;
for (i = 0; i < PropCount; i++) {
((TLabel*)GetComponent(i))->Caption = frmEditor->Memo1->Lines->Text;
}
Modified();
}
} catch (...) {
}
frmEditor->Free();
}
};
//---------------------------------------------------------------------------
extern PACKAGE TfrmLabelEditor *frmLabelEditor;
//---------------------------------------------------------------------------
#endif
************** THE CPP FILE *************************
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "ufrmLabelEditor.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmLabelEditor *frmLabelEditor;
//---------------------------------------------------------------------------
__fastcall TfrmLabelEditor::TfrmLabelEditor(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
namespace Labelproperty {
void __fastcall PACKAGE Register()
{
TTypeInfo* typeInfo = new TTypeInfo();
typeInfo->Name = "AnsiString";
typeInfo->Kind = tkLString;
Designintf::RegisterPropertyEditor(typeInfo,__classid(TfrmLabelEditor),"Caption", __classid(TLabelProperty));
TComponentClass classes[1] = {__classid(TfrmLabelEditor)};
RegisterComponents(L"SGM", classes, 0);
}
}
Both files are part of a design time only c++ package....
Any help? If not, please tell me about some c++ ide that realy works!!!!! THANKS.....
Your Register() function relies on an unnecessary hack to fake AnsiString RTTI. Not only that, but the VCL uses Unicode strings in XE6, so unless your Caption property is actually declared as AnsiString then your property editor will not register correctly.
Let the property itself provide the correct RTTI to you. The RegisterPropertyEditor() documentation even demonstrates this. This approach works in every version of C++Builder (and Delphi):
void __fastcall PACKAGE Register()
{
PPropInfo pProp = GetPropInfo(__typeinfo(TfrmLabelEditor), "Caption");
RegisterPropertyEditor(*(pProp->PropType), __classid(TfrmLabelEditor), "Caption", __classid(TLabelProperty));
TComponentClass classes[1] = {__classid(TfrmLabelEditor)};
RegisterComponents(L"SGM", classes, 0);
}
Update: That being said, this registration will never work, because you are setting the second parameter of RegisterPropertyEditor() to the wrong value.
TfrmLabelEditor is itself implemented and exists only in a design-time package. By setting the second parameter to TfrmLabelEditor, the Object Inspector will invoke TLabelProperty only when an instance of TfrmLabelEditor is active in the Form Designer and its Caption property is edited in the Object Inspector. But the Form Designer will never see instances of TfrmLabelEditor in projects, so the Object Inspector will never invoke your TLabelProperty editor. That is why you don't see anything happen.
Read the documentation more carefully. The second parameter specifies a specific runtime component type, or NULL for all component types, that have the specified property of the specified property type. TfrmLabelEditor does not qualify for that.
A little adaptation of REMY SOLUTION have worked, not sure why:
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TfrmLabelEditor)};
//********* register my editors ******************
PPropInfo PropInfo = GetPropInfo(__typeinfo(TForm), "Caption");
Designintf::RegisterPropertyEditor(*(PropInfo->PropType),NULL,"Caption", __classid(TLabelProperty));
//*************************************************
RegisterComponents(L"SGM", classes, 0);
}

Porting javascript to dart

I'd like to port this javascript code to dart.
function Beagle() {
this.argv_ = null;
this.io = null;
};
Beagle.prototype.run = function() {
this.io = this.argv_.io.push();
};
runCommandClass(Beagle);
the probleme is
How to create object Beagle
How to create prototype object Beagle.prototype.run
This kind of Js code (function definition and prototype changes) can be ported to a Dart class. You can follow these main rules :
function Xxxx(){/* js code to init */} (pseudo Js class) translates to :
class Xxxx {
/// constructor
Xxxx() {
/* Dart code to init */
}
}
when you have contructor parameters like in function Xxxx(param1, param2){/* js code to init */} you have to create an other constructor with those parameters :
class Xxxx {
/// constructor with parameters
Xxxx(param1, param2) {
/* Dart code to init with param1, param2 */
}
}
Xxxx.prototype.method1 = function(p1, p2, p3){/* js code for method */} are like methods that have to be translated to :
class Xxxx {
// .... other code
/// method
method1(p1, p2, p3) {
/* Dart code */
}
}
To make your code more clear you can also add type annotations on methods and constructors. This is recommanded by the Dart Style Guide.
Type annotations are important documentation for how a library should be used. Annotating the parameter and return types of public methods and functions helps users understand what the API expects and what it provides.
For instance :
class Xxxx {
/// constructor
Xxxx(String param1, int param2) {
/* Dart code to init with param1, param2 */
}
/// method
void method1(num p1, String p2, DateTime p3) {
/* Dart code */
}
}
class Beagle { //
Map argv_;
int io;
Map portInfo;
// could make sense to make this a constructor, that depends how the Terminal class uses it (didn't look)
void run(this.argv_) {
this.portInfo_ = JSON.parse(this.argv_['argString']); // not tested
io = argv_['io'].length;
}
void sendString_(String s) { // no idea what the underlines at the end of argv_, sendString_, ... are for
// ...
}
void onRead_(String s) {}
void onTerminalResize_(int width, int height) {}
void exit(code) {
// ...
}
void close() {
// ...
}
}
var b = new Beagle(); // not translated from the JS source - just added to show how to create a new object from the Beagle class
b.run(argvFromSomewhere);
This includes a some guessing about what the intention of the JavaScript code might be.
I prefer using specific types when porting from JavaScript. It helped me a lot finding bugs and understanding the intention. When I guessed the wrong type I get an exception at runtime, then I can reason about why I got an unexpected type and which of my assumptions were wrong.

Resources