Where to initialize child controls on TCustomControl - c++

I'm trying to create a simple custom control using Borland C++ Builder 6. In this case, I am trying to create a TPageControl with a single TTabSheet on it. I am having trouble figuring out the proper place to initialize these child controls. At the moment I am initializing everything in the constructor. Everything compiles fine, but when I attempt to place the control onto a form, the Borland IDE gives me an error "Control '' has no parent window" or something very similar. I've found out that the line that is causing this specifically is the setting of the TTabSheet's PageControl property.
The code for my control is below:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "TestControl.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
static inline void ValidCtrCheck(TTestControl *)
{
new TTestControl(NULL);
}
//---------------------------------------------------------------------------
__fastcall TTestControl::TTestControl(TComponent* Owner)
: TCustomControl(Owner)
{
pageControl = new TPageControl(this);
pageControl->Parent = this;
tabSheet = new TTabSheet(pageControl);
tabSheet->Parent = pageControl;
tabSheet->Caption = "Page 1";
tabSheet->PageControl = pageControl;
}
//---------------------------------------------------------------------------
__fastcall TTestControl::~TTestControl()
{
pageControl->Free();
}
//---------------------------------------------------------------------------
namespace Testcontrol
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TTestControl)};
RegisterComponents("Test", classes, 0);
}
}
//---------------------------------------------------------------------------
Any assistance would be much appreciated--I'm finding that due to the age of this particular technology I'm not having much luck finding resources on this.

Related

BEGIN_MESSAGE_MAP caused C++ Builder 10.1 to crash to desktop

I am writing a VCL componenet, TGIcon, to mimic the Icons in windows desktop, it has been working fine until I decided to add MouseEnter and MouseLeave events to the component. I followed guides from: Embarcadero Community
and here is my code (header):
class PACKAGE TGIcon : public TGraphicControl
{
private:
AnsiString FCaption;
TPngImage *FIcon, *FDIcon;
TFont *FFont;
TNotifyEvent FOnMouseEnter;
TNotifyEvent FOnMouseLeave;
void __fastcall CMMouseEnter(TMessage &Message);
void __fastcall CMMouseLeave(TMessage &Message);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGIcon)
protected:
virtual void __fastcall Paint();
void __fastcall SetCaption(AnsiString value);
void __fastcall SetIcon(TPngImage *value);
void __fastcall SetFont(TFont *value);
public:
__fastcall TGIcon(TComponent* Owner);
__fastcall ~TGIcon();
void __fastcall MakeGray(void);
__published:
__property AnsiString Caption = {read=FCaption, write=SetCaption, nodefault};
__property TPngImage *Icon = {read=FIcon, write=SetIcon};
__property TFont *Font = {read=FFont, write=SetFont};
__property Parent;
__property Enabled;
__property OnClick;
__property TNotifyEvent OnMouseEnter = {read=FOnMouseEnter, write=FOnMouseEnter};
__property TNotifyEvent OnMouseLeave = {read=FOnMouseLeave, write=FOnMouseLeave};
};
Whenever I try to place the component on a Form, the IDE (C++ Builder Starter) would crash to desktop. I have traced the source of problem to be the "BEGIN_MESSAGE_MAP...END_MESSAGE_MAP" part. If I comment out that part, the component works fine.
I used to have the same component working in C++Builder XE5 (Professional) but since that's owned by a company I no longer work with, I don't have the binary of the component, so I have to re-write it here. As far as I can remember, what I did is exactly the same as the one I wrote in XE5, that one works but this one would crash the IDE, no error message, no Access Violation, just plain CTD.
Can someone please help, is there anything I need to do to make this work in C++ Builder 10.1 (Berlin) Starter Edition? Is this a bug of C++Builder or is this what cannot be done in Starter Edition, that it only can be done in the 'paid' editions?? Or is this method already obsolete? If so please show me how the "modernized" C++ Builder do it.
Thanks in advance.
Your MESSAGE_MAP is terminated incorrectly. In the END_MESSAGE_MAP macro, you must specify the base class that your component derives from (TGraphicControl).
A MESSAGE_MAP is just a fancy way to override the virtual Dispatch() method, where:
BEGIN_MESSAGE_MAP declares and opens the overridden method, and opens a switch statement
MESSAGE_HANDLER (use VCL_MESSAGE_HANDLER instead if your project uses ATL) declares case statements for the switch
END_MESSAGE_MAP calls the Dispatch() method of the specified class for unhandled messages, closes the switch, and closes the overridden method.
Here are the declarations from sysmac.h:
#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, this code:
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGIcon) // <-- error!
Gets translated by the preprocessor to this code, which is what the compiler sees:
virtual void __fastcall Dispatch(void *Message)
{
switch (((PMessage)Message)->Msg)
{
case CM_MOUSEENTER:
CMMouseEnter(*((TMessage *)Message));
break;
case CM_MOUSELEAVE:
CMMouseLeave(*((TMessage *)Message));
break;
default:
TGIcon::Dispatch(Message); // <-- recursive loop!
break;
}
}
As you can see, since you are specifying your own component class (TGIcon) instead of the base class (TGraphicControl) in END_MESSAGE_MAP, you are creating an endless recursion loop when the component receives an unhandled message. TGIcon::Dispatch() is calling TGIcon::Dispatch() again. It needs to call TGraphicControl::Dispatch() instead (so do your CMMouseEnter() and CMMouseLeave() methods):
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGraphicControl) // <-- fixed!

