Solved

A problem on the COM example in Mastering Delphi 5 by Marco Cantu

Posted on 2000-04-16
21
345 Views
Last Modified: 2012-05-04
I just start to learn COM. I tried to run a program in the Marco Cantu's 'Mastering Delphi 5'. The program is called FirstCom, in the Capter 15.
I regenerate the GUID for the interface and for the Class_Number. I also change GUID in the test program -- testcom.
I compile and register the dll. But we I run the testcom, I got two messages. first is 'Object destroyed' from the server destroy method. and the second is 'Interface not supported'.
what is the problem?

Best regards

Petershaw9
 
0
Comment
Question by:petershaw9
  • 11
  • 10
21 Comments
 
LVL 1

Expert Comment

by:xsoft
ID: 2724124
Hi Petershaw9,

could you post the code if it is not to big?

Thomas
0
 

Author Comment

by:petershaw9
ID: 2724697
Yes, I post it.
library FirstCom;

uses
  ComServ,
  NumIntf in 'NumIntf.pas',
  NumServ in 'NumServ.pas',
  FirstCom_TLB in 'FirstCom_TLB.pas';

exports
  DllGetClassObject,
  DllCanUnloadNow,
  DllRegisterServer,
  DllUnregisterServer;

{$R *.TLB}

{$R *.RES}

begin
end.

********************************
unit NumIntf;

interface

type
  INumber = interface
       ['{F2C3E3C5-146A-11D4-B1D2-0080C8D813CE}']
    function GetValue: Integer; stdcall;
    procedure SetValue (New: Integer); stdcall;
    procedure Increase; stdcall;
  end;

implementation

end.

**********************************
unit NumServ;

interface

uses
  Windows, ActiveX, ComObj, NumIntf;

type
  TNumber = class(TComObject, INumber)
  private
    fValue: Integer;
  public
    function GetValue: Integer; virtual; stdcall;
    procedure SetValue (New: Integer); virtual; stdcall;
    procedure Increase; virtual; stdcall;
    procedure Initialize; override;
    destructor Destroy; override;
  end;

const
  Class_Number: TGUID = '{F2C3E3C6-146A-11D4-B1D2-0080C8D813CE}';

implementation

uses ComServ;

{ TNumber }

destructor TNumber.Destroy;
begin
  inherited;
  MessageBox (0, 'Object Destroyed',
    'TDLLNumber', mb_OK); // API call
end;

function TNumber.GetValue: Integer;
begin
  Result := fValue;
end;

procedure TNumber.Increase;
begin
  Inc (fValue);
end;

procedure TNumber.Initialize;
begin
  inherited;
  fValue := 10;
end;

procedure TNumber.SetValue(New: Integer);
begin
  fValue := New;
end;

initialization
  TComObjectFactory.Create(ComServer, TNumber, Class_Number,
    'Number', 'Number Server', ciMultiInstance, tmApartment);
end.

*****************************
unit FirstCom_TLB;

// ************************************************************************ //
// WARNING                                                                    
// -------                                                                    
// The types declared in this file were generated from data read from a      
// Type Library. If this type library is explicitly or indirectly (via        
// another type library referring to this type library) re-imported, or the  
// 'Refresh' command of the Type Library Editor activated while editing the  
// Type Library, the contents of this file will be regenerated and all        
// manual modifications will be lost.                                        
// ************************************************************************ //

// PASTLWTR : $Revision:   1.88.1.0.1.0  $
// File generated on 17/04/00 3:28:46 PM from Type Library described below.

