?
Solved

How to access a COMObject: converting example from VB code

Posted on 2008-11-19
7
Medium Priority
?
475 Views
Last Modified: 2012-05-05
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

0
Comment
Question by:ttheimer
  • 3
  • 3
7 Comments
 
LVL 26

Expert Comment

by:Russell Libby
ID: 23004464
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
 

Author Comment

by:ttheimer
ID: 23007413
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
 
LVL 26

Accepted Solution

by:
Russell Libby earned 2000 total points
ID: 23008068

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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 46

Expert Comment

by:aikimark
ID: 23013205
@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
 

Author Closing Comment

by:ttheimer
ID: 31518575
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
 

Author Comment

by:ttheimer
ID: 23013534
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
 
LVL 26

Expert Comment

by:Russell Libby
ID: 23014084
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

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
This Micro Tutorial will teach you how to add a cinematic look to any film or video out there. There are very few simple steps that you will follow to do so. This will be demonstrated using Adobe Premiere Pro CS6.
With just a little bit of  SQL and VBA, many doors open to cool things like synchronize a list box to display data relevant to other information on a form.  If you have never written code or looked at an SQL statement before, no problem! ...  give i…
Suggested Courses
Course of the Month16 days, 10 hours left to enroll

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

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

Join & Ask a Question