Connecting to COM object with C++

Hi all,

Is there a way to connect to a specific COM Object using C++? I'm having a hard time finding anything on the Microsoft websites.

In vbscript, there is a way. Something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Sub UseTaskSequenceVariables()
   dim osd: set env = CreateObject("Microsoft.SMS.TSEnvironment")
   dim logPath

   ' You can query the environment to get an existing variable.
   logPath = env("_SMSTSLogPath")

    wscript.echo logPath 

   ' You can also set a variable in the Operating System Deployment environment.
   env("MyCustomVariable") = "My Custom Value"

   ' Set the OSDPartitions(0) Bootable array member to 0.
    env("OSDPartitions0Bootable") = "true"
End Sub 


Thanks all!
Don't attempt to do it directly. Use Microsoft's ATL.
This is a deep topic, I hope you understand. I've written quite a bit of tutorial material here...

http://www.jose.it-berater.org/smfforum/index.php?board=362.0

This is a mostly PowerBASIC oriented site, but a lot of my stuff is C++ as are my COM tutorials. To answer your question in just a few lines though, connecting to COM components only takes a few lines of code in a client app, athouugh if the COM object needs bi-directional communication, i.e., 'connection points', it gets a bit more complex.
Hi kbw and freddie1: Thanks for Replying!

@freddie1: Will gladly try your tutorial. I will go back on you if it works. Thank you very much for this! :)http://www.cplusplus.com/forum/windows/19738/#
Hi freddie,

I just want to confirm, if you say bi-directional communication, does it count you request something from the COM object?

For example, I connect to the COM Object "Microsoft.SMS.TSEnvironment" and then I request from that COM object the path contained in the _TSLogs variable. From what I understand, this already counts as bi-directional communication since it returns a value to you.

Please correct me if I am wrong.

Thank you!
No, that wouldn't be a case of bi-directional communication. If I've got it right what you are describing, that is simply a method/interface call, and a BSTR would hopefully be returned to you.

The bi-directional connection point mechanism comes into play frequently with COM objects that have a visual interface; for example, an ActiveX control such as a grid. In that case one could describe the client as being a host of the ActiveX control which would be the server. However, the client would implement a 'sink' object which the ActiveX control would 'call' to notify it of user interface interactions which occurred in the grid. So each object would hold pointers to objects within each other, so to speak.

I'm not sure what "Microsoft.SMS.TSEnvironment" is. I didn't see it on my machine. Is it a dll you load into your process, an exe server?
Hi freddie, thanks for replying again,

"Microsoft.SMS.TSEnvironment" is a COM Object used in a running Task Sequence in Windows PE (Pre-installation Environment).

I took a look in the tutorial that you provided. It seems that in there, a new COM object is created then registered in the computer. How about if the COM object is already existing? Is there no difference in the code in order to connect or gain access to it, as well as its variables?

For example, if you already want to access an existing COM object instead of creating a new one, which of this does not need to be used?

Server.cpp
CA.cpp
Registry.cpp
CA.h
Ifunctions.h
Registry.h
CA.def


Sorry for this, I am having quite a hard time understanding the codes as I'm not a very in-depth C++ programmer.

Thank you!
Hi Waterborne!

Yea, COM is hard to understand when attacked at a low level with C or C++. I've been working at it for years really, and still don't understand it all. Those tutorials resulted from my attempts to understand the memory layout because that's how my mind works. I seem to have to grasp all the little details such as where things are laid out in memory and how they are accessed through pointers. But to answer your question, its not the connecting part (which I think is what you want to do) that is hard. What's hard is building the COM object server. ATL (Active Template Library) and MFC (Microsoft Foundation Classes) make it easier to do than the low level raw code in my tutorials, but that's after you've learned ATL and MFC and those are no small chores!

But taking the simple COM object created in my tutorial #1, it could be connected to like so if it has been registered by using RegSvr32 on it...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <windows.h>            //CAClient6
#include <stdio.h>
static const CLSID CLSID_CA   = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}};
static const IID   IID_I_X    = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}};
static const IID   IID_I_Y    = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06}};


interface I_X : IUnknown
{
 virtual HRESULT __stdcall Fx1(int)=0;
 virtual HRESULT __stdcall Fx2(int)=0;
};


interface I_Y : IUnknown
{
 virtual HRESULT __stdcall Fy1(int)=0;
 virtual HRESULT __stdcall Fy2(int)=0;
};


int main(void)
{
 I_X* pIX=NULL;
 I_Y* pIY=NULL;
 HRESULT hr;

 hr=CoInitialize(NULL);
 hr=CoCreateInstance(CLSID_CA, NULL, CLSCTX_INPROC_SERVER, IID_I_X, (void**)&pIX);
 hr=pIX->Fx1(25);
 hr=pIX->Fx2(50);
 hr=pIX->QueryInterface(IID_I_Y,(void**)&pIY);
 hr=pIY->Fy1(75);
 hr=pIY->Fy2(100);
 hr=pIX->Release();
 hr=pIY->Release();
 CoUninitialize();
 
 return 0;
}

