declaration/definition and instantiation of COM objects with visual c++? - c++

i need to instantiate com object which is .dll and on local machine in visual c++,i know that it can be done by using CoCreateInstance("clsid") ,but i am confused about declaration.so can anyone explain all steps involved?
for late binding as well as early binding
is any import/inclusion required
how to declare com object ?
any other steps required before createinstance (e.g CoInitialize?)
or provide any specific reference involving step by step code

First you have to call CoInitialize and don't forget to callCoUnitialize if initialization was successful.
So your code will have the following structure:
HRESULT hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
try
{
CoCreateInstance(...)
// ...
}
catch (_com_error &e)
{
//...
}
CoUninitialize();
}
For more information visit MSDN. I recommend you to start with The COM Library and then you should read something about CoInitialize and CoCreateInstance functions before you use them.
This tutorial could help you too: Introduction to COM - What It Is and How to Use It.

#import is very much recommended. if you import the typelib with #import, you'll be using the Native COM framework, which isolates some gritty details and makes life generally easier.
In Native COM, something like this:
LibName::IMyInterfacePtr pInterface;
In raw C++:
IMyInterface *pInterface;
But see above.
Call CoInitialize() in the beginning of the program, CoUninitialize() in the end. if running inside a DLL, then it's much more complicated.

Related

Dynamic-like alternative for C++ and COM using IDispatch

I was showing a coworker how easily a COM object could be created and used in C++ using the Microsoft ATL library. In particular, I wanted to use demonstrate IDispatch to show how it can be used to dynamically call a method. However, I don't use C++/ATL frequently enough to not get lost in the templates and convenience methods and classes of ATL.
We created a small COM class, MyCOMLibrary.SimpleClass that has a single method named AppendMessage that takes 2 BSTRs and has no return value.
From a simple Win32 console application, creating and using the COM object was easy:
CComPtr<IDispatch> simpleClass;
debugPrint.CoCreateInstance(L"MyCOMLibrary.SimpleClass");
if (simpleClass) {
CComVariant vModule(L"Demo");
CComVariant vMessage(L"Welcome to COM");
simpleClass.Invoke2(L"AppendMessage", &vModule, &vMessage);
}
While this makes creating and managing the COM object nearly painless (especially when compared to using DISPPARAMS), I was looking for an even more concise way of calling the AppendMessage method that reflects modern C++/ATL/COM usage (in VS 2012).
The best case would be like C#'s dynamic keyword (dynamic documentation) (or any other "late-bound" language like JavaScript/VB6/etc):
simpleClass.AppendMessage(L"Demo", L"Welcome to COM");
Or, without that, this would be more readable:
simpleClass.Invoke2(L"AppendMessage", L"Demo", L"Welcome to COM");
However, I know the first won't compile as the method doesn't exist on CComPtr<IDispatch> and the second won't compile as Invoke2 requires VARIANTs.
I did try using the interface directly as a comparison:
// workaround VS2012 intellisense issue with #import
#ifndef __INTELLISENSE__
#import "progid:MyCOMLibrary.ISimpleClass" version("1.0")
#else
#include "Debug\MyCOMLibrary.tlh"
#endif
CComPtr<MyCOMLibrary::ISimpleClass> simpleClass;
simpleClass.CoCreateInstance(L"MyCOMLibrary.ISimpleClass");
if (simpleClass) {
CComBSTR module(L"Interfacing");
CComBSTR message(L"And, then, there was COM.");
simpleClass->AppendMessage((BSTR)module, (BSTR)message);
}
But, it's nearly identical to the original (and further, I want to do late-bound).
Question
Is there a different/shorter/better/awesome way of calling AppendMethod using IDispatch and ATL that would further impress upon my coworkers that C++ isn't always difficult? (Or, a better way without ATL would also be fine).
Take a look at VOLE by matthew wilson.
It is at http://vole.sourceforge.net/
It think it does what you want. I have used it before, and it makes IDispatch client programming a breeze.
Take a look at http://www.codeproject.com/Articles/19962/Driving-Microsoft-Word-using-VOLE for an example using Microsoft World

