Visual C++: InvokeHelper() function - c++

I am deciphering a huge project that uses COM, which I am completely new to. It's quite confusing and I can't figure out how everything interacts. All I see is InvokeHelper(...) where I would expect to see a big amount of code. What is InvokeHelper()? What does it do?
Thank you for any help.

Even though it's a late answer, I'd like to post it here as I have spent a couple of days to figure out how it's working. It may be interesting for someone else.
Below is the path how to get to the real code from InvokeHelper() call:
InvokeHelper() should be called for an object of a class, inherited from CWnd with DISPID specified, where DISPID is something like 0x00000261
The class should have inside a call to a method CreateControl() with a GUID of a COM class
The COM class with the GUID should be COM coclass with at least one IDL interface
The IDL interface should implement a method with the attribute [id(DISPID)]. This is the same DISPID as in item 1
Look for implementation of the interface and find the method with this id attribute
VoilĂ !
Sure, if you don't have a source code of the COM class with the CLSID you cannot take a look inside the method, but at least, you can find its name as follows:
DISPID dispidCommand = 0x1; /// This is the dispid, you're looking for
COleDispatchDriver driver;
BOOL bRes = driver.CreateDispatch(GetClsid());
ASSERT(bRes);
HRESULT hr;
CComPtr<ITypeInfo> pti;
hr = driver.m_lpDispatch->GetTypeInfo(0, GetUserDefaultLCID(), &pti);
ASSERT(SUCCEEDED(hr));
UINT nCount = 0;
CComBSTR bstrName; // Name of the method, which is called via DISPID
hr = pti->GetNames(dispidCommand, &bstrName, 1, &nCount);
ASSERT(SUCCEEDED(hr));
I hope it helps someone.
Take care.

Related

Marshalling D3D11Device and D3D11DeviceContext objects

This article says:
The ID3D11DeviceContext methods (except for those that exist on
ID3D11DeviceChild) are not free-threaded, that is, they require single
threading. Only one thread may safely be calling any of its methods
(Draw, Copy, Map, etc.) at a time.
I was wondering if I can make COM do the ID3D11DeviceContext synchronization for me.
Let's say I do this (in simplified code):
CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
// Create D3D11Device
CComPtr<ID3D11DeviceContext> pD3D11DeviceContext;
pD3D11Device->GetImmediateContext(&pD3D11DeviceContext);
Then I either marshall it:
IStream* pStreamD3D11DeviceContext = NULL;
CComPtr<IUnknown> pUnknownD3D11DeviceContext;
pD3D11DeviceContext->QueryInterface(IID_PPV_ARGS(&pUnknownD3D11DeviceContext));
::CoMarshalInterThreadInterfaceInStream( __uuidof(ID3D11DeviceContext), pUnknownD3D11DeviceContext, &pStreamD3D11DeviceContext );
Or us a GIT table:
CComPtr<IGlobalInterfaceTable> pIGlobalInterfaceTable;
::CoCreateInstance( CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (void **)&pIGlobalInterfaceTable );
CComPtr<IUnknown> pUnknownD3D11DeviceContext;
DWORD dwCookieD3D11DeviceContext = 0;
pD3D11DeviceContext->QueryInterface(IID_PPV_ARGS(&pUnknownD3D11DeviceContext));
pIGlobalInterfaceTable->RegisterInterfaceInGlobal( pUnknownD3D11DeviceContext, __uuidof(ID3D11DeviceContext), &dwCookieD3D11DeviceContext );
Unfortunately this doesn't seem to work.
CoMarshalInterThreadInterfaceInStream returns REGDB_E_IIDNOTREG (0x80040155, Interface not registered) and pStreamD3D11DeviceContext remains NULL.
GIT method goes one step further. I get the cookie, but when I try to use it on another MTA thread, the GetInterfaceFromGlobal returns E_INVALIDARG.
CComPtr<ID3D11DeviceContext> pD3D11DeviceContext;
hresult = pIGlobalInterfaceTable->GetInterfaceFromGlobal( dwCookieD3D11DeviceContext, __uuidof(ID3D11DeviceContext), (void**)&pD3D11DeviceContext );
The params for GetInterfaceFromGlobal seem okay, I tested getting the pointer back on the original thread and it worked.
The D3D11Device and D3D11DeviceContext appear to be unmarshallable. Obviously I have neither proxy DLL nor a typelib for the d3d11.
Am I missing anything?
Thank you.

