Pelles C forum

C language => Tips & tricks => Topic started by: CommonTater on June 03, 2012, 08:26:50 PM

Title: COM objects in plain C...
Post by: CommonTater on June 03, 2012, 08:26:50 PM
Well known musician, hardware designer and C programmer Jeff Glatt has authored an 8 part series on using COM objects in plain C... I found it to be very helpful.  It's clearly written and loaded with examples.  If you haven't seen it yet, you can access the whole series from his page at The Code Project...
 
http://www.codeproject.com/script/Articles/MemberArticles.aspx?amid=88625 (http://www.codeproject.com/script/Articles/MemberArticles.aspx?amid=88625)
 
Thanks Jeff.
 
 
Title: Re: COM objects in plain C...
Post by: Vortex on June 03, 2012, 11:10:46 PM
COM is very powerful but it can be very complicated too. Thanks for the tutorials.
Title: Re: COM objects in plain C...
Post by: CommonTater on June 04, 2012, 12:22:41 AM
COM is very powerful but it can be very complicated too. Thanks for the tutorials.

Well, since it seems my time has come to learn this I've been doing some searching for information... Thought I'd pass this one along.  I know Jeff from back in my "pro-sound" days so I trust it's mostly accurate.  If I find more, I'll pass them along as well...

Title: Re: COM objects in plain C...
Post by: czerny on March 27, 2013, 12:17:52 PM
Hallo,

I have read the first two parts of 'COM in plain C' and build corresponding Pelles C projects. If anyone has problems with this, I can post them.
Title: Re: COM objects in plain C...
Post by: EdPellesC99 on March 27, 2013, 03:56:31 PM
Thanks Tater, for the lead for future interests for me !
Title: Re: COM objects in plain C...
Post by: TimoVJL on November 24, 2017, 02:26:45 PM
Time pasts, but those tutorials are still valuable :)

A tiny example for testing IExample2 without COM registration.
Easier to develop similar one.
Title: Re: COM objects in plain C...
Post by: jj2007 on November 26, 2017, 01:49:45 AM
Hi Timo,
Can you explain in a few words what the program does? Just curious...
Title: Re: COM objects in plain C...
Post by: TimoVJL on November 26, 2017, 11:46:54 AM
That example loads IExample2.dll
 ask IClassFactory pointer using exported function DllGetClassObject()
 create object /CreateInstance IExample2 to the pointer pExample2
 release IClassFactory
 call methods/functions SetString() and GetString()
 finally release IExample2

In this way it's easier to develop functions and debug those.
Code: [Select]
int __cdecl main(void)
{
IClassFactory *pClassFactory;
HMODULE hModule = LoadLibrary(TEXT("iexample2\\IExample2.dll"));
if (!hModule) return 1;
HRESULT (WINAPI*DllGetClassObject)(REFCLSID,REFIID,LPVOID) =
(HRESULT(WINAPI*)(REFCLSID,REFIID,LPVOID))GetProcAddress(hModule, TEXT("DllGetClassObject"));
if (!DllGetClassObject) return 2;
HRESULT hr = DllGetClassObject(&CLSID_IExample2, &IID_IClassFactory, (void**)&pClassFactory);
printf("hr=%X\n", hr);
if (!hr) {
IExample2 *pExample2;
hr = pClassFactory->lpVtbl->CreateInstance(pClassFactory, NULL, &IID_IExample2, (void **)&pExample2);
pClassFactory->lpVtbl->Release(pClassFactory);
printf("hr=%X\n", hr);
BSTR bstr1 = SysAllocString(L"test");
pExample2->lpVtbl->SetString(pExample2, bstr1);
BSTR bstr2;
pExample2->lpVtbl->GetString(pExample2, &bstr2);
printf("%ls\n", bstr2);
SysFreeString(bstr2);
pExample2->lpVtbl->Release(pExample2);
}
return 0;
}

Hopefully we see something more in this thread.
Experts could fix code and tell us what other things have to care.

EDIT:
After dll debug next example:
Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <ole2.h>
#pragma comment(lib, "ole32")
#pragma comment(lib, "oleaut32")
#include "IExample2.h"
void ErrorString(HRESULT errno);
int __cdecl main(void)
{
IExample2 *pExample2 = NULL;
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(&CLSID_IExample2, NULL, CLSCTX_ALL, &IID_IExample2, (void**)&pExample2);
printf("hr=%X\n", hr);
if (!hr && pExample2) {
printf("hr=%X\n", hr);
BSTR bstr1 = SysAllocString(L"test");
pExample2->lpVtbl->SetString(pExample2, bstr1);
BSTR bstr2;
pExample2->lpVtbl->GetString(pExample2, &bstr2);
printf("%ls\n", bstr2);
SysFreeString(bstr2);
pExample2->lpVtbl->Release(pExample2);
} else ErrorString(hr);
CoUninitialize();
return 0;
}
void ErrorString(HRESULT errno)
{
#define BUFSIZE 1000
static TCHAR szMsgBuf[BUFSIZE];

FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
, NULL, errno
, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)
, (LPTSTR) szMsgBuf, BUFSIZE
, NULL);
printf("%Xh %s\n", errno, szMsgBuf);
}
Registration-Free COM manifest
Code: [Select]
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity type="win32" name="IExample2Test.exe" version="1.0.0.0" />
  <file name="IExample2.dll">
    <comClass progid="IExample2.Test"
       clsid="{520F4CFD-61C6-4EED-8004-C26D514D3D19}"
       description="IExample2 Control" />
  </file>