DirectDraw get procedure address using GetProcAddress

As stated in the documentation for the IDirectDraw7::SetCooperativeLevel method, it states
You must use LoadLibrary to explicitly link to Ddraw.dll and then use GetProcAddress to access the SetCooperativeLevel method.
in the remarks. However when I attempt to do so (code below), it fails to work. Am I doing something wrong?
typedef HRESULT (*pSetCooperativeLevelFunc)(HWND, DWORD);
HMODULE ddrawLib = LoadLibrary(L"ddraw.dll");
pSetCooperativeLevelFunc SCL = (pSetCooperativeLevelFunc) GetProcAddress(
ddrawLib,
"SetCooperativeLevel"
);
if (SCL == NULL) {
// this happens
int error = GetLastError(); // 127 (ERROR_PROC_NOT_FOUND)
printf("Error getting SetCooperativeLevel function address: %i", error);
}
There is no exported SetCooperativeLevel function in ddraw.dll. Use DUMPBIN utility and check it yourself. You can get DirectDrawCreate/DirectDrawCreateEx and similar functions using GetProcAddress, but you can't extract individual methods of COM object.
Article is quite ridiculous and doesn't make sense. Perhaps it was supposed to tell you to get DirectDrawCreate from ddraw.dll or something like that, but there's little reason to do that.
Link with ddraw.lib, call DirectDrawCreate and access methods provided by IDirectDraw7 interface.
P.S. If you aren't familiar with dumpbin, I'd suggest to learn at least basic usage of this utility.
I think that's a documentation bug. It's been a long time since I used DirectDraw7, but I don't recall having to load it dynamically. It was just a method of the IDirectDraw7 interface and called like any other method.
Since DX9, ddraw.lib was completely removed from the SDK, so you need to call LoadLibrary/GetProcAddress to call DirectDrawCreate or DirectDrawEnumerate. Unfortunately MSDN got it wrong, and added the GetProcAddress remark to EVERY DirectDraw function, even the COM interfaces' methods.

Is it safe to remove a call to OleInitialize from a non COM static library?