Custom Download Manager IWebbrowser2

Sorry if my question is previously answered here but I have, for days, searched the internet including SO with no solution.
Basically I want to Implement Download Manager for IE webbrowser control (Not IDE itself).
I have read a lot on MSDN and among them is this link which shows how to create it.
The Problem with this example (and my problem in that case) is where do I register/apply the IServiceProvider to my web browser. The Article does not say. However searching I found this question and it say I quote
Use CAxWindow::QueryHost to get IObjectWithSite pointer. Call SetSite
passing your IServiceProvider implementation.
Unfortunately I don't use or know anything about ATL as I use wxWidgets. So where do I get that in wxWebview or "vanilla" MS COM?
here is what I have so far
HRESULT wxDownloadMgr::Download(IMoniker *pmk, IBindCtx *pbc,DWORD dwBindVerb,
LONG grfBINDF,BINDINFO *pBindInfo, LPCOLESTR pszHeaders,LPCOLESTR pszRedir,UINT uiCP )
{
// Get URL
LPOLESTR urlToFile;
HRESULT result = pmk->GetDisplayName( pbc, NULL, &urlToFile );
//OLECHAR is simply a wchar_t and an LPOLESTR is a wide character string (e.g. wchar_t*).
wxString url(urlToFile);
wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_DOWNLOAD_BEGINS,GetId(), url, "");
event.SetEventObject(this);//WHICH OBJECT TO SET HERE????????
HandleWindowEvent(event);
::MessageBox(NULL,"Download","Download Manager",MB_OK);
return S_OK;
}
STDMETHODIMP wxServiceProvider::QueryService(REFGUID guidService,
REFIID riid,
void **ppv)
{
HRESULT hr = E_NOINTERFACE;
if (guidService == SID_SDownloadManager && riid == IID_IDownloadManager)
{
// Create new DownloadMgr object using ATL.
CComObject<wxDownloadMgr>* pDownloadMgr;
hr = CComObject<wxDownloadMgr>::CreateInstance(&pDownloadMgr);
// Query the new CDownloadMgr object for IDownloadManager interface.
hr = pDownloadMgr->QueryInterface(IID_IDownloadManager, ppv);
}
return hr;
}
You can override wxActiveXContainer::QueryClientSiteInterface to add your own interface implementation like IServiceProvider or IDocHostUIHandler to the client site. An example can be found in the wxIEContainer class.

#import lead to a HRESULT 0x80040154 "Not registered class"

I'm trying to use a COM DLL from VC++ 2005. I created a TestCOMlib.dll with ATL, created a simple interface ISimple and added one property (type LONG, name Property01) and one method (name Method01).
The DLL seems to be correctly registered in the system (I use OleView to check the entries).
I created a simple MFC dialog app to use the COM dll. I'm using the #import directive to incorporate information from the type library. Visual studio created for me the tlh and tli file.
Then I tried to obtain the ISimple interface but I'm obtaining the error 0x80040154.
The code I'm running inside the test application is the following:
HRESULT hr = S_OK;
hr = CoInitialize(NULL);
ISimplePtr myRef(__uuidof(ISimple));
// Test prop and method
myRef->Property01 = 5;
LONG test = myRef->Property01;
LONG ret = myRef->Method01(_T("Test input"));
ret = myRef->Method01(NULL);
myRef = NULL;
CoUninitialize();
The row returning the error 0x80040154 is ISimplePtr myRef(__uuidof(ISimple)).
OleView correctly display the interface and in the registry the entries seems to be good.
What am I doing wrong? Any idea?
Regards
The underlying class for these smart COM pointers is _com_ptr_t. You are trying to use this constructor:
// Constructs a smart pointer given the CLSID of a coclass. This
// function calls CoCreateInstance, by the member function
// CreateInstance, to create a new COM object and then queries for
// this smart pointer's interface type. If QueryInterface fails with
// an E_NOINTERFACE error, a NULL smart pointer is constructed.
explicit _com_ptr_t(
const CLSID& clsid,
IUnknown* pOuter = NULL,
DWORD dwClsContext = CLSCTX_ALL
);
Key point is that you have to pass the CLSID of the coclass, you are passing the IID of the interface. That's why __uuidof(Simple) works.