// ************************************************************************ //
// Type Lib: C:\Books\MasterDelphi5\md5code\Part4\15\FirstCom\FirstCom.tlb (1)
// IID\LCID: {5B2EF182-3AAE-11D3-B9F1-00000100A27B}\0
// Helpfile:
// DepndLst:
//   (1) v2.0 stdole, (C:\WINDOWS\SYSTEM\STDOLE2.TLB)
//   (2) v4.0 StdVCL, (C:\WINDOWS\SYSTEM\STDVCL40.DLL)
// ************************************************************************ //
{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers.
interface

uses Windows, ActiveX, Classes, Graphics, OleServer, OleCtrls, StdVCL;

// *********************************************************************//
// GUIDS declared in the TypeLibrary. Following prefixes are used:        
//   Type Libraries     : LIBID_xxxx                                      
//   CoClasses          : CLASS_xxxx                                      
//   DISPInterfaces     : DIID_xxxx                                      
//   Non-DISP interfaces: IID_xxxx                                        
// *********************************************************************//
const
  // TypeLibrary Major and minor versions
  FirstComMajorVersion = 1;
  FirstComMinorVersion = 0;

  LIBID_FirstCom: TGUID = '{5B2EF182-3AAE-11D3-B9F1-00000100A27B}';


implementation

uses ComObj;

end.


Best regards

PeterShaw
0
 
LVL 1

Expert Comment

by:xsoft
ID: 2727005
Hi Peter,

Your server is ok. I just wrote a simple client for your server end everything works fine.
I never get the 'Interface not supported' message. I only get the first message when I explicitly disconnect from the server or when I close my client without disconnecting from the server before.
The problem must be in your client. If you show me the code where you get that problem I can help you.
If you want, I can send you the code of my simple client which I mentioned before.
Thomas

0
 

Author Comment

by:petershaw9
ID: 2728805
Hi! Thomas,
The following is the client side test program code. if you can post your code to me, that would be very nice.

Best regardds

Peter

program TestCom;

uses
  Forms,
  TestComF in 'TestComF.pas' {Form1};

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.


//******************************************

unit TestComF;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Spin, NumIntf;

// redeclare the server GUID
const
  Class_Number: TGUID =
  '{F2C3E3C1-146A-11D4-B1D2-0080C8D813CE}';//this id is same as the                                            //class_number at the server end.

type
  TForm1 = class(TForm)
    SpinEdit1: TSpinEdit;
    Button1: TButton;
    Button2: TButton;
    SpinEdit2: TSpinEdit;
    Button3: TButton;
    Button4: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Button5: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
  private
    Num1, Num2 : INumber;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses
  ComObj;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // create first object
  Num1 := CreateComObject (Class_Number) as INumber;
  Num1.SetValue (SpinEdit1.Value);
  Label1.Caption := 'Num1: ' + IntToStr (Num1.GetValue);
  Button1.Enabled := True;
  Button2.Enabled := True;

  // create second object
  Num2 := CreateComObject (Class_Number) as INumber;
  Label2.Caption := 'Num2: ' + IntToStr (Num2.GetValue);
  Button3.Enabled := True;
  Button4.Enabled := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // change
  Num1.SetValue (SpinEdit1.Value);
  Label1.Caption := 'Num1: ' + IntToStr (Num1.GetValue);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  // increase
  Num1.Increase;
  Label1.Caption := 'Num1: ' + IntToStr (Num1.GetValue);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  Num2.SetValue (SpinEdit2.Value);
  Label2.Caption := 'Num2: ' + IntToStr (Num2.GetValue);
end;


procedure TForm1.Button4Click(Sender: TObject);
begin
  Num2.Increase;
  Label2.Caption := 'Num2: ' + IntToStr (Num2.GetValue);
end;

procedure TForm1.Button5Click(Sender: TObject);
var
  Num3: INumber;
begin
  // create a new temporary COM object
  Num3 := CreateComObject (Class_Number) as INumber;
  Num3.SetValue (100);
  Num3.Increase;
  ShowMessage ('Num3: ' + IntToStr (Num3.GetValue));
end;

end.

0
 
LVL 1

Expert Comment

by:xsoft
ID: 2730632
Hi Peter,

I copied your TestCom code, rebuilt it and - everything works as expected- no errors.
I made a few minor changes which won't affect the whole thing as you will see:

I declared   var Class_Number:TGUID instead of Const.
I added:

Initialization
Class_Number:= ProgIDToClassID('FirstCom.Number');

to the TestComF unit.

This makes me independent from a hardcoded GUID so the client programs will work on your pc and on mine even if we use different GUID's.

When do you get the 'Interface not supported' error?

Where does the Typelibrary come from?
How did you build the project?
In the TLB no interface is declared, therefore I think its totally useless.
How did you register your FirstCom.dll?

If you register the TLB from the TLB-editor no interface of INumber will be registered as it is not included in the TLB.
Try <regsvr32 FirstCom.dll> instead.

Then start your client again.

I would suggest You do the following too:
Edit your project and delete:

FirstCom_TLB in 'FirstCom_TLB.pas'
and
{$R *.TLB}
then compile and register as mentioned before.

If you want I can mail you my sources for the project either to your e-mail address or post it here.

Thomas



0
 

Author Comment

by:petershaw9
ID: 2733030
I use file>New>ActiveX page, select ActiveX Library to generate the FistCom unit.
use a new unit to write the NumberIntf unit script.
I use File > New > ActiveX page > COM Object to get the NumServ unit.
After finishing the three units, I Ctrl + F9/ or Project > compile FirstCom to compile it, then click Run > Register ActiveX Server, The FirstCom_TLB is auto generated during the registering process.
I checked the RegEdit, I found the entry of the FirstCom.
When I run the client end, first gives me is 'Object destroyed', and then, second is 'Interface not supported'. after the second message, the form showed.
Is any delphi enviroment setting problem?

Thanks

PeterShaw

0
 
LVL 1

Expert Comment

by:xsoft
ID: 2733727
Hi Peter,

its pretty funny:

If you click Run > Register ActiveX Server, The FirstCom_TLB is auto generated during the registering process.
This will also add:

FirstCom_TLB in 'FirstCom_TLB.pas'
and
{$R *.TLB}

to your Project file.

The resulting dll is 314 kb compared to 65 kb if you delete those 2 lines, compile again and register the server again.

Both dll's do work on my system without producing the errors, you mentioned before.

If you give me your e-mail address I can mail you my files.

I don't think that a delphi environment setting would cause the problems, but if nothing else works, we could examine this too.

Thomas

BTW: Did I mention, that 50 points is not very much for all the work...



0
 
LVL 1

Expert Comment

by:xsoft
ID: 2739630
Hi Peter,

r u still alive...
0
 

Author Comment

by:petershaw9
ID: 2749750
Hi!
I still have breath. Not many, still have 100 year to live.
I have 5 days holidays, and I travelled to the other city. But, anyway, sorry about my delay reply.

I tried to delete the two lines

FirstCom_TLB in 'FirstCom_TLB.pas'
{$R *.TLB}

then I press ctrl + F9 to recompile it, and click Register ActiveX Server. The registration is successful, but the problem is same as before.

Could you email me your file, and tell me how to compile and register it?
My email address is petershaw9@hotmail.com

Of caurse, 50 points is not enough for your work. But I don't have many points.
My boss don't pay the points for me. I can give you 150 points, is that OK?

Peter Shaw
0
 
LVL 1

Expert Comment

by:xsoft
ID: 2752863
Hi Peter,

I just sent you my files by e-mail.
I would suggest that you first unregister your server with regsvr32.exe /u ???.dll.
Then open the project group in delphi, build all and then register your server
with regsvr32.exe ???.dll.
If you then run the clients every thing should work and no TLB will be included in the project.

CU,

Thomas

If you can spend 150 pts without going bankrupt it would be fine, otherwise I will accept 100.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:petershaw9
ID: 2753590
Adjusted points from 50 to 150
0
 

Author Comment

by:petershaw9
ID: 2753591
Thank u,

Peter Shaw
0
 
LVL 1

Expert Comment

by:xsoft
ID: 2755665
Hi Peter,

have you been able to compile and run my code?
If not, what errors do you get?

Thomas
0
 

Author Comment

by:petershaw9
ID: 2764607
Hi!
I haven't tried compiling your code. I was sick for 4 days. I will try it today and I will let you know the result.

Thanks.

Peter Shaw
0
 

Author Comment

by:petershaw9
ID: 2771652
Hi!Thomas,
I uninstalled my firstcom.dll by using C:\windows>regsvr32 /u firstcom.dll
I got a message, said, LoadLibrary("Firstcom.dll") failed. GetLastError returns 0x00000???.

then I open your secondcom.dpr, and build it and go to dos,
use C:\windows>regsvr32  secondcom.dll.
I got the message,LoadLibrary("Firstcom.dll") failed. GetLastError returns 0x00000485.

Then I tried your firstcom.dpr, did samething, and got same message.

I tried to run the your TestCom, I get the error message, Runtime error 207 at 00048641.

So, what is the problem?
btw, I didn't chnage the GUID.


best regards

Peter Shaw
0
 
LVL 1

Expert Comment

by:xsoft
ID: 2772633
If you run regsvr32 you should give it the fully qualified path of the dll to operate on. Loadlibrary failed often means that regsvr32 could not find the specified library.
If you still have your Firstcom.dll then first do the regsvr32 /u firstcom.dll call on your library and then try to register mine.
If you run my TestCom.exe you will get a runtime error because you will not find the ProgID of SecondCom.Number which I use in the initialization of TestComF.pas.
You should also change that line to:
Class_Number:= ProgIDToClassID('FirstCom.Number');
unless you don't register both dlls.
Here I was just playing around a little bit:
If you have registered both dlls, this call will lead to the same ClassID no matter if you use FirstCom.Number or SecondCom.Number and it will load FirstCom.dll or SecondCom.dll depending
on the value of InprogServer32 in the registry.
BTW: what will you find in the registry if you search for FirstCom?

Thomas
0
 

Author Comment

by:petershaw9
ID: 2775795
Hi! Thomas,
You are right, The problem is the dll path.

I use your SecondCom and your testcom. It works.

Yesterday I manully deleted the firstcom entry in the registry. I could not re- regist my firstcom, so I change my firstcom name to comx3, build it, and register it, and successed. but, when I try my testcom, it still has the previous problem.

Best regards

petershaw

BTW: have u receive my points?

 
0
 
LVL 1

Accepted Solution

by:
xsoft earned 150 total points
ID: 2776960
Hi Peter,

as you see in my previous posting you have to take care for the ClassID and the ProgID entries when dealing with COM. The SecondCom and the FirstCom in my example both use the same ClassID because they share the NumServ-unit in which the server is implemented. You should never do this in real life...
I just did this to show you the dependecies of the registry entries.
You should unregister my secondCom.dll and reregister my firtsCom.dll and change the initialization of TestComF.pas to:
Class_Number:= ProgIDToClassID('FirstCom.Number');
If you use a line like this in the initialization code then you will not need to hardcode a ClassID in your code as you did. Hardcoding a ClassID is not wrong, but can lead to trouble if you are playing around, like we do here.
If you would build a new FirstCom whith a different ClassID and register it, then my TestCom would still work.
Does your comx3 have the same ClassID as your FirstCom? Do the ClassIDs in your comx3 and your testcom match?
If you have any problems like this you should allways compare the ClassIDs from the server, the client and the registry and then you would be able to solve most of the problems pretty easy.

Regards,

Thomas

BTW: I did not receive your points so far. :-(
0
 

Author Comment

by:petershaw9
ID: 2778993
Hi! Thomas,
comx3 has new classID, and the testcom match this id. I also checked the comx3 id in the registry, the three IDs in comx3, testcom and registry are same.

BTW: I only got 127 points now. Later I will give you the rest. Do u mind?

PeterShaw
0
 
LVL 1

Expert Comment

by:xsoft
ID: 2780084
Hi Peter,

I just received your points and they are complete, so maybe you have a debit now on EE...

Even if they would have given me only 127 points I could live with that, so don't worry - be happy.

I cannot understand whats going wrong on your pc. When my code works on your machine and yours does not, then I think we should try to find out what's going wrong here. If you like, you can send me your sources of comx3 and the testcom which uses it and I will try to find out.
Zip the code and mail it to me. You should have my mail address on your machine.

CU,

Thomas
0
 
LVL 1

Expert Comment

by:xsoft
ID: 2791747
Hi Peter,

I just took a short look on the files you sent me.
For the server you use NumberIntf.pas and for the client you use NumIntf.pas (in the uses clause of TestComF.pas), therefore you are using two different interface id's.
If you would change TestComF to use NumberIntf everything should work.

Bye,
Thomas
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now