Today I had to define the WIN32_MEAN_AND_LEAN preprocessor macro in a native C++ project because I decided to use boost::asio in it, and without that macro, I get build errors.
Thing is, the error I get now is OleInitialize: identifier not found. According to the MSDN, this function is used to initialize a COM library. My project is not a COM library now, but my partners say it used to be.
In this case, would it be safe to remove the call? The project uses a mix of Win32 serial port functions and boost::asio (gradually, I'll leave just boost::asio). My concern is that OleInitialize might be necessary for some Win32 calls.
This is all it is done with it:
HRESULT hOle = OleInitialize( 0 );
if( !SUCCEEDED( hOle ) )
throw "Could not initialize OLE";
The worst that will happen is COM methods may start failing, if you're still calling some. OleInitialize() calls CoInitialize() internally. Only those functions need this. The base Win32 functions (CreateWindow, CreateFile, etc) do not require this initialization.
If you don't call any COM methods (any of the CoXXX() functions) and you don't call any Ole methods (OleXXX() functions), then you should be fine if you remove it.
You should do a quick search of your code base for COM / OLE functions and make sure you're really not using those technologies anymore. Then you can make a build where you don't do this and test it to see if it still works (you have a suite of test cases, right?).
Have a look at the Docs for other things that may break that you should check on.

How do I use a COM DLL with LoadLibrary in C++

First, COM is like black magic for me. But I need to use COM dll in one project I'm working on.
So, I have a DLL I am developing and I need some functionalities that are available in a separate COM DLL. When I look to the COM DLL with Depends.exe I see methods like DllGetClassObject() and other functions but none of the functions I'm interested in.
I have access to the COM DLL (legacy) source code but it's a mess and I'd rather like to use the COM DLL in binary like a big black box not knowing what's going on inside.
So, how can I call the COM DLL functions from my code using LoadLibrary? Is it possible? If, yes, could you give me an example of how to do it?
I'm using Visual Studio 6 for this project.
Thanks a lot!
In general, you should prefer CoCreateInstance or CoGetClassObject rather than accessing DllGetClassObject directly. But if you're dealing with a DLL that you can't, or don't want to, register, then the below describes (part of) what these function do behind the scenes.
Given a CLSID, DllGetClassObject allows you to get the class object, from which you can create instances (via the IClassFactory interface, if I remember correctly).
Summary of steps (it's been a while since I've last touched COM, so pardon any obvious errors):
Call DllGetClassObject(clsid, IID_IClassFactory, &cf), where clsid is the CLSID you want to get the class object for, and cf is of course the class factory.
Call cf->CreateInstance(0, iid, &obj), where iid is the IID of the interface you'd like to use, and obj is of course the object.
???
Profit!
(CoCreateInstance performs steps 1 and 2. CoGetClassObject performs step 1. You would use CoGetClassObject if you need to create many instances of the same class, so that step 1 doesn't need to be repeated each time.)
Typically you would use CoCreateInstance() to instantiate an object from a COM DLL. When you do this, there's no need to load the DLL first and get proc addresses like you would need to do with a normal DLL. This is because Windows "knows" about the types that a COM DLL implements, what DLL they are implemented in, and how to instantiate them. (Assuming of course that the COM DLL is registered, which it typically is).
Suppose you have a COM DLL with the IDog interface you want to use. In that case,
dog.idl
interface IDog : IUnknown
{
HRESULT Bark();
};
coclass Dog
{
[default] Interface IDog;
};
myCode.cpp
IDog* piDog = 0;
CoCreateInstance(CLSID_DOG, 0, CLSCTX_INPROC_SERVER, IID_IDOG, &piDog); // windows will instantiate the IDog object and place the pointer to it in piDog
piDog->Bark(); // do stuff
piDog->Release(); // were done with it now
piDog = 0; // no need to delete it -- COM objects generally delete themselves
All this memory management stuff can get pretty grungy, though, and the ATL provides smart pointers that make the task of instantiating & managing these objects a little easier:
CComPtr<IDog> dog;
dog.CoCreateInstance(CLSID_DOG);
dog->Bark();
EDIT:
When I said above that:
Windows "knows" about the types that a COM DLL implements [...and]
what DLL they are implemented in
...I really glossed over exactly how Windows knows this. It's not magic, although it might seem a little occult-ish at first.
COM libraries come with Type Libraries, which list the Interfaces and CoClasses that the library provides. This Type Library is in the form of a file on your hard drive -- very often it is embedded directly in the same DLL or EXE as the library itself. Windows knows where to find the Type Library and the COM Library itself by looking in the Windows Registry. Entries in the Registry tell Windows where on the hard drive the DLL is located.
When you call CoCreateInstance, Windows looks the clsid up in the Windows Registry, finds the corresponding DLL, loads it, and executes the proper code in the DLL that implements the COM object.
How does this information get in to the Windows Registry? When a COM DLL is installed, it is registered. This is typically done by running regsvr32.exe, which in turn loads your DLL in to memory and calls a function named DllRegisterServer. That function, implemented in your COM server, adds the necesarry information to the Registry. If you are using ATL or another COM framework, this is probably being done under the hood so that you don't have to interface with the Registry directly. DllRegisterServer only needs to be called once, at install-time.
If you try to call CoCreateInstance for a COM object that has not yet been registered via the regsvr32/DllRegisterServer process, then CoCreateInstance will fail with an error that says:
Class Not Registered
Fortunately, the fix for this is to simply call regsvr32 on your COM server, and then try again.
You do not directly use LoadLibrary() with a COM library. CoCreateInstance() will call this function if it's not already, and then new an instance of the class you implemented in the library onto the heap and finally return to you a raw pointer to that object. Of course, it could fail during the process, and thus some mechanism for you to check the status like HRESULT.
For simplicity of using it, you can think of a COM library as a common DLL with 1) some predefined entry(main) function, 2) you have to call some predefined function like CoCreateInstance() to enter it, and accept that it's like that because it has to.
If the type library is embedded in the DLL you can import it into your project:
#import "whatever.dll"
This will auto-generate header files that get included in your project and allow you to use the exported objects.
Here's a bit of code showing how to get the class factory and use it to create a COM object. It uses a struct to keep track of the module handle and DllGetClassObject function pointer. You should hold on to the module handle until you are done with the COM object.
To use this function, you need to allocate an instance of the ComModuleInfo struct and set the szDLL to the DLL filename or full path name. Then call the function with the class id and interface Id of the COM object you want to get from that DLL.
typedef struct {
TCHAR szDLL[MAX_PATH];
HMODULE hModule;
HRESULT (WINAPI *pfnGetFactory)(REFCLSID, REFIID, void**);
} ComModuleInfo;
HRESULT CreateCOMObject(
ComModuleInfo & mod, // [in,out]
REFCLSID iidClass, // [in] CLSID of the COM object to create
REFIID iidInterface, // [in] GUID of the interface to get
LPVOID FAR* ppIface) // [in] on success, interface to the COM object is returned
{
HRESULT hr = S_OK;
*ppIface = NULL; // in case we fail, make sure we return a null interface.
// init the ComModuleInfo if this is the first time we have seen it.
//
if ( ! mod.pfnGetFactory)
{
if ( ! mod.hModule)
{
mod.hModule = LoadLibrary(mod.szDLL);
if ( ! mod.hModule)
return HRESULT_FROM_WIN32(GetLastError());
}
mod.pfnGetFactory = (HRESULT (WINAPI *)(REFCLSID, REFIID, void**))GetProcAddress(mod.hModule, "DllGetClassObject");
if ( ! mod.pfnGetFactory)
return HRESULT_FROM_WIN32(GetLastError());
}
IClassFactory* pFactory = NULL;
hr = mod.pfnGetFactory(iidClass, IID_IClassFactory, (void**)&pFactory);
if (SUCCEEDED(hr))
{
hr = pFactory->CreateInstance(NULL, iidInterface, (void**)ppIface);
pFactory->Release();
}
return hr;
}
If it's a COM DLL, all you need do is add it as a reference to your project, and then you can call the functions that are within the DLL.
Yes, you can use the low level COM functions like DLLGetClassObject, but why would you?

