Delphi toolbar OnClose

Delphi toolbar OnClose

Anonymous
Not applicable
412 Views
10 Replies
Message 1 of 11

Delphi toolbar OnClose

Anonymous
Not applicable
Hello.

I have created a Delphi toolbar that gets loaded in AutoCAD address
space via GetInterfaceObject. The toolbar is working without problem
with AutoCAD 14.01. I am running tests with AutoCAD 2000 and am getting
(among a lot other) an error after the OnClose and before the OnDestroy
handlers. I am using Delphi 4.

AutoCAD disapears and shows the following error: "ERROR FATAL: Unhandled
Access Violation Reading Oxffffffff Exception at 53b31ch".

From my point of view, this is a "dangled" pointer in AutoCAD 2000.

I am getting angry with AutoCAD 2000, the object model was changed for
good, but there are other changes that are not documented and that are
pointless. Hope to be patient enough.

Thanks for any help, Pablo.
0 Likes
413 Views
10 Replies
Replies (10)
Message 2 of 11

Anonymous
Not applicable
What kind of Toolbar is this (e.g., what VCL component
does it descend from)? Are you docking the toolbar to
something?

"P. F. Dueñas" wrote:
>
> Hello.
>
> I have created a Delphi toolbar that gets loaded in AutoCAD address
> space via GetInterfaceObject. The toolbar is working without problem
> with AutoCAD 14.01. I am running tests with AutoCAD 2000 and am getting
> (among a lot other) an error after the OnClose and before the OnDestroy
> handlers. I am using Delphi 4.
>
> AutoCAD disapears and shows the following error: "ERROR FATAL: Unhandled
> Access Violation Reading Oxffffffff Exception at 53b31ch".
>
> From my point of view, this is a "dangled" pointer in AutoCAD 2000.
>
> I am getting angry with AutoCAD 2000, the object model was changed for
> good, but there are other changes that are not documented and that are
> pointless. Hope to be patient enough.
>
> Thanks for any help, Pablo.

--

Checkout the AcadX(tm) ActiveX Extension Library at:

http://www.caddzone.com/acadx/acadx.htm

/*********************************************************/
/* Tony Tanzillo Design Automation Consulting */
/* Programming & Customization for AutoCAD & Compatibles */
/* ----------------------------------------------------- */
/* tony.tanzillo@worldnet.att.net */
/* http://www.caddzone.com */
/*********************************************************/
0 Likes
Message 3 of 11

Anonymous
Not applicable
It is a descendant of TForm. Relevant settings are:

HorzScrollBar.Visible = False
VertScrollBar.Visible = False
ActiveControl = tbToolbar
BorderIcons = [biSystemMenu, biMinimize]
BorderStyle = bsToolWindow
KeyPreview = True
OldCreateOrder = True
OnClose = FormClose
OnCreate = FormCreate
OnDestroy = FormDestroy
OnKeyDown = FormKeyDown

The controls it has are descendants of standard controls: TCoolbar,
TToolbar, TToolButton, TPanel, TTreeView, TImageList, TPopupMenu,
TMenuItem, TGroupBox, TLabel, TRadioButton, TComboBox...

I am not docking the toolbar to anything. I have tried disabling all the
extra code and showing only the form. The results are the same.

Tony Tanzillo wrote:
>
> What kind of Toolbar is this (e.g., what VCL component
> does it descend from)? Are you docking the toolbar to
> something?
>
0 Likes
Message 4 of 11

Anonymous
Not applicable
I have plenty of TForm descendents working correctly
in AutoCAD 2000. Are you setting the Application.Handle
property to something (like the AutoCAD main window)?

"P. F. Dueñas" wrote:
>
> It is a descendant of TForm. Relevant settings are:
>
> HorzScrollBar.Visible = False
> VertScrollBar.Visible = False
> ActiveControl = tbToolbar
> BorderIcons = [biSystemMenu, biMinimize]
> BorderStyle = bsToolWindow
> KeyPreview = True
> OldCreateOrder = True
> OnClose = FormClose
> OnCreate = FormCreate
> OnDestroy = FormDestroy
> OnKeyDown = FormKeyDown
>
> The controls it has are descendants of standard controls: TCoolbar,
> TToolbar, TToolButton, TPanel, TTreeView, TImageList, TPopupMenu,
> TMenuItem, TGroupBox, TLabel, TRadioButton, TComboBox...
>
> I am not docking the toolbar to anything. I have tried disabling all the
> extra code and showing only the form. The results are the same.
>
> Tony Tanzillo wrote:
> >
> > What kind of Toolbar is this (e.g., what VCL component
> > does it descend from)? Are you docking the toolbar to
> > something?
> >

--

Checkout the AcadX(tm) ActiveX Extension Library at:

http://www.caddzone.com/acadx/acadx.htm

