Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: What's the equivalent to this in Delphi ?


This question is not answered.


Permlink Replies: 56 - Last Post: Feb 22, 2016 2:18 PM Last Post By: Fred Smith
Fred Smith

Posts: 81
Registered: 12/4/15
What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 28, 2016 2:24 AM
Hi all,
What's the equivalent to this line of vb script in Delphi ?

set My_obj = wscript.CreateObject("COMtest","pref_")

Can anyone help ?
Thank you

Edited by: Fred Smith on Jan 28, 2016 2:25 AM
Peter Below

Posts: 1,227
Registered: 12/16/99
Re: What's the equivalent to this in Delphi ? [Edit]
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 28, 2016 10:32 AM   in response to: Fred Smith in response to: Fred Smith
Fred Smith wrote:

Hi all,
What's the equivalent to this line of vb script in Delphi ?

set My_obj = wscript.CreateObject("COMtest","pref_")

Can anyone help ?
Thank you

Edited by: Fred Smith on Jan 28, 2016 2:25 AM

The equivalent should be

Var
MyObj: OleVariant;
begin
MyObj := CreateOleObject('COMtest');

The resulting variant then holds a IDispatch interface reference for
the server instance and you can call methods of it an access its
properties using the late-bound OLe automation support of the Delphi
compiler.

If you need to create the object on a remote server (the second
parameter of wscript.CreateObject names a server) you may have to fall
back to CreateRemoteComObject, I don't remember whether there is an
overload for CreateOleObject that takes a server name in addition to
the COM class name.

--
Peter Below
TeamB

Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 29, 2016 5:55 AM   in response to: Peter Below in response to: Peter Below
Peter Below wrote:
Fred Smith wrote:

Hi all,
What's the equivalent to this line of vb script in Delphi ?

set My_obj = wscript.CreateObject("COMtest","pref_")

Can anyone help ?
Thank you

Edited by: Fred Smith on Jan 28, 2016 2:25 AM

The equivalent should be

Var
MyObj: OleVariant;
begin
MyObj := CreateOleObject('COMtest');

The resulting variant then holds a IDispatch interface reference for
the server instance and you can call methods of it an access its
properties using the late-bound OLe automation support of the Delphi
compiler.

If you need to create the object on a remote server (the second
parameter of wscript.CreateObject names a server) you may have to fall
back to CreateRemoteComObject, I don't remember whether there is an
overload for CreateOleObject that takes a server name in addition to
the COM class name.

--
Peter Below
TeamB

Hi,
Your suggestion did work. Thank you very much.
MyObj := CreateOleObject('COMtest');

I'm stuck on this line:
call init_lib.init_library(GetRef("Library_created"), myObj)

These are the relevant vbScript snippets:
Class myClass
Public user
public password
End class

dim myObj
Set myObj = New myClass
myObj.user = "userName"
myObj.password = "userPwrd"

set My_obj = wscript.CreateObject("COMtest","pref_")

Set init_lib = My_obj.get_init_library_obj

call init_lib.init_library(GetRef("Library_created"), myObj)

sub Library_created(p_Object)
result = TypeName( p_Object)
MsgBox "class: " + result +" called for user: "+p_Object.user, 0, "COM Test"
end sub

Thanks again.

Edited by: Fred Smith on Jan 29, 2016 6:06 AM

Peter Below

Posts: 1,227
Registered: 12/16/99
Re: What's the equivalent to this in Delphi ? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 29, 2016 9:54 AM   in response to: Fred Smith in response to: Fred Smith
Fred Smith wrote:

Peter Below wrote:
Fred Smith wrote:

Hi all,
What's the equivalent to this line of vb script in Delphi ?

set My_obj = wscript.CreateObject("COMtest","pref_")

Can anyone help ?
Thank you

Edited by: Fred Smith on Jan 28, 2016 2:25 AM

The equivalent should be

Var
MyObj: OleVariant;
begin
MyObj := CreateOleObject('COMtest');

The resulting variant then holds a IDispatch interface reference for
the server instance and you can call methods of it an access its
properties using the late-bound OLe automation support of the Delphi
compiler.

If you need to create the object on a remote server (the second
parameter of wscript.CreateObject names a server) you may have to
fall back to CreateRemoteComObject, I don't remember whether there
is an overload for CreateOleObject that takes a server name in
addition to the COM class name.

--
Peter Below
TeamB

Hi,
Your suggestion did work. Thank you very much.
MyObj := CreateOleObject('COMtest');

I'm stuck on this line:
call init_lib.init_library(GetRef("Library_created"), myObj)


I have no idea what this is supposed to do, sorry. I don't speak VB
script at all, and barely have a reading knowledge of VB (6, quite old).

Try to import the type library for this COMTest class. Component -->
Import Component in the IDE menu. If it is registered the type library
should be listed in the items the import wizard finds, and the result
of the import is a unit that defines the interfaces the COM class
supports in Delphi terms. That should clearify matters a bit.

--
Peter Below
TeamB
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 29, 2016 12:40 PM   in response to: Peter Below in response to: Peter Below
Peter wrote:

call init_lib.init_library(GetRef("Library_created"), myObj)

I have no idea what this is supposed to do, sorry.

GetRef() is VBScript's way of obtaining an OLE-compatible pointer to a function
in the script (GetRef() returns an IDispatch object that implments Invoke()
to call the function when dispid 0 is requested). So, this is VBScript's
equivilent of the following Delphi technique:

type
  TObjProc = procedure(Obj: TObject);
 
procedure init_library(Proc: TObjProc; Obj: TObject);
begin
  //...
  Proc(Obj);
end;
 
procedure library_created(Obj: TObject);
begin
  // do something...
end;
 
var
  obj: TMyClass;
begin
  obj := TMyClass.Create;
  init_library(@library_created, obj);
  obj.Free;
end;


--
Remy Lebeau (TeamB)
Peter Below

Posts: 1,227
Registered: 12/16/99
Re: What's the equivalent to this in Delphi ? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 30, 2016 6:19 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:

call init_lib.init_library(GetRef("Library_created"), myObj)

I have no idea what this is supposed to do, sorry.

GetRef() is VBScript's way of obtaining an OLE-compatible pointer to
a function in the script (GetRef() returns an IDispatch object that
implments Invoke() to call the function when dispid 0 is requested).
So, this is VBScript's equivilent of the following Delphi technique:

Thanks for this info. I've managed to stay out of VB's way for 25 years
now and don't intend to change that :-)...

--
Peter Below
TeamB
Quentin Correll


Posts: 2,412
Registered: 12/1/99
Re: What's the equivalent to this in Delphi ? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 30, 2016 11:25 AM   in response to: Peter Below in response to: Peter Below
Peter,

| I've managed to stay out of VB's way for 25 years
| now and don't intend to change that :-)...

Ditto! <g>

--

Q -- XanaNews 1.19.1.372 - 2016-01-30 11:25:42
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 1, 2016 8:08 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Peter wrote:

call init_lib.init_library(GetRef("Library_created"), myObj)

I have no idea what this is supposed to do, sorry.

GetRef() is VBScript's way of obtaining an OLE-compatible pointer to a function
in the script (GetRef() returns an IDispatch object that implments Invoke()
to call the function when dispid 0 is requested). So, this is VBScript's
equivilent of the following Delphi technique:

type
  TObjProc = procedure(Obj: TObject);
 
procedure init_library(Proc: TObjProc; Obj: TObject);
begin
  //...
  Proc(Obj);
end;
 
procedure library_created(Obj: TObject);
begin
  // do something...
end;
 
var
  obj: TMyClass;
begin
  obj := TMyClass.Create;
  init_library(@library_created, obj);
  obj.Free;
end;


--
Remy Lebeau (TeamB)

Thank you Remy. That's very helpful.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit] [Edit]
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 29, 2016 12:32 PM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

I'm stuck on this line:
call init_lib.init_library(GetRef("Library_created"), myObj)

You are going to be stuck on more than that. Your VB code is actually VBScript
code, which means it is running in an interpretted environment that lets
it do lots of things that are easy to do in scripts but much more difficult
to do in native environments, like Delphi.

Your VBScript code is creating the COMTest object and assigning the 'pref_'
prefix to it. That means any events fired by COMTest will call the corresponding
'pref_<EventName>' procedure in the script code. That is not going to translate
verbatim to Delphi. To handle such events, you would have to write a class
the implements the appropriate event interface defined by COMTest, then you
can query COMTest for its IConnectionPointContainer interface, call its FindConnectionPoint()
method to find the IConnectionPoint for that event interface, and then Advise()
an instance of your implementation class onto that IConnectionPoint to start
receiving events.

However, in this case, you don't need to worry about that, since the VBScript
is not utilizing that functionality. COMTest is using a completely different
technique to fire an event to the caller. The VBScript is using GetRef()
to obtain a reference to the script's Library_created() function directly
and passing that reference to COMTest. That is basically just a function
pointer. COMTest will call it like a normal function when needed. However,
in terms of native code, it is not really a function pointer at all. GetRef()
returns an object that implements the IDispatch interface and holds a reference
to the function internally, where the IDispatch.Invoke() implementation calls
the function as needed. You would have to manually implement that kind of
logic in your Delphi code, by writing a class that implements the IDispatch.Invoke()
method.

Also, the VBScript is creating a new instance of a custom class type and
passing that instance to COMTest as well (presumably to populate the p_Object
parameter of Library_created() when COMTest calls it). Objects in VB/VBScript
are themselves COM objects that implement the IDispatch interface. All property
accesses and method calls on an IDispatch object go through IDispatch.Invoke()
with different parameters. So, in your Delphi code, you could use the same
IDispatch object for both parameters of init_library(), or you could write
different object classes, your choice.

The easiest way to create IDispatch classes in Delphi is to add a TypeLibrary
to your Delphi project and populate it with Automation classes that have
properties and methods defined as needed, then you can instantiate those
classes in your Delphi code like normal classes when needed. The Delphi
equivilent of the VBScript code would then look roughly like the following
(I'm guessing on some on this, as you haven't provided any details about
what the COMTest API actually looks like):

// defined in the TypeLibrary
type
  IMyClass = interface(IDispatch)
    ['{B681D3D0-2279-491E-BF8C-E78CD0D9A35D}']
    function Get_User: WideString; safecall;
    procedure Set_User(const Value: WideString); safecall;
    function Get_Password: WideString; safecall;
    procedure Set_Password(const Value: WideString); safecall;
    procedure LibraryCreated(const p_Object: IDispatch); safecall;
    property User: WideString read Get_User write Set_User;
    property Password: WideString read Get_Password write Set_Password;
  end;
 
  ...
 
// implemented in the TypeLibrary unit
 
type
  TMyClass = class(TAutoObject, IMyClass)
  private
    fUser: string;
    fPassword: string;
  protected
    function Get_Password: WideString; safecall;
    function Get_User: WideString; safecall;
    procedure LibraryCreated(const p_Object: IDispatch); safecall; // <-- 
make sure this has dispid 0 assigned to it in the TypeLibrary
    procedure Set_Password(const Value: WideString); safecall;
    procedure Set_User(const Value: WideString); safecall;
  end;
 
function TMyClass.Get_Password: WideString;
begin
  Result := fPassword;
end;
 
function TMyClass.Get_User: WideString;
begin
  Result := fUser;
end;
 
function ObjTypeName(Obj: IDispatch): string;
var
  Count: Integer;
  TI: ITypeInfo;
  wName: WideString;
begin
  Result := 'Object';
  if Obj = nil then Exit;
  if Failed(Obj.GetTypeInfoCount(Count)) then Exit;
  if Count < 1 then Exit;
  if Failed(Obj.GetTypeInfo(0, 0, TI)) then Exit;
  if Failed(TI.GetDocumentation(MEMBERID_NIL, @wName, nil, nil, nil)) then 
Exit;
  Result := wName;
end;
 