How to initialize an instance of IVectorView for C++/WRL?

I'm trying to call get_Skus() method of IStoreProduct to retrieve its Skus property using C++/WRL (not C++/CX) and I can't find any suitable code examples. That method is defined as such (as I get it from the header file in Visual Studio):
virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Skus(
/* [out][retval] */ __RPC__deref_out_opt IVectorView<ABI::Windows::Services::Store::StoreSku*> **value) = 0;
So when I try to do:
#include <Windows.Services.Store.h>
#include <wrl.h>
using namespace ABI::Windows::Services::Store;
using namespace ABI::Windows::Foundation::Collections;
IVectorView<StoreSku*> pStrSkus;
//IStoreProduct* pStorePrdct = ...;
if (SUCCEEDED(pStorePrdct->get_Skus(&pStrSkus)))
{
}
it gives me an error that:
'ABI::Windows::Foundation::Collections::IVectorView'
: cannot instantiate abstract class
I'm relatively new to WRL. Can someone show me how am I supposed to call that method?
You forgot a star - it should have been this:
IVectorView<StoreSku*>* pStrSkus;
if (SUCCEEDED(pStorePrdct->get_Skus(&pStrSkus)))
{
...
pStrSkus->Release();
}
Even better, use a ComPtr instead, so you don't have to release it manually:
ComPtr<IVectorView<StoreSku*>> pStrSkus;
if (SUCCEEDED(pStorePrdct->get_Skus(&pStrSkus)))
{
...
}

Difference between bcc32 and bcc32c object lifetime