/*********************************************************/
/* Tony Tanzillo Design Automation Consulting */
/* Programming & Customization for AutoCAD & Compatibles */
/* ----------------------------------------------------- */
/* tony.tanzillo@worldnet.att.net */
/* http://www.caddzone.com */
/*********************************************************/
0 Likes
Message 5 of 11

Anonymous
Not applicable
Thanks for your answer.
Yes and no. I have tried both ways with the same result. Now what I do
is only to hide the window and let AutoCAD to unload the Dll. Any way
the OnDestroy event of the form is called and I can perform clean up.
But if I close the window myself, the error appears.

Thanks a lot, pablo.

Tony Tanzillo wrote:
>
> I have plenty of TForm descendents working correctly
> in AutoCAD 2000. Are you setting the Application.Handle
> property to something (like the AutoCAD main window)?
0 Likes
Message 6 of 11

Anonymous
Not applicable
Can you show me how you are creating the form?

"P. F. Dueñas" wrote:
>
> Thanks for your answer.
> Yes and no. I have tried both ways with the same result. Now what I do
> is only to hide the window and let AutoCAD to unload the Dll. Any way
> the OnDestroy event of the form is called and I can perform clean up.
> But if I close the window myself, the error appears.
>
> Thanks a lot, pablo.
>
> Tony Tanzillo wrote:
> >
> > I have plenty of TForm descendents working correctly
> > in AutoCAD 2000. Are you setting the Application.Handle
> > property to something (like the AutoCAD main window)?

--

Checkout the AcadX(tm) ActiveX Extension Library at:

http://www.caddzone.com/acadx/acadx.htm

/*********************************************************/
/* Tony Tanzillo Design Automation Consulting */
/* Programming & Customization for AutoCAD & Compatibles */
/* ----------------------------------------------------- */
/* tony.tanzillo@worldnet.att.net */
/* http://www.caddzone.com */
/*********************************************************/
0 Likes
Message 7 of 11

Anonymous
Not applicable
Yes, there is an exe file that registers the Dll, and calls the server:
// Get Server interface:
vServer := acAcad.GetInterfaceObject(cServer);
acRelease; // Not needed AutoCAD any more.
g_Server := IDispatch(vServer) as SenmutCom;
where vServer is an OleVariant, acAcad returns the AcadApplication
interface, and acRelease releases the interface.

Next, the server is called:
// Call Server's Execute method:
if Assigned(g_Server) then
g_Server.Execute(Integer(Application.Handle));
The handle that is passed is to send messages to the client exe.

This is the server Execute method:
procedure TSCom.Execute(CallerHW: Integer);
begin
// Use ever the handle of last invocation:
g_CallerHW := HWnd(CallerHW);
Forms.Application.Handle := acDrawingWnd;
if IsIconic(acDrawingWnd) then
ShowWindow(acDrawingWnd, SW_RESTORE);
SetForegroundWindow(acDrawingWnd);
SetActiveWindow(acDrawingWnd);
// Allow only one instance of the toolbar:
if not Assigned(fmToolbar) then
Application.CreateForm(TfmToolbar, fmToolbar);
fmToolbar.Show;
end;

And that's all, I have tried without assigning the Handle of AutoCAD
window and the result is the same.

Thanks for your help, Pablo.

Tony Tanzillo wrote:
>
> Can you show me how you are creating the form?
0 Likes
Message 8 of 11

Anonymous
Not applicable
I'm really not sure if you should be using
Application.CreateForm in a DLL. I've never
done that, because it makes the Application
object the owner of the form.

You might want to try declaring an instance
of the form as a private member of your COM
server, and then override the server's
Initialize() method to create the form, and
override Destroy() to delete the form.

Here's a simple COM server that creates a
form and displays it. When the server is
unloaded, the form is destroyed:

//--------------------------------------
unit Unit1;

interface

uses
ComObj, ActiveX, AcForm_TLB, StdVcl, Unit2;

type
TIPForm = class(TAutoObject, IIPForm)
private
FForm1: TForm1; // TForm1 is in Unit2.pas
protected
procedure Hide; safecall;
procedure Show; safecall;
procedure ShowModal; safecall;
public
procedure Initialize; override;
destructor Destroy; override;
end;

implementation

uses ComServ;

procedure TIPForm.Initialize;
begin
inherited;
FForm1 := TForm1.Create(nil); // <- FForm1 has no owner
end;

destructor TIPForm.Destroy;
begin
FForm1.Free;
inherited;
end;

procedure TIPForm.Hide;
begin
FForm1.Hide;
end;

procedure TIPForm.Show;
begin
FForm1.Show;
end;

procedure TIPForm.ShowModal;
begin
FForm1.ShowModal;
end;

initialization
TAutoObjectFactory.Create(ComServer, TIPForm, Class_IPForm,
ciMultiInstance, tmApartment);
end.