procedure TMyClass.LibraryCreated(const p_Object: IDispatch);
begin
  MessageBox(0, PChar('class: ' + ObjTypeName(p_Object) + ' called for user: 
' + (p_Object as IMyClass).User), 'COM Test', MB_OK);
end;
 
procedure TMyClass.Set_Password(const Value: WideString);
begin
  fPassword := Value;
end;
 
procedure TMyClass.Set_User(const Value: WideString);
begin
  fUser := Value;
end;


var
  myObj: IMyClass;
  My_obj, init_lib: OleVariant;
begin
  myObj := TMyClass.Create;
  myObj.User := 'userName';
  myObj.Password := 'userPwrd';
 
  My_obj := CreateOleObject('COMtest');
  init_lib := My_obj.get_init_library_obj();
  init_lib.init_library(myObj, myObj);
end;


Fun, huh?

Now, with that said, rather then going through all this trouble, you should
consider simply hosting the Windows Script Host in your Delphi code (look
at Microsoft's IActiveScript interface), and then you can actually run the
VBScript itself inside your Delphi app and let it do whatever it needs to
do. There are ways of letting the hosting app pass information into the
VBScript environment, and ways to allow the script to communicate with the
app.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 1, 2016 8:34 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

I'm stuck on this line:
call init_lib.init_library(GetRef("Library_created"), myObj)

You are going to be stuck on more than that. Your VB code is actually VBScript
code, which means it is running in an interpretted environment that lets
it do lots of things that are easy to do in scripts but much more difficult
to do in native environments, like Delphi.

Your VBScript code is creating the COMTest object and assigning the 'pref_'
prefix to it. That means any events fired by COMTest will call the corresponding
'pref_<EventName>' procedure in the script code. That is not going to translate
verbatim to Delphi. To handle such events, you would have to write a class
the implements the appropriate event interface defined by COMTest, then you
can query COMTest for its IConnectionPointContainer interface, call its FindConnectionPoint()
method to find the IConnectionPoint for that event interface, and then Advise()
an instance of your implementation class onto that IConnectionPoint to start
receiving events.

However, in this case, you don't need to worry about that, since the VBScript
is not utilizing that functionality. COMTest is using a completely different
technique to fire an event to the caller. The VBScript is using GetRef()
to obtain a reference to the script's Library_created() function directly
and passing that reference to COMTest. That is basically just a function
pointer. COMTest will call it like a normal function when needed. However,
in terms of native code, it is not really a function pointer at all. GetRef()
returns an object that implements the IDispatch interface and holds a reference
to the function internally, where the IDispatch.Invoke() implementation calls
the function as needed. You would have to manually implement that kind of
logic in your Delphi code, by writing a class that implements the IDispatch.Invoke()
method.

Also, the VBScript is creating a new instance of a custom class type and
passing that instance to COMTest as well (presumably to populate the p_Object
parameter of Library_created() when COMTest calls it). Objects in VB/VBScript
are themselves COM objects that implement the IDispatch interface. All property
accesses and method calls on an IDispatch object go through IDispatch.Invoke()
with different parameters. So, in your Delphi code, you could use the same
IDispatch object for both parameters of init_library(), or you could write
different object classes, your choice.

The easiest way to create IDispatch classes in Delphi is to add a TypeLibrary
to your Delphi project and populate it with Automation classes that have
properties and methods defined as needed, then you can instantiate those
classes in your Delphi code like normal classes when needed. The Delphi
equivilent of the VBScript code would then look roughly like the following
(I'm guessing on some on this, as you haven't provided any details about
what the COMTest API actually looks like):

// defined in the TypeLibrary
type
  IMyClass = interface(IDispatch)
    ['{B681D3D0-2279-491E-BF8C-E78CD0D9A35D}']
    function Get_User: WideString; safecall;
    procedure Set_User(const Value: WideString); safecall;
    function Get_Password: WideString; safecall;
    procedure Set_Password(const Value: WideString); safecall;
    procedure LibraryCreated(const p_Object: IDispatch); safecall;
    property User: WideString read Get_User write Set_User;
    property Password: WideString read Get_Password write Set_Password;
  end;
 
  ...
 
// implemented in the TypeLibrary unit
 
type
  TMyClass = class(TAutoObject, IMyClass)
  private
    fUser: string;
    fPassword: string;
  protected
    function Get_Password: WideString; safecall;
    function Get_User: WideString; safecall;
    procedure LibraryCreated(const p_Object: IDispatch); safecall; // <-- 
make sure this has dispid 0 assigned to it in the TypeLibrary
    procedure Set_Password(const Value: WideString); safecall;
    procedure Set_User(const Value: WideString); safecall;
  end;
 
function TMyClass.Get_Password: WideString;
begin
  Result := fPassword;
end;
 
function TMyClass.Get_User: WideString;
begin
  Result := fUser;
end;
 
function ObjTypeName(Obj: IDispatch): string;
var
  Count: Integer;
  TI: ITypeInfo;
  wName: WideString;
begin
  Result := 'Object';
  if Obj = nil then Exit;
  if Failed(Obj.GetTypeInfoCount(Count)) then Exit;
  if Count < 1 then Exit;
  if Failed(Obj.GetTypeInfo(0, 0, TI)) then Exit;
  if Failed(TI.GetDocumentation(MEMBERID_NIL, @wName, nil, nil, nil)) then 
Exit;
  Result := wName;
end;
 
procedure TMyClass.LibraryCreated(const p_Object: IDispatch);
begin
  MessageBox(0, PChar('class: ' + ObjTypeName(p_Object) + ' called for user: 
' + (p_Object as IMyClass).User), 'COM Test', MB_OK);
end;
 
procedure TMyClass.Set_Password(const Value: WideString);
begin
  fPassword := Value;
end;
 
procedure TMyClass.Set_User(const Value: WideString);
begin
  fUser := Value;
end;


var
  myObj: IMyClass;
  My_obj, init_lib: OleVariant;
begin
  myObj := TMyClass.Create;
  myObj.User := 'userName';
  myObj.Password := 'userPwrd';
 
  My_obj := CreateOleObject('COMtest');
  init_lib := My_obj.get_init_library_obj();
  init_lib.init_library(myObj, myObj);
end;


Fun, huh?

Now, with that said, rather then going through all this trouble, you should
consider simply hosting the Windows Script Host in your Delphi code (look
at Microsoft's IActiveScript interface), and then you can actually run the
VBScript itself inside your Delphi app and let it do whatever it needs to
do. There are ways of letting the hosting app pass information into the
VBScript environment, and ways to allow the script to communicate with the
app.

--
Remy Lebeau (TeamB)

Thanks Remy. Again, your answer & suggestions are very helpful.

I do think that I'll end up going the TypeLibrary route.
I'll be grateful for anymore pointers on this.

You are right, I left few bits out. I thought if I can these done, the rest should be easy. I hope!

I'm looking into IActiveScript option just out of interest.
I found an example & a demo here:
http://delphi-kb.blogspot.co.uk/2005_11_01_archive.html

At this moment it errors on all my VBSrcript lines but I'm looking into the cause of that.

Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 2, 2016 8:27 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

I'm stuck on this line:
call init_lib.init_library(GetRef("Library_created"), myObj)

You are going to be stuck on more than that. Your VB code is actually VBScript
code, which means it is running in an interpretted environment that lets
it do lots of things that are easy to do in scripts but much more difficult
to do in native environments, like Delphi.

Your VBScript code is creating the COMTest object and assigning the 'pref_'
prefix to it. That means any events fired by COMTest will call the corresponding
'pref_<EventName>' procedure in the script code. That is not going to translate
verbatim to Delphi. To handle such events, you would have to write a class
the implements the appropriate event interface defined by COMTest, then you
can query COMTest for its IConnectionPointContainer interface, call its FindConnectionPoint()
method to find the IConnectionPoint for that event interface, and then Advise()
an instance of your implementation class onto that IConnectionPoint to start
receiving events.

However, in this case, you don't need to worry about that, since the VBScript
is not utilizing that functionality. COMTest is using a completely different
technique to fire an event to the caller. The VBScript is using GetRef()
to obtain a reference to the script's Library_created() function directly
and passing that reference to COMTest. That is basically just a function
pointer. COMTest will call it like a normal function when needed. However,
in terms of native code, it is not really a function pointer at all. GetRef()
returns an object that implements the IDispatch interface and holds a reference
to the function internally, where the IDispatch.Invoke() implementation calls
the function as needed. You would have to manually implement that kind of
logic in your Delphi code, by writing a class that implements the IDispatch.Invoke()
method.

Also, the VBScript is creating a new instance of a custom class type and
passing that instance to COMTest as well (presumably to populate the p_Object
parameter of Library_created() when COMTest calls it). Objects in VB/VBScript
are themselves COM objects that implement the IDispatch interface. All property
accesses and method calls on an IDispatch object go through IDispatch.Invoke()
with different parameters. So, in your Delphi code, you could use the same
IDispatch object for both parameters of init_library(), or you could write
different object classes, your choice.

The easiest way to create IDispatch classes in Delphi is to add a TypeLibrary
to your Delphi project and populate it with Automation classes that have
properties and methods defined as needed, then you can instantiate those
classes in your Delphi code like normal classes when needed. The Delphi
equivilent of the VBScript code would then look roughly like the following
(I'm guessing on some on this, as you haven't provided any details about
what the COMTest API actually looks like):

// defined in the TypeLibrary
type
  IMyClass = interface(IDispatch)
    ['{B681D3D0-2279-491E-BF8C-E78CD0D9A35D}']
    function Get_User: WideString; safecall;
    procedure Set_User(const Value: WideString); safecall;
    function Get_Password: WideString; safecall;
    procedure Set_Password(const Value: WideString); safecall;
    procedure LibraryCreated(const p_Object: IDispatch); safecall;
    property User: WideString read Get_User write Set_User;
    property Password: WideString read Get_Password write Set_Password;
  end;
 
  ...
 
// implemented in the TypeLibrary unit
 
type
  TMyClass = class(TAutoObject, IMyClass)
  private
    fUser: string;
    fPassword: string;
  protected
    function Get_Password: WideString; safecall;
    function Get_User: WideString; safecall;
    procedure LibraryCreated(const p_Object: IDispatch); safecall; // <-- 
make sure this has dispid 0 assigned to it in the TypeLibrary
    procedure Set_Password(const Value: WideString); safecall;
    procedure Set_User(const Value: WideString); safecall;
  end;
 
function TMyClass.Get_Password: WideString;
begin
  Result := fPassword;
end;
 
function TMyClass.Get_User: WideString;
begin
  Result := fUser;
end;
 
function ObjTypeName(Obj: IDispatch): string;
var
  Count: Integer;
  TI: ITypeInfo;
  wName: WideString;
begin
  Result := 'Object';
  if Obj = nil then Exit;
  if Failed(Obj.GetTypeInfoCount(Count)) then Exit;
  if Count < 1 then Exit;
  if Failed(Obj.GetTypeInfo(0, 0, TI)) then Exit;
  if Failed(TI.GetDocumentation(MEMBERID_NIL, @wName, nil, nil, nil)) then 
Exit;
  Result := wName;
end;
 
procedure TMyClass.LibraryCreated(const p_Object: IDispatch);
begin
  MessageBox(0, PChar('class: ' + ObjTypeName(p_Object) + ' called for user: 
' + (p_Object as IMyClass).User), 'COM Test', MB_OK);
end;
 
procedure TMyClass.Set_Password(const Value: WideString);
begin
  fPassword := Value;
end;
 
procedure TMyClass.Set_User(const Value: WideString);
begin
  fUser := Value;
end;


var
  myObj: IMyClass;
  My_obj, init_lib: OleVariant;
begin
  myObj := TMyClass.Create;
  myObj.User := 'userName';
  myObj.Password := 'userPwrd';
 
  My_obj := CreateOleObject('COMtest');
  init_lib := My_obj.get_init_library_obj();
  init_lib.init_library(myObj, myObj);
end;


Fun, huh?

Now, with that said, rather then going through all this trouble, you should
consider simply hosting the Windows Script Host in your Delphi code (look
at Microsoft's IActiveScript interface), and then you can actually run the
VBScript itself inside your Delphi app and let it do whatever it needs to
do. There are ways of letting the hosting app pass information into the
VBScript environment, and ways to allow the script to communicate with the
app.

--
Remy Lebeau (TeamB)

Hi Remy,
I created a small project, created a type library but I'm getting this error:
"Object factory for class TMyClass missing"
Could you tell me where am I going wrong ?

Thank you.

unit ScriptUnit;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, ScriptProj_TLB, Winapi.ActiveX, ComObj,
Vcl.StdCtrls;

type
TForm6 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
public
end;

var
Form6: TForm6;

implementation

{$R *.dfm}

procedure TForm6.Button1Click(Sender: TObject);

var
myObj: IMyClass;
My_obj, init_lib: OleVariant;
begin
myObj := TMyClass.Create; // <-- Object factory for class TMyClass missing !!
myObj.User := 'userName';
myObj.Password := 'userPwrd';
My_obj := CreateOleObject('COMtest');
init_lib := My_obj.get_init_library_obj();
init_lib.init_library(myObj, myObj);
end;
end.

///////////////////////////////////////////////////////////////
unit ScriptProj_TLB;

{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers.
{$WARN SYMBOL_PLATFORM OFF}
{$WRITEABLECONST ON}
{$VARPROPSETTER ON}
{$ALIGN 4}

interface

uses Winapi.Windows, System.Classes, System.Variants, System.Win.StdVCL, Vcl.Graphics, Winapi.ActiveX, comObj;

// TypeLibrary

const
// TypeLibrary Major and minor versions
ScriptProjMajorVersion = 1;
ScriptProjMinorVersion = 0;

LIBID_ScriptProj: TGUID = '{C18817F2-364B-441C-B46B-D778834B0C34}';

IID_IMyClass: TGUID = '{7A7FB885-2A02-45E2-AC08-C2B2E7CDDA2C}';
type

// *********************************************************************//
// Forward declaration of types defined in TypeLibrary
// *********************************************************************//
IMyClass = interface;
IMyClassDisp = dispinterface;

// *********************************************************************//
// Interface: IMyClass
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {7A7FB885-2A02-45E2-AC08-C2B2E7CDDA2C}
// *********************************************************************//
IMyClass = interface(IDispatch)
['{7A7FB885-2A02-45E2-AC08-C2B2E7CDDA2C}']
function Get_User: WideString; safecall;
procedure Set_User(const Value: WideString); safecall;
function Get_Password: WideString; safecall;
procedure Set_Password(const Value: WideString); safecall;
procedure LibraryCreated(const p_Object: IDispatch); safecall;
property User: WideString read Get_User write Set_User;
property Password: WideString read Get_Password write Set_Password;
end;

// *********************************************************************//
// DispIntf: IMyClassDisp
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {7A7FB885-2A02-45E2-AC08-C2B2E7CDDA2C}
// *********************************************************************//
IMyClassDisp = dispinterface
['{7A7FB885-2A02-45E2-AC08-C2B2E7CDDA2C}']
end;
type
TMyClass = class(TAutoObject, IMyClass)
private
fUser: string;
fPassword: string;
protected
function Get_Password: WideString; safecall;
function Get_User: WideString; safecall;
procedure LibraryCreated(const p_Object: IDispatch); safecall; // <--make sure this has dispid 0 assigned to it in the TypeLibrary
procedure Set_Password(const Value: WideString); safecall;
procedure Set_User(const Value: WideString); safecall;
end;
implementation

//uses System.Win.ComObj;

{ TMyClass }

function TMyClass.Get_Password: WideString;
begin
Result := fPassword;
end;

function TMyClass.Get_User: WideString;
begin
Result := fUser;
end;

function ObjTypeName(Obj: IDispatch): string;
var
Count: Integer;
TI: ITypeInfo;
wName: WideString;
begin
Result := 'Object';
if Obj = nil then Exit;
if Failed(Obj.GetTypeInfoCount(Count)) then Exit;
if Count < 1 then Exit;
if Failed(Obj.GetTypeInfo(0, 0, TI)) then Exit;
if Failed(TI.GetDocumentation(MEMBERID_NIL, @wName, nil, nil, nil)) then
Exit;
Result := wName;
end;

procedure TMyClass.LibraryCreated(const p_Object: IDispatch);
begin
MessageBox(0, PChar('class: ' + ObjTypeName(p_Object) + ' called for user:' + (p_Object as IMyClass).User), 'COM Test', MB_OK);
end;

procedure TMyClass.Set_Password(const Value: WideString);
begin
fPassword := Value;
end;

procedure TMyClass.Set_User(const Value: WideString);
begin
fUser := Value;
end;

end.

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 2, 2016 9:18 AM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

I created a small project, created a type library but I'm getting
this error: "Object factory for class TMyClass missing"

Your project is missing a TAutoObjectFactory registration for the TMyClass
class:

initialization
  TAutoObjectFactory.Create(ComServer, TMyClass, Class_MyClass, ciMultiInstance, 
tmApartment);


Probably because your TypeLibrary is apparently missing a CoClass that implements
the IMyClass interface. Did you set up everything by hand? You should use
the IDE's Automation wizard to create it instead, so it hooks everything
up correctly.

That being said, TAutoObject is meant for COM objects that can be created
via CoCreateInstance(), thus the need for a class factory. For internal
use, you can simply define the IMyClass interface in the TypeLibrary by itself
and then derive a TMyClass class from TAutoIntfObject instead of TAutoObject.
TAutoIntfObject does not use a class factory. I don't know if/how to use
the Automation wizard to generate TAutoIntfObject classes, so you will have
to do it manually.

I don't do COM programming in Delphi, I use C++ instead, and COM handling
is a bit different in C++ than in Delphi.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 3, 2016 6:31 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

I created a small project, created a type library but I'm getting
this error: "Object factory for class TMyClass missing"

Your project is missing a TAutoObjectFactory registration for the TMyClass
class:

initialization
  TAutoObjectFactory.Create(ComServer, TMyClass, Class_MyClass, ciMultiInstance, 
tmApartment);


Probably because your TypeLibrary is apparently missing a CoClass that implements
the IMyClass interface. Did you set up everything by hand? You should use
the IDE's Automation wizard to create it instead, so it hooks everything
up correctly.

That being said, TAutoObject is meant for COM objects that can be created
via CoCreateInstance(), thus the need for a class factory. For internal
use, you can simply define the IMyClass interface in the TypeLibrary by itself
and then derive a TMyClass class from TAutoIntfObject instead of TAutoObject.
TAutoIntfObject does not use a class factory. I don't know if/how to use
the Automation wizard to generate TAutoIntfObject classes, so you will have
to do it manually.

I don't do COM programming in Delphi, I use C++ instead, and COM handling
is a bit different in C++ than in Delphi.

--
Remy Lebeau (TeamB)

You are right, I did setup everything by hand.
Now, I'm trying to use IDE's automation wizard. There are few things the wizard doesn't allow me to do. For example, it doesn't allow me to choose WideString as a return type for function Get_User.
So, I'm creating the Type Library using the wizard then I amend value\return types manually.

I've added the CoClass that implements the IMyClass interface.

Also, I'm using TAutoIntfObject (instead of TAutoObject):
TMyClass = class(TAutoIntfObject, IMyClass)

In my case what params do I need to pass to create an instance of TMyClass ?

myObj := tmyClass.Create(TypeLib,LIBID_IntfSrv);

myObj := TmyClass.Create( :ITypeLib, :TGUID); // Params
myObj.User := 'userName';
myObj.Password := 'userPwrd';
My_obj := CreateOleObject('COMtest');
init_lib := My_obj.get_init_library_obj();
init_lib.init_library(myObj, myObj);

Thanks


unit ScriptProj_TLB;

{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers.
{$WARN SYMBOL_PLATFORM OFF}
{$WRITEABLECONST ON}
{$VARPROPSETTER ON}
{$ALIGN 4}

interface

uses Winapi.Windows, System.Classes, System.Variants, System.Win.StdVCL, Vcl.Graphics, Vcl.OleServer, Winapi.ActiveX, ComObj, ComServ;


const
// TypeLibrary Major and minor versions
ScriptProjMajorVersion = 1;
ScriptProjMinorVersion = 0;

LIBID_ScriptProj: TGUID = '{C18817F2-364B-441C-B46B-D778834B0C34}';

IID_IMyClass: TGUID = '{7A7FB885-2A02-45E2-AC08-C2B2E7CDDA2C}';
CLASS_CoClass: TGUID = '{B9DD0E35-EA80-4002-95C7-7EED25F17D67}';
type

IMyClass = interface;
IMyClassDisp = dispinterface;

CoClass = IMyClass;


IMyClass = interface(IDispatch)
['{7A7FB885-2A02-45E2-AC08-C2B2E7CDDA2C}']
// function Get_User: OleVariant; stdcall;
function Get_User : WideString; safecall;
procedure Set_User(const Value: WideString); safecall;
function Get_Password:WideString safecall;
procedure Set_Password(const Value: WideString); safecall;
procedure LibraryCreated(const p_Object: IDispatch); safecall;
//function Get_User: Integer; safecall;
//procedure Set_User(Value: Integer); safecall;
//function Get_Password: Integer; safecall;
//procedure Set_Password(Value: Integer); safecall;

property User: WideString read Get_User write Set_User;
property Password: WideString read Get_Password write Set_Password;
end;

IMyClassDisp = dispinterface
['{7A7FB885-2A02-45E2-AC08-C2B2E7CDDA2C}']
function Get_User: OleVariant; dispid 201;
procedure Set_User(Value: Integer); dispid 202;
procedure Get_Password; dispid 203;
procedure Set_Password; dispid 204;
procedure LibraryCreated; dispid 0;
property User: Integer dispid 206;
property Password: Integer dispid 207;
end;

CoCoClass = class
class function Create: IMyClass;
class function CreateRemote(const MachineName: string): IMyClass;
end;

//type
//TMyClass = class(TAutoObject, IMyClass)
TMyClass = class(TAutoIntfObject, IMyClass)
private
fUser: string;
fPassword: string;
protected
function Get_Password: WideString; safecall;
function Get_User: WideString; safecall;
procedure LibraryCreated(const p_Object: IDispatch); safecall; // <--make sure this has dispid 0 assigned to it in the TypeLibrary
procedure Set_Password(const Value: WideString); safecall;
procedure Set_User(const Value: WideString); safecall;
function ObjTypeName(Obj: IDispatch): string;
end;

implementation

class function CoCoClass.Create: IMyClass;
begin
Result := CreateComObject(CLASS_CoClass) as IMyClass;
end;

class function CoCoClass.CreateRemote(const MachineName: string): IMyClass;
begin
Result := CreateRemoteComObject(MachineName, CLASS_CoClass) as IMyClass;
end;


{ TMyClass }

function TMyClass.Get_Password: WideString;
begin
Result := fPassword;
end;

function TMyClass.Get_User: WideString;
begin
Result := fUser;
end;

procedure TMyClass.LibraryCreated(const p_Object: IDispatch);
begin
MessageBox(0, PChar('class: ' + ObjTypeName(p_Object) + ' called for user:' + (p_Object as IMyClass).User), 'COM Test', MB_OK);
end;

function TMyClass.ObjTypeName(Obj: IDispatch): string;
var
Count: Integer;
TI: ITypeInfo;
wName: WideString;
begin
Result := 'Object';
if Obj = nil then Exit;
if Failed(Obj.GetTypeInfoCount(Count)) then Exit;
if Count < 1 then Exit;
if Failed(Obj.GetTypeInfo(0, 0, TI)) then Exit;
if Failed(TI.GetDocumentation(MEMBERID_NIL, @wName, nil, nil, nil)) then
Exit;
Result := wName;
end;

procedure TMyClass.Set_Password(const Value: WideString);
begin
fPassword := Value;
end;

procedure TMyClass.Set_User(const Value: WideString);
begin
fUser := Value;
end;

end.

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 3, 2016 5:08 PM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

Now, I'm trying to use IDE's automation wizard. There are few things
the wizard doesn't allow me to do. For example, it doesn't allow me
to choose WideString as a return type for function Get_User.

WideString doesn't exist in COM. That is just a Delphi-specific wrapper
around COM's BSTR type. In the TypeLibrary, you have to use BSTR for strings,
which Delphi will then wrap with WideString in the implementation code.
also, make sure you are defining the BSTR as [in] and [out, retval] parameters
in the property getter/setter methods, respectively, not as the actual "Return
Type", which needs to always be HRESULT (I don't know why the TypeLibrary
editor even allows that to be cusomizable).

Also, I'm using TAutoIntfObject (instead of TAutoObject): TMyClass =
class(TAutoIntfObject, IMyClass)

Then you do not need a CoClass at all.

In my case what params do I need to pass to create an instance of
TMyClass ?

I already showed you how to create it at runtime:

myObj := TMyClass.Create;


What I didn't take into account is the extra parameters in the TAutoIntfObject
constructor. You can give your class a no-parameter constructor that passes
the necessary parameters to the base constructor:

constructor TMyClass.Create;
var
  TypeLib: ITypeLib;
  ExeName: WideString;
begin
  ExeName := ParamStr(0);
  OleCheck(LoadTypeLib(PWideChar(ExeName), TypeLib));
  inherited Create(TypeLib, IMyClass);
end;


--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 4, 2016 9:26 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thank you for your suggestions.
I think there's a problem with the Library Type Editor in XE8. It resets my code every time I go into the editor.
Going to upgrade to Seattle 10.

Now, I'm getting this error:
  ProjectScript.exe raised exception class EOLeSysError with message 'Error loading type library/DLL'


This is the line which is causing the error:
  OleCheck(LoadTypeLib(PWideChar(ExeName), TypeLib))


ExeName correctly holds the path & exe name.

This is my code:

  myObj := TMyClass.Create;
  myObj.User := 'userName';
  myObj.Password := 'userPwrd';
  My_obj := CreateOleObject('COMtest');
  init_lib := My_obj.get_init_library_obj();
  init_lib.init_library(myObj, myObj);


unit ScriptProj_TLB;
 
{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers.
{$WARN SYMBOL_PLATFORM OFF}
{$WRITEABLECONST ON}
{$VARPROPSETTER ON}
{$ALIGN 4}
 
interface
 
uses Winapi.Windows, System.Classes, System.Variants, System.Win.StdVCL, Vcl.Graphics, Vcl.OleServer, Winapi.ActiveX, System.Win.ComObj;
 
 
const
  ScriptProjMajorVersion = 1;
  ScriptProjMinorVersion = 0;
 
  LIBID_ScriptProj: TGUID = '{F37D010F-8D1D-49BD-A417-46A7C47FB233}';
 
  IID_IMyClass: TGUID = '{16E99C35-E876-4F80-BAA1-41465722A4F0}';
  CLASS_CoClass: TGUID = '{98EF2C89-74D8-40C4-823C-75E627475FCE}';
type
 
  IMyClass = interface;
  IMyClassDisp = dispinterface;
 
  CoClass = IMyClass;
 
  IMyClass = interface(IDispatch)
    ['{16E99C35-E876-4F80-BAA1-41465722A4F0}']
    procedure Set_User(const Value: WideString); safecall;
    procedure Set_Password(const Value: WideString); safecall;
    procedure LibraryCreated(const p_Object: IDispatch); safecall;
    function Get_User: WideString; safecall;
    property User: WideString read Get_User write Set_User;
    function Get_Password:WideString safecall;
 
     property Password: WideString read Get_Password write Set_Password;
  end;
 
 
  IMyClassDisp = dispinterface
    ['{16E99C35-E876-4F80-BAA1-41465722A4F0}']
    procedure Get_User; dispid 201;
    procedure Set_User(const Value: WideString); dispid 202;
    procedure Get_Password; dispid 203;
    procedure Set_Password(const Value: WideString); dispid 204;
    procedure LibraryCreated(const p_Object: IDispatch); dispid 0;
    property User: WideString dispid 206;
    property Password: Integer dispid 207;
  end;
 
 
  //CoCoClass = class
  //  class function Create: IMyClass;
  //  class function CreateRemote(const MachineName: string): IMyClass;
  //end;
 
    TMyClass = class(TAutoIntfObject, IMyClass)
  public
     constructor create;
  private
    fUser: string;
    fPassword: string;
  protected
    function Get_Password: WideString; safecall;
    function Get_User: WideString; safecall;
    procedure LibraryCreated(const p_Object: IDispatch); safecall; // <--make sure this has dispid 0 assigned to it in the TypeLibrary
    procedure Set_Password(const Value: WideString); safecall;
    procedure Set_User(const Value: WideString); safecall;
    function ObjTypeName(Obj: IDispatch): string;
 
  end;
implementation
 
 
{ TMyClass }
 
constructor TMyClass.create;
var
  TypeLib : ITypeLib;
  ExeName : WideString;
begin
  ExeName := ParamStr(0);
  OleCheck(LoadTypeLib(PWideChar(ExeName), TypeLib));
  inherited create(TypeLib, IMyClass);
end;
 
function TMyClass.Get_Password: WideString;
begin
 Result := fPassword;
end;
 
function TMyClass.Get_User: WideString;
begin
  Result := fUser;
end;
 
procedure TMyClass.LibraryCreated(const p_Object: IDispatch);
begin
  MessageBox(0, PChar('class: ' + ObjTypeName(p_Object) + ' called for user:' + (p_Object as IMyClass).User), 'COM Test', MB_OK);
end;
 
function TMyClass.ObjTypeName(Obj: IDispatch): string;
var
  Count: Integer;
  TI: ITypeInfo;
  wName: WideString;
begin
  Result := 'Object';
  if Obj = nil then Exit;
  if Failed(Obj.GetTypeInfoCount(Count)) then Exit;
  if Count < 1 then Exit;
  if Failed(Obj.GetTypeInfo(0, 0, TI)) then Exit;
  if Failed(TI.GetDocumentation(MEMBERID_NIL, @wName, nil, nil, nil)) then
Exit;
  Result := wName;
end;
 
procedure TMyClass.Set_Password(const Value: WideString);
begin
  fPassword := Value;
end;
 
procedure TMyClass.Set_User(const Value: WideString);
begin
 fUser := Value;
end;
 
 
{ CoCoClass }
 
//class function CoCoClass.Create: IMyClass;
//begin
//  Result := CreateComObject(CLASS_CoClass) as IMyClass;
//end;
 
//class function CoCoClass.CreateRemote(const MachineName: string): IMyClass;
//begin
//  Result := CreateRemoteComObject(MachineName, CLASS_CoClass) as IMyClass;
//end;
 
initialization
  //TAutoObjectFactory.Create(ComServer, TMyClass, Class_MyClass, ciMultiInstance,tmApartment);
 
 
end.


Edited by: Fred Smith on Feb 4, 2016 9:27 AM

Edited by: Fred Smith on Feb 4, 2016 11:04 AM
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit] [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 4, 2016 11:58 AM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

I think there's a problem with the Library Type Editor in XE8.
It resets my code every time I go into the editor.

Now, I'm getting this error:

ProjectScript.exe raised exception class EOLeSysError with message
'Error loading type library/DLL'


This is the line which is causing the error:

OleCheck(LoadTypeLib(PWideChar(ExeName), TypeLib))

Sounds like your EXE's TypeLibrary is not actually registered on the machine
that your app runs on.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 5, 2016 1:13 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Sounds like your EXE's TypeLibrary is not actually registered on the machine
that your app runs on.

--
Remy Lebeau (TeamB)

That's what I thought. Not sure where I'm going wrong though.
When I click on "Register Type Library" in the editor it says :
  "Successfully registered ActiveX Sever, path + ScriptProj.exe"


I cannot find any of the GUIDs in the registry!

Edited by: Fred Smith on Feb 5, 2016 1:13 AM

Edited by: Fred Smith on Feb 5, 2016 1:15 AM
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 9, 2016 4:15 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Sounds like your EXE's TypeLibrary is not actually registered on the machine
that your app runs on.

--
Remy Lebeau (TeamB)

These are more details regarding the vbscript & what I'm trying to achieve.

1st, I register a COM library in the registry by executing this command:
  LibraryCOM.exe /RegServer


Then I run this VBScript which uses callbacks. Everything works fine. I need to convert the VBScript to Delphi.
The VBscript is very basic at this moment.


This an updated version of the vbScript:

Class myClass
  Public user
  public password
End class
 
dim myObj
Set myObj = New myClass
myObj.user = "userName"
myObj.password = "userPwrd"
 
' Initialise COM object (callbacks)
set My_obj = wscript.CreateObject("COMtest","pref_")
 
Set init_lib = My_obj.get_init_library_obj
 
init_lib.Flags(&h7fff)
init_lib.Environment(1)
 
call init_lib.init_library(GetRef("Library_created"), myObj)
 
dim MyIndex
dim MyDevice(MyIndex)
For MyIndex =1 to 2
  Set MyDevice(MyIndex) = My_obj.RegisterDevice("10.19.1"+Cstr(MyIndex)) 
Next
 
sub Library_created(p_Object)
  result = TypeName( p_Object) 
  MsgBox "class: " + result +" called for user: "+p_Object.user, 0, "COM Test"
end sub

I'm new to COM. Could you tell me why my Type Library isn't registering ?
Thank you for your help.

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit] [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 9, 2016 10:45 AM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

I'm new to COM. Could you tell me why my Type Library isn't
registering ? Thank you for your help.

I can't answer that. The /RegServer switch should have registered it, so
apparently it is fully hooked up. You might have to deploy and run Delphi's
TRegSvr.exe on your EXE file. Or wrap it in an installer that installs the
necessary TypeLibrary entries in the Registry.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 10, 2016 2:38 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

I'm new to COM. Could you tell me why my Type Library isn't
registering ? Thank you for your help.

I can't answer that. The /RegServer switch should have registered it, so
apparently it is fully hooked up. You might have to deploy and run Delphi's
TRegSvr.exe on your EXE file. Or wrap it in an installer that installs the
necessary TypeLibrary entries in the Registry.

--
Remy Lebeau (TeamB)

My apologies, I don't think I explained myself very well.

LibraryCOM.exe is not my software and it works fine.

This command works fine & registers LibraryCOM in the registry (I've checked the registry):
  LibraryCOM.exe /RegServer

That's why when I execute the VBScript in the command line, everything works fine:
  cscript TestingVBScript.vbs


This message gets displayed just before the end fo the VBScript execution:
  "class: myClass called for user: userName"

It's just a small test which shows everything works fine.



What I'm trying do is communicate with LibraryCOM, which is already registered (by executing LibraryCOM.exe /RegServer), & do something similar to what the VBScript does.
So, if I do this in Delphi:
  myObj := TMyClass.Create;
  myObj.User := 'DelphiUser';
  myObj.Password := 'userPwrd';
  My_obj := CreateOleObject('COMtest'); //should initialise main COM object in the LibraryCOM \equivalent to VBScript: set My_obj = wscript.CreateObject("COMtest","pref_")
  init_lib := My_obj.get_init_library_obj();
  init_lib.init_library(myObj, myObj);


I'd like to see a message similar to this:
  "class: myClass called for user: DelphiUser "

(I know that I still need to create in Delphi the equivalent of VBScript sub Library_created(p_Object))

If I can communicate with the (already registered) LibraryCOM & set the user & Password, I'll know I'm on the right track.
----
At this moment, Delphi code errors on this line:
  OleCheck(LoadTypeLib(PWideChar(ExeName), TypeLib)) //ExeName evaluates to path + Delphi project name which is: ScriptProj.exe

The error is :
  ScriptProject.exe raised exception class EOLeSysError with message 'Error loading type library/DLL'


If I run this:
  tregsvr ScriptProj.exe

I get the following:
  ScriptProj.exe /RegServer successfully called.

It just launches my exe. If I click on the button which runs the delphi code I get the same error:
  'Error loading type library/DLL'


These are the steps I'm following:
Create a Delphi project
Go to File->New->Other to Add a Type Library
Create the interface, functions, & properties in the Type Library Editor, Refresh, then add the implentations manually.
then Generate the exe.

Edited by: Fred Smith on Feb 10, 2016 2:39 AM

Edited by: Fred Smith on Feb 10, 2016 4:35 AM

Edited by: Fred Smith on Feb 10, 2016 4:39 AM

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit] [Edit] [Edit][Edit]
Correct
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 10, 2016 11:24 AM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

My apologies, I don't think I explained myself very well.

You are explaining yourself jsut fine. Maybe you are not understanding what
I have explained to you.

LibraryCOM.exe is not my software and it works fine.

I don't care about that. YOUR software is declaring and passing its own
COM object to the COM object implemented by LibraryCOM. YOUR software is
trying to replicate a similar environment as cscript.exe host. YOUR software
requires its own TypeLibrary to declare the properties and methods that LibraryCOM
will be accessing. YOUR TypeLibrary is not getting registered correctly,
and that is the problem that needs to be solved.

Create a Delphi project

Go to File->New->Other to Add a Type Library

And here is where the problem lies. The TypeLibrary is not being hooked
up to Delphi's COM registration framework by default. Try using "File >
New > Other > Delphi Projects > ActiveX > Automation Object" instead, which
also creates a TypeLibrary but also creates and hooks up a default object
within it. That should also hook up the registration code for it.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit] [Edit][Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 11, 2016 10:45 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

My apologies, I don't think I explained myself very well.

You are explaining yourself jsut fine. Maybe you are not understanding what
I have explained to you.

LibraryCOM.exe is not my software and it works fine.

I don't care about that. YOUR software is declaring and passing its own
COM object to the COM object implemented by LibraryCOM. YOUR software is
trying to replicate a similar environment as cscript.exe host. YOUR software
requires its own TypeLibrary to declare the properties and methods that LibraryCOM
will be accessing. YOUR TypeLibrary is not getting registered correctly,
and that is the problem that needs to be solved.

Create a Delphi project

Go to File->New->Other to Add a Type Library

And here is where the problem lies. The TypeLibrary is not being hooked
up to Delphi's COM registration framework by default. Try using "File >
New > Other > Delphi Projects > ActiveX > Automation Object" instead, which
also creates a TypeLibrary but also creates and hooks up a default object
within it. That should also hook up the registration code for it.

--
Remy Lebeau (TeamB)

I tried your suggestion and it did work. Thank you very much.
I'm a bit further now.
Now my TypeLibrary is getting registered & it talks to LibraryCOM.

I have a couple of questions, if you don't mind.
Could you tell me why when I call :

  My_obj.RegisterDevice('...')

I get method not found error.

Aso, the VBScript defines this callback method
sub pref_library_info(header,info)
	WScript.StdOut.WriteLine header + " - " + info
end sub


which works fine in the VBScript.
How do I hook it up in my Delphi code ?
Still not sure how to use IConnectionPointContainer to receive events.

Thanks again. Your help is appreciated.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 11, 2016 5:23 PM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

Could you tell me why when I call :
My_obj.RegisterDevice('...')

I get method not found error.

I assume this is in your VBScript code, right? Does your Delphi COM object
have a RegisterDevice() method defined in the TypeLibrary? What does your
TypeLibrary actually look like?

Aso, the VBScript defines this callback method
sub pref_library_info(header,info)
WScript.StdOut.WriteLine header + " - " + info
end sub


which works fine in the VBScript.
How do I hook it up in my Delphi code ?

I thought I already explained how to do that. Maybe not.

Your Delphi code needs to call IActiveScript.GetScriptDispatch() to get an
IDispatch interface for "pref_library_info" (this is where "pref_" comes
into play when your VBScript calls wscript.CreateObject(), so WScript can
find "pref_library_info" when it wants to call the script's "library_info"
handler). You can then call the IDispatch.Invoke() method, setting its dispid
parameter to 0, its wFlags paerameter to DISPATCH_METHOD, and passing the
desired header and info values in its pDispParams parameter.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 12, 2016 9:34 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

Could you tell me why when I call :
My_obj.RegisterDevice('...')

I get method not found error.

I assume this is in your VBScript code, right? Does your Delphi COM object
have a RegisterDevice() method defined in the TypeLibrary? What does your
TypeLibrary actually look like?

No, that's the Delphi code to test if I can call the procedure. (By the way that method works fine in the VBScript: My_obj.RegisterDevice("10.19.1"+Cstr(MyIndex)))
Yes, I defined the method in the TypeLibrary.
This how my type library looks like:
some of the code in the .ridl file (I used the library type editor)
  HRESULT _stdcall RegisterDevice([in] BSTR IPaddress); 


IMyClass :

  IMyClass = interface(IDispatch)
    ['{DD6C837F-BE9B-48EB-B648-8A5AED06EB87}']
    procedure Set_User(const Value: WideString); safecall;
    function Get_User: WideString; safecall;
    procedure LibraryCreated(const p_Object: IDispatch); safecall;
    function Get_Password: WideString; safecall;
    procedure Set_Password(const Value: WideString); safecall;
    property User: WideString read Get_User write Set_User;
    property Password: WideString read Get_Password write Set_Password;
    procedure RegisterDevice( IPaddress: WideString); safecall;
  end;


IMyClassDisp:
  IMyClassDisp = dispinterface
    ['{DD6C837F-BE9B-48EB-B648-8A5AED06EB87}']
    procedure Get_User; dispid 201;
    procedure Set_User(const Value: WideString); dispid 202;
    property User: WideString dispid 203;
    procedure LibraryCreated(const p_Object: IDispatch); dispid 0;
    procedure Get_Password; dispid 204;
    procedure Set_Password(const Value: WideString); dispid 205;
    property Password: WideString dispid 206;
    procedure RegisterDevice(IPaddress: WideStringg); dispid 207;
  end;


TMyClass:
  TMyClass = class(TAutoIntfObject, IMyClass)
  public
    constructor create;
  private
    fUser:string;
    fPassword : string;
    function ObjTypeName(Obj: IDispatch): string;
  protected
  function Get_User : WideString;safecall;
  function Get_Password : WideString;safecall;
  procedure Set_User (const Value : WideString);safecall;
  procedure Set_Password (const Value : WideString);safecall;
  procedure LibraryCreated(const p_Object:IDispatch);safecall;
  procedure RegisterDevice(IPaddress:WideString; Param2, Param3:WideString);safecall;
end;


// Implementation section
procedure TMyClass.RegisterDevice(IPaddress: WideString);
begin
 // No body at this moment.  Just checking if this method gets called.  It isn't being called !!!
end;


Aso, the VBScript defines this callback method
sub pref_library_info(header,info)
WScript.StdOut.WriteLine header + " - " + info
end sub


which works fine in the VBScript.
How do I hook it up in my Delphi code ?

I thought I already explained how to do that. Maybe not.

Your Delphi code needs to call IActiveScript.GetScriptDispatch() to get an
IDispatch interface for "pref_library_info" (this is where "pref_" comes
into play when your VBScript calls wscript.CreateObject(), so WScript can
find "pref_library_info" when it wants to call the script's "library_info"
handler). You can then call the IDispatch.Invoke() method, setting its dispid
parameter to 0, its wFlags paerameter to DISPATCH_METHOD, and passing the
desired header and info values in its pDispParams parameter.

--
Remy Lebeau (TeamB)

I thought IActiveScript is used only if the script is being included. I'll give it a go.
Thank you very much.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 12, 2016 10:31 AM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

No, that's the Delphi code to test if I can call the procedure.

Then what is My_obj actually declared as? IMyClass or OleVariant? Please
provide a more complete code snippet.

TMyClass = class(TAutoIntfObject, IMyClass)
public
...
procedure RegisterDevice(IPaddress:WideString; Param2, Param3:WideString);safecall;
end;

Why does RegisterDevice() have 3 parameters in TMyClass? It only has 1 parameter
in IMyClass.

I thought IActiveScript is used only if the script is being included.

Sorry, my bad. I lost track of what we were talking about.

Yes, IActiveScript is used only if you want your Delphi code to run the original
VBScript as-is. If you are just trying to replicate what the VBScript code
does, but in native Delphi code, you don't need IActiveScript at all. However,
in that latter situation, the only way LibraryCOM will be able to fire events
to your Delphi code is if either:

1. LibraryCOM exposes an IConnectionPoint that you can provide a COM object
to, which implements the appropriate events interface that LibraryCOM can
call into when needed.

2. LibraryCOM provides a method that you can pass a COM object to, where
that object implements IDispatch dispid 0 for LibraryCOM to call when needed
(ie, the LibraryCreated() example I showed you earlier).

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 15, 2016 7:10 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

No, that's the Delphi code to test if I can call the procedure.

Then what is My_obj actually declared as? IMyClass or OleVariant? Please
provide a more complete code snippet.

I declared My_obj as OleVariant.
procedure TForm6.Button1Click(Sender: TObject);
var
  myObj : IMyClass;
  My_obj, init_lib : OleVariant;
begin
   myObj := TMyClass.Create;
  myObj.User := 'DelphiUser';
  myObj.Password := 'userPwrd';
  My_obj := CreateOleObject('COMtest'); //should initialise main COM object in the LibraryCOM \equivalent to VBScript: set My_obj = wscript.CreateObject("COMtest","pref_")
  // If I change COMtest to something else or unregister LibraryCOM.exe, I get this error: 'Invalid class string'
  init_lib := My_obj.get_init_library_obj();
 
  // init_lib.Flags(&H7FFF); // Any idea how to assign this flag in Delphi ?
  init_lib.init_library(myObj, myObj);
  My_obj.RegisterDevice('IPAddress','test1','test2'); // Error: member not found
end;

TMyClass = class(TAutoIntfObject, IMyClass)
public
...
procedure RegisterDevice(IPaddress:WideString; Param2, Param3:WideString);safecall;
end;

Why does RegisterDevice() have 3 parameters in TMyClass? It only has 1 parameter
in IMyClass.

Sorry, that's my fault. It requires 3 params.

I thought IActiveScript is used only if the script is being included.

Sorry, my bad. I lost track of what we were talking about.

Yes, IActiveScript is used only if you want your Delphi code to run the original
VBScript as-is. If you are just trying to replicate what the VBScript code
does, but in native Delphi code, you don't need IActiveScript at all. However,
in that latter situation, the only way LibraryCOM will be able to fire events
to your Delphi code is if either:

1. LibraryCOM exposes an IConnectionPoint that you can provide a COM object
to, which implements the appropriate events interface that LibraryCOM can
call into when needed.

2. LibraryCOM provides a method that you can pass a COM object to, where
that object implements IDispatch dispid 0 for LibraryCOM to call when needed
(ie, the LibraryCreated() example I showed you earlier).

I'm looking into this. I don't have access to the code insdie LibraryCOM.exe
I just register it & run the VBScript to test it. I will talk to the people developing it. Thanks.

This is all the Delphi code:
text file:
https://drive.google.com/file/d/0B2PTdsZrN1wyRExCaGxMajB0MkE/view?usp=sharing

zip file:
https://drive.google.com/file/d/0B2PTdsZrN1wyeFRNVGNIa3U2Q0k/view?usp=sharing

VBScript:
https://drive.google.com/file/d/0B2PTdsZrN1wyUklBV285Q2RMQ1U/view?usp=sharing
--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit][Edit][Edit][Edit][Edit] [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 16, 2016 1:17 PM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

My_obj.RegisterDevice('IPAddress','test1','test2'); // Error: member not
found

Does LibraryCOM have a RegisterDevice() method to begin with? Probably
not. You created a RegisterDevice() method in your COM object, but My_obj
points at LibraryCOM's COM object instead.

I'm looking into this. I don't have access to the code insdie
LibraryCOM.exe

Do you have any documentation for it, at least? Or more VBScript examples?

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 17, 2016 7:01 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

No, that's the Delphi code to test if I can call the procedure.

Then what is My_obj actually declared as? IMyClass or OleVariant? Please
provide a more complete code snippet.

TMyClass = class(TAutoIntfObject, IMyClass)
public
...
procedure RegisterDevice(IPaddress:WideString; Param2, Param3:WideString);safecall;
end;

Why does RegisterDevice() have 3 parameters in TMyClass? It only has 1 parameter
in IMyClass.

I thought IActiveScript is used only if the script is being included.

Sorry, my bad. I lost track of what we were talking about.

Yes, IActiveScript is used only if you want your Delphi code to run the original
VBScript as-is. If you are just trying to replicate what the VBScript code
does, but in native Delphi code, you don't need IActiveScript at all. However,
in that latter situation, the only way LibraryCOM will be able to fire events
to your Delphi code is if either:

1. LibraryCOM exposes an IConnectionPoint that you can provide a COM object
to, which implements the appropriate events interface that LibraryCOM can
call into when needed.

2. LibraryCOM provides a method that you can pass a COM object to, where
that object implements IDispatch dispid 0 for LibraryCOM to call when needed
(ie, the LibraryCreated() example I showed you earlier).

--
Remy Lebeau (TeamB)

Is it possible to give me more pointers regarding how to implement the callback function pref_library_info(header, info) in Delphi.
Couldn't see IConnectionPoint in the OLE/COM Object viewer. Maybe the author will expose it at a later date, not sure.

Could you elaborate a bit more regarding the 2nd alternative i.e. using IDispatch & dispid 0.
Thanks. You've been very helpful.

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 18, 2016 11:01 AM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

Is it possible to give me more pointers regarding how to implement
the callback function pref_library_info(header, info) in Delphi.

Looking at the TypeLibrary declarations you provided earlier, I see a COM_feedback
interface that has a library_info() method. That interface is marked with
a "source" attribute in the TypeLibrary's CoClass, which means that is LibraryCOM's
ConnectionPoint for providing events. So, you can:

1. write a TInterfacedObject-derived class that implements the COM_feedback
interface and its methods (I don't know why the method parameters are all
marked as [out] though, that is not usual for events).

2. query the LibraryCOM object for its IConnectionPointContainer interface.

3. call IConnectionPointContainer.FindConnectionPoint(), specifying COM_feedback's
IID, to get an IConnectionPoint interface.

4. pass an instance of your event class to the IConnectionPoint.Advise()
method.

If you figure out how to import the LibraryCOM library into the IDE, it will
create a wrapper VCL component that handles these details for you.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 18, 2016 3:27 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

Is it possible to give me more pointers regarding how to implement
the callback function pref_library_info(header, info) in Delphi.

Looking at the TypeLibrary declarations you provided earlier, I see a COM_feedback
interface that has a library_info() method. That interface is marked with
a "source" attribute in the TypeLibrary's CoClass, which means that is LibraryCOM's
ConnectionPoint for providing events. So, you can:

1. write a TInterfacedObject-derived class that implements the COM_feedback
interface and its methods (I don't know why the method parameters are all
marked as [out] though, that is not usual for events).

2. query the LibraryCOM object for its IConnectionPointContainer interface.

3. call IConnectionPointContainer.FindConnectionPoint(), specifying COM_feedback's
IID, to get an IConnectionPoint interface.

4. pass an instance of your event class to the IConnectionPoint.Advise()
method.
I'll try your suggestions. Thank you very much.
When I scan the EXE for the interface & function strings you mentioned(using hex editor or TEXT Crawler), I can see them.

If you figure out how to import the LibraryCOM library into the IDE, it will
create a wrapper VCL component that handles these details for you.

--
Remy Lebeau (TeamB)

I can't understand why I can't import it.
It's not visible in the import screen whether I use the name of the library or the GUID.
when I try to add the LibraryCOM.exe in xe8 & Seattle 10 (Delphi & C++), both IDEs throw an error.
The library is written in C and it's a 32bit with an .EXE extension.
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 19, 2016 6:29 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

Is it possible to give me more pointers regarding how to implement
the callback function pref_library_info(header, info) in Delphi.

Looking at the TypeLibrary declarations you provided earlier, I see a COM_feedback
interface that has a library_info() method. That interface is marked with
a "source" attribute in the TypeLibrary's CoClass, which means that is LibraryCOM's
ConnectionPoint for providing events. So, you can:

1. write a TInterfacedObject-derived class that implements the COM_feedback
interface and its methods (I don't know why the method parameters are all
marked as [out] though, that is not usual for events).

2. query the LibraryCOM object for its IConnectionPointContainer interface.

3. call IConnectionPointContainer.FindConnectionPoint(), specifying COM_feedback's
IID, to get an IConnectionPoint interface.

4. pass an instance of your event class to the IConnectionPoint.Advise()
method.

If you figure out how to import the LibraryCOM library into the IDE, it will
create a wrapper VCL component that handles these details for you.

--
Remy Lebeau (TeamB)

I managed to import the library into my project. This is the .pas file generated:
https://drive.google.com/file/d/0B2PTdsZrN1wyTUJDcXV2cC1JV1E/view?usp=sharing

Not sure why no wrapper VCL component has been generated.
I was hoping that would help me sort out the events.

Do still think this code is going about it the right way?

var
  My_obj : OleVariant;
 
procedure TForm6.Button1Click(Sender: TObject);
var
  myObj : IMyClass;
  init_lib : OleVariant;
begin
  myObj := TMyClass.Create;
  myObj.User := 'DelphiUser';
  myObj.Password := 'userPwrd';
  My_obj := CreateOleObject('COMtest');
  init_lib := My_obj.get_init_library_obj;
  init_lib.Flags($7FFF);
  init_lib.Environment(1);
  init_lib.init_library(myObj, myObj)
  My_obj.RegisterDevice('IPAddress', 'test1', 'test2');
end;


Thanks


unit C_LIB_TLB;
 
interface
 
uses Winapi.Windows, System.Classes, System.Variants, System.Win.StdVCL, Vcl.Graphics, Vcl.OleServer, Winapi.ActiveX;
  
  
const
  // TypeLibrary Major and minor versions
  C_LIBMajorVersion = 1;
  C_LIBMinorVersion = 0;
 
  LIBID_C_LIB: TGUID = '{5D905FDE-5B9D-415D-B1D0-1E6461408969}';
 
  IID_the_device: TGUID = '{3247B37D-C8AC-11D5-A855-E1F7F2CE4ADA}';
  IID_COM_feedback: TGUID = '{CD223432-D643-428B-4F3C-1C5D446BC4CE}';
  IID_initLibraryStruct: TGUID = '{9222FF70-F454-4B36-B5D5-9C7F0DD6F4B4}';
  IID_COM_C_LIB: TGUID = '{B6127D34-D15F-4BA0-DAA3-7220C95EEF4D}';
  CLASS_C_LIB_: TGUID = '{652F4CFD-62D5-4EED-5987-C26D514D3D54}';
type
 
  the_device = interface;
  the_deviceDisp = dispinterface;
  COM_feedback = interface;
  initLibraryStruct = interface;
  initLibraryStructDisp = dispinterface;
  COM_C_LIB = interface;
  COM_C_LIBDisp = dispinterface;
 
  C_LIB_ = COM_C_LIB;
 
 
  the_device = interface(IDispatch)
    ['{3247B37D-C8AC-11D5-A855-E1F7F2CE4ADA}']
    function init_library(const a: IDispatch; const b: IDispatch): Integer; safecall;
    function Environment(a: Integer): Integer; safecall;
    function Flags(a: Integer): Integer; safecall;
  end;
 
  the_deviceDisp = dispinterface
    ['{3247B37D-C8AC-11D5-A855-E1F7F2CE4ADA}']
    function init_library(const a: IDispatch; const b: IDispatch): Integer; dispid 1;
    function Environment(a: Integer): Integer; dispid 2;
    function Flags(a: Integer): Integer; dispid 3;
  end;
 
  
  COM_feedback = interface(IDispatch)
    ['{CD223216-D698-428B-9F3C-1C5D446BC4CE}']
    function library_info(out a: WideString; out b: WideString): HResult; stdcall;
  end;
 
  
  initLibraryStruct = interface(IDispatch)
    ['{9222FF70-F454-4B36-B5D5-9C7F0DD6F4B4}']
    function init_library(const a: IDispatch; const b: IDispatch): Integer; safecall;
    function Environment(a: Integer): Integer; safecall;
    function Flags(a: Integer): Integer; safecall;
  end;
 
 
  initLibraryStructDisp = dispinterface
    ['{9222FF70-F454-4B36-B5D5-9C7F0DD6F4B4}']
    function init_library(const a: IDispatch; const b: IDispatch): Integer; dispid 1;
    function Environment(a: Integer): Integer; dispid 2;
    function Flags(a: Integer): Integer; dispid 3;
  end;
 
  COM_C_LIB = interface(IDispatch)
    ['{B6127C55-AC5F-4BA0-AFF6-7220C95EEF4D}']
    function Get_get_init_library_obj: initLibraryStruct; safecall;
    function Get_RegisterDevice(const a: WideString; const b: WideString; const c: WideString): the_device; safecall;
    property get_init_library_obj: initLibraryStruct read Get_get_init_library_obj;
    property RegisterDevice[const a: WideString; const b: WideString; const c: WideString]: the_device read Get_RegisterDevice;
  end;
 
 
  COM_C_LIBDisp = dispinterface
    ['{B6127C55-AC5F-4BA0-AFF6-7220C95EEF4D}']
    property get_init_library_obj: initLibraryStruct readonly dispid 1;
    property RegisterDevice[const a: WideString; const b: WideString; const c: WideString]: the_device readonly dispid 4;
  end;
 
 
  CoC_LIB_ = class
    class function Create: COM_C_LIB;
    class function CreateRemote(const MachineName: string): COM_C_LIB;
  end;
 
  TC_LIB_library_info = procedure(ASender: TObject; out a: WideString; out b: WideString) of object;
 
 
 
  TC_LIB_ = class(TOleServer)
  private
    FOnlibrary_info: TC_LIB_library_info;
    FIntf: COM_C_LIB;
    function GetDefaultInterface: COM_C_LIB;
  protected
    procedure InitServerData; override;
    procedure InvokeEvent(DispID: TDispID; var Params: TVariantArray); override;
    function Get_get_init_library_obj: initLibraryStruct;
    function Get_RegisterDevice(const a: WideString; const b: WideString; const c: WideString): the_device;
  public
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy; override;
    procedure Connect; override;
    procedure ConnectTo(svrIntf: COM_C_LIB);
    procedure Disconnect; override;
    property DefaultInterface: COM_C_LIB read GetDefaultInterface;
    property get_init_library_obj: initLibraryStruct read Get_get_init_library_obj;
    property RegisterDevice[const a: WideString; const b: WideString; const c: WideString]: the_device read Get_RegisterDevice;
  published   
    property Onlibrary_info: TC_LIB_library_info read FOnlibrary_info write FOnlibrary_info;
  end;
 
procedure Register;
 
resourcestring
  dtlServerPage = 'Servers';
 
  dtlOcxPage = 'ActiveX';
 
implementation
 
uses System.Win.ComObj;
 
class function CoC_LIB_.Create: COM_C_LIB;
begin
  Result := CreateComObject(CLASS_C_LIB_) as COM_C_LIB;
end;
 
class function CoC_LIB_.CreateRemote(const MachineName: string): COM_C_LIB;
begin
  Result := CreateRemoteComObject(MachineName, CLASS_C_LIB_) as COM_C_LIB;
end;
 
procedure TC_LIB_.InitServerData;
const
  CServerData: TServerData = (
    ClassID:   '{652F4CFD-62D5-4EED-5987-C26D514D3D54}';
    IntfIID:   '{B6127C55-AC5F-4BA0-AFF6-7220C95EEF4D}';
    EventIID:  '{CD223216-D698-428B-9F3C-1C5D446BC4CE}';
    LicenseKey: nil;
    Version: 500);
begin
  ServerData := @CServerData;
end;
 
procedure TC_LIB_.Connect;
var
  punk: IUnknown;
begin
  if FIntf = nil then
  begin
    punk := GetServer;
    ConnectEvents(punk);
    Fintf:= punk as COM_C_LIB;
  end;
end;
 
procedure TC_LIB_.ConnectTo(svrIntf: COM_C_LIB);
begin
  Disconnect;
  FIntf := svrIntf;
  ConnectEvents(FIntf);
end;
 
procedure TC_LIB_.DisConnect;
begin
  if Fintf <> nil then
  begin
    DisconnectEvents(FIntf);
    FIntf := nil;
  end;
end;
 
function TC_LIB_.GetDefaultInterface: COM_C_LIB;
begin
  if FIntf = nil then
    Connect;
  Assert(FIntf <> nil, 'DefaultInterface is NULL. Component is not connected to Server. You must call "Connect" or "ConnectTo" before this operation');
  Result := FIntf;
end;
 
 
procedure TC_LIB_.InvokeEvent(DispID: TDispID; var Params: TVariantArray);
begin
  case DispID of
    -1: Exit;  // DISPID_UNKNOWN
    2: if Assigned(FOnlibrary_info) then
         FOnlibrary_info(Self,
                        WideString((TVarData(Params[0]).VPointer)^) {out WideString},
                        WideString((TVarData(Params[1]).VPointer)^) {out WideString});
  end; {case DispID}
end;
 
function TC_LIB_.Get_get_init_library_obj: initLibraryStruct;
begin
  Result := DefaultInterface.get_init_library_obj;
end;
 
function TC_LIB_.Get_RegisterDevice(const a: WideString; const b: WideString; const c: WideString): the_device;
begin
  Result := DefaultInterface.RegisterDevice[a, b, c];
end;
 
procedure Register;
begin
  RegisterComponents(dtlServerPage, [TC_LIB_]);
end;
 
end.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 19, 2016 7:38 PM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

I managed to import the library into my project. This is the .pas
file generated:

https://drive.google.com/file/d/0B2PTdsZrN1wyTUJDcXV2cC1JV1E/view?usp=sharing

Not sure why no wrapper VCL component has been generated. I was hoping
that would help me sort out the events.

Did you enable the "Generate Component Wrappers" option in import wizard?

Do still think this code is going about it the right way?

With the new imported unit, you could make the following changes, at least:

var
  My_obj : COM_C_LIB;
 
procedure TForm6.Button1Click(Sender: TObject);
var
  myObj : IMyClass;
  init_lib : initLibraryStruct;
begin
  myObj := TMyClass.Create;
  myObj.User := 'DelphiUser';
  myObj.Password := 'userPwrd';
  
  My_obj := CoC_LIB_.Create;
  init_lib := My_obj.get_init_library_obj;
  init_lib.Flags($7FFF);
  init_lib.Environment(1);
  init_lib.init_library(myObj, myObj);
  My_obj.RegisterDevice['IPAddress', 'test1', 'test2'];
end;

--
Remy Lebeau (TeamB)

Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 19, 2016 7:52 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

I managed to import the library into my project. This is the .pas
file generated:

https://drive.google.com/file/d/0B2PTdsZrN1wyTUJDcXV2cC1JV1E/view?usp=sharing

Not sure why no wrapper VCL component has been generated. I was hoping
that would help me sort out the events.

Did you enable the "Generate Component Wrappers" option in import wizard?

The wizard keeps throwing errors. I used tlibimp. I don't that generates wrappers.

Do still think this code is going about it the right way?

With the new imported unit, you could make the following changes, at least:

var
  My_obj : COM_C_LIB;
 
procedure TForm6.Button1Click(Sender: TObject);
var
  myObj : IMyClass;
  init_lib : initLibraryStruct;
begin
  myObj := TMyClass.Create;
  myObj.User := 'DelphiUser';
  myObj.Password := 'userPwrd';
  
  My_obj := CoC_LIB_.Create;
  init_lib := My_obj.get_init_library_obj;
  init_lib.Flags($7FFF);
  init_lib.Environment(1);
  init_lib.init_library(myObj, myObj);
  My_obj.RegisterDevice['IPAddress', 'test1', 'test2'];
end;

Thank you.

--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 19, 2016 8:28 PM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

The wizard keeps throwing errors. I used tlibimp. I don't that
generates wrappers.

It does, actually, but only if you ask it to. Run tlibimp without any parameters
and it will output what parameters it supports:

Syntax: TLIBIMP [options] <typelibfile>
Files to Generate (Required): Output File Options:
-C Generate C++ Import file -D<path> Output directory path
-P Generate PASCAL Import file -Fe<name> TLB suffix (-Fe- none)
-I Generate .ridl Import file -Ft<name> TLB filename (no suffix)
-Ce<name> OCX suffix (-Ce- none)
-Co<name> OCX filename (no suffix)
Customize code generated:
-Ha+ Create IDE component for Controls -Hpa<name> Set palette name
-Hs+ Create IDE component for Servers -Hps<name> Set palette name
-Hr+ Generate component registration
C++ options: PASCAL options:
-Cd+ Generate dispinterfaces -Ps+ Map dual HRESULT to safecall
-Cm- Map disp interfaces to dual -Pt- Map all HRESULT to safecall
-Cn<name> Set namespace name
-Cs- declspec(__selectany) for GUIDs MISC options:
-Ct+ Force the use of a _TLB file -O+ Generate CoClassCreator wrappers
-Cu+ Expose namespace with 'using' -R+ Process dependent type libraries
-Cv+ BCB4-style server events -XM- Use MS-style getter/setter
-Cw- Use disp. in Control wrappers -W+ Emit warnings in files
-Wc+ Emit comments in files
Ignore Flags: -Ya- All special flags, -Yc+ [CanCreate],
-Yh- [Hidden], -Yp- [Predefined], -Yr- [Restricted]

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 19, 2016 9:26 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

The wizard keeps throwing errors. I used tlibimp. I don't that
generates wrappers.

It does, actually, but only if you ask it to. Run tlibimp without any parameters
and it will output what parameters it supports:

Syntax: TLIBIMP [options] <typelibfile>
Files to Generate (Required): Output File Options:
-C Generate C++ Import file -D<path> Output directory path
-P Generate PASCAL Import file -Fe<name> TLB suffix (-Fe- none)
-I Generate .ridl Import file -Ft<name> TLB filename (no suffix)
-Ce<name> OCX suffix (-Ce- none)
-Co<name> OCX filename (no suffix)
Customize code generated:
-Ha+ Create IDE component for Controls -Hpa<name> Set palette name
-Hs+ Create IDE component for Servers -Hps<name> Set palette name
-Hr+ Generate component registration
C++ options: PASCAL options:
-Cd+ Generate dispinterfaces -Ps+ Map dual HRESULT to safecall
-Cm- Map disp interfaces to dual -Pt- Map all HRESULT to safecall
-Cn<name> Set namespace name
-Cs- declspec(__selectany) for GUIDs MISC options:
-Ct+ Force the use of a _TLB file -O+ Generate CoClassCreator wrappers
-Cu+ Expose namespace with 'using' -R+ Process dependent type libraries
-Cv+ BCB4-style server events -XM- Use MS-style getter/setter
-Cw- Use disp. in Control wrappers -W+ Emit warnings in files
-Wc+ Emit comments in files
Ignore Flags: -Ya- All special flags, -Yc+ [CanCreate],
-Yh- [Hidden], -Yp- [Predefined], -Yr- [Restricted]
Thank you.
I tried few options but couldn't see any IConnectionPointContainer in the generated file.
  tlibimp -p -i -o+ -hr+ -hs+ -ha+ -ps+ -pt-

I will try again.

Tried your suggestion:
var
  My_obj : COM_C_LIB;
 
procedure TForm6.Button1Click(Sender: TObject);
var
  myObj : IMyClass;
  init_lib : initLibraryStruct;
begin
  myObj := TMyClass.Create;
  myObj.User := 'DelphiUser';
  myObj.Password := 'userPwrd';
  
  My_obj := CoC_LIB_.Create;
  init_lib := My_obj.get_init_library_obj;
  init_lib.Flags($7FFF);
  init_lib.Environment(1);
  init_lib.init_library(myObj, myObj);
  My_obj.RegisterDevice['IPAddress', 'test1', 'test2'];
end;


Trying to find out why this line throws "no such interface supported" error:
    init_lib := My_obj.get_init_library_obj; // no such interface supported !!


I tried re-registering my exe but that didn't make any difference.
--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 22, 2016 10:13 AM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

I tried few options but couldn't see any IConnectionPointContainer in
the generated file.

You wouldn't. It is something that has to be queried for at runtime.

Trying to find out why this line throws "no such interface supported" error:

init_lib := My_obj.get_init_library_obj; // no such interface supported !!

That means the object being returned by get_init_library_obj() does not implement
the initLibraryStruct interface. Which is odd, because we can clearly see
in the TypeLibrary that it does.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 22, 2016 2:18 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

I tried few options but couldn't see any IConnectionPointContainer in
the generated file.

You wouldn't. It is something that has to be queried for at runtime.

That makes sense.

Trying to find out why this line throws "no such interface supported" error:

init_lib := My_obj.get_init_library_obj; // no such interface supported !!

That means the object being returned by get_init_library_obj() does not implement
the initLibraryStruct interface. Which is odd, because we can clearly see
in the TypeLibrary that it does.
The debugging doesn't help at all: I just get that error message. It doesn't step into any code before that.

Do you have any suggestions I could try?
Do I need add get_init_library_obj to IMyClass ?

The previous line works fine:
  My_obj := CoC_LIB_.Create;


When I hover the pointer on My_obj, I get the following:
  my_obj: Pointer($1011F9C) as COM_C_LIB

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 21, 2016 4:14 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

I managed to import the library into my project. This is the .pas
file generated:

https://drive.google.com/file/d/0B2PTdsZrN1wyTUJDcXV2cC1JV1E/view?usp=sharing

Not sure why no wrapper VCL component has been generated. I was hoping
that would help me sort out the events.

Did you enable the "Generate Component Wrappers" option in import wizard?

Do still think this code is going about it the right way?

With the new imported unit, you could make the following changes, at least:

var
  My_obj : COM_C_LIB;
 
procedure TForm6.Button1Click(Sender: TObject);
var
  myObj : IMyClass;
  init_lib : initLibraryStruct;
begin
  myObj := TMyClass.Create;
  myObj.User := 'DelphiUser';
  myObj.Password := 'userPwrd';
  
  My_obj := CoC_LIB_.Create;
  init_lib := My_obj.get_init_library_obj;
  init_lib.Flags($7FFF);
  init_lib.Environment(1);
  init_lib.init_library(myObj, myObj);
  My_obj.RegisterDevice['IPAddress', 'test1', 'test2'];
end;

--
Remy Lebeau (TeamB)


Any idea why this line:
  init_lib := My_obj.get_init_library_obj; // no such interface supported !!

is throwing a "no such interface supported" error?
Could not find much info regarding this error. Some sites suggested re-registering the app. I tried that but it made no difference.
Thanks
Douglas Rudd

Posts: 314
Registered: 5/16/97
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 12, 2016 2:01 PM   in response to: Fred Smith in response to: Fred Smith
I think you are going off track.

It sounds like you have an application "LibraryCOM.exe" that is a COM server and you would like to call some of its functions from your own Delphi program.

First of all, when you go to Main Menu - Component - Import Component - Import a Type Library, does that list show up that LibraryCOM thing? If it does, then this should be fairly simple.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 12, 2016 2:21 PM   in response to: Douglas Rudd in response to: Douglas Rudd
Douglas wrote:

It sounds like you have an application "LibraryCOM.exe" that is a COM
server and you would like to call some of its functions from your own
Delphi program.

Yes, but it is also needs to be able to fire events back into the Delphi
app, and those events are usable in VBScript, which uses a different event
model then traditional COM event handling. Granted, it is possible that
that LibraryCOM does expose traditional events, but throughout this entire
discussion there have been NO DETAILS provided about what the LibraryCOM's
own TypeLibrary actually looks like.

First of all, when you go to Main Menu - Component - Import Component
- Import a Type Library, does that list show up that LibraryCOM thing?

It would have to, or else VBScript would not be able to access it.

--
Remy Lebeau (TeamB)
Douglas Rudd

Posts: 314
Registered: 5/16/97
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 12, 2016 4:01 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
I didn't get the impression that he ever actually used the VB Script. It sounded like he had a "LibraryCOM.exe" from a vendor that gave a VB Script example (which is common) of how to connect to it and wants to know how to do it in Delphi instead.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 12, 2016 4:28 PM   in response to: Douglas Rudd in response to: Douglas Rudd
Douglas wrote:

I didn't get the impression that he ever actually used the VB Script.

He is tyring to use the same LibraryCOM object that the VBScript is using.

It sounded like he had a "LibraryCOM.exe" from a vendor that gave a VB
Script example (which is common) of how to connect to it and wants to
know how to do it in Delphi instead.

Yes, but the situation is more complicated than that because of the events
that the vendor's COM object fires, one of which is a "LibraryCreated" event
to indicate the object is ready for use.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 15, 2016 7:33 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Douglas wrote:

It sounds like you have an application "LibraryCOM.exe" that is a COM
server and you would like to call some of its functions from your own
Delphi program.

Yes, but it is also needs to be able to fire events back into the Delphi
app, and those events are usable in VBScript, which uses a different event
model then traditional COM event handling. Granted, it is possible that
that LibraryCOM does expose traditional events, but throughout this entire
discussion there have been NO DETAILS provided about what the LibraryCOM's
own TypeLibrary actually looks like.

I still have no access to the code inside LibraryCOM.exe. I'll get some documentation in the next few days.
All I have at this moment is the .exe which I register & unregister and the VBScript which I use for testing.

First of all, when you go to Main Menu - Component - Import Component
- Import a Type Library, does that list show up that LibraryCOM thing?

It would have to, or else VBScript would not be able to access it.

It's odd but I cannot see it in XE8. I'll try tonight in Seattle 10.


--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 16, 2016 8:35 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
This code seems to work. I no longer get an error.
procedure TForm6.Button1Click(Sender: TObject);
var
  myObj : IMyClass;
  My_obj, init_lib : OleVariant;
begin
  myObj := TMyClass.Create;
  myObj.User := 'DelphiUser';
  myObj.Password := 'userPwrd';
  My_obj := CreateOleObject('COMtest');
  init_lib := My_obj.get_init_library_obj;
  init_lib.Flags($7FFF);
  init_lib.Environment(1);
  myobj.RegisterDevice('IPAddress','test1','test2');
end;

If I wanted to call the RegisterDevice('','','') method in the LibraryCOM.exe, what does the body of the
TMyClass.RegisterDevice procedure should look like ?
I think this where I need to call IDispatch.Invoke & pass the correct DispId.
I'll be grateful for any suggestions.
Thanks

This VBScript works too:

Class myClass
  Public user
  public password
End class
 
dim myObj
Set myObj = New myClass
myObj.user = "userName"
myObj.password = "userPwrd"
 
set My_obj = wscript.CreateObject("COMtest","pref_")
Set init_lib = My_obj.get_init_library_obj
 
init_lib.Flags(&h7fff)
init_lib.Environment(1)
 
call init_lib.init_library(GetRef("Library_created"), myObj)
 
dim MyIndex
dim MyDevice(2)
For MyIndex =1 to 2
  Set MyDevice(MyIndex) = My_obj.RegisterDevice("10.19.1"+Cstr(MyIndex),"test1","test2") 
Next
 
sub Library_created(p_Object)
  result = TypeName( p_Object) 
  MsgBox "class: " + result +" called for user: "+p_Object.user, 0, "COM Test"
end sub
 
sub pref_library_info(header,info) 
	WScript.StdOut.WriteLine header + " - " + info
end sub
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 15, 2016 7:18 AM   in response to: Douglas Rudd in response to: Douglas Rudd
Douglas Rudd wrote:
I think you are going off track.

It sounds like you have an application "LibraryCOM.exe" that is a COM server and you would like to call some of its functions from your own Delphi program.

First of all, when you go to Main Menu - Component - Import Component - Import a Type Library, does that list show up that LibraryCOM thing? If it does, then this should be fairly simple.

It's odd, but I can't see the LibraryCOM.exe if I go to Component, import component, Import a type library. I tried in xe8. I'll try the same thing in Seattle 10 later tonight.
(The registry is updated everytime I register\unregister it. Also, VBScript works fine everytime.)
I can see it if I do a similar thing in Visual Studio 2015.
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 15, 2016 7:50 AM   in response to: Fred Smith in response to: Fred Smith
Fred Smith wrote:
Douglas Rudd wrote:
I think you are going off track.

It sounds like you have an application "LibraryCOM.exe" that is a COM server and you would like to call some of its functions from your own Delphi program.

First of all, when you go to Main Menu - Component - Import Component - Import a Type Library, does that list show up that LibraryCOM thing? If it does, then this should be fairly simple.

It's odd, but I can't see the LibraryCOM.exe if I go to Component, import component, Import a type library. I tried in xe8. I'll try the same thing in Seattle 10 later tonight.
(The registry is updated everytime I register\unregister it. Also, VBScript works fine everytime.)
I can see it if I do a similar thing in Visual Studio 2015.

This is the Delphi code so far (done with Remy's help):
pas file:
https://drive.google.com/file/d/0B2PTdsZrN1wyRExCaGxMajB0MkE/view?usp=sharing

zip file:
https://drive.google.com/file/d/0B2PTdsZrN1wyeFRNVGNIa3U2Q0k/view?usp=sharing

VBScript:
https://drive.google.com/file/d/0B2PTdsZrN1wyUklBV285Q2RMQ1U/view?usp=sharing

//unit Unit6;
procedure TForm6.Button1Click(Sender: TObject);
var
  myObj : IMyClass;
  My_obj, init_lib : OleVariant;
begin
   myObj := TMyClass.Create;
  myObj.User := 'DelphiUser';
  myObj.Password := 'userPwrd';
  My_obj := CreateOleObject('COMtest'); //should initialise main COM object in the LibraryCOM \equivalent to VBScript: set My_obj = wscript.CreateObject("COMtest","pref_")
  // if I change the string 'COMtest' to something else, or unregister LibraryCOM.exe the above code will give this error: 'Invalid class string'
  init_lib := My_obj.get_init_library_obj();
 
  // init_lib.Flags(&H7FFF); // Any idea how to assign this flag ?
  init_lib.init_library(myObj, myObj);
  My_obj.RegisterDevice('IPAddress','test1','test2'); // Error: member not found.
end;
 
//----------------------------------------------------------------------------------
unit ScriptProject_TLB;
 
{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers.
{$WARN SYMBOL_PLATFORM OFF}
{$WRITEABLECONST ON}
{$VARPROPSETTER ON}
{$ALIGN 4}
 
interface
 
uses Winapi.Windows, System.Classes, System.Variants, System.Win.StdVCL, Vcl.Graphics, Vcl.OleServer, Winapi.ActiveX,
     System.Win.ComObj;
 
 
const
  // TypeLibrary Major and minor versions
  ScriptProjectMajorVersion = 1;
  ScriptProjectMinorVersion = 0;
 
  LIBID_ScriptProject: TGUID = '{CA510A3C-2AFD-480F-BF7E-DFFE57A2F542}';
 
  IID_IMyCoClass: TGUID = '{AAE58BEB-F486-4374-A083-4029F9DD7C77}';
  DIID_IMyCoClassEvents: TGUID = '{BA750447-CA45-4614-B4DA-C04AA00696D0}';
  CLASS_MyCoClass: TGUID = '{A772A11A-232B-475D-BB0E-51375FD8A1B4}';
  IID_IMyClass: TGUID = '{E6205397-2221-4E4E-9158-F83136EF8F1D}';
type
 
  IMyCoClass = interface;
  IMyCoClassDisp = dispinterface;
  IMyCoClassEvents = dispinterface;
  IMyClass = interface;
  IMyClassDisp = dispinterface;
 
  MyCoClass = IMyCoClass;
 
 
  IMyCoClass = interface(IDispatch)
    ['{AAE58BEB-F486-4374-A083-4029F9DD7C77}']
  end;
 
  IMyCoClassDisp = dispinterface
    ['{AAE58BEB-F486-4374-A083-4029F9DD7C77}']
  end;
 
 
  IMyCoClassEvents = dispinterface
    ['{BA750447-CA45-4614-B4DA-C04AA00696D0}']
  end;
 
 
  IMyClass = interface(IDispatch)
    ['{E6205397-2221-4E4E-9158-F83136EF8F1D}']
   // procedure Get_User; safecall;
   // procedure Set_User(const Value: WideString); safecall;
    function Get_User: WideString; safecall;
    procedure Set_User(const Value: WideString); safecall;
    procedure LibraryCreated(const p_Object: IDispatch); safecall;
  //  procedure Get_Password; safecall;
  //  procedure Set_Password(const Value: WideString); safecall;
    function Get_Password: WideString; safecall;
    procedure Set_Password(const Value: WideString); safecall;
    procedure RegisterDevice(const IPAddress: WideString; const Param2: WideString;
                             const Param3: WideString); safecall;
    property User: WideString read Get_User write Set_User;
    property Password: WideString read Get_Password write Set_Password;
  end;
 
 
  IMyClassDisp = dispinterface
    ['{E6205397-2221-4E4E-9158-F83136EF8F1D}']
    procedure Get_User; dispid 201;
    procedure Set_User(const Value: WideString); dispid 202;
    property User: WideString dispid 203;
    procedure LibraryCreated(const p_Object: IDispatch); dispid 0; //Zero
    procedure Get_Password; dispid 204;
    procedure Set_Password(const Value: WideString); dispid 205;
    property Password: WideString dispid 206;
    procedure RegisterDevice(const IPAddress: WideString; const Param2: WideString;
                             const Param3: WideString); dispid 207;
  end;
 
 
  CoMyCoClass = class
    class function Create: IMyCoClass;
    class function CreateRemote(const MachineName: string): IMyCoClass;
  end;
 
 
TMyClass = class(TAutoIntfObject, IMyClass)
  public
    constructor create;
  private
    fUser:string;
    fPassword : string;
    function ObjTypeName(Obj: IDispatch): string;
  protected
  function Get_User : WideString;safecall;
  function Get_Password : WideString;safecall;
  procedure Set_User (const Value : WideString);safecall;
  procedure Set_Password (const Value : WideString);safecall;
  procedure LibraryCreated(const p_Object:IDispatch);safecall;
  procedure RegisterDevice(const IPaddress:WideString; const Param2, Param3:WideString);safecall;
end;
 
 
implementation
 
//uses System.Win.ComObj;
 
class function CoMyCoClass.Create: IMyCoClass;
begin
  Result := CreateComObject(CLASS_MyCoClass) as IMyCoClass;
end;
 
class function CoMyCoClass.CreateRemote(const MachineName: string): IMyCoClass;
begin
  Result := CreateRemoteComObject(MachineName, CLASS_MyCoClass) as IMyCoClass;
end;
 
{ TMyClass }
 
constructor TMyClass.create;
var
  TypeLib : ITypeLib;
  ExeName : WideString;
begin
  ExeName := ParamStr(0);
  OleCheck(LoadTypeLib(PWideChar(ExeName), TypeLib));
  inherited create(TypeLib, IMyClass);
end;
 
function TMyClass.Get_Password: WideString;
begin
  result := fPassword;
end;
 
function TMyClass.Get_User: WideString;
begin
  result := fUser;
end;
 
procedure TMyClass.LibraryCreated(const p_Object: IDispatch);
begin
   MessageBox(0, PChar('class: ' + ObjTypeName(p_Object) + ' called for user:' + (p_Object as IMyClass).User), 'COM Test', MB_OK);
end;
function TMyClass.ObjTypeName(Obj: IDispatch): string;
var
  Count: Integer;
  TI: ITypeInfo;
  wName: WideString;
begin
  Result := 'Object';
  if Obj = nil then Exit;
  if Failed(Obj.GetTypeInfoCount(Count)) then Exit;
  if Count < 1 then Exit;
  if Failed(Obj.GetTypeInfo(0, 0, TI)) then Exit;
  if Failed(TI.GetDocumentation(MEMBERID_NIL, @wName, nil, nil, nil)) then
Exit;
  Result := wName;
end;
procedure TMyClass.Set_Password(const Value: WideString);
begin
  fPassword := value;
end;
 
procedure TMyClass.Set_USer(const Value: WideString);
begin
  fUser := value;
end;
 
procedure TMyClass.RegisterDevice(const IPaddress: WideString;  const Param2, Param3: WideString);
begin
 // No procedure body at this moment
end;
 
end.
//----------------------------------------------------------------------------------
 
//ScriptProject.rdl
 
[
  uuid(CA510A3C-2AFD-480F-BF7E-DFFE57A2F542),
  version(1.0)
 
]
library ScriptProject
{
 
  importlib("stdole2.tlb");
  importlib("stdvcl40.dll");
 
  interface IMyCoClass;
  dispinterface IMyCoClassEvents;
  coclass MyCoClass;
  interface IMyClass;
 
 
  [
    uuid(AAE58BEB-F486-4374-A083-4029F9DD7C77),
    helpstring("Dispatch interface for MyCoClass Object"),
    dual,
    oleautomation
  ]
  interface IMyCoClass: IDispatch
  {
  };
 
  [
    uuid(E6205397-2221-4E4E-9158-F83136EF8F1D),
    dual,
    oleautomation
  ]
  interface IMyClass: IDispatch
  {
    [id(0x000000C9)]
    HRESULT _stdcall Get_User(void);
    [id(0x000000CA)]
    HRESULT _stdcall Set_User([in] BSTR Value);
    [propget, id(0x000000CB)]
    HRESULT _stdcall User([out, retval] BSTR Value);
    [propput, id(0x000000CB)]
    HRESULT _stdcall User([in] BSTR Value);
    [id(0x00000000)]
    HRESULT _stdcall LibraryCreated([in]  IDispatch* p_Object);
    [id(0x000000CC)]
    HRESULT _stdcall Get_Password(void);
    [id(0x000000CD)]
    HRESULT _stdcall Set_Password([in] BSTR Value);
    [propget, id(0x000000CE)]
    HRESULT _stdcall Password([out, retval] BSTR* Value);
    [propput, id(0x000000CE)]
    HRESULT _stdcall Password([in] BSTR Value);
    [id(0x000000CF)]
    HRESULT _stdcall RegisterDevice([in] BSTR IPAddress, [in] BSTR Param2, [in] BSTR Param3);
  };
 
  [
    uuid(BA750447-CA45-4614-B4DA-C04AA00696D0),
    helpstring("Events interface for MyCoClass Object")
  ]
  dispinterface IMyCoClassEvents
  {
    properties:
    methods:
  };
 
  [
    uuid(A772A11A-232B-475D-BB0E-51375FD8A1B4),
    helpstring("MyCoClass Object")
  ]
  coclass MyCoClass
  {
    [default] interface IMyCoClass;
    [default, source] dispinterface IMyCoClassEvents;
  };
 
};
//----------------------------------------------------------------------------------
 
 
unit Unit1;
 
{$WARN SYMBOL_PLATFORM OFF}
 
interface
 
uses
  ComObj, ActiveX, AxCtrls, Classes,
ScriptProject_TLB, StdVcl;
 
type
  TMyCoClass = class(TAutoObject, IConnectionPointContainer, IMyCoClass)
  private
    { Private declarations }
    FConnectionPoints: TConnectionPoints;
    FConnectionPoint: TConnectionPoint;
    FEvents: IMyCoClassEvents;
    { note: FEvents maintains a *single* event sink. For access to more
      than one event sink, use FConnectionPoint.SinkList, and iterate
      through the list of sinks. }
  public
    procedure Initialize; override;
  protected
    { Protected declarations }
    property ConnectionPoints: TConnectionPoints read FConnectionPoints
      implements IConnectionPointContainer;
    procedure EventSinkChanged(const EventSink: IUnknown); override;
 
  end;
 
implementation
 
uses ComServ;
 
procedure TMyCoClass.EventSinkChanged(const EventSink: IUnknown);
begin
  FEvents := EventSink as IMyCoClassEvents;
end;
 
procedure TMyCoClass.Initialize;
begin
  inherited Initialize;
  FConnectionPoints := TConnectionPoints.Create(Self);
  if AutoFactory.EventTypeInfo <> nil then
    FConnectionPoint := FConnectionPoints.CreateConnectionPoint(
      AutoFactory.EventIID, ckSingle, EventConnect)
  else FConnectionPoint := nil;
end;
 
 
initialization
  TAutoObjectFactory.Create(ComServer, TMyCoClass, Class_MyCoClass,
    ciMultiInstance, tmApartment);
end.
 
 


VBScript:
Class myClass
  Public user
  public password
End class
 
dim myObj
Set myObj = New myClass
myObj.user = "userName"
myObj.password = "userPwrd"
 
' Initialise COM object (callbacks)
set My_obj = wscript.CreateObject("COMtest","pref_")
 
Set init_lib = My_obj.get_init_library_obj
 
init_lib.Flags(&h7fff)    ' If this flags commented out VBScript doesn't work
init_lib.Environment(1)   'If this flags commented out VBScript doesn't work
 
call init_lib.init_library(GetRef("Library_created"), myObj)
 
dim MyIndex
dim MyDevice(MyIndex)
For MyIndex =1 to 2
  Set MyDevice(MyIndex) = My_obj.RegisterDevice("10.19.1"+Cstr(MyIndex),"test1","test2") 
Next
 
sub Library_created(p_Object)
  result = TypeName( p_Object) 
  MsgBox "class: " + result +" called for user: "+p_Object.user, 0, "COM Test"
end sub
 
sub pref_library_info(header,info)
	WScript.StdOut.WriteLine header + " - " + info
end sub
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 16, 2016 1:40 AM   in response to: Fred Smith in response to: Fred Smith
Can someone explain what this line does:
  Flags(&h7fff)


And what it translates to in Delphi.
Thanks
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 16, 2016 6:02 AM   in response to: Fred Smith in response to: Fred Smith
Fred Smith wrote:
Can someone explain what this line does:
  Flags(&h7fff)


And what it translates to in Delphi.
Thanks

Found it. It translates to:
  init_lib.Flags($7FFF);
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 16, 2016 8:41 AM   in response to: Fred Smith in response to: Fred Smith
This code seems to work. I no longer get an error.
procedure TForm6.Button1Click(Sender: TObject);
var
  myObj : IMyClass;
  My_obj, init_lib : OleVariant;
begin
  myObj := TMyClass.Create;
  myObj.User := 'DelphiUser';
  myObj.Password := 'userPwrd';
  My_obj := CreateOleObject('COMtest');
  init_lib := My_obj.get_init_library_obj;
  init_lib.Flags($7FFF);
  init_lib.Environment(1);
  myobj.RegisterDevice('IPAddress','test1','test2');
end;


If I wanted to call the RegisterDevice('','','') method in the LibraryCOM.exe, what does the body of the
TMyClass.RegisterDevice procedure should look like ?
I think this where I need to call IDispatch.Invoke & pass the correct DispId.
I'll be grateful for any suggestions.
Thanks

This VBScript works too:

Class myClass
  Public user
  public password
End class
 
dim myObj
Set myObj = New myClass
myObj.user = "userName"
myObj.password = "userPwrd"
 
set My_obj = wscript.CreateObject("COMtest","pref_")
Set init_lib = My_obj.get_init_library_obj
 
init_lib.Flags(&h7fff)
init_lib.Environment(1)
 
call init_lib.init_library(GetRef("Library_created"), myObj)
 
dim MyIndex
dim MyDevice(2)
For MyIndex =1 to 2
  Set MyDevice(MyIndex) = My_obj.RegisterDevice("10.19.1"+Cstr(MyIndex),"test1","test2") 
Next
 
sub Library_created(p_Object)
  result = TypeName( p_Object) 
  MsgBox "class: " + result +" called for user: "+p_Object.user, 0, "COM Test"
end sub
 
sub pref_library_info(header,info) 
	WScript.StdOut.WriteLine header + " - " + info
end sub
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit][Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 16, 2016 1:28 PM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

This code seems to work. I no longer get an error.

Well yeah, because you are calling YOUR RegisterDevice(), not LibraryCOM's
RegisterDevice().

If I wanted to call the RegisterDevice('','','') method in the
LibraryCOM.exe, what does the body of the TMyClass.RegisterDevice
procedure should look like ?

You don't need your own RegisterDevice() to begin with. Just get rid of
it and call LibraryCOM's directly, just like the VBScript does:

var
  My_obj : OleVariant;
 
procedure TForm6.Button1Click(Sender: TObject);
var
  myObj : IMyClass;
  init_lib : OleVariant;
begin
  myObj := TMyClass.Create;
  myObj.User := 'DelphiUser';
  myObj.Password := 'userPwrd';
  My_obj := CreateOleObject('COMtest');
  init_lib := My_obj.get_init_library_obj;
  init_lib.Flags($7FFF);
  init_lib.Environment(1);
  init_lib.init_library(myObj, myObj)
  My_obj.RegisterDevice('IPAddress', 'test1', 'test2');
end;


I think this where I need to call IDispatch.Invoke & pass the correct
DispId.

OleVariant handles that for you.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit] [Edit][Edit][Edit][Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 17, 2016 4:33 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

This code seems to work. I no longer get an error.

Well yeah, because you are calling YOUR RegisterDevice(), not LibraryCOM's
RegisterDevice().

If I wanted to call the RegisterDevice('','','') method in the
LibraryCOM.exe, what does the body of the TMyClass.RegisterDevice
procedure should look like ?

You don't need your own RegisterDevice() to begin with. Just get rid of
it and call LibraryCOM's directly, just like the VBScript does:

var
  My_obj : OleVariant;
 
procedure TForm6.Button1Click(Sender: TObject);
var
  myObj : IMyClass;
  init_lib : OleVariant;
begin
  myObj := TMyClass.Create;
  myObj.User := 'DelphiUser';
  myObj.Password := 'userPwrd';
  My_obj := CreateOleObject('COMtest');
  init_lib := My_obj.get_init_library_obj;
  init_lib.Flags($7FFF);
  init_lib.Environment(1);
  init_lib.init_library(myObj, myObj)
  My_obj.RegisterDevice('IPAddress', 'test1', 'test2');
end;


I think this where I need to call IDispatch.Invoke & pass the correct
DispId.

OleVariant handles that for you.

--
Remy Lebeau (TeamB)

Thanks. Got that.
I'm back to square 1. I'm getting these 2 errors:

  init_lib.init_library(myObj, myObj); // access violation error
   My_obj.RegisterDevice('IPAddress', 'test1', 'test2');//   EOleSysError "Member not found"

VBScript works so the function RegisterDevice() is there. It's a shame the EOleSysError error is not more descriptive.


An update:
I managed to download a copy of OLE/COM Object viewer:
https://www.autoitscript.com/autoit3/docs/intro/ComRef.htm#Table1
This is some of the info it dispalyed (LibraryCOM.exe):
Still not sure why I can't see the library when I go to main menu, Component, Import Component, Import a Type Library!
I initially I thought I could see the library in Visual Studio but I was wrong.

library C_LIB
{
    importlib("stdole2.tlb");
 
    // Forward declare all types defined in this typelib
    interface the_device;
    interface COM_feedback;
    interface initLibraryStruct;
    interface COM_C_LIBRARY;
 
    [
      odl,
      uuid(1847B37D-C8ED-44D5-A535-E057F2CE3AA9),
      dual,
      oleautomation
    ]
    interface the_device : IDispatch {
        [id(0x00000001)]
        HRESULT init_library(
                        [in] IDispatch* a, 
                        [in, optional, defaultvalue(<unprintable IDispatch*>)] IDispatch* b, 
                        [out, retval] long* c);
        [id(0x00000002)]
        HRESULT Environment(
                        [in] long a, 
                        [out, retval] long* b);
        [id(0x00000003)]
        HRESULT Flags(
                        [in] long a, 
                        [out, retval] long* b);
    };
 
    [
      odl,
      uuid(CD223216-D698-428B-9F3C-1C5D446BC4CE),
      hidden,
      nonextensible
    ]
    interface COM_feedback : IDispatch {
        [helpstring("library exception callback")]
        HRESULT _stdcall library_exception([out] BSTR* a);
        [helpstring("library info callback")]
        HRESULT _stdcall library_info(
                        [out] BSTR* a, 
                        [out] BSTR* b);
    };
 
    [
      odl,
      uuid(9222FF70-F454-4B36-B5D5-9C7F0DD6F4B4),
      dual,
      oleautomation
    ]
    interface initLibraryStruct : IDispatch {
        [id(0x00000001)]
        HRESULT init_library(
                        [in] IDispatch* a, 
                        [in, optional, defaultvalue(<unprintable IDispatch*>)] IDispatch* b, 
                        [out, retval] long* c);
        [id(0x00000002)]
        HRESULT Environment(
                        [in] long a, 
                        [out, retval] long* b);
        [id(0x00000003)]
        HRESULT Flags(
                        [in] long a, 
                        [out, retval] long* b);
    };
 
    [
      odl,
      uuid(B6547C55-AC5F-4BA0-AFF9-7220C95EEF4D),
      hidden,
      dual,
      nonextensible,
      oleautomation
    ]
    interface COM_C_LIBRARY : IDispatch {
        [id(0x00000001), propget, helpstring("get init library object")]
        HRESULT get_init_library_obj([out, retval] initLibraryStruct** a);
 
        [id(0x00000004), propget, helpstring("register device")]
        HRESULT registerDevice(
                        [in] BSTR a, 
                        [in] BSTR b, 
                        [in] BSTR c, 
                        [out, retval] the_device** d);
    };
 
    [
      uuid(520F4CFD-61C6-4EED-8004-C26D514D3D19),
      helpstring("C_LIB object"),
      appobject
    ]
    coclass C_LIB {
        [default] interface COM_C_LIBRARY;
        [default, source] interface COM_feedback;
    };
};
 
 
////////////////////////////////////////////
[
  uuid(1847B37D-C8ED-44D5-A535-E057F2CE3AA9),
  dual
]
dispinterface the_device {
    properties:
    methods:
        [id(0x00000001)]
        long init_library(
                        [in] IDispatch* a, 
                        [in, optional, defaultvalue(<unprintable IDispatch*>)] IDispatch* b);
        [id(0x00000002)]
        long Environment([in] long a);
        [id(0x00000003)]
        long Flags([in] long a);
};
///////////////////////////////////////////// Methods
[id(0x00000001)]
HRESULT init_library(
                [in] IDispatch* a, 
                [in, optional, defaultvalue(<unprintable IDispatch*>)] IDispatch* b, 
                [out, retval] long* c);
				
[id(0x00000002)]
HRESULT Environment(
                [in] long a, 
                [out, retval] long* b);
 
[id(0x00000003)]
HRESULT Flags(
                [in] long a, 
                [out, retval] long* b);				
/////////////////////////////////////////////
[helpstring("library info callback")]
HRESULT _stdcall library_info(
                [out] BSTR* a, 
                [out] BSTR* b);
////////////////////////////////////////////
[
  odl,
  uuid(B6547C55-AC5F-4BA0-AFF9-7220C95EEF4D),
  hidden,
  dual,
  nonextensible,
  oleautomation
]
interface COM_C_LIBRARY : IDispatch {
    [id(0x00000001), propget, helpstring("get init library object")]
    HRESULT get_init_library_obj([out, retval] initLibraryStruct** a);
    
    [id(0x00000004), propget, helpstring("register device")]
    HRESULT registerDevice(
                    [in] BSTR a, 
                    [in] BSTR b, 
                    [in] BSTR c, 
                    [out, retval] the_device** d);
};
 
/////////////////////////////
[id(0x00000001), propget, helpstring("get init library object")]
HRESULT get_init_library_obj([out, retval] initLibraryStruct** a);
//////////////////////////////
[id(0x00000004), propget, helpstring("register device")]
HRESULT registerDevice(
                [in] BSTR a, 
                [in] BSTR b, 
                [in] BSTR c, 
                [out, retval] the_device** d);
////////////////////////////////
[
  uuid(B6547C55-AC5F-4BA0-AFF9-7220C95EEF4D),
  hidden,
  dual,
  nonextensible
]
dispinterface COM_C_LIBRARY {
    properties:
    methods:
        [id(0x00000001), propget, helpstring("get init library object")]
        initLibraryStruct* get_init_library_obj();
 
        [id(0x00000004), propget, helpstring("register device")]
        the_device* registerDevice(
                        [in] BSTR a, 
                        [in] BSTR b, 
                        [in] BSTR c);
};
/////////////////////////////////////////////
[id(0x00000001), propget, helpstring("get init library object")]
initLibraryStruct* get_init_library_obj();
/////////////////////////////////////////////
[id(0x00000004), propget, helpstring("register device")]
the_device* registerDevice(
                [in] BSTR a, 
                [in] BSTR b, 
                [in] BSTR c);
//////////////////////////////////////////////
[helpstring("library info callback")]
HRESULT _stdcall library_info(
                [out] BSTR* a, 
                [out] BSTR* b);
///////////////////////////
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ? [Edit][Edit][Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 17, 2016 11:21 AM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

init_lib.init_library(myObj, myObj); // access violation error

Did you verify that init_lib is not empty? Did you verify that your TMyClass.LibraryCreated()
method is being called and is operating correctly?

My_obj.RegisterDevice('IPAddress', 'test1', 'test2');// EOleSysError "Member
not found"

I cannot comment on that. OleVariant uses the same late-binding mechanism
that VBScript uses. When a property or procedure is accessed via an OleVariant
variable, Delphi automatically generates code to call IDispatch.GetIDsOfNames()
to convert the name on the right of the '.' into a DispID, and then calls
IDispatch.Invoke() with the reported DispID. The "Member not Found" error
means the COM object cannot resolve the "RegisterDevice" name to a DispID.

Looking at the TypeLibrary declarations you got from Object Viewer, "RegisterDevice"
is actually declared as "registerDevice", so try using "r" instead of "R":

My_obj.registerDevice('IPAddress', 'test1', 'test2');


[id(0x00000001), propget, helpstring("get init library
object")]
HRESULT get_init_library_obj([out, retval] initLibraryStruct** a);
[id(0x00000004), propget, helpstring("register device")]
HRESULT registerDevice(
[in] BSTR a,
[in] BSTR b,
[in] BSTR c,
[out, retval] the_device** d);

Interesting that get_init_library_obj() and registerDevice() are declared
as property getters and not methods.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ? [Edit][Edit][Edit][Edit][Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 17, 2016 3:00 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

init_lib.init_library(myObj, myObj); // access violation error

Did you verify that init_lib is not empty? Did you verify that your TMyClass.LibraryCreated()
method is being called and is operating correctly?
init_lib isn't empty:
  init_lib $010b8724


TMyClass.LibraryCreated() is being called & operating correctly & displays this message:
  class: IMyClass called for user DelphiUser


My_obj.RegisterDevice('IPAddress', 'test1', 'test2');// EOleSysError "Member
not found"

I cannot comment on that. OleVariant uses the same late-binding mechanism
that VBScript uses. When a property or procedure is accessed via an OleVariant
variable, Delphi automatically generates code to call IDispatch.GetIDsOfNames()
to convert the name on the right of the '.' into a DispID, and then calls
IDispatch.Invoke() with the reported DispID. The "Member not Found" error
means the COM object cannot resolve the "RegisterDevice" name to a DispID.

Looking at the TypeLibrary declarations you got from Object Viewer, "RegisterDevice"
is actually declared as "registerDevice", so try using "r" instead of "R":
RegisterDevice() call errors in
DispatchInvoke (System.Win.ComObj) on this line:
     Status := Dispatch.Invoke(DispID, GUID_NULL, 0, InvKind, DispParams,
                              Result, @ExcepInfo, nil);

DispID evaluates to 4

I renamed the function. I got the same error. I'll recreate the whole project from the scratch and see what I get.

My_obj.registerDevice('IPAddress', 'test1', 'test2');


[id(0x00000001), propget, helpstring("get init library
object")]
HRESULT get_init_library_obj([out, retval] initLibraryStruct** a);
[id(0x00000004), propget, helpstring("register device")]
HRESULT registerDevice(
[in] BSTR a,
[in] BSTR b,
[in] BSTR c,
[out, retval] the_device** d);

Interesting that get_init_library_obj() and registerDevice() are declared
as property getters and not methods.

--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi ?[Edit][Edit][Edit][Edit][Edit] [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 17, 2016 3:26 PM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

RegisterDevice() call errors in DispatchInvoke (System.Win.ComObj)
on this line:

Status := Dispatch.Invoke(DispID, GUID_NULL, 0, InvKind,
DispParams,
Result, @ExcepInfo, nil);


DispID evaluates to 4

Then IDispatch.GetIDsOfNames() is working fine. Double-check the InvKind
value in DispatchInvoke(), I suspect it is being set to DISPATCH_METHOD,
whereas the TypeLibrary declarations you showed earlier say registerDevice()
is a 'propget', so InvKind should be DISPATCH_PROPERTYGET instead.

I renamed the function. I got the same error.

You can't rename it, since it is in LibraryCOM's COM object, not in your
COM object.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi ?[Edit][Edit][Edit][Edit][Edit] [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 17, 2016 4:58 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

RegisterDevice() call errors in DispatchInvoke (System.Win.ComObj)
on this line:

Status := Dispatch.Invoke(DispID, GUID_NULL, 0, InvKind,
DispParams,
Result, @ExcepInfo, nil);


DispID evaluates to 4

Then IDispatch.GetIDsOfNames() is working fine. Double-check the InvKind
value in DispatchInvoke(), I suspect it is being set to DISPATCH_METHOD,
whereas the TypeLibrary declarations you showed earlier say registerDevice()
is a 'propget', so InvKind should be DISPATCH_PROPERTYGET instead.

You are right. InvKind is set to DISPATCH_METHOD.
When I amended it in the debugger to DISPATCH_PROPERTYGET I didn't get an error.
What changes do I need to make so DISPATCH_PROPERTYGET is selected automatically?

I renamed the function. I got the same error.

You can't rename it, since it is in LibraryCOM's COM object, not in your
COM object.

I meant I tried :
  My_Obj.registerDevice('','',''); // instead of My_Obj.RegisterDevice('','','')as you suggested

And got the same error.

Not sure if renaming the registerDevice() I created in the Type Editor will make any difference.

The access violation error is puzzling me. Trying to figure out what's causing it.

Thanks again.


--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: What's the equivalent to this in Delphi?[Edit][Edit][Edit][Edit][Edit] [Edit] [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 17, 2016 6:09 PM   in response to: Fred Smith in response to: Fred Smith
Fred wrote:

What changes do I need to make so DISPATCH_PROPERTYGET is selected
automatically?

I don't think you can. From Delphi's perspective, "My_Obj.registerDevice(...)"
is a method call, not a property read. I don't know why LibraryCOM is marking
its COM procedures as 'propget', they are clearly not properties. I think
that is a bug on LibraryCOM's part that its author should fix. How VBScript
handles this without error, I don't know. To work around this, you will
likely have to bypass OleVariant's late-binding feature and call IDispatch.Invoke()
directly.

--
Remy Lebeau (TeamB)
Fred Smith

Posts: 81
Registered: 12/4/15
Re: What's the equivalent to this in Delphi?[Edit][Edit][Edit][Edit][Edit] [Edit] [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 17, 2016 6:47 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Fred wrote:

What changes do I need to make so DISPATCH_PROPERTYGET is selected
automatically?

I don't think you can. From Delphi's perspective, "My_Obj.registerDevice(...)"
is a method call, not a property read. I don't know why LibraryCOM is marking
its COM procedures as 'propget', they are clearly not properties. I think
that is a bug on LibraryCOM's part that its author should fix. How VBScript
handles this without error, I don't know. To work around this, you will
likely have to bypass OleVariant's late-binding feature and call IDispatch.Invoke()
directly.

--
Remy Lebeau (TeamB)

I'll email the author & see what he says.
I'll have to call IDispatch.Invoke() for now as a temporary solution.
Thanks.
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02