How to access a COMObject: converting example from VB code

I need to use the services of a COM server application in my Delphi (2007) application.  I have VB code from a working sample application.  One of the subroutines that I need to replicate is attached..

The two lines that are specific to the COMObject are
 - Set app = New xxQCom
 - ret = app.GetRateGroups(sXML, outstr)

How do I perform the equivalent of "Set app = ..." in Delphi?  And once that is done can I assume that the call to GetRateGroups would be similar to VB?

Thanks.
Private Sub GetRatesBtn_Click()
    Dim fso As FileSystemObject
    Set fso = New FileSystemObject
    Dim f As TextStream
    Dim fn As String
    Dim sXml As String
    Dim app As xxQCom
    Dim sXmlResults As String
   
    GetRatesTxt.Text = sXmlResults
    fn = GetRatesIn.Text
   
    If fn = "" Then
        Exit Sub
    End If
   
    Set f = fso.OpenTextFile(fn, ForReading)
    sXml = f.ReadAll
    f.Close
       
    Set app = New xxQCom
    
    Dim ret
    Dim outstr
    
    ret = app.GetRateGroups(sXml, outstr)
    
    Set app = Nothing
    If ret = QIB_E_CALCSUCCESS Then
        sXmlResults = outstr
        GetRatesTxt.Text = sXmlResults
        fn = GetRatesOut.Text
   
        If fn <> "" Then
            Set f = fso.CreateTextFile(fn)
            f.Write (sXmlResults)
            f.Close
        End If
        
    Else
        GetRatesTxt.Text = "Error happened while retrieving rates."
    End If
    
End Sub

Open in new window

ttheimerAsked:
Who is Participating?
 
Russell LibbyConnect With a Mentor Software Engineer, Advisory Commented:

The programmatic ID is a human readable id, like "MSCalendar.Calendar.7". Thats not to say you could not work with a guid **IF** you had the guid for the CLSID (which you don't). What you have is the (type) library ID, but by having the .exe file you are set to start the early binding.

Now I'm not sure how much the IDE has changed between my version of Delphi and yours, but for me it would be the following process:

- Project | Import Type Library
- Click add
- Browse to the ..\runcom\mcqcomap.exe and select it
- Select Create Unit to have the typelib converted to a pascal unit
- Include this unit in the uses clause of your main unit (or wherever you plan on referencing)
- Open the generated unit and look for the corresponding CoXXXX class that matches the interface you plan on working with.
- define a var of this interface type and instantiate it as in my first example.

Hopefully this will get you on the right track. Unfortunately, without access to the COM object in question, its hard to be more specific (is it available for download somewhere?)

Russell



0
 
Russell LibbySoftware Engineer, Advisory Commented:
You will need to check the VB program for the included type library references in order to determine what the programmatic ID / or supporting .exe/.dll is for xxQCom. Once you have done that, you can choose to either late bind (if dual dispatch based), eg:

var xxQCom:  OleVariant;
begin

  xxQCom:=CreateOleObject('{programmatic id for interface}');

or you can early bind by using; Project | Import Type Library, select the corresponding exe/library, etc. (This is what the VB code is doing... early binding) In the imported unit you will find a class constructor for the interface, eg:

  CoxxQCom = class
    class function Create: IxxQCom ;
    class function CreateRemote(const MachineName: string): IxxQCom ;
  end;

and then you can perform:

var xxQCom:  IxxQCom;
begin

 xxQCom:=CoxxQCom.Create;

Biggest challenge will be determining what the AX library is. Once that is known, the rest should be fairly easy.

Regards,
Russell
0
 
ttheimerAuthor Commented:
Russell,

Thanks for the response.  I am trying to sort out some of the details.

In your line
    xxQCom:=CreateOleObject('{programmatic id for interface}');
is the programmatic id for interface a GUID?  In a .vbp file which is part of the VB sample program I found the following three lines:

Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\WINDOWS\system32\stdole2.tlb#OLE Automation
Reference=*\G{420B2830-E718-11CF-893D-00A0C9054228}#1.0#0#C:\WINDOWS\system32\scrrun.dll#Microsoft Scripting Runtime
Reference=*\G{F55D8B7F-AB6D-499D-8DE9-64282FFAFBF2}#1.0#0#..\RUNCOM\mcqcomap.exe#mcqcomap 1.0 Type Library

The 3rd reference (mcqcomap.exe) is the Type Library that I need to access for the subroutine that I initially included.  Would I use that GUID in your code snippet?
0
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
aikimarkCommented:
@ttheimer
Can you open the VB project in the VB IDE?  If so, the list of selected REFERENCES is available through the menus.
You should be able to find the title to the referenced TLB in the registry.  Search for the GUID.
0
 
ttheimerAuthor Commented:
Can't thank you enough for both the simple example and the step by step in your second response.  With those two pieces I finally had a context for the other documentation I had been reading and the final errors in my test code were quickly cleared .
0
 
ttheimerAuthor Commented:
Russell,

Thanks for the step by step details.  For the record (i.e., anyone else researching this topic) in Delphi 2007 I only needed to replace the first 4 steps above with the following:
 - Selected menu items Component | Import component...
 - Selected Import a Type Library (radio button options)
 - Checked "Generate Component Wrappers" when entering the Unit Dir Name
 - Selected Add unit to <my_project_name>.dproj project (radio button options)

Tom
0
 
Russell LibbySoftware Engineer, Advisory Commented:
Tom, glad I was able to help. Sorry that the steps were off for your version; should have mentioned that I still work in D5 ;-).

