How can I easily use a COM component in Native Visual C++ - 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.

Related

Reading structured data in VB.NET from MFC DLL function using P/Invoke

I have the following structure in an MFC DLL:
struct retornoSAP
{
enum tipoRetorno
{
Ok,
Falha,
AbrirArquivo, // mStrData válido
InserirArquivo, // mStrData válido
retornoMap, // mLstData válido
retornoTable, // mLstTable válido
retornoString, // mStrData válido
};
tipoRetorno mTipo;
CString mStrData;
CMapStringToString mLstData;
retTable* mLstTable;
CMapStringToString mLstVars;
retornoSAP( tipoRetorno pTipo )
{
mTipo = pTipo;
mLstTable = NULL;
}
~retornoSAP()
{
if ( mLstTable ) CISap::release( mLstTable );
}
};
retTable definition is:
typedef vector<CMapStringToString*> retTable;
This structure is used to store data read from an SAP API, and I have a lot of functions that return a "retornoSAP" value.
It happens that I have to call those functions from VB.NET, using P/Invoke (DllImport). I have read some material about marshaling unmanaged types to .NET (like this http://blogs.msdn.com/b/dsvc/archive/2009/02/18/marshalling-complicated-structures-using-pinvoke.aspx), and it probably would be easy to marshal a structure with some basic types in it, but I wonder if it is even possible to marshal a CMapStringToString or, even worse, a vector of CMapStringToString.
My question is if it's worth spending some time trying to translate this structure to a .NET type (in this case, where I could find some good documentation)?
If not, I wonder if it sounds like a good idea to use a XML parser in C++, write all my data to a XML structure, and then return that XML structure as a BSTR string, so I could read the BSTR return value easily it in my .NET application and parse it back to a XML structure. In that case, I would pass some big strings between the MFC DLL and the .NET application...
You can't really deal with MFC classes with P/INVOKE. I think you can choose one of two option:
Not touching the MFC dll at all: create a dll with CLI C++. Some effort to learn the language, but is a thunk dll, you don't need to study it all. This way you can expose some ref classes to .NET world and call from its methods the MFC dll. From inside the ref class you can read your original MFC structures and populate some other structures more .NET friendly.
Modify the MFC dll, expose some entry point with extern "C" decoration, in order to avoid name mangling, and convert internal structure in something easyer to manage, string as you guess, would be a not so elegant, but cutting edge solution;)
Both solution have some performance overhead, but I guess the first one would pay better, and it is sometimes the only one preventing modification to the original MFC dll, and sometimes this is desiderable. Second one is probably simpler, but passing magic string would involve some parsing leading to performance leak, possible errors so you need more test, more costs and so on.
Another drawback of solution 1 is you need an extra deploy for the C++/CLI redistributables.
I did not mention since you probably already know, but doing this kind of interop needs the .NET code compiled in x86 mode if your target C++ dll are 32 bit compiled.

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

declaration/definition and instantiation of COM objects with visual 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.

Implementing the CLR into old MFC/Win32 DLL and hosting DLL into MFC/Win32 Application

I have an old MFC application which I currently import an old MFC/Win32 DLL into.
In this old DLL, I have been tasked with writing a bunch of Multi-Threaded code which I was planning on writing using the .NET framework (hence needing the CLR).
I've made cracks at this before, and even if I can get the project to compile properly with the CLR, I find that as soon as I try to use the DLL's user interface (written in MFC) after loading the DLL into the MFC/Win32 application, the application will crash pointing to problems with the user interface.
This DLL has always worked without the CLR, so I know that it is not broken.
What is the best way of implementing the CLR in my project, even if it is only for one class?
EDIT: I currently can get the code to build with the CLR only on the one class I need it in, but the application I load the DLL into still crashes upon trying to load the user interface contained in the DLL.
EDIT2: I have figured out that it is failing an assertion on afxCurrentResourceHandle in afxwin1.inl. After doing more reading, I have a feeling that this has to do with MFC being in a "shared DLL" instead of "static DLL." Is there a workaround for this assertion?
_AFXWIN_INLINE HINSTANCE AFXAPI AfxGetResourceHandle()
{ ASSERT(afxCurrentResourceHandle != NULL);
return afxCurrentResourceHandle; }
EDIT3: I have made progress, but am still failing assertions! Apparently before you create the objects of the pages within the user interface, you must use the AFX_MANAGE_STATE macro to have afxCurrentResourceHandle be defined!
Here's an example of what I mean:
CPropertySheet Sheet("Config"); //Assume this is defined
AFX_MANAGE_STATE(AfxGetStaticModuleStatus());
CConfigPage ConfigPage;
CTestPage TestPage;
//Now I am failing an assertion when trying to run the following code
if (Sheet.DoModal() == ID_OK)
{
//Do stuff...
}
The assertion currently failing now is:
CObject* AFX_CDECL AfxStaticDownCast(CRunTimeClass* pClass, CObject* pObject)
{
ASSERT(pObject == NULL || pObject->IsKindOf(pClass));
return pObject
}
pObject certainly isn't null: pObject: 0x043fd4fc {CWnd hWnd=0x002c0abe}
Combining MFC and .NET/CLR is unlikely to work, unless you can recompile the old MFC application with CLR support. Even then, I would strongly discourage it; the two frameworks are not intended to be used simultaneously. Keep in mind that you can only use one GUI thread even if you don't use MFC.
A better solution would be to use the standard MFC threading mechanisms. It's really not hard; just make a new class with a member function like this:
static UINT Go(LPVOID pParam);
Then call AfxBeginThread(Go, this) from somewhere else in your class. Recast pParam to pointer to your class and then start calling functions on it. You don't have to use anything fancy to make that strategy work in MFC, and you've got all the standard Win32/MFC/C++ resources available. Tell me what you need from .NET and I bet I can find a way to do the same thing in C++ or through COM.

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?