//----------------------------------------------------

"P. F. Dueñas" wrote:
>
> Yes, there is an exe file that registers the Dll, and calls the server:
> // Get Server interface:
> vServer := acAcad.GetInterfaceObject(cServer);
> acRelease; // Not needed AutoCAD any more.
> g_Server := IDispatch(vServer) as SenmutCom;
> where vServer is an OleVariant, acAcad returns the AcadApplication
> interface, and acRelease releases the interface.
>
> Next, the server is called:
> // Call Server's Execute method:
> if Assigned(g_Server) then
> g_Server.Execute(Integer(Application.Handle));
> The handle that is passed is to send messages to the client exe.
>
> This is the server Execute method:
> procedure TSCom.Execute(CallerHW: Integer);
> begin
> // Use ever the handle of last invocation:
> g_CallerHW := HWnd(CallerHW);
> Forms.Application.Handle := acDrawingWnd;
> if IsIconic(acDrawingWnd) then
> ShowWindow(acDrawingWnd, SW_RESTORE);
> SetForegroundWindow(acDrawingWnd);
> SetActiveWindow(acDrawingWnd);
> // Allow only one instance of the toolbar:
> if not Assigned(fmToolbar) then
> Application.CreateForm(TfmToolbar, fmToolbar);
> fmToolbar.Show;
> end;
>
> And that's all, I have tried without assigning the Handle of AutoCAD
> window and the result is the same.
>
> Thanks for your help, Pablo.
>
> Tony Tanzillo wrote:
> >
> > Can you show me how you are creating the form?

--

Checkout the AcadX(tm) ActiveX Extension Library at:

http://www.caddzone.com/acadx/acadx.htm

/*********************************************************/
/* Tony Tanzillo Design Automation Consulting */
/* Programming & Customization for AutoCAD & Compatibles */
/* ----------------------------------------------------- */
/* tony.tanzillo@worldnet.att.net */
/* http://www.caddzone.com */
/*********************************************************/
0 Likes
Message 9 of 11

Anonymous
Not applicable
Thanks for your help.

Don't remember what the documentation about Forms in Dlls says, I am
very tired of fighting with AutoCAD 2000 ActiveX bugs. I have another
question at the end of this message, if you don't mind.

What I can do is this code for the Execute method:

procedure TSCom.Execute(CallerHW: Integer);
begin
g_CallerHW := HWnd(CallerHW);
Forms.Application.Handle := acDrawingWnd;
if IsIconic(acDrawingWnd) then
ShowWindow(acDrawingWnd, SW_RESTORE);
SetForegroundWindow(acDrawingWnd);
SetActiveWindow(acDrawingWnd);
// Allow only one instance of the toolbar:
if not Assigned(fmSToolbar) then
fmSToolbar := TfmSToolbar.Create(nil) ;
fmSToolbar.Show;
end;

and this for the Close method (in the server):

procedure TSCom.Close;
begin
g_CallerHW := 0;
if Assigned(fmSToolbar) then
fmSToolbar.Free;
end;

- - - - - - - - - - - - -

I think your code is much better. Don't needed to close the form. When
the server is released, the form is freed automatically. Let me check it
next week, ok?

I think that GetInterfaceObject treats modules as demand load Dlls and I
cannot close the form, but AutoCAD needs to do it itself. You only close
your forms in the Destroy event that is called when AutoCAD unloads the
Dll, don't you? Well, your help is excellent.

- - - - - - - - - - - - -

I have another question. AutoCAD 2000 is returning the same error
message when the user pressed a keyword and Enter. So, from Delphi, how
do you know what the user did?

Thanks a lot, Pablo.

Tony Tanzillo wrote:
>
> I'm really not sure if you should be using
> Application.CreateForm in a DLL. I've never
> done that, because it makes the Application
> object the owner of the form.
0 Likes
Message 10 of 11

Anonymous
Not applicable
In your form's OnClose event, set the CloseAction
paramter to caHide, and this will prevent the form
from destroying itself when it's closed.

Regarding the InitGet problem, if the user presses
ENTER, the GetInput() method should return an empty
string.