I'm going to add one more piece of code in case others want a quick / simple way of getting programmatic ID's for dispatch based CoClass implementations (having only the .dll/exe file to go from).

Russell

--- Console app for dumping info from COM based exe/dll files ---

Example usage:
>clsinfo "c:\windows\system32\shell32.dll"

program clsinfo;
////////////////////////////////////////////////////////////////////////////////
//
//   Program     :  ClsInfo
//   Author      :  rllibby
//   Date        :  11.21.2008
//   Description :  Utility program that can be used to dump the CoClass info
//                  from a COM library (or .exe).
//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//   Console based application
////////////////////////////////////////////////////////////////////////////////
{$APPTYPE CONSOLE}

////////////////////////////////////////////////////////////////////////////////
//   Include units
////////////////////////////////////////////////////////////////////////////////
uses
  Windows, SysUtils, ComObj, ActiveX;

////////////////////////////////////////////////////////////////////////////////
//   DumpTypeInfo
////////////////////////////////////////////////////////////////////////////////
procedure DumpTypeInfo(FileName: String);
var  pvTypeLib:     ITypeLib;
     pvTypeInfo:    ITypeInfo;
     ptlAttr:       PTLibAttr;
     ptAttr:        PTypeAttr;
     pwszName:      PWideChar;
     lpszProgID:    Array [0..1024] of Char;
     dwSize:        DWORD;
     hkProgID:      HKEY;
     dwCount:       Integer;
     dwIndex:       Integer;
begin

  // Attempt to load the type library
  if Failed(LoadTypeLib(PWideChar(WideString(FileName)), pvTypeLib)) then
     // Failed to load type library
     WriteLn('Failed to load type library...')
  else
  begin
     // Resource protection
     try
        // Get the type library guid
        if (pvTypeLib.GetLibAttr(ptlAttr) = S_OK) then
        begin
           // Resource protection
           try
              // Dump info
              WriteLn(Format('Type Library GUID : %s', [GuidToString(ptlAttr^.guid)]));
              WriteLn;
           finally
              // Release attr
              pvTypeLib.ReleaseTLibAttr(ptlAttr);
           end;
        end;
        // Get type info count
        dwCount:=pvTypeLib.GetTypeInfoCount;
        // Iterate each type info
        for dwIndex:=0 to Pred(dwCount) do
        begin
           // Get the type info at the given index
           if (pvTypeLib.GetTypeInfo(dwIndex, pvTypeInfo) = S_OK) then
           begin
              // Resource protection
              try
                 // Get the type info attribute
                 if (pvTypeInfo.GetTypeAttr(ptAttr) = S_OK) then
                 begin
                    // Resource protection
                    try
                       // Only work with CoClass items
                       if (ptAttr^.typekind = TKIND_COCLASS) then
                       begin
                          // Get the class name
                          if (pvTypeInfo.GetDocumentation(MEMBERID_NIL, @pwszName, nil, nil, nil) = S_OK) then
                          begin
                             // Resource protection
                             try
                                // Dump the name
                                WriteLn(Format('CoClass Name      : %s', [String(Widestring(pwszName))]));
                                // Dump the guid
                                WriteLn(Format('CoClass CLSID     : %s', [GuidToString(ptAttr^.guid)]));
                                // Check for programmatic ID
                                if (RegOpenKeyEx(HKEY_CLASSES_ROOT, PChar(Format('CLSID\%s\ProgID', [GuidToString(ptAttr^.guid)])), 0, KEY_QUERY_VALUE, hkProgID) = ERROR_SUCCESS) then
                                begin
                                   // Resource protection
                                   try
                                      // Set size
                                      dwSize:=SizeOf(lpszProgID);
                                      // Query default value
                                      if (RegQueryValueEx(hkProgID, nil, nil, nil, @lpszProgID, @dwSize) = ERROR_SUCCESS) then
                                      begin
                                         // Dump programmtic ID
                                         WriteLn(Format('Programmatic ID   : %s', [lpszProgID]));
                                      end;
                                   finally
                                      // Close the key
                                      RegCloseKey(hkProgID);
                                   end;
                                end;
                                // Finish the line
                                WriteLn;
                             finally
                                // Free string
                                SysFreeString(pwszName);
                             end;
                          end;
                       end;
                    finally
                       // Release attr
                       pvTypeInfo.ReleaseTypeAttr(ptAttr);
                    end;
                 end;
              finally
                 // Release type info
                 pvTypeInfo:=nil;
              end;
           end;
        end;
     finally
        // Release the type library
        pvTypeLib:=nil;
     end;
  end;

end;

////////////////////////////////////////////////////////////////////////////////
//   Global variables
////////////////////////////////////////////////////////////////////////////////
var
  szFileName:       String;

////////////////////////////////////////////////////////////////////////////////
//   WinMain(...)
////////////////////////////////////////////////////////////////////////////////
begin

  // Load command line
  if (ParamCount <> 1) then
     // Display info
     WriteLn('Expected COM (.dll/.exe/.ocx) file name')
  else
  begin
     // Get file name
     szFileName:=ParamStr(1);
     // Make sure it exists
     if FileExists(szFileName) then
        // Dump type info
        DumpTypeInfo(szFileName)
     else
        // File does not exist
        WriteLn('File does not exist!');
  end;

  // Finish up
  WriteLn;
  Write('Press enter to finish...');

  // Wait for enter
  Readln;

end.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.