And here is an SDK style C++ host that I originally did in VC6 but just compiled using GNU CodeBlocks in the hope it would crash like the VB6 program, but no luck. It works perfect too. I'll also include the console window output from this where I clicked on he control once then closed out.
//C++
//Main.cpp
#include <windows.h>
#include <tchar.h>
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
#include <ocidl.h>
#include "Main.h"
#include "CSink.h"
extern "C" const CLSID CLSID_CD ={0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40}};
extern "C" const IID IID_ICOMCtrl ={0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41}};
extern "C" const IID IID_IOutGoing ={0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42}};
IConnectionPointContainer* pConnectionPointContainer=NULL;
IConnectionPoint* pConnectionPoint=NULL;
EVENTHANDLER EventHandler[3];
ICOMCtrl* pComCtrl=NULL;
DWORD dwCookie=NULL;
CSink* mySink=NULL;
long fnWndProc_OnCreate(lpWndEventArgs Wea)
{
HWND hButton,hContainer;
IUnknown* pUnk=0;
HRESULT hr;
FILE* hf;
int hCrt;
Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance;
AllocConsole();
hCrt=_open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT);
hf = _fdopen( hCrt, "w" );
_iob[1]=*hf;
printf(_T("Entering fnWndProc_OnCreate()\n"));
hr=CoInitialize(NULL);
if(SUCCEEDED(hr))
{
printf(" CoInitialize() Succeeded!\n");
hr=CoCreateInstance(CLSID_CD,NULL,CLSCTX_INPROC_SERVER,IID_ICOMCtrl,(void**)&pComCtrl);
if(SUCCEEDED(hr))
{
printf(" CoCreateInstance() Succeeded! -- pComCtrl = %u\n",(unsigned)pComCtrl);
hr=pComCtrl->Initialize();
if(SUCCEEDED(hr))
{
printf(" pComCtrl->Initialize() Succeeded!\n");
hButton=CreateWindowEx(0,"button","Blue",WS_CHILD|WS_VISIBLE,8,10,80,25,Wea->hWnd,(HMENU)IDC_BUTTON1,Wea->hIns,0);
hButton=CreateWindowEx(0,"button","Green",WS_CHILD|WS_VISIBLE,8,40,80,25,Wea->hWnd,(HMENU)IDC_BUTTON2,Wea->hIns,0);
hButton=CreateWindowEx(0,"button","Red",WS_CHILD|WS_VISIBLE,8,70,80,25,Wea->hWnd,(HMENU)IDC_BUTTON3,Wea->hIns,0);
//hButton=CreateWindowEx(0,"button","Kill COM Control",WS_CHILD|WS_VISIBLE,203,100,120,25,Wea->hWnd,(HMENU)IDC_KILL_CD,Wea->hIns,0);
hContainer=CreateWindowEx(WS_EX_CLIENTEDGE,_T("static"),_T(""),WS_CHILD|WS_VISIBLE|WS_THICKFRAME,100,12,325,80,Wea->hWnd,(HMENU)1600,Wea->hIns,0);
hr=pComCtrl->QueryInterface(IID_IUnknown,(void**)&pUnk);
if(SUCCEEDED(hr))
{
printf(" Got IUnknown From CLSID_CD! -- pUnk = %u\n",(unsigned)pUnk);
hr = pUnk->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
if(SUCCEEDED(hr))
{
printf(" Got pConnectionPointContainer = %u\n",(unsigned)pConnectionPointContainer);
hr = pConnectionPointContainer->FindConnectionPoint(IID_IOutGoing, &pConnectionPoint);
if(SUCCEEDED(hr))
{
printf(" Got pConnectionPoint = %u\n",(unsigned)pConnectionPoint);
mySink = new CSink;
printf(" mySink = %u\n",(unsigned)mySink);
hr=pConnectionPoint->Advise((IUnknown*)mySink, &dwCookie);
if(SUCCEEDED(hr))
{
printf(" pConnectionPoint->Advise() Succeeded!\n");
hr=pComCtrl->CreateControl((int)hContainer);
if(SUCCEEDED(hr))
printf(" pComCtrl->CreateControl(hContainer) Succeeded!\n");
else
printf(" pComCtrl->CreateControl(hContainer) Failed!\n");
}
else
puts(" pConnectionPoint->Advise() Failed!");
}
else
printf(" Failed To Get pConnectionPoint!\n");
}
else
printf(" Failed To Get IConnectionPointContainer*\n");
pUnk->Release();
}
else
printf("QueryInterface(IUnknown) Failed!\n");
}
else
printf("pComCtrl->Initialize() Failed!\n");
}
else
printf(_T(" CoCreateInstance() Failed!\n"));
}
else
printf(_T(" CoInitialize() Failed!\n"));
printf(_T("Leaving fnWndProc_OnCreate()\n\n"));
return 0;
}
long fnWndProc_OnCommand(lpWndEventArgs Wea)
{
switch(LOWORD(Wea->wParam))
{
case IDC_BUTTON1:
pComCtrl->SetColor((int)RGB(0,0,255));
break;
case IDC_BUTTON2:
pComCtrl->SetColor((int)RGB(0,255,0));
break;
case IDC_BUTTON3:
pComCtrl->SetColor((int)RGB(255,0,0));
break;
}
return 0;
}
long fnWndProc_OnClose(lpWndEventArgs Wea)
{
printf(_T("Entering fnWndProc_OnClose()\n"));
if(dwCookie && pConnectionPoint)
pConnectionPoint->Unadvise(dwCookie);
if(pConnectionPoint)
pConnectionPoint->Release();
if(pConnectionPointContainer)
pConnectionPointContainer->Release();
if(pComCtrl)
pComCtrl->Release();
delete mySink;
CoUninitialize();
printf(_T("Leaving fnWndProc_OnClose()\n\n"));
MessageBox
(
Wea->hWnd,
_T("Have Just Released Object! You Can Copy The Output From The Console If You Want Though!"),
_T("Will Close App!"),
MB_OK
);
DestroyWindow(Wea->hWnd);
PostQuitMessage(0);
return 0;
}
void AttachEventHandlers(void) //This procedure maps windows messages to the
{ //procedure which handles them.
EventHandler[0].Code=WM_CREATE, EventHandler[0].fnPtr=fnWndProc_OnCreate;
EventHandler[1].Code=WM_COMMAND, EventHandler[1].fnPtr=fnWndProc_OnCommand;
EventHandler[2].Code=WM_CLOSE, EventHandler[2].fnPtr=fnWndProc_OnClose;
}
long __stdcall fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam,LPARAM lParam)
{
WndEventArgs Wea; //This procedure loops through the EVENTHANDER array
//of structs to try to make a match with the msg parameter
for(unsigned int i=0; i<3; i++) //of the WndProc. If a match is made the event handling
{ //procedure is called through a function pointer -
if(EventHandler[i].Code==msg) //(EventHandler[i].fnPtr). If no match is found the
{ //msg is passed onto DefWindowProc().
Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
return (*EventHandler[i].fnPtr)(&Wea);
}
}
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
int __stdcall WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
TCHAR szClassName[]=_T("C++ Visual COM Control Demo");
WNDCLASSEX wc;
MSG messages;
HWND hWnd;
AttachEventHandlers();
wc.lpszClassName=szClassName; wc.lpfnWndProc=fnWndProc;
wc.cbSize=sizeof (WNDCLASSEX); wc.style=CS_DBLCLKS;
wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); wc.hInstance=hIns;
wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION); wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW; wc.cbWndExtra=0;
wc.lpszMenuName=NULL; wc.cbClsExtra=0;
RegisterClassEx(&wc);
hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,400,550,440,140,HWND_DESKTOP,0,hIns,0);
ShowWindow(hWnd,iShow);
while(GetMessage(&messages,NULL,0,0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
Main.h
//Main.h
#define IDC_BUTTON1 1300 //Control ID For Blue' Button
#define IDC_BUTTON2 1305 //Control ID For Green' Button
#define IDC_BUTTON3 1310 //Control ID For Red' Button
#define IDC_KILL_CD 1315 //Control ID For Kill CD
interface ICOMCtrl : IUnknown
{
virtual HRESULT __stdcall Initialize ( )=0;
virtual HRESULT __stdcall CreateControl (const int)=0;
virtual HRESULT __stdcall SetColor (int )=0;
virtual HRESULT __stdcall GetColor (int* )=0;
virtual HRESULT __stdcall GetCtrlId (int* )=0;
virtual HRESULT __stdcall GetHWND (int* )=0;
};
typedef struct WindowsEventArguments
{
HWND hWnd;
WPARAM wParam;
LPARAM lParam;
HINSTANCE hIns;
}WndEventArgs, *lpWndEventArgs;
struct EVENTHANDLER
{
unsigned int Code;
long (*fnPtr)(lpWndEventArgs);
};
//CSink.h
#ifndef CSINK_H
#define CSINK_H
interface IOutGoing : IUnknown //IOutGoing
{
virtual HRESULT __stdcall ControlEvent(int) = 0;
};
class CSink : public IOutGoing //CSink
{
public:
CSink();
~CSink() { }
HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);
ULONG __stdcall AddRef(); //IUnknown
ULONG __stdcall Release();
HRESULT __stdcall ControlEvent(int Message); //IOutGoing
private:
long m_cRef;
};
#endif
//CSink.cpp
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <ocidl.h>
#include "Main.h"
#include "CSink.h"
extern ICOMCtrl* pComCtrl;
extern "C" const IID IID_IOutGoing;
CSink::CSink() : m_cRef(0)
{
printf(_T("Entering CSink Constructor!\n"));
printf(_T(" this = %u\n"),this);
printf(_T("Leaving CSink Constructor!\n"));
}
ULONG CSink::AddRef()
{
return ++m_cRef;
}
ULONG CSink::Release()
{
printf("Entering CSink::Release()\n");
printf(_T(" this = %u\n"),this);
if(--m_cRef != 0)
{
printf(" m_cRef != 0 : m_cRef=%u\n",m_cRef);
return m_cRef;
}
else
{
printf(" m_cRef == 0 And Will Now Delete CSink!\n");
//delete this;
}
printf("Leaving CSink::Release()\n");
return 0;
}
HRESULT CSink::QueryInterface(REFIID riid, void** ppv)
{
printf(" Entering CSink::QueryInterface() -- this = %u\n",this);
if(riid == IID_IUnknown)
{
*ppv = (IUnknown*)this;
}
else if(riid == IID_IOutGoing)
{
printf(" Client: CSink::QueryInterface() for IOutGoing -- this = %u\n", (IOutGoing*)this);
*ppv = (IOutGoing*)this;
printf(" *ppv = %u\n", *ppv);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
printf(" Leaving CSink::QueryInterface()\n");
return S_OK;
}
HRESULT CSink::ControlEvent(int Message)
{
TCHAR szBuffer[256],szTmp[64];
int iColor,iCtlId,iWndHdl;
HWND hContainer,hMain;
_tprintf(_T("\nEntering CSink::ControlEvent()\n"));
printf(" CSink::ControlEvent is %u\n", Message);
switch(Message)
{
case WM_CREATE:
printf(" WM_CREATE\n");
break;
case WM_CHAR:
printf(" WM_CHAR\n");
break;
case WM_LBUTTONDOWN:
printf(" WM_LBUTTONDOWN\n");
pComCtrl->GetColor(&iColor);
pComCtrl->GetCtrlId(&iCtlId);
pComCtrl->GetHWND(&iWndHdl);
hContainer=GetParent((HWND)iWndHdl);
hMain=GetParent(hContainer);
_tprintf(_T(" hContainer = %u\n"),hContainer);
_tprintf(_T(" hMain = %u\n"),hMain);
if(iColor==(int)RGB(0,0,255))
_tcscpy(szBuffer,_T("The COM Control Is Blue! Its Control ID Is\r\n"));
if(iColor==(int)RGB(255,255,0))
_tcscpy(szBuffer,_T("The COM Control Is Yellow! Its Control ID Is\r\n"));
if(iColor==(int)RGB(0,255,0))
_tcscpy(szBuffer,_T("The COM Control Is Green! Its Control ID Is\r\n"));
if(iColor==(int)RGB(255,0,0))
_tcscpy(szBuffer,_T("The COM Control Is Red! Its Control ID Is\r\n"));
_stprintf(szTmp,_T("%u"),iCtlId);
_tcscat(szBuffer,szTmp);
_tcscat(szBuffer,_T(" And Its HWND Is "));
_stprintf(szTmp,_T("%u"),iWndHdl);
_tcscat(szBuffer,szTmp);
_tcscat(szBuffer,_T("."));
MessageBox(hMain,szBuffer,_T("Report From Control!"),MB_OK);
break;
case WM_CLOSE:
printf(" WM_CLOSE\n");
break;
}
printf("Leaving CSink::GotMessage()\n\n");
return S_OK;
}
Here is the output from the console window from above...
Entering fnWndProc_OnCreate()
CoInitialize() Succeeded!
Entering DllGetClassObjectImpl()
Varptr(CDClassFactory) = 10860532
Entering IClassFactory_QueryInterface()
this = 10860532
Somebody's Looking For IID_IUnknown Or IID_IClassFactory!
Leaving IClassFactory_QueryInterface()
IClassFactory_QueryInterface() Succeeded!
Leaving DllGetClassObjectImpl()
Entering IClassFactory_CreateInstance()
pCD = 2446624
Varptr(@pCD.lpComCtrlVtbl) = 2446624
Varptr(@pCD.lpICPCVtbl) = 2446628
Varptr(@pCD.lpICPVtbl) = 2446632
@ppv = 0 << Before QueryInterface() Call
Entering IComCtrl_QueryInterface()
Trying To Get IComCtrl
this = 2446624
Leaving IComCtrl_QueryInterface()
@ppv = 2446624 << After QueryInterface() Call
Leaving IClassFactory_CreateInstance()
Entering IComCtrl_Release()
@pCD.m_cRef = 2
Leaving IComCtrl_Release()
Entering IComCtrl_QueryInterface()
Trying To Get IComCtrl
this = 2446624
Leaving IComCtrl_QueryInterface()
Entering IComCtrl_Release()
@pCD.m_cRef = 2
Leaving IComCtrl_Release()
CoCreateInstance() Succeeded! -- pComCtrl = 2446624
Entering IComCtrl_Initialize()
this = 2446624
Leaving IComCtrl_Initialize()
pComCtrl->Initialize() Succeeded!
Entering IComCtrl_QueryInterface()
Trying To Get IUnknown
this = 2446624
Leaving IComCtrl_QueryInterface()
Got IUnknown From CLSID_CD! -- pUnk = 2446624
Entering IComCtrl_QueryInterface()
Trying To Get IConnectionPointContainer
this = 2446624
this = 2446628
Leaving IComCtrl_QueryInterface()
Got pConnectionPointContainer = 2446628
Entering IConnectionPointContainer_FindConnectionPoint()
this = 2446628
@ppCP = 0
@ppCP = 2446632
Leaving IConnectionPointContainer_FindConnectionPoint()
Got pConnectionPoint = 2446632
Entering CSink Constructor!
this = 9775280
Leaving CSink Constructor!
mySink = 9775280
Entering IConnectionPoint_Advise()! Grab Your Hardhat And Hang On Tight!
pUnkSink = 9775280
@pUnkSink = 4226576
Vtbl = 4226576
@Vtbl[0] = 4202364
g_ptrOutGoing = 0 << Before Call Of QueryInterface() On Sink
Entering CSink::QueryInterface() -- this = 9775280
Client: CSink::QueryInterface() for IOutGoing -- this = 9775280
*ppv = 9775280
Leaving CSink::QueryInterface()
g_ptrOutGoing = 9775280 << After Call Of QueryInterface() On Sink
Call Dword Succeeded!
Leaving IConnectionPoint_Advise() And Still In One Piece!
pConnectionPoint->Advise() Succeeded!
Entering IComCtrl_CreateControl()
this = 2446624
Leaving IComCtrl_CreateControl()
pComCtrl->CreateControl(hContainer) Succeeded!
Entering IComCtrl_Release()
@pCD.m_cRef = 4
Leaving IComCtrl_Release()
Leaving fnWndProc_OnCreate()
WM_LBUTTONDOWN
g_ptrOutGoing = 9775280
@Vtbl = 4202364
@Vtbl[0] = 4202364
Entering CSink::ControlEvent()
CSink::ControlEvent is 513
WM_LBUTTONDOWN
hContainer = 329166
hMain = 853550
Leaving CSink::GotMessage()
Entering fnWndProc_OnClose()
Entering IConnectionPoint_Unadvise()
Entering CSink::Release()
this = 9775280
m_cRef == 0 And Will Now Delete CSink!
Leaving CSink::Release()
Release() Returned 0
Leaving IConnectionPoint_Unadvise()
Entering IConnectionPoint_Release()
Leaving IConnectionPoint_Release()
Entering IConnectionPointContainer_Release()
Leaving IConnectionPointContainer_Release()
Entering IComCtrl_Release()
@pCD.m_cRef = 1
@pCD.m_cRef = 0
CD Was Deleted!
Leaving IComCtrl_Release()
Leaving fnWndProc_OnClose()