Link to home
Start Free TrialLog in
Avatar of petershaw9
petershaw9

asked on

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

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
 
Avatar of xsoft
xsoft

Hi Petershaw9,

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

Thomas
Avatar of petershaw9

ASKER

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
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

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.

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



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

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...



Hi Peter,

r u still alive...
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
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.
Adjusted points from 50 to 150
Thank u,

Peter Shaw
Hi Peter,

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

Thomas
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
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
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
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?

 
ASKER CERTIFIED SOLUTION
Avatar of xsoft
xsoft

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
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
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