Deleting dynamically created component? - c++builder

In the OnCreate event, I have code which adds menu items to a std::vector (for the purposes of this question, it could be buttons, or any other components we create dynamically with the new operator):
// Iterrate through styles and hints and construct menu
for (int i=0; i<styleNamesAndHints->Count; i++) {
TMenuItem* miTheme = new TMenuItem(miRoot);
miTheme->Caption = styleNamesAndHints->Strings[i].SubString(0, styleNamesAndHints->Strings[i].Pos(styleNamesAndHints_Delimeter)-1);
miTheme->AutoCheck = false;
miTheme->AutoHotkeys = maManual;
miTheme->RadioItem = false;
miTheme->GroupIndex = MENU_GROUP_INDEX_STYLES;
miTheme->OnClick = &miStyles_Click;
miTheme->OnDrawItem = &miStyles_DrawItem;
miTheme->OnMeasureItem = &miStyles_MeasureItem;
miTheme->ImageIndex = IL_MENU_A_THEME;
miTheme->Tag = miStyleArray.size();
miStyleArray.push_back(miTheme);
miRoot->Add(miTheme);
}
Then in the OnDestroy event, we clean up the vector miStyleArray:
// Clean up miStyleArray vector, delete each element
while(miStyleArray.empty()==false) {
delete miStyleArray.back();
miStyleArray.pop_back();
}
This code works... I have no errors, everything works perfectly....
Now, someone told me that code like this could lead to errors and that, I quote, I should not use operator delete on objects that have parent, parent of the object is responsible for destroying and clean up..
As a matter of fact, the person that told me this is a moderator at a C++Builder forum, and warned me that I could be banned next time for such code! Here is the post link.
Who is right, who is wrong??

It is perfectly safe to manually delete a component instance that has an Owner or Parent assigned. The component's destructor will remove the instance from its Owner/Parent's internal list so the instance is not freed a 2nd time.
On the other hand, a component instance with an Owner assigned does not need to be delete'd manually, it will be freed when its Owner is freed, so your OnDestroy code is redundant and can be removed.
On a side note: you should NOT use the Form's OnCreate and OnDestroy events in C++Builder. They are a Delphi idiom that can lead to undefined behavior in C++ if you are not careful. OnCreate can fire before your Form's constructor, and OnDestroy can fire after your Form's destructor. As such, you should use the Form's actual constructor and destructor instead.

Related

Assigning IHTMLDocument2 instance to a TWebBrowser instance

I am using an instance of the IHTMLDocument2 interface to parse some HTML as described in this post:
Load from IPersistMoniker takes long time to load unresolvable URL
The code is relatively simple:
DelphiInterface<IHTMLDocument2> diDoc2;
HRESULT hr = CoCreateInstance(CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER, IID_IHTMLDocument2, (LPVOID*)&diDoc2);
// Load and process HTML here and save into memory stream or to disk after the processing is done
When I am done I save the HTML contents of the newly modified diDoc2 above and load the HTML into TWebBrowser.
Can I instead just "assign" the already parsed IHTMLDocument2 above directly to the IHTMLDocument2 contained in the TWebBrowser, which seems would be much faster way of doing it. I can use probably IHTMLDocument2.write or some other method to do so, but there would be likely some performance penalty than simply assigning a pointer to already initialized object, if that is possible in the first place. In other words, I simply want to "show"/"render" what I have just parsed in the "back buffer" of sort.
Is there a need to call CoInitialize and CoUninitialize before and after calling CoCreateInstance? I've seen some code which does that but it works without it, unless Delphi/C++ Builder do some under-the-hood initialization.
I used IHTMLDocument2.write and it appears to work well.
WideString HTML = "<html><body>test</body></html>";
if (diDoc)
{
// Creates a new one-dimensional array
SAFEARRAY *psaStrings = SafeArrayCreateVector(VT_VARIANT,0,1);
if (psaStrings)
{
VARIANT *param;
BSTR bstr = SysAllocString(HTML.c_bstr());
SafeArrayAccessData(psaStrings, (LPVOID*)&param);
param->vt = VT_BSTR;
param->bstrVal = bstr;
SafeArrayUnaccessData(psaStrings);
diDoc->write(psaStrings);
diDoc->close();
// SafeArrayDestroy calls SysFreeString for each BSTR
//SysFreeString(bstr); // SafeArrayDestroy should be enough
SafeArrayDestroy(psaStrings);
return S_OK;
}
}
return E_FAIL;

How to find if an IHTMLDocument2 is equal to IDispatch document in Delphi?