</assembly>

EDIT: small tool to create manifest lines:
Code: [Select]
#define UNICODE
#define _UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <ole2.h>
#include <tchar.h>
#include <stdio.h>

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleaut32.lib")

//int DumpTLib(WCHAR *szFileName)
int __cdecl wmain(int argc, wchar_t **argv)
{
LPTYPELIB pITypeLib;
WCHAR wsGuid[40];

if (!LoadTypeLibEx(argv[1], REGKIND_NONE, &pITypeLib))
{
BSTR bstrLib;
pITypeLib->lpVtbl->GetDocumentation(pITypeLib, -1, &bstrLib, 0, 0, 0);
TLIBATTR *pLibAttr;
pITypeLib->lpVtbl->GetLibAttr(pITypeLib, &pLibAttr);
StringFromGUID2(&pLibAttr->guid, wsGuid, sizeof(wsGuid));
_tprintf(_T("<file name=\"%ls\">\n<typelib tlbid=\"%ls\" />\n"),
argv[1], wsGuid);
pITypeLib->lpVtbl->ReleaseTLibAttr(pITypeLib, pLibAttr);
UINT tiCount = pITypeLib->lpVtbl->GetTypeInfoCount(pITypeLib);
for (UINT i = 0; i < tiCount; i++)
{
TYPEKIND TypeKind;
BSTR bstrName;
LPTYPEINFO pITypeInfo;
pITypeLib->lpVtbl->GetTypeInfoType(pITypeLib, i, &TypeKind);
pITypeLib->lpVtbl->GetDocumentation(pITypeLib, i, &bstrName, 0, 0, 0);
if (!pITypeLib->lpVtbl->GetTypeInfo(pITypeLib, i, &pITypeInfo))
{
TYPEATTR *pTypeAttr;
if (!pITypeInfo->lpVtbl->GetTypeAttr(pITypeInfo, &pTypeAttr))
{
if (TypeKind == TKIND_COCLASS) {
StringFromGUID2(&pTypeAttr->guid, wsGuid, sizeof(wsGuid));
//_tprintf(_T("<comClass clsid=\"%ls\" />\n"), wsGuid);
_tprintf(_T("<comClass clsid=\"%ls\" progid=\"%ls.%ls\"/>\n"),
wsGuid, bstrLib, bstrName);
}
pITypeInfo->lpVtbl->ReleaseTypeAttr(pITypeInfo, pTypeAttr);
}
pITypeInfo->lpVtbl->Release(pITypeInfo);
}
if (bstrName) SysFreeString(bstrName);
}
if (bstrLib) SysFreeString(bstrLib);
_tprintf(_T("</file>\n"));
}
return 0;
}
Title: Re: COM objects in plain C...
Post by: jj2007 on July 01, 2018, 10:57:58 AM
Hi Timo,
Just tried to build this project with the new Pelles C version, and it shows plenty of warnings.
Code: [Select]
Building DllMainStartup.obj.
Building IExample2.obj.
C:\PellesC\Timo\Timo\COM\iexample2\IExample2.c(209): warning #2030: '=' used in a conditional expression.
C:\PellesC\Timo\Timo\COM\iexample2\IExample2.c(222): warning #2071: Overflow or truncation in constant expression.
C:\PellesC\Timo\Timo\COM\iexample2\IExample2.c(229): warning #2030: '=' used in a conditional expression.
Building IExample2.dll.
POLINK: warning: Unrecognized keyword 'PRIVATE' in module-definition file 'C:\PellesC\Timo\Timo\COM\iexample2\IExample2.def'; ignored.
POLINK: warning: Unrecognized keyword 'PRIVATE' in module-definition file 'C:\PellesC\Timo\Timo\COM\iexample2\IExample2.def'; ignored.
Creating object: C:\PellesC\Timo\Timo\COM\iexample2\IExample2.exp
Creating library: C:\PellesC\Timo\Timo\COM\iexample2\IExample2.lib
Done.
It builds, but VBS complains that the ActiveX component cannot create the IExample2.object
Title: Re: COM objects in plain C...
Post by: TimoVJL on July 01, 2018, 12:20:06 PM
That dll need a typelib and registeration for that :(
Use midl compiler from SDK to make typelib.

Those warnings, add !=0
Code: [Select]
if ((hr = loadMyTypeInfo())!=0) return(hr);cast with (ULONG)
Code: [Select]
return((ULONG)DISP_E_UNKNOWNINTERFACE);and remove or comment out that PRIVATE