I have a cross platform C++ application build with C++ Builder 10.1 Berlin and have a problem understanding the lifetime handling of objects, in this case strings, wich are declared outside the class.
I have created a new forms application and added some code. The cpp file looks like this:
#include
#pragma hdrstop
#include "FmrMain.h"
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;
const String Hello = "Hello";
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ShowMessage(Hello);
}
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
ShowMessage(Hello);
}
I compile this with the CLANG enhanced C++11 compiler bcc32c, run the application and close the form again. When TForm1::FormDestroy is called Hello is allready destroyed. When I compile the code for win32 with the classic compiler bcc32 the string is destroyed after FormDestroy.
Can someone explain this or provide some information about the topics I have to look for? Why is the CLANG based compiler behaving different here?
Edit
It's easier to debug when I use a self defined class instead of a string.
class Foo {
public:
Foo(){};
~Foo(){}
};
Foo A;
//--------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//--------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
}
The creation and destruction oder is like this. I have added the call stacks.
bcc32c (CLANG C++11 compiler)
create Foo
:004052C0 Foo(this=:00400000)
:00405070 __cxx_global_var_init3()
:004052A3 _GLOBAL__I_a()
:00405ab7 ; ~Foo
:321fa2b7 ; C:\Program Files (x86)\Embarcadero\Studio\18.0\bin\CC32C240MT.DLL
:321fa6ff CC32C240MT.__wstartup + 0xbb
create Form1
:004052EC TForm1(this=:00402422, __ctor_flag='\0')
:0085c139 fmx240.#Fmx#Forms#TApplication#CreateForm$qqrxp17System#TMetaClasspv + 0x5d
:0085c349 fmx240.#Fmx#Forms#TApplication#RealCreateForms$qqrv + 0x81
destroy Foo
:004052D0 ~Foo(this=:0040B7DC)
:0040509E __dtor_A()
:321f6246 CC32C240MT.___call_atexit_procs + 0x52
:321f671c CC32C240MT.___exit + 0x20
destroy Form1
:00405868 ~TForm1(this=:5016E698)
bcc32 (Classic borland compiler)
create Foo
:00404950 Foo::Foo(this=:00409B74)
:004048A0 STCON0()
:00405727 ; IRoot
:322190f1 ; C:\Program Files (x86)\Embarcadero\Studio\18.0\bin\CC32240MT.DLL > :322193b5 CC32240MT.__wstartup + 0xa5
create Form1
:00404994 TForm1::TForm1(this=:02F2AE20, Owner=:02F39620)
:0095c139 fmx240.#Fmx#Forms#TApplication#CreateForm$qqrxp17System#TMetaClasspv +
0x5d
:0095c349 fmx240.#Fmx#Forms#TApplication#RealCreateForms$qqrv + 0x81
destroy Form1
:00404ABC TForm1::~TForm1(this=:02F2AE20)
destroy Foo
:00404978 Foo::~Foo(this=:00409B74)
:0040493F STDES0()
:0040573f ;IRoot>
:3221910f ; C:\Program Files(x86)\Embarcadero\Studio\18.0\bin\CC32240MT.DLL
:3221915b ; C:\Program Files (x86)\Embarcadero\Studio\18.0\bin\CC32240MT.DLL > :3221944a ; C:\Program Files (x86)\Embarcadero\Studio\18.0\bin\CC32240MT.DLL
Auto-created TForm objects are owned by the global TApplication object. That object is destroyed (thus destroying its owned Forms) after the application's main()/wmain()/WinMain() entry point function has exited. Globals are destroyed during application cleanup.
The lifetime of your global String is not guaranteed to outlive the lifetime of the global TApplication object, in either compiler. You are relying on undefined behavior based on the cleanup order of globals across different units. And worse, you are relying on the cleanup order across different frameworks! Your String is in your own C++ code, but the TApplication object is in the Delphi-based RTL library.
If your String needs to remain alive for the lifetime of the TForm that uses it, you should declare it as a static member of that class instead:
FmrMain.h:
//---------------------------------------------------------------------------
#ifndef FmrMainH
#define FmrMainH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
private: // User declarations
static const String Hello;
public: // User declarations
__fastcall TForm1(TComponent* Owner);
__fastcall ~TForm1();
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
FmrMain.cpp:
//---------------------------------------------------------------------------
#include <fmx.h>
#pragma hdrstop
#include "FmrMain.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;
const String TForm1::Hello = "Hello";
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ShowMessage(Hello);
}
void __fastcall TForm1::~TForm1()
{
ShowMessage(Hello);
}
//---------------------------------------------------------------------------
Alternatively, use a wchar_t* instead of a String, then you don't run into any cleanup issues:
//---------------------------------------------------------------------------
#include <fmx.h>
#pragma hdrstop
#include "FmrMain.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;
static const wchar_t* Hello = L"Hello";
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ShowMessage(Hello);
}
void __fastcall TForm1::~TForm1()
{
ShowMessage(Hello);
}
//---------------------------------------------------------------------------

Problems creating a unmanaged regular MFC DLL and call it from an managed C++ .NET app