I have a TEmbeddedWB (https://sourceforge.net/projects/embeddedwb/) with an iFrame in it. I have to find out that a specific HTML Tag is inside that iFrame or not. My iFrame object is a IHTMLFrameBase2, while the Tag is a IHTMLElement. I know that the iFrame.contentWindow.document (which is a IHTMLDocument2) is the same as Tag.document. But the Tag.document is an IDispatch object, therefore the following gives a false:
if iFrame.contentWindow.document = Tag.document then ShowMessage('In iFrame')
else ShowMessage('Not in iFrame');
I know that the two object is the same, because the Watch List can show their memory address:
But I can't get their addresses from code. What I've tried:
Addr(iFrame.contentWindow.document) // Gives variable required error
#iFrame.contentWindow.document // Gives variable required error
Pointer(iFrame.contentWindow.document) //Compiles, but gives wrong address
Format('%p',[iFrame.contentWindow.document]) //Compiles, but gives EConvertError
Note: If I run line-by-line the addresses that the Watch List is showing change after EVERY line of code, no matter the code affects the WebBrowser or not.
From the rules of COM:
It is required that any call to QueryInterface on any interface for a given object instance for the specific interface IUnknown must always return the same physical pointer value. This enables calling QueryInterface(IID_IUnknown, ...) on any two interfaces and comparing the results to determine whether they point to the same instance of an object (the same COM object identity).
So, ask them both for their IUnknown interface, and compare.
var
disp: IDispatch;
doc: IHTMLDocument2;
....
if (disp as IUnknown) = (doc as IUnknown) then
....

Control has no parent window

I've checked out many threads of a similar title but they haven't helped.
The following compiles and installs to the component palette, but when I try to add the component to a panel, I get the error message mentioned in the thread title.
Could anyone please explain why?
__fastcall TEditBox::TEditBox(TComponent* Owner) : TGroupBox(Owner)
{
ToolBar=new TToolBar(this);
ToolBar->Parent=this;
TToolButton *Btn=new TToolButton(ToolBar);
Btn->Parent=ToolBar;
}
If I omit the Btn->Parent=ToolBar line, everything's OK, so presumably that's the problem line?
Assigning a ToolButton's Parent requires the ToolBar to have an allocated HWND, which requires it to have a Parent with an allocated HWND, and so on. But your EditBox does not have a Parent (or a Name) assigned yet when its constructor is called, so the ToolBar cannot allocate an HWND yet, hence the error.
If you want your Toolbar to have a default button at runtime, you need to move the creation of the button to the EditBox's virtual Loaded() method (or even the SetParent() method), eg:
__fastcall TEditBox::TEditBox(TComponent* Owner)
: TGroupBox(Owner)
{
ToolBar=new TToolBar(this);
ToolBar->Parent=this;
}
void __fastcall TEditBox::Loaded()
{
TGroupBox::Loaded();
TToolButton *Btn=new TToolButton(ToolBar);
Btn->Parent=ToolBar;
}

How do I set the provider for a TPushEvent?

I have a TPushEvent and TKinveyProvider declared on my firemonkey form
I'm trying to manually set the value of the Provider in code. I realize that by default when you drop those controls on a form the the PushEvent's Provider property is automatically set to the TKinveyProvider. However, I'm working around an apparent bug and I'd like set it later.
Am I setting the provider property correctly in this snippet?
//In my form class
//...
myPushEvents: TPushEvents;
myKinveyProvider: TKinveyProvider;
//later on in one of my procedures/methods
//...
myPushEvents.Provider := myKinveyProvider;
When I look a the value else later on after it should have been set, it still appears to be nil.
Provider appears to be defined as a IBackendProvider which is an interface and I'm not sure if I have to assign it its provider differently than I would with a simple data type like an Integer or a String.
Yes, this is the right way to do it.
myPushEvents.Provider := myKinveyProvider
In this cases myPushEvents.Provider is being assigned a reference to myKinveyProvider. You don't have to do any special casting because myPushEvents.Provider expects something that conforms to the IBackendProvider interfcase, and myKinveyProvider (a TKinveyProvider) does.
Note: In my specific case, thanks to myPushEvents.Provider being set as the result of a timer finishing, it was indeed still nil.
Adding an
if (myPushEvents.Provider <> nil) then
begin
// ... use myPushEvents.Provider
end;
protected the usage of it until the value had been set properly after the timer ran.

How does FreeNotification work?

Currently, I am trying to understand Delphi's VCL, specifically, the notification mechanism (which is a great mechanism in my point of view).
When I was studying on this subject, I remembered of the TLabeledEdit, of course I have been using it for long time, but I never had chance to stop and study it's code.
As I understand so far:
When a TComponent is destroyed:
It will notify all its children's components, to include csDestroying in its state.
FreeNotifiers part. I can't understand.
Will iterate the components list and:
Remove each item from the components list
Actually destroy each component instance.
When a child component is being destroyed, it restarts the same process for all of its children components. So, as far as I can tell, this is a chain effect.
What I can't understand is the FreeNotification, what could I possibly do with it?
Let's think about the TLabeledEdit in first place. The relevant part of the notification, in TLabeledEdit's code is an override on the Notification function, with the following code:
if (AComponent = FEditLabel) and (Operation = opRemove) then
FEditLabel := nil;
What could have happened if FreeNotification was not used?
In General, what benefits would I have because of this mechanism and what am I not seeing that might eventually make its existence necessary?
What the FreeNotification mechanism does is notifies registered components that this component is being freed. They then use their Notification method to ensure that they don't hold any references to it (which is what your example is doing) so that they don't end up with dangling references to an invalid object.
The point of FreeNotification is to allow you to clean up references to form children in cases where these components close and free themselves. In this example I use a Modal form, the FreeNotification sets the reference to NULL which allows me to detect if the form is still open or already exists if the user creates another one
void __fastcall TForm1::OpenForm(TObject *Sender)
{
frmGetPrint = new TfrmGetPrint(Application);
frmGetPrint->FreeNotification( this);
frmGetPrint->Show();
}
frmGetPrint must free itself when closed:
void __fastcall TfrmSetPrint::FormClose(TObject *Sender, TCloseAction &Action)
{
Action = caFree;
}
You need to create a function in the parent form referred to by this in the call to FreeNotification( this), in this case Form1
void __fastcall TForm1::Notification(Classes::TComponent* AComponent,
Classes::TOperation Operation)
{
if( AComponent == frmGetPrint && Operation == opRemove)
frmGetPrint = NULL;
}

Resources