That presumably applies to C too. In that case why all the fuss in this
thread? Or maybe:
(from an expert in writing C compilers specific to Windows) using COM isn't
as simple as you seem to be implying.
He was talking about reimplementing his compiler so that it ran as a metro app (which is pretty crazy to even think about, and as he's been told, he doesn't need to do that; the desktop still exists in Windows 8). He wasn't talking about using COM in general.
But, seeing as you're the expert, perhaps you can give an example in writing
a simple task in C to run under Windows, without using 'stone-age' DLLs and
without a console. Such as Hello, World (just an alert box will do). You
might need to explain exactly how the executable that the C is compiled to,
actually talks to Windows.
When I said "stone age" I was referring to DLL-exported functions, not about DLLs themselves. COM components are DLLs anyway (or EXEs sometimes).
Anyway, the easiest way to create a COM component in C++ is with ATL. Thereisn't an equivalent for C, but you can do it without ATL (be it C or C++),although you have to do manually a lot of the things VS does for you.
First thing is to create an interface in an IDL (Interface Definition Language) file for the functionality you need:
[uuid(CBC6B4ED-107C-43b3-BA0A-054E6430F435), object]
interface IHelloCom : IUnknown
{
HRESULT SayHello();
}
Then you compile the IDL file with the MIDL compiler, which creates the equivalent interfaces in C or C++. For C++ it gives:
MIDL_INTERFACE("CBC6B4ED-107C-43b3-BA0A-054E6430F435")
IHelloCom : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE SayHello( void) = 0;
};
For C it gives:
typedef struct IHelloComVtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
IHelloCom * This,
/* [in] */ REFIID riid,
/* [annotation][iid_is][out] */
__RPC__deref_out void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(
IHelloCom * This);
ULONG ( STDMETHODCALLTYPE *Release )(
IHelloCom * This);
HRESULT ( STDMETHODCALLTYPE *SayHello )(
IHelloCom * This);
END_INTERFACE
} IHelloComVtbl;
interface IHelloCom
{
CONST_VTBL struct IHelloComVtbl *lpVtbl;
};
Then you need to implement the interface:
class __declspec(uuid("7A5F33E4-F4B8-4932-9207-1EF2B642C910")) HelloCom : public IHelloCom
{
public:
// IUnknown methods:
HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject) { ... }
ULONG __stdcall AddRef() { ... }
ULONG __stdcall Release() { ... }
// IHelloCom methods:
HRESULT __stdcall SayHello()
{
MessageBox(nullptr, L"Hello COM!", L"Hello COM", 0);
return S_OK;
}
};
I don't really know how to do that one in C.
You also need to implement IClassFactory so that COM can instantiate our HelloCom class:
class HelloComFactory : public IClassFactory
{
public:
// ...
// same IUnknown methods
// ...
// IClassFactory methods:
HRESULT __stdcall CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppvObject)
{
if (pUnkOuter != nullptr)
return CLASS_E_NOAGGREGATION;
HelloCom* pObject = new HelloCom();
pObject->AddRef();
HRESULT hr = pObject->QueryInterface(riid, ppvObject);
pObject->Release();
return hr;
}
HRESULT __stdcall LockServer(BOOL fLock) { ... }
};
And finally you need to write a function that will be called by COM in order to obtain the class factory:
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppvObject)
{
IUnknown* pClassFactory;
if (rclsid == __uuidof(HelloCom))
pClassFactory = new HelloComFactory();
else
{
*ppvObject = nullptr;
return CLASS_E_CLASSNOTAVAILABLE;
}
pClassFactory->AddRef();
HRESULT hr = pClassFactory->QueryInterface(riid, ppvObject);
pClassFactory->Release();
return hr;
}
That's it for the server (the COM DLL containing the COM classes and interfaces). You need to build it and register the class and the interface in theWindows registry (that's something VS will do automatically for ATL projects).
And this could be the client:
int main()
{
CoInitialize(nullptr);
IHelloCom* pHelloCom;
HRESULT hr = CoCreateInstance(
__uuidof(HelloCom),
nullptr,
CLSCTX_INPROC_SERVER,
__uuidof(IHelloCom),
reinterpret_cast<void**>(&pHelloCom)
);
if (FAILED(hr))
return -1;
pHelloCom->SayHello(); // or IHelloCom_SayHello(pHelloCom) in C
pHelloCom->Release(); // IHelloCom_Release(pHelloCom)
CoUninitialize();
}
It looks way involved but it does have advantages for any real app, and like I said it's easier with ATL.
Besides, COM was succeeded by .NET. That's what puts me (and lots of other people, even inside Microsoft) off about Windows 8: they have downgraded ontechnologies. They went from .NET back to C++ and COM and (worse still) HTML and JavaScript.
(BTW my Windows 7 still seems to have some 19,000 DLL files; somebody's got
their work cut out if they're all going to be replaced by Windows 8.)
The destkop and everything there is in Windows 7 is still there...