I have a COM project which does not support MFC and needs to communicate with another App through a MFC interface.
I cannot use directly in MFC interface with my COM project as it is not an MFC project.
A solution was to create an automation interface for the Of the MFC interface which I would be able to use as a layer through which my COM project can communicate to the MFC project.
As I understood, the automation app will run in a different thread. My COM project will invoke methods from the automation interface to call the MFC interface.
The Automation project and its IDL file were provided to me and provides me with a Pure Dispinterface.
Before integrating the implementation of the IDispatch interface to my COM project I decided to create a new C++ console project in order to focus on simply using the automation interface.
Using the documentation provided by microsoft (https://learn.microsoft.com/en-us/previous-versions/windows/desktop/automat/implementing-the-idispatch-interface) I implemented the IDispatch interface as follows:
#include "TTAutomate.h"
HRESULT hresult;
DISPID dispid;
DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
EXCEPINFO excepinfo;
UINT nArgErr;
ClassFromIDL* m_ClassFromIDL;
_DTTAutomateEvents* m_DTTAutomateEvents;
_DTTAutomate* m_DTTAutomate;
hresult = OleInitialize(NULL);
// OLE function CoCreateInstance starts application using GUID.
hresult = CoCreateInstance(CLSID_TTfromIDL, NULL, CLSCTX_INPROC_SERVER, DIID__DTTAutomateEvents, (LPVOID*)m_Automate);
// Call QueryInterface to see if object supports IDispatch.
hresult = m_ClassFromIDL->QueryInterface(DIID__DTTfromIDL, (LPVOID*)pdisp);
// Retrieve the dispatch identifier for the SayHello method.
// Use defaults where possible.
OLECHAR* szMember = "SayHello";
DISPID dispid_Item;
hresult = pdisp->GetIDsOfNames(
IID_NULL,
&szFunction,
1,
LOCALE_USER_DEFAULT,
&dispid_Item);
First of all the implementation is a bit different as the one in the documentation because with the line :
hresult = CoCreateInstance(CLSID_Hello, NULL, CLSCTX_SERVER, IID_IUnknown, (void **)&punk);
I would get an error "amp undefined".
With the code above I currently get an error stating a const char * cannot initialize a OLECHAR *.
On my COM project I have a line:
LPOLESTR szFunction = OLESTR("SayHello");
which compiles but the same line on my test project does not work.
Did I miss some includes to add?
Did I not create the right kind of test project?
So I found a way to fix my code so that it compiles but not exactly sure if it is a proper solution:
#include "TTAutomate.h"
#include <string>
HRESULT hresult;
DISPID dispid;
DISPPARAMS dispparamsNoArgs = { NULL, NULL, 0, 0 };
EXCEPINFO excepinfo;
UINT nArgErr;
ClassFromIDL* m_ClassFromIDL;
IDispatch* m_Automate; // fixed
hresult = OleInitialize(NULL);
// OLE function CoCreateInstance starts application using GUID.
hresult = CoCreateInstance(CLSID_TTfromIDL, NULL, CLSCTX_INPROC_SERVER, DIID__DTTAutomateEvents, (void**)&m_Automate); // fixed
// Call QueryInterface to see if object supports IDispatch.
hresult = m_ClassFromIDL->QueryInterface(DIID__DTTfromIDL, (void**)&pdisp); // fixed
// Retrieve the dispatch identifier for the SayHello method.
// Use defaults where possible.
// here I create a wchar_t* variable as LPOESTR is casted from that.
std::string functionName = "SayHello";
int wchars_num = MultiByteToWideChar(CP_UTF8, 0, functionName.c_str(), -1, NULL, 0);
wchar_t* wstr = new wchar_t[wchars_num];
LPOLESTR szMember = wstr;
DISPID dispid_Item;
hresult = pdisp->GetIDsOfNames(
IID_NULL,
&szFunction,
1,
LOCALE_USER_DEFAULT,
&dispid_Item);
I now get a E_NOINTERFACE No such interface supported but it is probably unrelated to this topic.
Related
I have a question about virtual table.
The virtual table as i know is the function address arrays which can find
the function address when the polymorphism object call virtual function.
But In directx, some people mentioned about dx vtable that the table of d3d9.dll
's import function address arrays.
Why they call the import function address arrays to directx vtable?
It seems to not relevant with a vtable.
Did My knowledge was incorrect? May i know about vtable in detail?
Thanks!
When exporting COM objects from a DLL, there are usually two parts at work. First is the 'factory'. The factory can be a standard C-callable function exported from the DLL (which is the case with Direct3D), or a class registered with the system registry in which case you'd use CoCreateInstance to create the COM interface instance. An example of the first is creating a Direct3D device:
ID3D11Device* d3dDevice = nullptr;
hr = D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
0,
0,
nullptr,
0,
D3D11_SDK_VERSION,
&d3dDevice,
nullptr,
nullptr);
After this call, the d3dDevice interface points to an allocated COM interface object. The DLL that contains D3D11CreateDevice has to be implicitly linked to the calling program--or you can use LoadLibrary to do explicitly linking in which case you'd use a pointer to the function D3D11CreateDevice which amounts to much the same thing . This is derived from the 'import table' for the DLL.
An example of the second is what you do when using Windows Imaging Component (WIC):
IWICImagingFactory* factory = nullptr;
hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
__uuidof(IWICImagingFactory),
&factory);
This has the COM system look up the class GUID in the registry, load up the referenced DLL, and then invoke the factory methods in there to create a COM interface object which it returns to you.
In both cases, the actual thing pointed to by the interface is of the form:
typedef struct IUnknownVtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
IUnknown * This,
/* [in] */ REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(
IUnknown * This);
ULONG ( STDMETHODCALLTYPE *Release )(
IUnknown * This);
END_INTERFACE
} IUnknownVtbl;
which is contrived to exactly map to the Visual C++ implementation of virtual:
MIDL_INTERFACE("00000000-0000-0000-C000-000000000046")
IUnknown
{
public:
BEGIN_INTERFACE
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject) = 0;
virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
END_INTERFACE
};
COM doesn't really have a notion of inheritance, but again it's a convenience for ID3D11Device1 to use C++ public inheritance from ID3D1Device which only works because the language type has no data members declared. COM "inheritance" of interfaces is really just concatenation of the methods which you can see if you look at the C definitions in the headers:
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("cc86fabe-da55-401d-85e7-e3c9de2877e9")
ID3D11BlendState1 : public ID3D11BlendState
{
public:
virtual void STDMETHODCALLTYPE GetDesc1(
/* [annotation] */
_Out_ D3D11_BLEND_DESC1 *pDesc) = 0;
};
#else /* C style interface */
typedef struct ID3D11BlendState1Vtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )( /* ... */ );
ULONG ( STDMETHODCALLTYPE *AddRef )( ID3D11BlendState1 * This);
ULONG ( STDMETHODCALLTYPE *Release )( ID3D11BlendState1 * This);
void ( STDMETHODCALLTYPE *GetDevice )( /* ... */ );
HRESULT ( STDMETHODCALLTYPE *GetPrivateData )( /* ... */ );
HRESULT ( STDMETHODCALLTYPE *SetPrivateData )( /* ... */ );
HRESULT ( STDMETHODCALLTYPE *SetPrivateDataInterface )( /* ... */ );
void ( STDMETHODCALLTYPE *GetDesc )(
ID3D11BlendState1 * This,
/* [annotation] */
_Out_ D3D11_BLEND_DESC *pDesc);
void ( STDMETHODCALLTYPE *GetDesc1 )(
ID3D11BlendState1 * This,
/* [annotation] */
_Out_ D3D11_BLEND_DESC1 *pDesc);
END_INTERFACE
} ID3D11BlendState1Vtbl;
#endif
It's important to note this only works for the case of pure virtual (i.e. abstract) C++ classes with no data members and only virtual methods using public inheritance (i.e. interfaces). Constructors and destructors are ignored as COM life-time is managed through reference-counting via IUnknown.
The calling signatures of methods also take a pointer to the COM object as the first parameter which maps to the C++ calling convention for this.
COM interfaces are therefore designed to work like C++ virtual methods so you can use C++ syntax to call them, but they aren't necessarily C++ class objects at all.
From IUnknown there is a known standard way in COM to get a specific interface, which is QueryInterface. The Direct3D factory functions take care of this for you as well, and just return the base interface. In the case of Direct3D 11, that's a ID3D11Device.
If you want to get an interface to say 11.1, you then use QueryInterface on the ID3D11Device asking for a ID3D11Device1. It would fail on a DirectX 11.0 system, but works on a DirectX 11.1 or later system.
For a C++ programmer using Direct3D, the design purposely keeps the "COM" to a minimum (colloquially known as "COM lite"). Really just enough COM is used to make it easier to deal with interface changes over time and to provide a reasonable ABI. The Direct3D factory functions are simple C-callable exports from a known DLL, so you don't even have to muck about with the standard COM factories and in fact the API isn't designed to work if you try to use CoCreateInstance. You can technically use C via some macros that the standard MIDL compiler generates along with the C++ definitions, but it's a bit challenging to do and isn't particularly well tested these days.
Really all you need to know as a consumer of Direct3D COM is the basics of IUnknown reference counting and querying--which today is best done by using the Microsoft::WRL::ComPtr smart-pointer--and how to properly check HRESULT values--see ThrowIfFailed.
See The Component Object Model and Reference Counting (Direct3D 10)
I need to search for maximized windows from Win32 (by using EnumWindows) but I also want to filter for windows which are on the current virtual desktop. On MSDN, I found a page about the IVirtualDesktopManager interface but there seems to be no information on how to use this interface.
IVirtualDesktopManager::IsWindowOnCurrentVirtualDesktop(/*args...*/);
Throws the following error:
Non static member reference must be relative to a specific object
VirtualDesktopManager mVirtualDeskManager;
mVirtualDesktopManager.IsWindowOnCurrentVirtualDesktop(/args...*/)
Throws this error:
Incomplete type is not allowed
I have only found solutions on using the IVirtualDesktopManager interface in C# yet.
IVirtualDesktopManager is a COM interface. You need to instantiate the COM object that implements the interface.
Based on code from this blog, you can use IServiceProvider to access IVirtualDesktopManager (and IVirtualDesktopManagerInternal, which has much more functionality than IVirtualDesktopManager has), eg:
IServiceProvider* pServiceProvider = NULL;
HRESULT hr = ::CoCreateInstance(
CLSID_ImmersiveShell, NULL, CLSCTX_LOCAL_SERVER,
__uuidof(IServiceProvider), (PVOID*)&pServiceProvider);
if (SUCCEEDED(hr))
{
IVirtualDesktopManager *pDesktopManager = NULL;
hr = pServiceProvider->QueryService(__uuidof(IVirtualDesktopManager), &pDesktopManager);
if (SUCCEEDED(hr))
{
BOOL bIsOnCurrentDesktop = FALSE;
hr = pDesktopManager->IsWindowOnCurrentVirtualDesktop(hWnd, &bIsOnCurrentDesktop);
if (SUCCEEDED(hr))
{
// use bIsOnCurrentDesktop as needed...
}
pDesktopManager->Release();
}
pServiceProvider->Release();
}
Use case: Someone asked me to automate his internet explorer. Every day, he has to navigate to the same URL, enter the same credentials und log in. He'd like the computer to do that automatically: With an application that navigates to the URL, enters the post data and logs in automatically. He then can continue to navigate manually through the page.
So, if I want to control directly an existing internet explorer instance, how would I do that with C++?
After hours of research, I managed to open a new instance of the IE and navigating to a specific URL.
The steps I undertook:
Link the following libraries in the project options: libole32.a, liboleaut32.a, liboleacc.a, libuuid.a
Include cassert and exdisp.h at the beginning of the main cpp-file.
Insert the following code in the main cpp-file:
int main(void) {
HRESULT hret;
hret=CoInitialize(NULL);
assert(SUCCEEDED(hret));
CLSID clsid; // Get IE CLSID
hret=CLSIDFromProgID(L"InternetExplorer.Application",&clsid);
assert(SUCCEEDED(hret));
IUnknown *p; // Get IUnknown Interface
hret=CoCreateInstance(clsid,NULL,CLSCTX_ALL,IID_IUnknown,reinterpret_cast<void**>(&p));
assert(SUCCEEDED(hret));
IDispatch *q; // Get IDispatch Interface from IUnknown
hret=p->QueryInterface(IID_IDispatch,reinterpret_cast<void**>(&q));
assert(SUCCEEDED(hret));
IWebBrowser2 *r; // Get IWebBrowser2 Interface from IDispatch
hret=q->QueryInterface(IID_IWebBrowser2,reinterpret_cast<void**>(&r));
assert(SUCCEEDED(hret));
IUnknown *s; // Get IUnknown from IWebBrowser2
hret=r->QueryInterface(IID_IUnknown,reinterpret_cast<void**>(&s));
assert(SUCCEEDED(hret));
///// Transitive //////////////////////////
assert(p==s);
////////////////////////////////////////
VARIANT vEmpty;
VariantInit(&vEmpty);
VARIANT vFlags;
V_VT(&vFlags) = VT_I4;
V_I4(&vFlags) = navOpenInNewWindow;
BSTR bstrURL = SysAllocString(L"http://www.google.com");
r->Navigate(bstrURL, &vFlags, &vEmpty, &vEmpty, &vEmpty);
r->Quit();
SysFreeString(bstrURL);
p->Release(); q->Release(); r->Release(); s->Release();
CoUninitialize(); return 0;
}
I have C++/ATL-based COM object with method that accepts interface to allow callbacks:
MIDL
[object, uuid(...), dual, nonextensible, oleautomation, pointer_default(unique)]
interface IAsyncEvents : IDispatch{
[id(1)]
HRESULT OnProgress([in]BSTR message);
};
[object, uuid(...), dual, nonextensible, pointer_default(unique)]
interface IAsyncWorker : IDispatch{
HRESULT CallMe(BSTR message, IAsyncEvents* events);
};
COM Object implements IAsyncWorker interface. The only method "CallMe" expects that client should pass "events" interface to allow callbacks from worker thread. "CallMe" implementation looks like the following:
STDMETHOD(CallMe)(BSTR message, IAsyncEvents* events)
{
IStream *pStm = NULL;
HRESULT hRes = CoMarshalInterThreadInterfaceInStream(IID_IAsyncEvents, events, &pStm);
if (hRes != S_OK)
{
ATL::CAtlString str;
str.Format(_T("Failed CoMarshallInterThread... %i"), hRes);
MessageBox(0, str, NULL, MB_TOPMOST);
return E_FAIL;
}
m_hThread = ::CreateThread(NULL, 0, WorkerFunc, (LPVOID)pStm, 0, &m_dwThreadId);
return ::GetLastError();
}
And I try to call "CallMe" from Visual Basic like that:
MyCallBack Class
Option Explicit
Implements AsyncDllLib.IAsyncEvents
Public Sub IAsyncEvents_OnProgress(ByVal message As String)
MsgBox (message)
End Sub
VB6 com-object call code
Dim obj As Object
Set obj = CreateObject("C++ Com Object ProgID")
Dim callback As New MyCallbackClass
obj.CallMe "123", callback
Everything looks ok but suddenly MyCallback class instances fail to be marshalled into stream. Meanwhile I can use "events" interface pointer from C++ implementation from the same thread.
CoMarshalInterThreadInterfaceInStream fails with undocumented error: 0x800A0062
What I do wrong here?
Thank you in advance!
You cannot marshal private classes, standard marshaling needs a typelib to transport arguments cross-thread.
You can implement MyCallbackClass as a public (multi-use or public-not-creatable) class on an ActiveX DLL project in VB6 for marshaling to work or better implement a callback-proxy in your ATL component.
Your CallMe will create the proxy on the calling thread passing original VB6 interface then marshal IAsyncEvents interface of proxy object to worker-thread.
I've written a simple COM DLL inproc server with a single simple COM object. The COM object implements a connection point.
I know how to create an ATL client that derives from IDispEventImpl, and uses a sink map to simplify this process.
But, for the purposes of demonstration, I'd like to create a win32 console application that uses a class that calls my simple COM object, then acts as a connection point sink.
I've got no idea how to provide an implementation of IDispatch - can someone recommend documentation on this, as I can't find any (I've got ATL Internals, but this doesn't seem to cover what I need ).
Here's the class I've already got:
#pragma once
#include <iostream>
using namespace std;
// Because we're implementing a connection points sink (_IPogFarmEvents)
// in a non-ATL class, we must provide implementations for IUnknown and IDispatch.
class KidWithAPogFarm : public _IPogFarmEvents
{
private:
DWORD m_dwRefCount;
LONG m_lNumPogs;
public:
KidWithAPogFarm() :
m_dwRefCount (0),
m_lNumPogs (0)
{
}
~KidWithAPogFarm()
{
}
// -- IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject)
{
if (iid == DIID__IPogFarmEvents)
{
m_dwRefCount++;
*ppvObject = (void *)this;
return S_OK;
}
if (iid == IID_IUnknown)
{
m_dwRefCount++;
*ppvObject = (void *)this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef()
{
m_dwRefCount++;
return m_dwRefCount;
}
ULONG STDMETHODCALLTYPE Release()
{
ULONG l;
l = m_dwRefCount--;
if ( 0 == m_dwRefCount)
delete this;
return l;
}
// -- IDispatch
STDMETHODIMP GetTypeInfoCount(UINT *pctinfo)
{
return E_NOTIMPL;
}
STDMETHODIMP GetTypeInfo( UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo )
{
return E_NOTIMPL;
}
STDMETHODIMP GetIDsOfNames(const IID &riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId )
{
return E_NOTIMPL;
}
STDMETHODIMP Invoke(DISPID dispIdMember, const IID &riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr )
{
return E_NOT_IMPL;
}
// -- IAntFarmEvents
STDMETHODIMP OnFarmCreated(LONG lInitialPopulation)
{
m_lNumPogs = lInitialPopulation;
cout << "The kid has a pog farm with " << m_lNumPogs << " pogs " << endl;
return S_OK;
}
};
Since you already have ATL you can examine its sources and see how IDispatchImpl does all that stuff. IDispatch methods are implemented therehby reading data from the type library in the same module since it's the easiest and most reliable way when a type library is already present.
It's also worth noting that it's a rather hard topic for making a demonstration on it - you'll need to write a lot of code that doesn't really bring any insight. IMO you'll be much better off if you implement an events interface that doesn't inherit from IDispatch but rather inherits directly from IUnknown - this will demonstrate how events work without dragging too much of attention to IDispatch inner workings.
I think the easiest way of doing this is through CreateStdDispatch
You can use this IDispatch implementation.
It's not exactly what you're looking for, but FireBreath uses IDispatchEx and connection points to provide an ActiveX control that runs in IE. Because FireBreath is an abstraction to allow plugins to be written once and used in all major browsers, the IDispatch interface needed to be written by hand -- including connection points.
The code may be a little confusing, since there is a templated mixin class used to provide IDispatch and ConnectionPoints to two different COM object classes, but it may help.
Mixin class
ActiveX Control
Second COM control (not OLE)
You've already accepted an answer, but perhaps it will still help. Sorry I didn't see the question sooner.