• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 391
  • Last Modified:

Accessing a COM DLL in C++

In Microsoft Visual C++ 6.0, I want to access a COM DLL (written in VFoxpro 6.0).  In VB and VFP the syntax was CREATEOBJECT("test.class").  How do I go about doing this?  

Thanks.
0
mgonyea
Asked:
mgonyea
  • 5
  • 5
  • 3
1 Solution
 
jkrCommented:
Well, in C/C++ things are more compilcated. The instantiation is done by 'CoCreateInstance()' which takes a CLSID as the parameter, and additionally an interface ID. But, as you're referring to VB, these objects usually use IDispatch interfaces, which makes life easier. When you aren't about to use any class library or framework (like MFC), the code would be

#include <tchar.h>

    HRESULT    sc;
      IDispatch* pObj;
      CLSID      clsid;

      CLSIDFromProgID ( TEXT( "test.class"), &clsid);

    sc    =     CoCreateInstance  (   clsid,
                                      NULL,
                                      CLSCTX_SERVER,
                                      IID_IDispatch,
                                      ( void**) &pObj
                                  );


Feel free to ask if you need more information!
0
 
Brain2000Commented:
I just ran into this solution about 2 days ago.  I asked a similar question about a month ago, but it wasn't answered quite how I wanted, so I continued to research it myself.  It has taken me over a year to not only use, but also understand what I'm going to post here.  It seems this is sorely undocumented, and what little is documented, is buried deep within pages of specs and nothingness.

So here's how to do Automation in C++.  This example would be equivalent to VB:

wordApplication=CreateObject("Word.Application")
wordDocuments=wordApplication.Documents
currentDocument=wordDocuments.Open('file',0,0,0,'','',0,'','',wdOpenFormatAuto)


Now, in C++ (this is a roller coaster ride...):

//got this definition from the .idl file
int wdOpenFormatAuto=0;

void main(void)
{
  CLSID wordCLSID;
  IDispatch *wordApplication,*wordDocuments,*currentDocument;
  DISPID dispid;
  HRESULT hr;
  DISPPARAMS dp;
  VARIANT res;
  VARIANTARG va[11];
  OLECHAR *oc;
  int x;

  OleInitialize(NULL);
  //get the CLSID of Word.Application
  CLSIDFromProgID(L"Word.Application",&wordCLSID);

  hr = CoCreateInstance(wordCLSID,NULL,CLSCTX_LOCAL_SERVER,IID_IDispatch,(void **)&wordApplication);

  //find the dispatch id for "Documents"
  oc=L"Documents";
  hr=wordApplication->GetIDsOfNames(IID_NULL,&oc,1,LOCALE_SYSTEM_DEFAULT,&dispid);
  printf("Documents DispID=0x%x\n",dispid);

  //setup for 0 arguments
  dp.rgvarg=NULL;
  dp.cArgs=0;
  dp.rgdispidNamedArgs=NULL;
  dp.cNamedArgs=0;

  //now get the Documents interface.  Note, this is NOT a COM function, it is a property.
  hr=wordApplication->Invoke(dispid,IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_PROPERTYGET,&dp,&res,NULL,NULL);

  //now save the IDispatch interface pointer for Documents into our wordDocuments variable
  wordDocuments=res.pdispVal;


  //now let's use this new interface to Open() a .doc file

  //get the Open() dispatch ID
  oc=L"Open";
  hr=wordDocuments->GetIDsOfNames(IID_NULL,&oc,1,LOCALE_SYSTEM_DEFAULT,&dispid);

  //now set up the parameters needed for the open function.
  //note, there are 10 variants that need to be set up!
  dp.rgvarg=va;
  dp.cArgs=10;
  dp.cNamedArgs=0;
  dp.rgdispidNamedArgs=NULL;

  VariantInit(&dp.rgvarg[0]);
  dp.rgvarg[0].vt=VT_I4;
  dp.rgvarg[0].lVal=wdOpenFormatAuto;

  VariantInit(&dp.rgvarg[1]);
  dp.rgvarg[1].vt=VT_BSTR;
  oc=L"";
  dp.rgvarg[1].bstrVal=SysAllocString(oc);

  VariantInit(&dp.rgvarg[2]);
  dp.rgvarg[2].vt=VT_BSTR;
  oc=L"";
  dp.rgvarg[2].bstrVal=SysAllocString(oc);

  VariantInit(&dp.rgvarg[3]);
  dp.rgvarg[3].vt=VT_BOOL;
  dp.rgvarg[3].boolVal=0x0000;

  VariantInit(&dp.rgvarg[4]);
  dp.rgvarg[4].vt=VT_BSTR;
  oc=L"";
  dp.rgvarg[4].bstrVal=SysAllocString(oc);

  VariantInit(&dp.rgvarg[5]);
  dp.rgvarg[5].vt=VT_BSTR;
  oc=L"";
  dp.rgvarg[5].bstrVal=SysAllocString(oc);

  VariantInit(&dp.rgvarg[6]);
  dp.rgvarg[6].vt=VT_BOOL;
  dp.rgvarg[6].boolVal=0x0000;

  VariantInit(&dp.rgvarg[7]);
  dp.rgvarg[7].vt=VT_BOOL;
  dp.rgvarg[7].boolVal=0x0000;

  VariantInit(&dp.rgvarg[8]);
  dp.rgvarg[8].vt=VT_BOOL;
  dp.rgvarg[8].boolVal=0x0000;

  VariantInit(&dp.rgvarg[9]);
  dp.rgvarg[9].vt=VT_BSTR;
  oc=L"test.doc"
  dp.rgvarg[9].bstrVal=SysAllocString(oc);

  //now call the Open() function.  Note that this IS a method, not a property like above
  hr=wordDocuments->Invoke(dispid,IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_METHOD,&dp,&res,NULL,NULL);

  //now free up variables if needed
  for(x=0;x<10;x++) VariantClear(&dp.rgvarg[x]);

  //now save the IDispatch Interface to the newly opened document
  currentDocument=res.pdispVal;


  currentApplication->Release();
  wordDocuments->Release();
  wordApplication->Release();

  OleUninitialize();
}
0
 
