C++ DispInvoke fails to find member - c++

The scenario is this:
I have a COM object to ask questions. Name it ICom.
The COM object requires me to implement an IDispatch , descendant of , say, IComEvents, that notifies me for events.
I implement an IDispatch and connect it to the COM interface.
So far so good. My IComEvents descentant's Invoke() is called when the events occur.
The point is now that I must manually parse Invoke() parameters. For example, if a notification function is HRESULT OnMouseHit(int x), I have to detect this function from the DispID, then call it manually, for example
if (dispIdMember == 0xfa)
{
OnMouseHit(pDispParams->rgvarg[0].pIntVal);
}
I would have to do it for all the functions I want to implement. However I saw the DispInvoke() function which presumably will automatically do this for me and call the appropriate overloaded method for the dispId, with the correct parameters:
DispInvoke(this,m_ptinfo,dispIdMember,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
How do I generate m_ptinfo? By calling LoadRegTypeLib with the libid of the COM object, and then ITypeLib::GetTypeInfoOfGuid() with the IID of IComEvents. However, DispInvoke() always returns "member not found".
What would be wrong? I expect DispInvoke to parse the type information, find the member function name from the DispID and then use the "this" pointer to get the function address from the vtbl.
What am I doing wrong?
Thanks a lot.
Michael.

Is IComEvents a dual interface or a dispinterface? If it is a pure dispinterface it doesn't have a vtable. DispInvoke requires the interface to have a vtable (ie that it is a dual interface).

Related

COM: Getting GUID of coclass object using pointer to interface it implements

Having pointer to COM interface that are implemented by some concrete component class object is it possible to get a GUID of the underlying object that implements this interface (CLSID)?
Update 1
More generally, I have a function like SetFont(ICanvasFont* font) and I need a way to determine if the underlying object that implements the ICanvasFont interface is of a certain class (say MCanvasFont).
IUnknown::QueryInterface on this interface pointer to obtain one of the following: IPersist, IPersistStream, IPersistStreamInit or other IPersist* interfaces. If you are lucky to get one, then GetClassID method will get you the CLSID class identifier (alternate option is IProvideClassInfo and IProvideClassInfo::GetClassInfo).
Note that this kind of information does not have to exist. An interface pointer can be valid without having CLSID on the class implementing it.
UPD. If the main goal is to recognize your own implementation on the provided interface ("Is the provided ICanvasFont the instance of my own MCanvasFont class, or it is something different?"), then the easiest yet efficient way is to implement some extra private interface on the class. If your querying it succeeds, then you recognize the instance. Provided no marshaling takes place, you can possibly even static_cast back to original C++ pointer.

Having issues with C++ Function pointers in COM

There is one thing that bothers me, C++ function pointers. I'm asking this question because I'm trying to implement callback functions used in my game engine. The issue is, for example:
// Callback function
HRESULT RenderScene(float fps){ HRESULT hr; return S_OK; }
// Set the message
msk->SetMessage(0, SM_RENDERSCENE, (void*) RenderScene);
The problem is COM doesn't allow function pointers in their member functions. Also, doesn't allow for polymorphism. As you can see, I made it a void*. Fine with me because I know what the callback function is. The main issue is that I want something that is type-safe.
Now say if the user doesn't know the callback function declaration. For example,
// Callback function
HRESULT CALLBACK RenderScene() or RenderScene(int fps) or RenderScene(int a, int b)
Is implemented in WndProc as:
...
SM_RENDERSCENE:
((void (_stdcall*)(float fps)) pfn)(1.0f);
break;
...
The first, doesn't have an argument, therefore, he doesn't see fps. The second, loses precision. The third, loses precision and has an unused argument. Do you see where I'm going at? Tried using a union but COM doesn't allow function pointers in the member function.
I tried, and tried again. Nothing works, even the MFC message maps are ugly if they didnt have those macros.
To clarify, I rather have it return an error like E_FAIL or E_INVALIDFUNCTION if the function doesn't match the specification of SM_RENDERSCENE.
Does anyone have a solution to this problem.
Note: I like the COM specification and I'm not going to change, so focus on the issue not about why I'm using COM. Thank you, any help will do.
HRESULT RenderScene(float fps){ ...}
HRESULT CALLBACK RenderScene() or ...
Is implemented ... ((void (_stdcall*)(float fps)) pfn)(1.0f);
No, COM definitely supports function pointers. It is only when you use the subset of COM Automation or need to marshal function calls that you could get in trouble. Which is not the case here, you don't marshal between processes or threads and don't need automation since you work with only one language.
The simple problem is that you have the issue that you are trying to protect against, the function pointer definition doesn't match the implementation. Yes, a (void*) cast will stop the compiler from complaining about it, nothing good happens at runtime.
Your first declaration has the wrong calling convention. Using the STDMETHODIMP macro is wise.
Your second set of declarations have the wrong arguments.
The third snippet is applying an invalid function pointer cast, a cast to a function that returns void instead of HRESULT. And assumes __stdcall even though your RenderScene() function didn't use STDMETHODIMP or CALLBACK. Which is why you don't see a proper value for the argument.
Solve function pointer problems by declaring an alias for the pointer type:
typedef HRESULT (__stdcall * RenderSceneCallback)(float fps);
And consistenly use RenderSceneCallback in all your declarations. Never cast.
COM is a technology that is supposed to support multiple programming languages, and not all programming languages have support for all kind of features, hence some features like function pointers and exceptions are not (in general) supported in COM.
In the case of callbacks, usually the way to go is to define a COM interface that includes the method you need to call. You can implement this function in a COM class of your choice, and you can specify this interface as a parameter to any other COM function.
If you are using ATL for your COM implementation, here is a link on how to add an new interface to an ATL project. And you could also take a look on this article at codeproject about COM Event Handling
Pass interface pointers instead of function pointers. Also there is no function overloading in COM, so use different function names. Here is a pseudocode:
struct IRenderScene : public IUnknown
{
HRESULT RenderScene(); // Callback function
HRESULT RenderSceneFps(float fps); // Callback function
HRESULT RenderSceneAB(int a, int b); // Callback function
}
IRenderScene *renderScene = ...;
msk->SetRenderScene(renderScene); // Set the callback
You don't need to implement COM Event Handling (Connection Points) if it is superfluous to you.

How can you get a prototype member function (C++ -> Javascript)

Does anyone know how you can call a method of a prototype in Javascript from C++?
I have an pointer to script IDispatch, and I can get the IDsOfNames for the prototype, but I can't find how to get the IDispatch of it's member function.
Say (pseudocode):
JSprototype foo
{
method bar(baz);
}
I can get a valid DISPID of foo, but I don't know how to call bar(baz). Does anyone have an idea?
That's what IDispatch::Invoke is for. You don't need a separate IDispatch for every function. However, you do need a DISPID of bar, and therefore an IDispatch of foo. That means you'll have to call iFoo->Invoke(DISPID_bar) and QueryInterface(IDispatch) the result.

Call to VB's CreateObject method in C++

I'm trying to call Visual Basic's CreateObject method from my C++ code. In VB, I'd simply type:
Dim obj As Object
obj = CreateObject("WScript.Network")
And that returns me the object from which I can call more methods. But how can I do that in C++? I'm following the MSDN documentation in http://msdn.microsoft.com/en-us/library/bb776046(v=VS.85).aspx, but those parameters are very obscure and I can't figure them out.
The first parameter is a reference to a CLSID, and I can see from the registry that the CLSID for "WScript.Network" is {093FF999-1EA0-4079-9525-9614C3504B74}. But what's the difference between this parameter and the third one, REFIID?
Thanks in advance!
I'll provide my solution, just for the record. It calls the AddWindowsPrinterConnection to install a network printer. It asks for user confirmation, so if you want to bypass that, you need to set HKEY_CURRENT_USER/Printers/LegacyPointAndPrint/DisableLegacyPointAndPrintAdminSecurityWarning to 1 (you can change it back to 0, after everything is done).
CoInitialize(NULL);
{
ATL::CComPtr<IDispatch> test;
_variant_t printerConnection = "\\\\serverAddress\\printerName";
_variant_t result;
test.CoCreateInstance(L"WScript.Network");
test.Invoke1(L"AddWindowsPrinterConnection", &printerConnection, &result);
}
CoUninitialize();
First, you probably want to use CoCreateInstance http://msdn.microsoft.com/en-us/library/ms686615%28VS.85%29.aspx, or the equivalent call inside a smart pointer wrapper (eg: CComPtr<>, _com_ptr<>, etc.).
Second, to your specific question, the IID is the interface ID, the CLSID is the class ID. COM objects can have multiple interfaces on the same object in general, which is why there is a distinction (although VB can only see one, which is why you don't need so to specify anything other than the CLSID for VB).
The "correct" way to duplicate what VB is doing is to create the IDispatch interface on the object, and then enumerate the methods using IDispatch. The "better" way in C++ is to create the direct interface you want to use, and call methods directly through it. However, this requires knowing the interface ID (IID, or REFIID passing the struct by reference), which is specific to the other object.
Hope that helps. I can't provide specifics for your particular interface, but maybe this points you in the right direction.

C++ ATL Member Variable access help

I am not familiar with this, and can use a kick start.
I am using ATL (unmanaged C++) user control and would like to use the ShockWave ActiveX object. I need to know how to declare it so that I can set a property or call a method.
For instance, if I could assign a variable to it, then I would like to call 'variable->LoadMovie()'
I know this is super ridiculous... almost embarrassed to ask it here. ;) (almost)
If you #import the dll (which I recommend when working with COM because it makes your life SO much easier), you can use a smart pointer paired with the CLSID of the object. Remember that smart pointer classes have the post-fix 'Ptr' after the interface name.
For instance:
ISomeInterfacePtr pSomeInterface( CLSID_SomeComponent );
HRESULT hr = pSomeInterface->SomeMethod();
Hope that helps.
EDIT: If you want to check the HRESULT of the allocation, you can do the following:
ISomeInterfacePtr pSomeInterface = 0;
HRESULT hr = pSomeInterface.CreateInstance( CLSID_SomeComponent );
I cut&paste the necessary code so many times I can't remember the exact syntax but you have to:
get a CComPtr<> of the correct interface,
CreateInstance the object
QueryInterface to get the interface you want (assuming you're not using the CComPtr)
then call methods on it.
Alternatively you can #import the dll, then the compiler will generate a c++ class with all the methods and properties for you.