How can I easily use a COM component in Native Visual C++

I am trying to build an app that uses a COM component in VisualStudio ยด05
in native C++.
The mix of native and managed desciptions of things in the MSDN totally wrecked my
brain. (I think the MSDN is a total mess in that respect)
I need a short and simple native C++ sample of code to load my Component
and make it usable.
I am ok with the compiler creating wrappers and the like.
Please don't advise me to use the dialog based MFC example, because
it does not work with this component and is in itself a huge
pile of c... code.
Can this be an issue native com vs managed com?
I am totally lost, please give me some bearings...
EDIT: Thanks for all the help.
My problem is that all I have is a registered dll (actually the OCX, see below)
. I (personally) know
what the Interface should look like, but how do I tell my program?
There are no headers that define
IDs for Interfaces that I could use. But I read that the c++ compiler
can extract and wrap it up for me. Anyone know how this is done?
CLARIFICATION: I have only the OCX and a clue from the documentation
of the component, what methods it should expose.
Fully working example (exactly what you need) from my blog article: How to Call COM Object from Visual Studio C++?
// https://helloacm.com/how-to-call-com-object-from-visual-studio-c/
#include <iostream>
#include <objbase.h>
#include <unknwn.h>
#include <Propvarutil.h>
#import "wshom.ocx" no_namespace, raw_interfaces_only
using namespace std;
int main() {
HRESULT hr;
CLSID clsid;
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
CLSIDFromProgID(OLESTR("WScript.Shell"), &clsid);
IWshShell *pApp = nullptr;
hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IWshShell), reinterpret_cast<LPVOID *>(&pApp));
if (FAILED(hr) || pApp == nullptr) {
throw "Cannot Create COM Object";
}
int out;
VARIANT s;
InitVariantFromInt32(0, &s);
VARIANT title;
InitVariantFromString(PCWSTR(L"title"), &title);
VARIANT type;
InitVariantFromInt32(4096, &type);
BSTR msg = ::SysAllocString(L"Hello from https://helloacm.com");
pApp->Popup(msg, &s, &title, &type, &out);
CoUninitialize();
cout << "Out = " << out;
return 0;
}
The bare minimums for instantiating a COM object are as follows:
1) Must have a COM apartment available.
This is accomplished by most applications by calling CoInitialize / CoInitializeEx to setup the COM library and the initial COM apartment if it is the first time for a process.
2) Call CoCreateInstance / CoCreateInstanceEx to create an object, and specify flags to denote how it will be instantiated.
3) Properly balance calls of AddRef and Release on the interfaces of any COM components that you create, calling the last Release() when you are done using a COM component.
-
In a managed application, #1 is almost always handled for you. #2 is abstracted away if you import a reference to a COM library, and you can just use the imported names as if they were .NET class definitions and such. #3 is automatically handled for you, but your needs may vary. Unfortunately, there are sometimes quirks in how references are handled in managed applications, which can cause COM objects to stick around longer than intended. The Marshal helper class in System.Runtime has methods that can help you out there if you encounter issues.
-
In an unmanaged application, you will have to do some legwork if you are creating an application from scratch.
Call CoInitialize/CoInitializeEx early in your application's main thread to setup the apartment.
When your application's main thread is about to exit, call CoUninitialize() to close out the apartment.
For additional threads that you create, you should also call CoInitialize/CoInitializeEx when they start if you need to use COM objects from those threads. Also, depending on your application you may want to set the apartment parameters.
For those threads, also call CoUninitialize() when they are exiting to cleanup properly.
I applaud your efforts to go with native C++ to deal with COM - you need to go through the pain to truly appreciate today's luxurious (managed) development environment :)
Back when the world (and I) were younger, Kraig Brockshmidt's book "Inside OLE" was the tome for making sense of COM (before COM even was COM). This book predates managed code, so no chance of managed confusion here. There's a second edition, too.
Don Box's books "Essential COM" and "Effective COM" were later, but welcome additions to the store of (unmanaged) COM knowledge.
However, if your wallet doesn't extend to acquiring these dusty old books, the Microsoft COM tutorial material here could help set you on the right track.
Happy hacking.
I use a combination of ATL smart COM pointers and the ATL::CAxWindow class for COM objects and components. I find the smart pointers particularly easy to use.
http://www.murrayc.com/learning/windows/usecomfromatl.shtml
http://76.105.92.243/notes/atlcom.html#import
http://msdn.microsoft.com/en-us/library/yx242b61%28VS.80%29.aspx
It would help if you gave a little more information about what you're exactly doing. Do you know what interfaces the object implements, etc?
In general though, the API that you can Google for more specific help is CoCreateInstance. You'll need to pass it the GUID of the object you want to play with. All COM objects implement the IUnknown interface, and you can query for any others it might have. So some sample pseudocode to get you started might look something like:
CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
CoCreateInstance( CLSID,
ptrIUnknown,
ClassCxt, // generally CLSCTX_INPROC_SERVER,
riid , // reference id
(void **)&pRequest); // the interface that corresponds to the riid
Here you can query additional interfaces using the IUnknown interface you got from the ptrIUnknown.
Then clean up with
CoUninitialize()
Don Box's Essential COM is a great book on this topic. Also, just for testing how your COM object works, using something like VBScript makes this super easy. Also, it's probably worthy of note that the GUID of the class ID is stored in a somewhat unusual way, so if you're just ripping a GUID from the registry, you might have some trouble figuring out the ordering. That's probably for a different question though.
Try using #import from Visual C++. This will create smart pointer wrappers for the interfaces.