"P. F. Dueñas" wrote:
>
> Thanks for your help.
>
> Don't remember what the documentation about Forms in Dlls says, I am
> very tired of fighting with AutoCAD 2000 ActiveX bugs. I have another
> question at the end of this message, if you don't mind.
>
> What I can do is this code for the Execute method:
>
> procedure TSCom.Execute(CallerHW: Integer);
> begin
> g_CallerHW := HWnd(CallerHW);
> Forms.Application.Handle := acDrawingWnd;
> if IsIconic(acDrawingWnd) then
> ShowWindow(acDrawingWnd, SW_RESTORE);
> SetForegroundWindow(acDrawingWnd);
> SetActiveWindow(acDrawingWnd);
> // Allow only one instance of the toolbar:
> if not Assigned(fmSToolbar) then
> fmSToolbar := TfmSToolbar.Create(nil) ;
> fmSToolbar.Show;
> end;
>
> and this for the Close method (in the server):
>
> procedure TSCom.Close;
> begin
> g_CallerHW := 0;
> if Assigned(fmSToolbar) then
> fmSToolbar.Free;
> end;
>
> - - - - - - - - - - - - -
>
> I think your code is much better. Don't needed to close the form. When
> the server is released, the form is freed automatically. Let me check it
> next week, ok?
>
> I think that GetInterfaceObject treats modules as demand load Dlls and I
> cannot close the form, but AutoCAD needs to do it itself. You only close
> your forms in the Destroy event that is called when AutoCAD unloads the
> Dll, don't you? Well, your help is excellent.
>
> - - - - - - - - - - - - -
>
> I have another question. AutoCAD 2000 is returning the same error
> message when the user pressed a keyword and Enter. So, from Delphi, how
> do you know what the user did?
>
> Thanks a lot, Pablo.
>
> Tony Tanzillo wrote:
> >
> > I'm really not sure if you should be using
> > Application.CreateForm in a DLL. I've never
> > done that, because it makes the Application
> > object the owner of the form.

--

Checkout the AcadX(tm) ActiveX Extension Library at:

http://www.caddzone.com/acadx/acadx.htm

/*********************************************************/
/* Tony Tanzillo Design Automation Consulting */
/* Programming & Customization for AutoCAD & Compatibles */
/* ----------------------------------------------------- */
/* tony.tanzillo@worldnet.att.net */
/* http://www.caddzone.com */
/*********************************************************/
0 Likes
Message 11 of 11

Anonymous
Not applicable
Tried caHide, but the form wasn't hidden. I think your solution is best.

GetInput: _shoud_ return en empty string, but it is allways returning
"close". As crazy as it sounds. Its like a nightmare...

thanks a lot for your help, Pablo.

Tony Tanzillo wrote:
>
> In your form's OnClose event, set the CloseAction
> paramter to caHide, and this will prevent the form
> from destroying itself when it's closed.
>
> Regarding the InitGet problem, if the user presses
> ENTER, the GetInput() method should return an empty
> string.
>
> "P. F. Dueñas" wrote:
> >
> > Thanks for your help.
> >
> > Don't remember what the documentation about Forms in Dlls says, I am
> > very tired of fighting with AutoCAD 2000 ActiveX bugs. I have another
> > question at the end of this message, if you don't mind.
> >
> > What I can do is this code for the Execute method:
> >
> > procedure TSCom.Execute(CallerHW: Integer);
> > begin
> > g_CallerHW := HWnd(CallerHW);
> > Forms.Application.Handle := acDrawingWnd;
> > if IsIconic(acDrawingWnd) then
> > ShowWindow(acDrawingWnd, SW_RESTORE);
> > SetForegroundWindow(acDrawingWnd);
> > SetActiveWindow(acDrawingWnd);
> > // Allow only one instance of the toolbar:
> > if not Assigned(fmSToolbar) then
> > fmSToolbar := TfmSToolbar.Create(nil) ;
> > fmSToolbar.Show;
> > end;
> >
> > and this for the Close method (in the server):
> >
> > procedure TSCom.Close;
> > begin
> > g_CallerHW := 0;
> > if Assigned(fmSToolbar) then
> > fmSToolbar.Free;
> > end;
> >
> > - - - - - - - - - - - - -
> >
> > I think your code is much better. Don't needed to close the form. When
> > the server is released, the form is freed automatically. Let me check it
> > next week, ok?
> >
> > I think that GetInterfaceObject treats modules as demand load Dlls and I
> > cannot close the form, but AutoCAD needs to do it itself. You only close
> > your forms in the Destroy event that is called when AutoCAD unloads the
> > Dll, don't you? Well, your help is excellent.
> >
> > - - - - - - - - - - - - -
> >
> > I have another question. AutoCAD 2000 is returning the same error
> > message when the user pressed a keyword and Enter. So, from Delphi, how
> > do you know what the user did?
> >
> > Thanks a lot, Pablo.
> >
> > Tony Tanzillo wrote:
> > >
> > > I'm really not sure if you should be using
> > > Application.CreateForm in a DLL. I've never
> > > done that, because it makes the Application
> > > object the owner of the form.
>
> --
>
> Checkout the AcadX(tm) ActiveX Extension Library at:
>
> http://www.caddzone.com/acadx/acadx.htm
>
> /*********************************************************/
> /* Tony Tanzillo Design Automation Consulting */
> /* Programming & Customization for AutoCAD & Compatibles */
> /* ----------------------------------------------------- */
> /* tony.tanzillo@worldnet.att.net */
> /* http://www.caddzone.com */
> /*********************************************************/
0 Likes