How to share COM objects between 2 processes?

I want Application1.exe to instantiate an instance of its Item class.
I want Application2.exe to call GetPrice() on this object.
I have followed steps 1-7 on the following website:
http://www.codeguru.com/Cpp/COM-Tech/activex/tutorials/article.php/c5567/
This is what I have so far.
Application1's main looks like this:
CoInitialize( NULL );
DWORD dwRegister;
ItemFactory *pFactory = new ItemFactory;
CoRegisterClassObject( CLSID_Item, pFactory, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegister );
_getch();
return 0;
Application2's main looks like this:
CoInitialize( NULL );
CoGetClassObject( CLSID_Item, CLSCTX_LOCAL_SERVER, NULL, IID_IItem, (LPVOID *)&pFactory );
My Issue (hopefully my only issue) is that I have no idea how to associate my Item class (or its interface, IItem) with CLSID_Item; this is just some random GUID I defined in another file. I've tried
CoRegisterPSClsid( IID_IItem, CLSID_Item );
After this line, I tried
Item *pItem;
CoCreateInstance( CLSID_Item, NULL, CLSCTX_LOCAL_SERVER, IID_IItem, (LPVOID *)&pItem );
I get an E_NOINTERFACE error.
Should I be creating a factory with CoCreateInstance? Ugh, so confused...
In order to use COM across process or thread boundraries, you must tell COM about your interfaces so it can marshal your function arguments/return values between processes. The easiest way to do this is to use an interface predefined in the system, such as IDispatch, but if you want to use your own, you must either register a proxy/stub DLL, or a type library. If you don't do this, then calls to QueryInterface for your custom interface across COM domains will fail with E_NOINTERFACE, as you are seeing.

How to prevent crashing if com dll isnt registered

From some old c++ code im trying to use a com dll, it works fine when the dll is registered, but it crahses if the dll isnt registered.
// Initialize COM.
HRESULT hr = CoInitialize(NULL);
IGetTestPtr ptest(__uuidof(tester));
"Use method from the dll"
// Uninitialize COM.
CoUninitialize();
Is it anyway to check if the dll has been registered, before calling IGetTestPtr ptest(__uuidof(tester))?
Or what is the correct way to prevent the crash?
Calling CreateInstance on your object will return an HRESULT that can be tested for success:
IGetTestPtr p = null;
HRESULT hRes = p.CreateInstance( __uuidof(tester) );
bool bSuccess = SUCCEEDED(hRes);
This assumes you've created an interface wrapper around your type library using Visual Studio, where COM Smart Pointers are used in the interface (this gives you the CreateInstance method).
If the DLL is registered, there is a record in HKCR/CLSID/{uuidof(tester)} (curly brackets do matter).
Actually, if it's not, then CoCreateInstance will return an error. Check for this error before using the pointer.
If the COM class is not registered then CoCreateInstance will return REGDB_E_CLASSNOTREG. You should check for general success or failure by using the SUCCEEDED() or FAILED() macros. You also need to create the object properly - see MDSN for an introduction to COM. For example:
HRESULT hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
IGetTestPtr ptr = NULL;
hr = CoCreateInstance(CLSID_MyObjectNULL, CLSCTX_INPROC_SERVER, IID_IMyInterface, ptr)
if (SUCCEEDED(hr))
{
Do something with your COM object
...
// Don't forget to release your interface pointer or the object will leak
ptr->Release();
}
hr = CoUninitialize();
}
return hr;
If I recall correctly this "#import" styled COM framework throws exceptions. Add a try-catch block around the code. Google tells me the exceptions are of type _com_error.
Unless you twiddle the params on #import to prevent this, all failing COM calls are going to throw exceptions. You're going to have to turn this off (#import "raw" interfaces I think does it - look at the #import docs) or get real familiar with these exceptions.