Brain2000Commented:
I forgot to mention one VERY important thing.  If you're compiling this yourself with a makefile, you will pull out your hair wondering why IID_IDispatch and IDispatch is not declared anywhere.  To get it to compile, also include uuid.lib

i.e.

cl test.cpp ole32.lib oleaut32.lib uuid.lib
0
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

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.

 
mgonyeaAuthor Commented:
In MS Visual C++ 6, the first parameter expected in CLSISFromProgID is an unsigned short *, and won't accept a char[x].
0
 
jkrCommented:
>>the first parameter expected in CLSISFromProgID is an
>>unsigned short *

Thus the 'TEXT()' macro, which will expand to a 'L' string prefix that instructs the compiler to handle the following string as UNICODE, which in fact is 'unsigned short*'

The macro is sth. like that:

#ifdef UNICODE
#define TEXT(x) L##x
#else
#define TEXT(x) x

You could of course hard-code it:

CLSIDFromProgID ( L"test.class", &clsid);
0
 
Brain2000Commented:
Yes, what he said.
0
 
mgonyeaAuthor Commented:
One last thing, and I'll bump the points up to 200.  The "VARIANT res;" now contains the results of my OLE functions (Yay!).  How do I convert it BACK from a BSTR, into a char *?

Thanks everyone.
0
 
jkrCommented:
As BSTR* is the same as OLECHAR* (which is the same as LPOLESTR ;-)

(see wtypes.h, i just left out the RPC stuff:
typedef OLECHAR *BSTR;
)

this function does what you need:
char* ANSIStringFromUNICODE( LPOLESTR pszOLE)
{
HRESULT hResult;

static char acBuffer[ BUFFER_MAX];


    hResult =   ::WideCharToMultiByte   (   CP_ACP,
                                            0,
                                            pszOLE,
                                            -1,
                                            acBuffer,
                                            sizeof  (   acBuffer),
                                            NULL,
                                            NULL
                                        );


    if  (   FAILED  (   hResult))
            return  (   NULL)

    return ( acBuffer);
}

So, just call it like

char* pc = ANSIStringFromUNICODE ( res.bstrVal);
0
 
Brain2000Commented:
Also, don't forget to call VariantClear() when you're done so you don't get memory leaks.
0
 
Brain2000Commented:
So who gets the points on this one?

jkr proposed the original answer and locked the question, but I answered your question much more thorough.  But then he answered your second part.  I think it should split 100/100, but that's a pain.
0
 
mgonyeaAuthor Commented:
Unfortunately, I'll grade the answer.  Works great!  I'm posting another question Brain, so you can answer that one and I'll give you the same amount of points.  The question is "Declaring absolute globals in MSVC++6"

Thanks to you to, jkr!
0
 
jkrCommented:
Fine that I could be of some help!
0
 
jkrCommented:
mgonyea, you should grade this one so that it moves to the PAQ section...
0

Featured Post

Learn to develop an Android App

Want to increase your earning potential in 2018? Pad your resume with app building experience. Learn how with this hands-on course.

  • 5
  • 5
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now