/*
//Output From printf debug output statrements in COM dll containing Class CA
//======================================================
sizeof(CA) = 12
this       = 10355696
Called CA::AddRef()
Called CA::AddRef()
Called CA::Release()
Called CA::AddRef()
Called CA::Release()
Called Fx1()  :  iNum = 25
Called Fx2()  :  iNum = 50
Called CA::AddRef()
Called Fy1()  :  iNum = 75
Called Fy2()  :  iNum = 100
Called CA::Release()
Called CA::Release()
*/


Now in that code above, only two lines of code really were needed to connect, and they are...

1
2
 hr=CoInitialize(NULL);
 hr=CoCreateInstance(CLSID_CA, NULL, CLSCTX_INPROC_SERVER, IID_I_X, (void**)&pIX);


The top line initializes the Windows COM library. The second line passes into CoCreateInstance() the class id (CLSID_CA) of the object you want to use. Windows then looks up in the registry where the CLSCTX_INPROC_SERVER is located on the computer or network (the path is in the registry), and then does a LoadLibrary() call on the dll, then does a GetProcAddress() call on the exported DllGetClassObject() function, which then creates the object CA (class A) and returns a pointer to it in the las parameter of the CoCreateInstance() call - &pIX above.

Now all that is for a OM object in a dll. If you are accessing a COM object contained in an executable, its a bit different.
Last edited on
So you see, it doesn't really take that much code to connect to an already existing and registered COM object. In reading over my post and looking at the code it occurred to me that a person not familiar with this material might wonder where the various GUIDs (globally unique identifiers) and interface descriptions are coming from. Any real and self-respecting COM object (unlike the very simple example in my tutorial) would create something known as a type library. The class ids (CLSID) and interface identifiers (IIDs) would be found there. Also found there would be the interfaces and their member functions. Your C++ program would typically need to include these in the form of header files. These header files are typically created by a tool called a 'type lib browser'. Maybe someone else here knows some good ones for C++. I could use one myself. I do a lot of PowerBASIC programming, and there are a couple I use for that that are good, but I really don't have one that specifically exports C interface declarations (I believe OLE View or something like that comes with Windows). Its something I was thinking of writing for myself someday as an exercise.
Hi freddie!

Thanks very much for all the effort and for this. This really made me understand what is being used in order to connect COM Objects!

Although now I have a different problem, still regarding the COM object. I used regedit and saw the CLSID of Microsoft.SMS.TSEnvironment. It looks something like this: {2D26B0A2-A1C9-4E75-84CB-9102F6842FE5}

The problem is, this doesn't seem to be accepted by the program. I get an error when I input this:

static const CLSID CLSID_CA = {2D26B0A2-A1C9-4E75-84CB-9102F6842FE5}

Any idea to solve this? I have tried using CLSIDFromString but I seem to be using it wrongly.

I also did not see the where the IID is, only the CLSID. Any idea where to start looking for the type library that you mentioned?

Thank you very much!
Class IDs are a struct known as a GUID that looks like this...

1
2
3
4
5
6
7
typedef struct_GUID
{
   unsigned long Data1;
   unsigned short Data2;
   unsigned short Data3;
   unsigned char Data4[8];
}GUID;


So you'll need a declaration like this...

static const CLSID CLSID_TSENV = {0x2D26B0A2, 0xA1C9, 0x4E75, {0x84,0xCB,0x91,0x02,0xF6,0x84,0x2F,0xE5}};

Microsoft.SMS.TSEnvironment is known as a Program ID. When you find it under HKEY_CLASSES_ROOT the class id will be listed there. If you then scroll up and find the HKEY_CLASSES_ROOT\CLSID\{2D26B0A2-A1C9-4E75-84CB-9102F6842FE5} entry, you'll be given the file location of the dll if it is a dll in the InProcServer32 sub-key. Type libraries are sometimes compiled right into the binary and other times are seperate files with a *.tlb extension. I'd recommend you do a search on your compute for OleView.exe. With that tool you can find out just about everything you need to know about a COM object including the member functions of the exposed interfaces.

If you need to work with this stuff you really need to get yourself a few books on it. One I'd recommend to get started with is "Inside COM" by Dale Rogerson. Another book I have that I like is "Inside Distributed COM" by Guy and Henry Eddon. A pretty good book on ATL is "Developer's Workshop To COM and ATL 3.0" by Andrew W. Troelsen. These books are rather old. There may be newer ones available. You would have to check.

Hi freddie,

Ok, I'll look into those books. Thank you very much for all the help!

Ok, I'll look into those books. Thank you very much for all the help!


No problem. COM is one of my interests/challenges. I'll answer more questions if I can. Its just that I'm not at all familiar with Microsoft.SMS.TSEnvironment. My main interests in COM are in ActiveX controls in dlls.

Tom Armstrong also has a good book on COM. Thought I'd mention that.

Another thought is that PowerBASIC really makes working with COM a pleasure. If you want it to, it handles all the low level stuff. Unfortunately, there are'nt any books that teach COM from a PowerBASIC perspective. That's why I mostly learn and study it in a C/C++ context, because I know those languages fairly well too. However, I pretty much try to translate everything I learn to PowerBASIC then.
Topic archived. No new replies allowed.