Visual Studio 2008 Pro puts a bunch of shortcuts on the Start Menu and one of those will start a command line session where paths and environment variables are set up to invoke either the 32 bit or 64 bit tool chain. So I made a directory for my 64 bit code at C:\Code\VStudio\VC++9\64_Bit\FHGrid and I navigate to there from where VStudio's command prompt opens up. I use midl to create the type library, then rc and cvtres to create the FHGridRes.obj file containing the resources. Then I use cl.exe to link all the pieces together and create the dll. Here is the complete 64 bit console output for building the dll from the above code ...
Setting environment for using Microsoft Visual Studio 2008 Beta2 x64 tools.
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC>CD\
c:\>CD C:\Code\VStudio\VC++9\64_Bit\FHGrid
C:\Code\VStudio\VC++9\64_Bit\FHGrid>midl FHGrid.idl
Microsoft (R) 32b/64b MIDL Compiler Version 7.00.0500
Copyright (c) Microsoft Corporation 1991-2006. All rights reserved.
64 bit Processing .\FHGrid.idl
FHGrid.idl
64 bit Processing C:\Program Files\\Microsoft SDKs\Windows\v6.0A\include\unknwn.idl
unknwn.idl
64 bit Processing C:\Program Files\\Microsoft SDKs\Windows\v6.0A\include\wtypes.idl
wtypes.idl
64 bit Processing C:\Program Files\\Microsoft SDKs\Windows\v6.0A\include\basetsd.h
basetsd.h
64 bit Processing C:\Program Files\\Microsoft SDKs\Windows\v6.0A\include\guiddef.h
guiddef.h
64 bit Processing C:\Program Files\\Microsoft SDKs\Windows\v6.0A\include\oaidl.idl
oaidl.idl
64 bit Processing C:\Program Files\\Microsoft SDKs\Windows\v6.0A\include\objidl.idl
objidl.idl
64 bit Processing C:\Program Files\\Microsoft SDKs\Windows\v6.0A\include\oaidl.acf
oaidl.acf
C:\Code\VStudio\VC++9\64_Bit\FHGrid>rc.exe /v /foFHGridRes.res FHGrid.rc
Microsoft (R) Windows (R) Resource Compiler Version 6.0.5724.0
Copyright (C) Microsoft Corporation. All rights reserved.
Using codepage 1252 as default
Creating FHGridRes.res
FHGrid.rc.
Writing TYPELIB:1, lang:0x409, size 5056
C:\Code\VStudio\VC++9\64_Bit\FHGrid>cvtres.exe /MACHINE:X64 /v FHGridRes.res
Microsoft (R) Windows Resource To Object Converter Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.
adding resource. type:TYPELIB, name:1, language:0x0409, flags:0x30, size:5056
C:\Code\VStudio\VC++9\64_Bit\FHGrid>cl Server.cpp Grid.cpp Registry.cpp FHGridRes.obj UUID.lib Advapi32.lib Ole32.lib OleAut32.lib FHGrid.def /O1 /Os /FeFHGrid.dll /LD
Microsoft (R) C/C++ Optimizing Compiler Version 15.00.21022.08 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
Server.cpp
Grid.cpp
Registry.cpp
Generating Code...
Microsoft (R) Incremental Linker Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.
/out:FHGrid.dll
/dll
/implib:FHGrid.lib
/def:FHGrid.def
Server.obj
Grid.obj
Registry.obj
FHGridRes.obj
UUID.lib
Advapi32.lib
Ole32.lib
OleAut32.lib
Creating library FHGrid.lib and object FHGrid.exp
C:\Code\VStudio\VC++9\64_Bit\FHGrid>
Next you'll want to Register the Server with RegSvr32.exe. You may need to run your command prompt window using the 'Run As Administrator' option to get that to work. Note I don't have a hard coded debug output file created in DllRegisterServer(), but rather I believe my code will work wherever you want to create this. Here is part of that routine that gets called by RegSvr32...
STDAPI DllRegisterServer()
{
ITypeLib* pTypeLib=NULL;
TCHAR szBuffer[512];
wchar_t szWide[512];
HRESULT hr=E_FAIL;
#if defined MYDEBUG
GetCurrentDirectory(512,szBuffer);
_tcscat(szBuffer,_T("\\Output.txt"));
fp=_tfopen(szBuffer,_T("w"));
if(!fp)
return E_FAIL;
fprintf(fp,"Entering DLLRegisterServer\n");
...
...
Here is the Output.txt file I got through the registration when I was testing with ansi...
Entering DLLRegisterServer
szBuffer = C:\Code\VStudio\VC++9\64_Bit\FHGrid\FHGrid.dll
iReturn = 46
szWide = C:\Code\VStudio\VC++9\64_Bit\FHGrid\FHGrid.dll
LoadTypeLibEx() Succeeded!
Entering RegisterServer()
szFriendlyName = Fred Harris Grid Control v1
szVerIndProgID = FHGrid.Grid
szProgID = FHGrid.Grid.1
szModule = C:\Code\VStudio\VC++9\64_Bit\FHGrid\FHGrid.dll
Entering CLSIDToTChar()
iStrLen = 39
wszCLSID = {30000000-0000-0000-0000-000000000000}
szCLSID = {30000000-0000-0000-0000-000000000000}
pRet = 39
Leaving CLSIDToTChar()
szCLSID = {30000000-0000-0000-0000-000000000000}
szKey = {30000000-0000-0000-0000-000000000000}
Entering SetKeyAndValue()
szKey = CLSID\{30000000-0000-0000-0000-000000000000}
szSubkey = (null)
szValue = Fred Harris Grid Control v1
Leaving SetKeyAndValue()
Entering SetKeyAndValue()
szKey = CLSID\{30000000-0000-0000-0000-000000000000}
szSubkey = InprocServer32
szValue = C:\Code\VStudio\VC++9\64_Bit\FHGrid\FHGrid.dll
szKeyBuf = CLSID\{30000000-0000-0000-0000-000000000000}\InprocServer32
Leaving SetKeyAndValue()
Entering SetKeyAndValue()
szKey = CLSID\{30000000-0000-0000-0000-000000000000}
szSubkey = ProgID
szValue = FHGrid.Grid.1
szKeyBuf = CLSID\{30000000-0000-0000-0000-000000000000}\ProgID
Leaving SetKeyAndValue()
Entering SetKeyAndValue()
szKey = CLSID\{30000000-0000-0000-0000-000000000000}
szSubkey = VersionIndependentProgID
szValue = FHGrid.Grid
szKeyBuf = CLSID\{30000000-0000-0000-0000-000000000000}\VersionIndependentProgID
Leaving SetKeyAndValue()
Entering SetKeyAndValue()
szKey = FHGrid.Grid
szSubkey = (null)
szValue = Fred Harris Grid Control v1
Leaving SetKeyAndValue()
Entering SetKeyAndValue()
szKey = FHGrid.Grid
szSubkey = CLSID
szValue = {30000000-0000-0000-0000-000000000000}
szKeyBuf = FHGrid.Grid\CLSID
Leaving SetKeyAndValue()
Entering SetKeyAndValue()
szKey = FHGrid.Grid
szSubkey = CurVer
szValue = FHGrid.Grid.1
szKeyBuf = FHGrid.Grid\CurVer
Leaving SetKeyAndValue()
Entering SetKeyAndValue()
szKey = FHGrid.Grid.1
szSubkey = (null)
szValue = Fred Harris Grid Control v1
Leaving SetKeyAndValue()
Entering SetKeyAndValue()
szKey = FHGrid.Grid.1
szSubkey = CLSID
szValue = {30000000-0000-0000-0000-000000000000}
szKeyBuf = FHGrid.Grid.1\CLSID
Leaving SetKeyAndValue()
Leaving RegisterServer()
RegisterServer() Succeeded!
Leaving DllRegisterServer()
I intend to discuss the above code in detail, but to do that one pretty much needs a client/host to work with. So here is Client.h and Client.cpp. This is a Windows GUI app that creates a little Window/Dialog/Form ...
//Client.h
#ifndef CLIENT_H_INCLUDED
#define CLIENT_H_INCLUDED
#define dim(x) (sizeof(x) / sizeof(x[0]))
#define IDC_STATIC -1
#define IDC_UNLOAD_GRID 1500
#define IDC_DUMP_COM_MEMORY 1505
struct WindowsEventArguments
{
HWND hWnd;
WPARAM wParam;
LPARAM lParam;
HINSTANCE hIns;
};
typedef WindowsEventArguments* lpWndEventArgs;
long fnWndProc_OnCreate (lpWndEventArgs Wea);
long fnWndProc_OnCommand (lpWndEventArgs Wea);
long fnWndProc_OnPaint (lpWndEventArgs Wea);
long fnWndProc_OnDestroy (lpWndEventArgs Wea);
struct EVENTHANDLER
{
unsigned int iMsg;
long (*fnPtr)(lpWndEventArgs);
};
const EVENTHANDLER EventHandler[]=
{
{WM_CREATE, fnWndProc_OnCreate},
{WM_COMMAND, fnWndProc_OnCommand},
{WM_PAINT, fnWndProc_OnPaint},
{WM_DESTROY, fnWndProc_OnDestroy}
};
#endif // CLIENT_H_INCLUDED
//Client.cpp
// cl Client.cpp Kernel32.lib User32.lib Gdi32.lib UUID.lib Ole32.lib OleAut32.lib /O1 /Os /MT /GA
// CD C:\Code\VStudio\VC++9\64_Bit\FHGrid
#define UNICODE
#define _UNICODE //At this point the grid doesn't exist yet, however, the COM infrastructure code in
#include <windows.h> //which it will eventually be created does. This client app exercises that COM
#include <objbase.h> //infrastructure code by instantiating an FHGrid object and iterating through its
#include <tchar.h> //various structures and virtual function tables (VTables) to elucidate its memory
#include <fcntl.h> //footprint. The app is a GUI Windows App and creates a small window with two buttons
#include <io.h> //on it. The button on the left outputs the memory footprint of the various interfaces
#include <stdio.h> //and COM structures to the console window which the program creates. The button on
#include <ocidl.h> //the right releases the COM object.
#include "Client.h"
const CLSID CLSID_FHGrid = {0x30000000, 0x0000, 0x0000, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} };
const IID IID_IFHGrid = {0x30000000, 0x0000, 0x0000, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01} };
const IID IID_IFHGrid_Events = {0x30000000, 0x0000, 0x0000, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02} };
const IID LIBID_FHGrid = {0x30000000, 0x0000, 0x0000, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03} };
const IID IID_Junk = {0x12345678, 0x1234, 0x5678, {0x12,0x34,0x56,0x78,0x98,0x76,0x54,0x32} };
interface IGrid : IUnknown
{
virtual HRESULT STDMETHODCALLTYPE CreateGrid (HWND, BSTR, int, int, int, int, int, int, int, int, int, BSTR, int, int ) = 0;
virtual HRESULT STDMETHODCALLTYPE SetRowCount (int, int ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetRowCount (int* ) = 0;
virtual HRESULT STDMETHODCALLTYPE SetData (int, int, BSTR ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetData (int, int, BSTR* ) = 0;
virtual HRESULT STDMETHODCALLTYPE FlushData (void ) = 0;
virtual HRESULT STDMETHODCALLTYPE Refresh (void ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetVisibleRows (int ) = 0;
virtual HRESULT STDMETHODCALLTYPE GethGrid (HWND* ) = 0;
virtual HRESULT STDMETHODCALLTYPE GethCell (int, int, HWND* ) = 0;
virtual HRESULT STDMETHODCALLTYPE GethComboBox (int, HWND* ) = 0;
virtual HRESULT STDMETHODCALLTYPE SetCellAttributes (int, int, int, int ) = 0;
virtual HRESULT STDMETHODCALLTYPE DeleteRow (int ) = 0;
};
long fnWndProc_OnCreate(lpWndEventArgs Wea) //This code can be compiled for either 32 bit or 64 bit. If compiled for 32 bit it will
{ //attempt to load a 32 bit grid. If compiled with a 64 bit C++ compiler it will attempt
IClassFactory* pClassFactory=NULL; //to load the 64 bit version. Of course, to succeed those versions have to be registered.
SMALL_RECT sm_rect;
IGrid* pGrid=NULL;
HANDLE hStdOut;
HWND hCtl=NULL;
HRESULT hr;
FILE* hf=0;
COORD pt;
int hCrt;
Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance;
AllocConsole();
hStdOut=GetStdHandle(STD_OUTPUT_HANDLE); //This mess at left is some pretty obscure stuff related
hCrt=_open_osfhandle((long)hStdOut,_O_TEXT); //to the fact that when a GUI process is started by
hf=_fdopen( hCrt, "w" ); //Windows the standard output handles are zeroed out and
__iob_func()[1]=*hf; //printf needs them. This code re-initializes it so printf
pt.X=120, pt.Y=600; //works. I had to change it a little from what it used to be.
SetConsoleScreenBufferSize(hStdOut,pt);
sm_rect.Left=0, sm_rect.Top=0, sm_rect.Right=119, sm_rect.Bottom=39;
SetConsoleWindowInfo(hStdOut,TRUE,&sm_rect);
printf("Entering fnWndProc_OnCreate()\n");
printf(" sizeof(IGrid*) = %d\n",sizeof(IGrid*));
hr=CoInitialize(NULL);
if(SUCCEEDED(hr))
{
hCtl=CreateWindow(_T("button"),_T("Dump COM Memory"),WS_CHILD|WS_VISIBLE,30,120,150,25,Wea->hWnd,(HMENU)IDC_DUMP_COM_MEMORY,Wea->hIns,NULL);
hCtl=CreateWindow(_T("button"),_T("Destroy Grid"),WS_CHILD|WS_VISIBLE,225,120,150,25,Wea->hWnd,(HMENU)IDC_UNLOAD_GRID,Wea->hIns,NULL);
printf(" CoInitialize() Succeeded!\n");
hr=CoGetClassObject(CLSID_FHGrid,CLSCTX_INPROC_SERVER,NULL,IID_IClassFactory,(void**)&pClassFactory);
if(SUCCEEDED(hr))
{
printf(" CoGetClassObject() Succeeded!\n");
printf(" pClassFactory = %u\n",pClassFactory);
hr=pClassFactory->CreateInstance(NULL,IID_IFHGrid,(void**)&pGrid);
if(SUCCEEDED(hr))
{
printf(" IClassFactory->CreateInstance() Succeeded!\n");
printf(" pGrid = %u\n",pGrid);
SetWindowLongPtr(Wea->hWnd,0,(LONG_PTR)pGrid);
}
else
printf(" IClassFactory->CreateInstance() Failed!\n");
pClassFactory->Release();
}
else
printf(" CoGetClassObject() Failed!\n");
}
else
printf(" CoInitialize() Failed!\n");
printf("Leaving fnWndProc_OnCreate()\n\n");
return 0;
}
void DumpCOMMemory(HWND hHost)
{
IConnectionPointContainer* pCnPtCnt=NULL;
size_t* pVTbl=0;
size_t* pIUnk=0;
size_t* VTbl=0;
HRESULT hr;
printf(" Entering DumpCOMMemory()\n");
IGrid* pGrid=(IGrid*)GetWindowLongPtr(hHost,0);
printf(" pGrid = %u\n",pGrid);
if(pGrid)
{
pVTbl=(size_t*)pGrid;
printf(" pVTbl = %u\n",pVTbl);
printf(" &pVTbl[0] = %u\n", &pVTbl[0]);
printf(" &pVTbl[1] = %u\n", &pVTbl[1]);
printf(" &pVTbl[2] = %u\n", &pVTbl[2]);
VTbl=(size_t*)pVTbl[0];
printf(" VTbl = %u\n",VTbl);
printf(" VTbl[0] = %u\n\n", VTbl[0]);
//IGrid Function Pointers
HRESULT (STDMETHODCALLTYPE* pQueryInterface )(size_t* pThis, REFIID riid, void** ppv );
ULONG (STDMETHODCALLTYPE* pAddRef )(size_t* );
ULONG (STDMETHODCALLTYPE* pRelease )(size_t* );
HRESULT (STDMETHODCALLTYPE* pCreateGrid )(size_t*, HWND, BSTR, int, int, int, int, int, int, int, int, int, BSTR, int, int);
HRESULT (STDMETHODCALLTYPE* pSetRowCount )(size_t*, int, int );
HRESULT (STDMETHODCALLTYPE* pGetRowCount )(size_t*, int* );
HRESULT (STDMETHODCALLTYPE* pSetData )(size_t*, int, int, BSTR );
HRESULT (STDMETHODCALLTYPE* pGetData )(size_t*, int, int, BSTR* );
HRESULT (STDMETHODCALLTYPE* pFlushData )(size_t* );
HRESULT (STDMETHODCALLTYPE* pRefresh )(size_t* );
HRESULT (STDMETHODCALLTYPE* pGetVisibleRows )(size_t*, int* );
HRESULT (STDMETHODCALLTYPE* pGethGrid )(size_t*, HWND* );
HRESULT (STDMETHODCALLTYPE* pGethCell )(size_t*, int, int, HWND* );
HRESULT (STDMETHODCALLTYPE* pGethComboBox )(size_t*, int, HWND* );
HRESULT (STDMETHODCALLTYPE* pSetCellAttributes )(size_t*, int, int, int, int );
HRESULT (STDMETHODCALLTYPE* pDeleteRow )(size_t*, int );
//IConnectionPointContainer Function Pointers
HRESULT (STDMETHODCALLTYPE* pEnumConnectionPoints )(size_t* This, IEnumConnectionPoints** ppEnum );
HRESULT (STDMETHODCALLTYPE* pFindConnectionPoint )(size_t* This, REFIID riid, IConnectionPoint** ppCP );
//IConnectionPoint Function Pointers
HRESULT (STDMETHODCALLTYPE* pGetConnectionInterface )(size_t*, IID* pIID );
HRESULT (STDMETHODCALLTYPE* pGetConnectionPointContainer)(size_t*, IConnectionPointContainer** ppCPC );
HRESULT (STDMETHODCALLTYPE* pAdvise )(size_t*, IUnknown* pUnkSink, DWORD* pdwCookie );
HRESULT (STDMETHODCALLTYPE* pUnadvise )(size_t*, DWORD dwCookie );
HRESULT (STDMETHODCALLTYPE* pEnumConnections )(size_t*, IEnumConnections** ppEnum );
//IGrid::QueryInterface()
pQueryInterface=(HRESULT (STDMETHODCALLTYPE*)(size_t*, REFIID, void**))VTbl[0];
pQueryInterface(&pVTbl[0],IID_Junk,(void**)&pIUnk);
//IGrid::AddRef()
pAddRef=(ULONG (STDMETHODCALLTYPE*)(size_t*))VTbl[1];
pAddRef(&pVTbl[0]);
//IGrid::Release()
pRelease=(ULONG (STDMETHODCALLTYPE*)(size_t*))VTbl[2];
pRelease(&pVTbl[0]);
printf("\n");
printf(" &pVTbl[i] &VTbl[j] pFn=VTbl[j] pFn() Function Pointer Call\n");
printf(" ===========================================================================\n");
//IGrid::QueryInterface()
pQueryInterface=(HRESULT (STDMETHODCALLTYPE*)(size_t*, REFIID, void**))VTbl[0];
printf(" %u\t%u\t%u\n",&pVTbl[0],&VTbl[0],pQueryInterface);
//IGrid::AddRef()
printf(" %u\t%u\t%u\n",&pVTbl[0],&VTbl[1],pAddRef);
//IGrid::Release()
printf(" %u\t%u\t%u\n",&pVTbl[0],&VTbl[2],pRelease);
//IGrid::CreateGrid()
pCreateGrid=(HRESULT (STDMETHODCALLTYPE*)(size_t*,HWND,BSTR,int,int,int,int,int,int,int,int,int,BSTR,int,int))VTbl[3];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[3],pCreateGrid);
HWND hWnd=NULL;
BSTR strNothing=NULL;
pCreateGrid(&pVTbl[0], hWnd, strNothing, 0, 0, 0, 0, 0, 0, 0, 0, 0, strNothing, 0, 0);
//IGrid::SetRowCount()
pSetRowCount=(HRESULT (STDMETHODCALLTYPE*)(size_t*, int, int))VTbl[4];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[4],pSetRowCount);
pSetRowCount(&pVTbl[0],0,0);
//IGrid::GetRowCount()
pGetRowCount=(HRESULT (STDMETHODCALLTYPE*)(size_t*, int*))VTbl[5];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[5],pSetRowCount);
pGetRowCount(&pVTbl[0],0);
//IGrid::SetData()
pSetData=(HRESULT (STDMETHODCALLTYPE*)(size_t*, int, int, BSTR))VTbl[6];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[6],pSetData);
pSetData(&pVTbl[0],0,0,strNothing);
//IGrid::GetData()
pGetData=(HRESULT (STDMETHODCALLTYPE*)(size_t*, int, int, BSTR*))VTbl[7];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[7],pGetData);
pGetData(&pVTbl[0],0,0,&strNothing);
//IGrid::FlushData()
pFlushData=(HRESULT (STDMETHODCALLTYPE*)(size_t*))VTbl[8];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[8],pFlushData);
pFlushData(&pVTbl[0]);
//IGrid::Refresh()
pRefresh=(HRESULT (STDMETHODCALLTYPE*)(size_t*))VTbl[9];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[9],pRefresh);
pRefresh(&pVTbl[0]);
//IGrid::GetVisibleRows()
pGetVisibleRows=(HRESULT (STDMETHODCALLTYPE*)(size_t*, int*))VTbl[10];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[10],pGetVisibleRows);
pGetVisibleRows(&pVTbl[0],NULL);
//IGrid::GethGrid()
pGethGrid=(HRESULT (STDMETHODCALLTYPE*)(size_t*, HWND*))VTbl[11];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[11],pGethGrid);
pGethGrid(&pVTbl[0],&hWnd);
//IGrid::GethCell()
pGethCell=(HRESULT (STDMETHODCALLTYPE*)(size_t*, int, int, HWND*))VTbl[12];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[12],pGethCell);
pGethCell(&pVTbl[0],0,0,&hWnd);
//IGrid::GethComboBox()
pGethComboBox=(HRESULT (STDMETHODCALLTYPE*)(size_t*, int, HWND*))VTbl[13];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[13],pGethComboBox);
pGethComboBox(&pVTbl[0],0,&hWnd);
//IGrid::SetCellAttributes()
pSetCellAttributes=(HRESULT (STDMETHODCALLTYPE*)(size_t*, int, int, int, int))VTbl[14];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[14],pSetCellAttributes);
pSetCellAttributes(&pVTbl[0],0,0,0,0);
//IGrid::DeleteRow()
pDeleteRow=(HRESULT (STDMETHODCALLTYPE*)(size_t*, int))VTbl[15];
printf(" %u\t%u\t%u\t",&pVTbl[0],&VTbl[15],pDeleteRow);
pDeleteRow(&pVTbl[0],0);
printf("\n");
//End IGrid VTable
VTbl=(size_t*)pVTbl[1]; //Get Base Address Of IConnectionPointContainer VTable
//IConnectionPointContainer::EnumConnectionPoints()
pEnumConnectionPoints=(HRESULT (STDMETHODCALLTYPE*)(size_t*, IEnumConnectionPoints**))VTbl[3];
IEnumConnectionPoints* pEnumConnPts=NULL;
printf(" %u\t%u\t%u\t",&pVTbl[1],&VTbl[3],pEnumConnectionPoints);
pEnumConnectionPoints(&pVTbl[1],&pEnumConnPts);
//IConnectionPointContainer::FindConnectionPoint()
pFindConnectionPoint=(HRESULT (STDMETHODCALLTYPE*)(size_t*, REFIID, IConnectionPoint**))VTbl[4];
printf(" %u\t%u\t%u\t",&pVTbl[1],&VTbl[4],pFindConnectionPoint);
IConnectionPoint* pConnectionPoint=NULL;
pFindConnectionPoint(&pVTbl[1],IID_Junk,&pConnectionPoint);
printf("\n");
//End IConnectionPointContainer VTable
VTbl=(size_t*)pVTbl[2]; //Get Base Address Of IConnectionPoint VTable
//IConnectionPoint::GetConnectionInterface()
pGetConnectionInterface=(HRESULT (STDMETHODCALLTYPE*)(size_t*, IID*))VTbl[3];
printf(" %u\t%u\t%u\t",&pVTbl[2],&VTbl[3],pGetConnectionInterface);
IID pJunk;
pGetConnectionInterface(&pVTbl[2],&pJunk);
//IConnectionPoint::GetConnectionPointContainer
pGetConnectionPointContainer=(HRESULT (STDMETHODCALLTYPE*)(size_t*, IConnectionPointContainer**))VTbl[4];
printf(" %u\t%u\t%u\t",&pVTbl[2],&VTbl[4],pGetConnectionPointContainer);
pGetConnectionPointContainer(&pVTbl[2],&pCnPtCnt);
//IConnectionPoint::Advise()
pAdvise=(HRESULT (STDMETHODCALLTYPE*)(size_t*, IUnknown*, DWORD*))VTbl[5];
printf(" %u\t%u\t%u\t",&pVTbl[2],&VTbl[5],pAdvise);
DWORD dwCookie;
pAdvise(&pVTbl[2],(IUnknown*)pCnPtCnt,&dwCookie);
//IConnectionPoint::Unadvise()
pUnadvise=(HRESULT (STDMETHODCALLTYPE*)(size_t*, DWORD))VTbl[6];
printf(" %u\t%u\t%u\t",&pVTbl[2],&VTbl[6],pUnadvise);
pUnadvise(&pVTbl[2],dwCookie);
//IConnectionPoint::EnumConnections
pEnumConnections=(HRESULT (STDMETHODCALLTYPE*)(size_t*, IEnumConnections**))VTbl[7];
IEnumConnections* pIEnumConnections=NULL;
printf(" %u\t%u\t%u\t",&pVTbl[2],&VTbl[7],pEnumConnections);
pEnumConnections(&pVTbl[2],&pIEnumConnections);
printf("\n");
hr=pGrid->QueryInterface(IID_IConnectionPointContainer, (void**)&pCnPtCnt);
if(SUCCEEDED(hr))
{
printf(" pGrid->QueryInterface(IID_IConnectionPointContainer) Succeeded!\n");
printf(" pCnPtCnt = %u\n",pCnPtCnt);
pCnPtCnt->Release();
}
else
printf(" pGrid->QueryInterface(IID_IConnectionPointContainer) Failed!\n");
}
printf(" Leaving DumpCOMMemory()\n");
}
void DestroyGrid(HWND hHost)
{
printf(" Entering DestroyGrid()\n");
IGrid* pGrid=(IGrid*)GetWindowLongPtr(hHost,0);
printf(" pGrid = %u\n",pGrid);
if(pGrid)
{
pGrid->Release();
SetWindowLongPtr(hHost,0,NULL);
}
printf(" Leaving DestroyGrid()\n");
}
long fnWndProc_OnCommand(lpWndEventArgs Wea)
{
switch(LOWORD(Wea->wParam))
{
case IDC_UNLOAD_GRID:
{
printf("\nEntering fnWndProc_OnCommand()\n");
DestroyGrid(Wea->hWnd);
printf("Leaving fnWndProc_OnCommand()\n");
break;
}
case IDC_DUMP_COM_MEMORY:
{
printf("\nEntering fnWndProc_OnCommand()\n");
DumpCOMMemory(Wea->hWnd);
printf("Leaving fnWndProc_OnCommand()\n");
break;
}
}
return 0;
}
long fnWndProc_OnPaint(lpWndEventArgs Wea)
{
PAINTSTRUCT ps;
int iBkMode;
HDC hDC;
hDC=BeginPaint(Wea->hWnd,&ps);
iBkMode=SetBkMode(hDC,TRANSPARENT);
TextOut(hDC,40,45,_T("The ActiveX Grid Control Will Eventually Go Here!"),49);
SetBkMode(hDC,iBkMode);
EndPaint(Wea->hWnd,&ps);
return 0;
}
long fnWndProc_OnDestroy(lpWndEventArgs Wea)
{
DestroyGrid(Wea->hWnd);
PostQuitMessage(0);
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
WindowsEventArguments Wea;
for(unsigned int i=0; i<dim(EventHandler); i++)
{
if(EventHandler[i].iMsg==msg)
{
Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
return (*EventHandler[i].fnPtr)(&Wea);
}
}
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
TCHAR szClass[]=_T("64 Bit Grid");
WNDCLASSEX wc;
HWND hWnd;
MSG Msg;
wc.lpszClassName=szClass, wc.lpfnWndProc=WndProc, wc.cbSize=sizeof(WNDCLASSEX);
wc.style=0, wc.cbClsExtra=0, wc.cbWndExtra=40;
wc.hInstance=hInstance, wc.hIcon=LoadIcon(NULL,IDI_APPLICATION), wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW, wc.lpszMenuName=NULL, wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
hWnd=CreateWindow(szClass,_T("64 Bit Grid ActiveX Control"),WS_OVERLAPPEDWINDOW,350,550,425,200,NULL,NULL,hInstance,NULL);
ShowWindow(hWnd,nCmdShow);
while(GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
} CoFreeUnusedLibraries(), CoUninitialize(), MessageBox(NULL,_T("... Before I Throw It Out!"),_T("Come And Get It ..."),MB_OK);
return (int)Msg.wParam;
}
continued ...