I have a few questions about DLL's. I tried a lot but I can not get the complete picture. Most examples are in C# etc.
With the wizard in VS2005 I created a unmanaged MFC regular DLL (must be MFC because of remaining code). Then I tried to import it in a VS2005 managed .NET C++ application. See code below.
mfc_main.h:
//---------------------------------------------------------
// mfc_main.h : main header file for the mfc_main DLL
//---------------------------------------------------------
#pragma once
#ifndef __AFXWIN_H__
#error "include 'stdafx.h' before including this file for PCH"
#endif
#include "resource.h" // main symbols
class __declspec(dllexport) Cmfc_mainApp : public CWinApp
{
public:
Cmfc_mainApp();
// Overrides
public:
virtual BOOL InitInstance();
int SayHello(int j);
int init;
DECLARE_MESSAGE_MAP()
};
mfc_main.cpp:
//----------------------------------------------------------------
// mfc_main.cpp : Defines the initialization routines for the DLL.
//----------------------------------------------------------------
#include "stdafx.h"
#include "mfc_main.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
BEGIN_MESSAGE_MAP(Cmfc_mainApp, CWinApp)
END_MESSAGE_MAP()
Cmfc_mainApp::Cmfc_mainApp()
{
}
Cmfc_mainApp theApp;
BOOL Cmfc_mainApp::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
int Cmfc_mainApp::SayHello(int j)
{
init = 12; // Comment this out the application works !!!!
return j * 6;
};
in application
[DllImport("mfc_main.dll",
EntryPoint = "?SayHello#Cmfc_mainApp##QAEHH#Z",
ExactSpelling = true)]
static int SayHello(int a);
......
private: System::Void button_Click(System::Object^ sender, System::EventArgs^ e)
{
int retval = SayHello(2);
}
My questions are:
1 - Why is it working without the init = 12 in the function SayHello and with the application crashes (error: Attempted to read or write protected memory)?
2 - Is in this case the InitInstance() executed although I don't call it (and why is there no ExitInstance)?
3 - Why do I see some examples giving the EntryPoint when using DLLImport and some don't?
4 - Can I give a delegate as parameter to a function in a MFC C++ DLL instead of a normal function pointer, to create a callback?
Methods cannot be P/Invoked. If you want to export a class from unmanaged DLL to be used in managed world, you have to flatten it, eg.
Create a constructor function, which looks like:
__declspec(dllexport) void * __stdcall MyClass_Create()
{
return new MyClass();
}
Create a destructor function, which looks like:
__declspec(dllexport) void * __stdcall MyClass_Destroy(MyClass * instance)
{
delete instance;
}
Flatten method calls. Let's suppose, that you have the following method in your class:
int MyClass::MyMethod(int i, double j) { ... }
Then you have to create a following function:
__declspec(dllexport) int __stdcall MyClass_MyMethod(MyClass * instance, int i, double j)
{
return instance->MyMethod(i, j);
}
Prepare P/Invoked external methods in C# (You already know how to do it, so I'll omit these)
Create instance of your class:
IntPtr instance = MyClass_Create();
Then call its method:
int i = MyClass_MyMethod(instance, 4, 2.0);
Finally, destroy the class:
MyClass_Destroy(instance);
Don't forget to add some error checking - I omitted it to keep the example clear.

C++ Builder XE2: Color2RGB not found

The documentation for the function TGIFColor Color2RGB(TColor) should be in the Vcl.Imaging.GIFImg.hpp source file. But when I try to use it I get the error Call to undefined function 'Color2RGB'. Here is a short example:
//---------------------------------------------------------------------------
#include <Vcl.Imaging.GIFImg.hpp>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma package(smart_init)
TGIFColor TestRGB(TColor fColor) {
TGIFColor RGBColor = Color2RGB(fColor);
return RGBColor;
}
Can anyone explain how to call this function, because the documentation doesn't!?
// Thanks
PS. I did started the question with "Hello, " but even when I edit the question it is removed :(
Read the documentation again more carefully. Color2RGB() is not a standalone function like you are trying to use it as. It is a static method of the TGIFColorMap class instead, eg:
TGIFColor TestRGB(TColor fColor)
{
TGIFColor RGBColor = TGIFColorMap::Color2RGB(fColor);
return RGBColor;
}