‘ObjPtr.bas
#Compile Exe 'While the interface declarations just
#Dim All 'below for I_X and I_Y can be deleted
Declare Sub pFn(dwPtr As Dword) 'and this program will still work, I...
Interface I_X : Inherit IUnknown '...thought for clarity sake it might be
Method Fx1() 'worthwhile to include them for the purpose
Method Fx2() 'of making the point that COM architecture
End Interface 'is based on the idea of seperating the...
Interface I_Y : Inherit IUnknown '...interface from the implementation of
Method Fy1() 'the interface. Here, I_X and I_Y are
Method Fy2() 'declared - but not implemented. They are
End Interface 'implemented in class CA, and the ObjPtr()
Class CA
Interface I_X : Inherit IUnknown '...function can be used to obtain the
Method Fx1() 'address of each interface's VTbl. Where
Print "Called Fx1()" 'PowerBASIC seems to differ somewhat from
End Method 'C++ is that in this situation in C++ the
'Sizeof(CA) would be 8 and those 8 bytes
Method Fx2() 'would be two contiguous VTable pointers.
Print "Called Fx2()" 'PowerBASIC will return two interface
End Method 'pointers also but they do not appear to
End Interface 'be contiguous. Below the I_X pVTbl is
'1280208 and the I_Y interface pointer is
Interface I_Y : Inherit IUnknown 'at 1280340 - not 1280212. Nonetheless
Method Fy1() 'they each can be used to obtain the
Print "Called Fy1()" 'address of each interface's VTable, and
End Method 'the function pointers held in the VTables
'can be used to call the interface
Method Fy2() 'functions. This probably isn't really
Print "Called Fy2()" 'recommended but this exercise at least
End Method 'shows the memory layout.
End Interface
End Class
Function PBMain() 'When one uses ObjPtr() on a variable of type
Local pVTbl As Dword Ptr 'interface one obtains a pointer to the base
Local VTbl As Dword Ptr 'address of the interface/vtable. In the case
Register i As Long 'here where each interface only has two functions
Local ifX As I_X 'the base address will point to a block of memory
Local ifY As I_Y 'occupying 20 bytes - 12 bytes for pointers to
'the three IUnknown functions of QueryInterface(),
Let ifX = Class "CA" 'AddRef(), and Release(), and 8 more bytes for
Let ifY = Class "CA" 'pointers to the two functions. In the output
Call ifX.Fx1() : Call ifX.Fx2() 'below pVTbl=1280208 represents a memory address
Call ifY.Fy1() : Call ifY.Fy2() 'where the number 4200192 is stored - and 4200192
'is the base address of the I_X Virtual Function
'Call methods using 'Table. If one sets another Dword Ptr variable
'interface/vtable 'such as VTbl to this base address in the VTable,
'pointers. 1st I_X 'one will be able to step through the VTable in
pVTbl=ObjPtr(ifX) 'four byte increments using base pointer
Print "pVTbl = " pVTbl 'subscript notation, i.e., @VTbl[i], and output
VTbl=@pVTbl[0] 'either the pointer address in the VTable -
Print "VTbl = " VTbl 'Varptr(@VTbl[i]), or the function/method address
Print:Print 'being pointed to - @VTbl[i].
Print " i Varptr(@VTbl[i]) @VTbl[i] Call Dword @VTbl[i]"
Print "========================================================================="
For i=0 To 4
If i<=2 Then
Print i, Varptr(@VTbl[i]), @VTbl[i]; " IUnknown Fns (better not call!)"
Else 'The reason we had better not try to
Print i, Varptr(@VTbl[i]), @VTbl[i],; 'call the IUnknown procedures in the same
Call DWord @VTbl[i] Using pFn(0) 'manner as we are calling the I_X and I_Y
End If 'methods that we have implemented is that
Next i 'we are using function pointers to call
Print:Print 'these functions, and to do that one needs
'a properly configured function pointer
'Then I_Y 'definition. At top our pFn Declare won't
pVTbl=ObjPtr(ifY) 'work for the IUnknown functions as their
Print "pVTbl = " pVTbl 'function signatures are quite different.
VTbl=@pVTbl[0] 'If you try to call them a crash will be
Print "VTbl = " VTbl 'quite imminent in your future.
Print
Print " i Varptr(@VTbl[i]) @VTbl[i] Call Dword @VTbl[i]"
Print "========================================================================="
For i=0 To 4
If i<=2 Then
Print i, Varptr(@VTbl[i]), @VTbl[i]; " IUnknown Fns (better not call!)"
Else 'One other issue observant readers may note
Print i, Varptr(@VTbl[i]), @VTbl[i],; 'is that the pFn Declare shows a DWord
Call DWord @VTbl[i] Using pFn(0) 'parameter in the declaration of the function
End If 'to be used in calling the interface functions,
Next i 'but the interface functions lack any function
Waitkey$ 'parameters. This is due to the fact that all
'OOP implementations pass a hidden class pointer
PBMain=0 'as the first argument of all implemented
End Function 'function calls. If I didn't use this dummy
'argument the program would likely crash after
'the function call when a non-existent parameter
'Called Fx1() 'would be popped off the stack.
'Called Fx2()
'Called Fy1()
'Called Fy2()
'
'pVTbl = 1280208
'VTbl = 4200192
'
' i Varptr(@VTbl[i]) @VTbl[i] Call Dword @VTbl[i]
'=========================================================================
' 0 4200192 4208481 IUnknown Fns (better not call!)
' 1 4200196 4208461 IUnknown Fns (better not call!)
' 2 4200200 4208604 IUnknown Fns (better not call!)
' 3 4200204 4198799 Called Fx1()
' 4 4200208 4198867 Called Fx2()
'
'pVTbl = 1280340
'VTbl = 4200152
'
' i Varptr(@VTbl[i]) @VTbl[i] Call Dword @VTbl[i]
'=========================================================================
' 0 4200152 4208481 IUnknown Fns (better not call!)
' 1 4200156 4208461 IUnknown Fns (better not call!)
' 2 4200160 4208604 IUnknown Fns (better not call!)
' 3 4200164 4198935 Called Fy1()
' 4 4200168 4199003 Called Fy2()
Server.cpp This file comprises the component’s dll housing and contains the only exported functions (4) and DllMain().
CA.cpp This file consists of the implementations of component CA, its Class Factory, and the two interfaces.
Registry.cpp This file contains boilerplate registry code for registering and unregistering the component
CA.h Declarations of class CA and class CAClassFactory
Ifunctions.h Guids and declarations of abstract base classes I_X and I_Y that are implemented in CA.cpp
Registry.h Declarations of RegisterServer() and UnregisterServer() so they can be referenced in Server.cpp
CA.def Module Definition File listing the four exported functions so the linker can export them.
//Server.cpp //Note that all the functions in this file are exported. That's what
#include <windows.h> //STDAPI in C mumbo jumbo stands for. Its a macro that expands to
#include <initguid.h> //extern "C" HRESULT __export __stdcall. The extern "C" part tells the
#include "CA.h" //C++ compiler not to mangle the function names so that other system
#include "Registry.h" //code can recognize these names in a GetProcAddress() call.
//Globals
HINSTANCE g_hModule = NULL; //Store dll instance handle
const char g_szFriendlyName[] = "Com Object CA"; //Store friendly name of component
const char g_szVerIndProgID[] = "ComObject.CA"; //Store Version Independent ProgID
const char g_szProgID[] = "ComObject.CA.1"; //Store Versioned Program ID.
long g_lObjs = 0; //count of outstanding objects
long g_lLocks = 0; //used to keep server from unloading
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
{
CAClassFactory* pCF=NULL; //DllGetClassObject() is critically important because
HRESULT hr; //it is this function that the operating system calls
//when a client attempts to instantiate an object
if(rclsid!=CLSID_CA) //contained within this dll through a CoCreateInstance()
return E_FAIL; //call, or, in the case of the PowerBASIC compiler when
pCF=new CAClassFactory; //it internally makes the call on the client's behalf.
if(pCF==0) //Whether PowerBASIC does it or we do it through a
return E_OUTOFMEMORY; //CoCreateInstance() call, the operating system locates
hr=pCF->QueryInterface(riid,ppv); //the path to the dll containing some specific CLSID
if(FAILED(hr)) //from the \CLSID\InProcServer32 key in the registry,
delete pCF; //does a LoadLibrary() and GetProcAddress() call on the
//dll, and then calls DllGetClassObject(). If the CLSID
return hr; //passed in matches CLSID_CA, then the C++ 'new' operator
} //is used to create an instance of CA's Class Factory (in...
STDAPI DllCanUnloadNow() //CA.cpp. Having done that it then checks to see if it
{ //can obtain an IUnknown or IClassFactory pointer on CA's
if(g_lObjs||g_lLocks) //Class Factory. If it can the reference count on the
return S_FALSE; //class factory is incremented. What happens next is
else //critical. COM internal system code now calls
return S_OK; //CAClassFactory::CreateInstance() and that is what
} //actually causes a new instance of the CA class to be...
STDAPI DllRegisterServer() //created - which creation causes memory allocations for
{ //both the class's VTable pointers and the VTables
return RegisterServer //themselves. Further, class CA implements the abstract
( //base classes I_X and I_Y, and pointers to the
g_hModule, //implementations of the pure virtual functions contained
CLSID_CA, //within these base classes are placed in the respective
g_szFriendlyName, //VTable of each interface. At this point we have an
g_szVerIndProgID, //object in memory which can be called to do work for us.
g_szProgID
); //DllRegisterServer() and DllUnregisterServer are for
} //adding or eliminating class ids, program ids, etc.,...
STDAPI DllUnregisterServer() //relating to the component from the registry. They are
{ //called by the RegSvr32.exe Windows component. For
return UnregisterServer //example, on this development machine CA.dll is in
( //C:\Code\VStudio\VC++6\Projects\COM\ComObjects\CA\Release\CA.dll
CLSID_CA, //I'd register it by doing this...
g_szVerIndProgID,
g_szProgID //RegSvr32 C:\Code\VStudio\VC++6\Projects\COM\ComObjects\CA\Release\CA.dll
);
} //Having done that I thankfully saw a message box telling...
BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved)
{
switch (reason) //me registration was successful. Registry code is pretty
{ //horrible and in this code was relegated to Registry.cpp
case DLL_PROCESS_ATTACH: //Note that that code needs the dll's instance handle
g_hModule=hInst; //and that is saved just at left in DllMain in a global
break; //variable just for that purpose.
case DLL_PROCESS_DETACH:
break;
}
return TRUE; //Returning FALSE causes the dll to not load.
}
//End Server.cpp
//CA.cpp //If you don't mind doing command line compiling with
#include <windows.h> //Microsoft C++ 6 you can use this command line...
#include <stdio.h> //
#include "CA.h" //cl /LD CA.cpp Server.cpp Registry.cpp UUID.lib Advapi32.lib Ole32.lib CA.def
CA::CA() //CA Constructor. The creation/instantiation of every
{ //object will cause a thread safe increment of the global
m_lRef=0; //count of CA objects created in the Server. The CA
InterlockedIncrement(&g_lObjs); //member variable m_lRef will count the number of outstanding
} //interface pointers handed out through QueryInterface().
CA::~CA()
{ //When a CA object is destroyed the count of objects is
InterlockedDecrement(&g_lObjs); //decremented by the thread safe InterlockedDecrement()
} //function.
HRESULT __stdcall CA::QueryInterface(REFIID riid, void** ppv)
{
*ppv=0; //Store initial null at address pointed to by ppv.
if(riid==IID_IUnknown) //If GUID of either IID_IUnknown or IID_IX
*ppv=(I_X*)this; //is passed 'in', cast this pointer to point
else if(riid==IID_I_X) //to the 1st of the two pVTbl pointers that constitute
*ppv=(I_X*)this; //the class. If client wants an IID_IY interface, return
else if(riid==IID_I_Y) //the 2nd pointer - which pointer points to the IY
*ppv=(I_Y*)this; //VTable. If *ppv has been set, then do an AddRef() and
if(*ppv) //return S_OK. Otherwise, return E_NOINTERFACE. The
{ //printf statement below will only execute if a non-
AddRef(); //supported interface IID was passed in through the
return S_OK; //REFIID parameter. This is how the Called CA::QueryInterface()
} //output was generated in the client app through a function
printf("Called CA::QueryInterface()\n"); //pointer call.
return(E_NOINTERFACE);
}
ULONG __stdcall CA::AddRef() //The member variable of class CA this->m_lRef
{ //counts interface pointers handed out by
printf("Called CA::AddRef()\n"); //QueryInterface(). InterlockedIncrement takes
return InterlockedIncrement(&m_lRef); //a pointer parameter so the address ( & ) of
} //this->m_lRef is passed in.
ULONG __stdcall CA::Release() //When you are done using an interface pointer
{ //Release() should be called on the pointer so
printf("Called CA::Release()\n"); //that the count of references to the object can
if(InterlockedDecrement(&m_lRef)==0) //be decremented. When the count reaches zero
{ //the class automatically deletes itself from
delete this; //memory., i.e., delete this;. However, the
return 0; //dll server may still reside in memory if the
} //global count of objects created is greater
//than zero, i.e., g_lObjs isn't zero..
return m_lRef;
}
HRESULT __stdcall CA::Fx1(int iNum) //These functions just output a
{ //message that they were called
printf("Called Fx1() : iNum = %u\n",iNum); //plus the value of the parameter
return S_OK; //passed in. Fx1() and Fx2() are
} //part of the I_X interface/vtable
HRESULT __stdcall CA::Fx2(int iNum) //and Fy1() and Fy2() part of the
{ //I_Y vtable, i.e., these respective
printf("Called Fx2() : iNum = %u\n",iNum); //vtables contain pointers to these
return S_OK; //functions.
}
HRESULT __stdcall CA::Fy1(int iNum)
{
printf("Called Fy1() : iNum = %u\n",iNum);
return S_OK;
}
HRESULT __stdcall CA::Fy2(int iNum)
{
printf("Called Fy2() : iNum = %u\n",iNum);
return S_OK;
}
CAClassFactory::CAClassFactory() //CAClassFactory Constructor. Four procedures are exported from
{ //a com server. They are DllGetClassObject(), DllCanUnloadNow()
m_lRef=0; //DllRegisterServer(), and DllUnregisterServer(). When a
} //client app calls CoCreateInstance() with the CLSID of a....
CAClassFactory::~CAClassFactory() //component that can be located in the registry, code internal
{ //to COM's implementation will do a LoadLibrary() and GetProcAddress()
//MathClassFactory Destructor //on DllGetProcAddress(). See my discussion in Server.cpp about this.
}
HRESULT __stdcall CAClassFactory::QueryInterface(REFIID riid, void** ppv)
{
*ppv=0;
if(riid==IID_IUnknown || riid==IID_IClassFactory) //In this component that doesn’t do very much,
*ppv=this; //the whole class factory thing seems kind of
if(*ppv) //superfluous. In other words, when COM Services
{ //calls DllGetClassObject(), why not just create
AddRef(); //the component CA directly with the C++ new
return S_OK; //operator instead of 1st creating a class
} //factory which in this case does absolutely
//nothing but create and destroy itself (and
return E_NOINTERFACE; //uses new to create CA in the process)? Well,
} //I suppose you can think of the class factory…
ULONG __stdcall CAClassFactory::AddRef() //concept something like the WM_CREATE message
{ //in Windows Api coding. In that context one
return InterlockedIncrement(&m_lRef); //usually creates the various user interface
} //elements, i.e., buttons, labels, etc., that…
ULONG __stdcall CAClassFactory::Release() //will appear on the window being created. That
{ //is how the class factory can be used. It does
if(InterlockedDecrement(&m_lRef)==0) //whatever it takes to uniquely create the object.
{
delete this;
return 0;
}
return m_lRef;
}
HRESULT __stdcall CAClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
{
HRESULT hr; //You won't find anywhere within the code here within any
CA* pCA; //of these project files where CAClassFactory::CreateInstance()
//is called to create a new instance of class CA. This
*ppvObj=0; //function gets called in a somewhat roundabout manner by
pCA=new CA; //the client app's CoCreateInstance() or CoGetClassObject()
if(pCA==0) //call. See my discussion in Server.cpp. First the Windows
return E_OUTOFMEMORY; //COM subsystem loads the dll from info it obtains on the
hr=pCA->QueryInterface(riid,ppvObj); //class from the registry. Then it calls DllGetClassObject(),
if(FAILED(hr)) //which is an exported function. Internal Windows code then
delete pCA; //creates a CAClassFactory instance and from that instance
//calls the CAClassFactory::CreateInstance() code you see
return hr; //here. And just left you see where a 'new' CA is created,
} //and a QueryInterface() done on it to see if riid is there.
HRESULT __stdcall CAClassFactory::LockServer(BOOL fLock)
{
if(fLock) //This function can be called to lock the dll in memory
InterlockedIncrement(&g_lLocks); //even if no outstanding instances of CA are present. This
else //works good in cases where you need to create and destroy
InterlockedDecrement(&g_lLocks); //objects without having to reload the dll between creation/
//destruction cycles.
return S_OK;
}
//End CA.cpp
//IFunctions.h
DEFINE_GUID(CLSID_CA,0x20000000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04);
DEFINE_GUID(IID_I_X,0x20000000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05);
DEFINE_GUID(IID_I_Y,0x20000000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06);
interface I_X : IUnknown //In C++ lingo an interface declaration such as this is known
{ //as an abstract base class. It can’t be instantiated directly
virtual HRESULT __stdcall Fx1(int)=0; //because it only contains what are known as pure virtual
virtual HRESULT __stdcall Fx2(int)=0; //functions (note the ‘=0’ part). What is actually going on
}; //here is the creation of a specific footprint in memory that…
interface I_Y : IUnknown //COM uses as its fundamental basis of operation. Let me
{ //elaborate. The C++ language was created long before COM and
virtual HRESULT __stdcall Fy1(int)=0; //most implementations of the language allocate a pointer
virtual HRESULT __stdcall Fy2(int)=0; //within a class for each abstract base class from which it
}; //inherits. If you look just below and left you’ll see that class
//End Ifunctions.h //CA inherits publiclly from interfaces I_X and I_Y. In C++…
//CA.h //the term interface means the same thing as a struct, which
#include "IFunctions.h" //in PowerBASIC means the same thing as a good old BASIC TYPE.
extern long g_lObjs; //This #define macro can be found in objbase.h. Further, in
extern long g_lLocks; //C++ structs are almost the same thing as classes except that
class CA : public I_X, public I_Y //all their members are public by default, i.e., visible in
{ //inheriting classes. That is the simple reason they are used.
public: //Now, when class CA is constructed by most C++ compilers a memory
CA(); //Constructor //allocation will be made for two pointers that point to other
virtual ~CA(); //Destructor //blocks of memory where pointers to the implemented functions
//Iunknown Functions //will be stored. This is the virtual function table. Our
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv); //client programs will show its
virtual ULONG __stdcall AddRef(); //exact structure in withering detail. Suffice it to say here
virtual ULONG __stdcall Release(); //though that the block of memory CA allocates for interface I_X
//I_X Interface Methods/Functions //(its virtual function table) will be 20 bytes, and the same
virtual HRESULT __stdcall Fx1(int); //for interface I_Y. This is because these interfaces, each of
virtual HRESULT __stdcall Fx2(int); //which only contains two functions, themselves inherit from
//I_ Interface Methods/Functions //another struct, i.e., IUnknown, which itself contains pointers
virtual HRESULT __stdcall Fy1(int); //to three functions – QueryInterface(), AddRef(), and Release().
virtual HRESULT __stdcall Fy2(int); //This is the absolute most fundamental rule in the COM standard
protected: //that all interfaces, i.e., structs, classes, virtual function
long m_lRef; //tables, whatever you want to call them – must have pointers to
}; //QueryInterface(), AddRef(), and Release() as their first three…
class CAClassFactory : public IClassFactory //members. You can easily see that
{ //to be true by just looking directly
public: //left at the two classes there that
CAClassFactory(); //contain these functions. Note that
virtual ~CAClassFactory(); //it may not look like these functions
public: //are at position one because they are
//IUnknown //not first in the declarations, but that
virtual HRESULT __stdcall QueryInterface(REFIID, void**); //is somewhat confusing because the order
virtual ULONG __stdcall AddRef(); //of declaration there isn’t the
virtual ULONG __stdcall Release(); //controlling factor, but rather the
//IclassFactory //controlling factor is the inheritance
virtual HRESULT __stdcall CreateInstance(LPUNKNOWN, REFIID, void**); //chain which forms the basis of the
virtual HRESULT __stdcall LockServer(BOOL); //class. At left CAClassFactory inherits
protected: //from IclassFactory which is a system
//Reference Count //defined class. And in the declaration
long m_lRef; //of IclassFactory it would be found that
}; //it itself inherits from IUnknown.
//End CA.h
HRESULT RegisterServer(HMODULE hModule, const CLSID& clsid, const char* szFriendlyName, const char* szVerIndProgID, const char* szProgID);
HRESULT UnregisterServer(const CLSID& clsid, const char* szVerIndProgID, const char* szProgID);
// Registry.cpp
#include <objbase.h>
const int CLSID_STRING_SIZE = 39;
BOOL setKeyAndValue(const char* szKey, const char* szSubkey, const char* szValue)
{
char szKeyBuf[1024];
long lResult;
HKEY hKey;
strcpy(szKeyBuf,szKey); //Copy keyname into buffer.
if(szSubkey!=NULL) // Add subkey name to buffer.
{
strcat(szKeyBuf, "\\") ;
strcat(szKeyBuf, szSubkey ) ;
}
//Create and open key and subkey.
lResult=RegCreateKeyEx(HKEY_CLASSES_ROOT,szKeyBuf,0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,NULL);
if(lResult!=ERROR_SUCCESS)
return FALSE ;
if(szValue!=NULL) //Set the Value.
RegSetValueEx(hKey,NULL,0,REG_SZ,(BYTE*)szValue,strlen(szValue)+1);
RegCloseKey(hKey);
return TRUE ;
}
void CLSIDtochar(const CLSID& clsid, char* szCLSID, int length) // Convert a CLSID to a char string.
{
LPOLESTR wszCLSID=NULL;
HRESULT hr;
hr=StringFromCLSID(clsid,&wszCLSID); // Get CLSID
if(SUCCEEDED(hr))
{
wcstombs(szCLSID, wszCLSID,length); // Covert from wide characters to non-wide.
CoTaskMemFree(wszCLSID); // Free memory.
}
}
LONG recursiveDeleteKey(HKEY hKeyParent, const char* lpszKeyChild) // Key to delete
{
char szBuffer[256];
DWORD dwSize=256 ;
HKEY hKeyChild;
FILETIME time;
LONG lRes;
lRes=RegOpenKeyEx(hKeyParent,lpszKeyChild,0,KEY_ALL_ACCESS,&hKeyChild); //Open the child.
if(lRes!=ERROR_SUCCESS)
return lRes;
while(RegEnumKeyEx(hKeyChild,0,szBuffer,&dwSize,NULL,NULL,NULL,&time)==S_OK) //Enumerate all of the decendents of this child.
{
lRes=recursiveDeleteKey(hKeyChild,szBuffer); //Delete the decendents of this child.
if(lRes!=ERROR_SUCCESS)
{
RegCloseKey(hKeyChild); //Cleanup before exiting.
return lRes;
}
dwSize=256;
}
RegCloseKey(hKeyChild); // Close the child.
return RegDeleteKey(hKeyParent,lpszKeyChild); //Delete this child.
}
HRESULT RegisterServer(HMODULE hModule,const CLSID& clsid,const char* szFriendlyName,const char* szVerIndProgID,const char* szProgID)
{
char szCLSID[CLSID_STRING_SIZE];
char szModule[512];
char szKey[64];
if(GetModuleFileName(hModule,szModule,sizeof(szModule)/sizeof(char)))
{
CLSIDtochar(clsid, szCLSID,sizeof(szCLSID)); //Get server location &Convert the CLSID into a char.
strcpy(szKey, "CLSID\\"); //Build the key CLSID\\{...}
strcat(szKey,szCLSID);
setKeyAndValue(szKey,NULL,szFriendlyName); //Add the CLSID to the registry.
setKeyAndValue(szKey, "InprocServer32", szModule); //Add the server filename subkey under the CLSID key.
setKeyAndValue(szKey, "ProgID", szProgID); //Add the ProgID subkey under the CLSID key.
setKeyAndValue(szKey,"VersionIndependentProgID",szVerIndProgID); //Add the version-independent ProgID subkey under CLSID key.
setKeyAndValue(szVerIndProgID, NULL, szFriendlyName); //Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT.
setKeyAndValue(szVerIndProgID, "CLSID", szCLSID);
setKeyAndValue(szVerIndProgID, "CurVer", szProgID);
setKeyAndValue(szProgID, NULL, szFriendlyName) ; //Add the versioned ProgID subkey under HKEY_CLASSES_ROOT.
setKeyAndValue(szProgID, "CLSID", szCLSID) ;
}
else
return E_FAIL;
return S_OK ;
}
HRESULT UnregisterServer(const CLSID& clsid, const char* szVerIndProgID, const char* szProgID)
{
char szCLSID[CLSID_STRING_SIZE];
char szKey[64];
LONG lResult;
CLSIDtochar(clsid, szCLSID, sizeof(szCLSID)); //Convert the CLSID into a char.
strcpy(szKey, "CLSID\\"); //Build the key CLSID\\{...}
strcat(szKey, szCLSID) ;
lResult=recursiveDeleteKey(HKEY_CLASSES_ROOT, szKey); //Delete the CLSID Key - CLSID\{...}
lResult=recursiveDeleteKey(HKEY_CLASSES_ROOT, szVerIndProgID); //Delete the version-independent ProgID Key.
lResult=recursiveDeleteKey(HKEY_CLASSES_ROOT, szProgID) ; //Delete the ProgID key.
return S_OK ;
}
//End Registry.cpp
;//CA.def
LIBRARY "CA"
DESCRIPTION "CA Windows Dynamic Link Library"
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
1) Create Dll Project In VStudio C++ 2008;
2) Add all CA files discussed here to project;
3) Open Properties Sheet for project CA and under
CA Property Pages \Configuration Properties \General \Project Defaults \Character Set...
Choose Not Set or Multi-Byte Character Set;
4) Under \Configuration Properties \Linker \Input \Module Definition File...
Set the Module Definition File to CA.def;
5) Use my RegistryAlt.cpp file instead of Registry.cpp. Rename it to Registry.cpp.
#Compile Exe "CAClient.exe"
#Dim All
#Include "Win32Api.inc"
%CLSCTX_INPROC_SERVER =&H1???
$IID_IUnknown =Guid$("{00000000-0000-0000-C000-000000000046}") 'Microsoft Defined
$CLSID_CA =Guid$("{20000000-0000-0000-0000-000000000004}") 'Class ID of Class CA, ie., Class A
$IID_IX =Guid$("{20000000-0000-0000-0000-000000000005}") 'Interface X
$IID_IY =Guid$("{20000000-0000-0000-0000-000000000006}") 'Interface Y
$IID_Junk =Guid$("{12345678-9876-5432-1012-345678901234}") 'Junk Number So QueryInterface() Fails
Declare Function ptrQueryInterface(Byval this As Dword, Byref iid As Guid, Byref pUnknown As Any) As Long
Declare Function ptrAddRef(Byval this As Dword) As Dword
Declare Function ptrRelease(Byval this As Dword) As Dword
Declare Function ptrFn(Byval this As Dword, ByVal iNum As Long) As Long
Interface I_X $IID_IX : Inherit IUnknown
Method Fx1(ByVal iNum As Long) As Long
Method Fx2(ByVal iNum As Long) As Long
End Interface
Interface I_Y $IID_IY : Inherit IUnknown
Method Fy1(ByVal iNum As Long) As Long
Method Fy2(ByVal iNum As Long) As Long
End Interface
Function PBMain() As Long
Local pVTbl,VTbl,pUnk As Dword Ptr
Local hResult As Long
Register i As Long
hResult=CoCreateInstance($CLSID_CA, Byval %NULL, %CLSCTX_INPROC_SERVER, $IID_IUnknown, pVTbl)
If SUCCEEDED(hResult) Then
Print "CoCreateInstance() For IUnknown On " ProgID$($CLSID_CA) " Succeeded!"
Print "pVTbl = " pVTbl
Print
Print "Varptr(@pVTbl[i]) Varptr(@VTbl[i]) @VTbl[i] Function Call With Call Dword"
Print "==============================================================================="
For i=0 To 1
VTbl=@pVTbl[i] 'Call...
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[0]) Tab(37)@VTbl[0] " ";
Call DWord @VTbl[0] Using ptrQueryInterface(Varptr(@pVTbl[i]), $IID_Junk, pUnk) To hResult 'QueryInterface()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[1]) Tab(37)@VTbl[1] " ";
Call DWord @VTbl[1] Using ptrAddRef(Varptr(@pVTbl[i])) To hResult 'AddRef()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[2]) Tab(37)@VTbl[2] " ";
Call DWord @VTbl[2] Using ptrRelease(Varptr(@pVTbl[i])) To hResult 'Release()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[3]) Tab(37)@VTbl[3] " ";
Call DWord @VTbl[3] Using ptrFn(Varptr(@pVTbl[i]),i) To hResult 'Fx1() / Fy1()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[4]) Tab(37)@VTbl[4] " ";
Call DWord @VTbl[4] Using ptrFn(Varptr(@pVTbl[i]),i) To hResult 'Fy1() / Fy2()
Print
Next i
Call DWord @VTbl[2] Using ptrRelease(pVTbl) To hResult
End If
Waitkey$
PBMain=0
End Function
'Called CA::AddRef()
'Called CA::AddRef()
'Called CA::Release()
'Called CA::AddRef()
'Called CA::Release()
'CoCreateInstance() For IUnknown On ComObject.CA.1 Succeeded!
'pVTbl = 9569824
'
'Varptr(@pVTbl[i]) Varptr(@VTbl[i]) @VTbl[i] Function Call With Call Dword
'===============================================================================
'9569824 268464412 268439632 Called CA::QueryInterface()
'9569824 268464416 268439776 Called CA::AddRef()
'9569824 268464420 268439808 Called CA::Release()
'9569824 268464424 268439888 Called Fx1() : iNum = 0
'9569824 268464428 268439920 Called Fx2() : iNum = 0
'
'9569828 268464392 268440384 Called CA::QueryInterface()
'9569828 268464396 268440400 Called CA::AddRef()
'9569828 268464400 268440416 Called CA::Release()
'9569828 268464404 268439952 Called Fy1() : iNum = 1
'9569828 268464408 268439984 Called Fy2() : iNum = 1
'
'Called CA::Release()
#Compile Exe "CAClient.exe"
#Dim All
#Include "Windows.inc"
#Include "ObjBase.inc"
%CLSCTX_INPROC_SERVER =&H1???
$IID_IUnknown =Guid$("{00000000-0000-0000-C000-000000000046}") 'Microsoft Defined
$CLSID_CA =Guid$("{20000000-0000-0000-0000-000000000004}") 'Class ID of Class CA, ie., Class A
$IID_IX =Guid$("{20000000-0000-0000-0000-000000000005}") 'Interface X
$IID_IY =Guid$("{20000000-0000-0000-0000-000000000006}") 'Interface Y
$IID_Junk =Guid$("{12345678-9876-5432-1012-345678901234}") 'Junk Number So QueryInterface() Fails
Declare Function ptrQueryInterface(Byval this As Dword, Byref iid As Guid, Byref pUnknown As IUnknown) As Long
Declare Function ptrAddRef(Byval this As Dword) As Dword
Declare Function ptrRelease(Byval this As Dword) As Dword
Declare Function ptrFn(Byval this As Dword, ByVal iNum As Long) As Long
Interface I_X $IID_IX : Inherit IUnknown
Method Fx1(ByVal iNum As Long) As Long
Method Fx2(ByVal iNum As Long) As Long
End Interface
Interface I_Y $IID_IY : Inherit IUnknown
Method Fy1(ByVal iNum As Long) As Long
Method Fy2(ByVal iNum As Long) As Long
End Interface
Function PBMain() As Long
Local pVTbl,VTbl As Dword Ptr
Local pUnk As IUnknown
Local hResult As Long
Register i As Long
hResult=CoCreateInstance($CLSID_CA, Nothing, %CLSCTX_INPROC_SERVER, $IID_IUnknown, pVTbl)
If SUCCEEDED(hResult) Then
Print "CoCreateInstance() For IUnknown On " ProgID$($CLSID_CA) " Succeeded!"
Print "pVTbl = " pVTbl
Print
Print "Varptr(@pVTbl[i]) Varptr(@VTbl[i]) @VTbl[i] Function Call With Call Dword"
Print "==============================================================================="
For i=0 To 1
VTbl=@pVTbl[i] 'Call...
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[0]) Tab(37)@VTbl[0] " ";
Call DWord @VTbl[0] Using ptrQueryInterface(Varptr(@pVTbl[i]), $IID_Junk, pUnk) To hResult 'QueryInterface()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[1]) Tab(37)@VTbl[1] " ";
Call DWord @VTbl[1] Using ptrAddRef(Varptr(@pVTbl[i])) To hResult 'AddRef()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[2]) Tab(37)@VTbl[2] " ";
Call DWord @VTbl[2] Using ptrRelease(Varptr(@pVTbl[i])) To hResult 'Release()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[3]) Tab(37)@VTbl[3] " ";
Call DWord @VTbl[3] Using ptrFn(Varptr(@pVTbl[i]),i) To hResult 'Fx1() / Fy1()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[4]) Tab(37)@VTbl[4] " ";
Call DWord @VTbl[4] Using ptrFn(Varptr(@pVTbl[i]),i) To hResult 'Fy1() / Fy2()
Print
Next i
Call DWord @VTbl[2] Using ptrRelease(pVTbl) To hResult
End If
Waitkey$
PBMain=0
End Function
'Called CA::AddRef()
'Called CA::AddRef()
'Called CA::Release()
'Called CA::AddRef()
'Called CA::Release()
'CoCreateInstance() For IUnknown On ComObject.CA.1 Succeeded!
'pVTbl = 9568672
'
'Varptr(@pVTbl[i]) Varptr(@VTbl[i]) @VTbl[i] Function Call With Call Dword
'===============================================================================
'9568672 268464492 268439920 Called CA::QueryInterface()
'9568672 268464496 268440064 Called CA::AddRef()
'9568672 268464500 268440096 Called CA::Release()
'9568672 268464504 268440160 Called Fx1() : iNum = 0
'9568672 268464508 268440192 Called Fx2() : iNum = 0
'
'9568676 268464472 268440672 Called CA::QueryInterface()
'9568676 268464476 268440688 Called CA::AddRef()
'9568676 268464480 268440704 Called CA::Release()
'9568676 268464484 268440224 Called Fy1() : iNum = 1
'9568676 268464488 268440256 Called Fy2() : iNum = 1
'
'Called CA::Release()
#include <objbase.h> //CAClient
#include <stdio.h>
const CLSID CLSID_CA ={0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}}; //Class ID of Class CA, ie., Class A
const IID IID_I_X ={0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}}; //Interface X
const IID IID_I_Y ={0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06}}; //Interface Y
const IID IID_Junk ={0x12345678,0x9876,0x5432,{0x12,0x34,0x56,0x78,0x98,0x76,0x54,0x32}}; //Junk Number So QueryInterface() Fails
HRESULT (__stdcall* ptrQueryInterface) (int, const IID&, void**); //these are C function pointers somewhat analogous to
ULONG (__stdcall* ptrAddRef) (int); //PowerBASIC’s Call Dword setup (but not as easy to
ULONG (__stdcall* ptrRelease) (int); //understand!!!!!).
void (__stdcall* pIFn) (int,int);
interface I_X : IUnknown
{
virtual HRESULT __stdcall Fx1(int)=0;
virtual HRESULT __stdcall Fx2(int)=0;
};
interface I_Y : IUnknown
{
virtual HRESULT __stdcall Fy1(int)=0;
virtual HRESULT __stdcall Fy2(int)=0;
};
int main(void)
{
IUnknown* pIUnk=NULL;
unsigned int* pVTbl=0;
unsigned int* VTbl=0;
unsigned int i=0;
HRESULT hr;
hr=CoInitialize(NULL);
if(SUCCEEDED(hr))
{
hr=CoCreateInstance(CLSID_CA,NULL,CLSCTX_INPROC_SERVER,IID_IUnknown,(void**)&pVTbl);
if(SUCCEEDED(hr))
{
puts("CoCreateInstance() For IUnknown Succeeded!");
printf("pVTbl = %u\n",pVTbl);
printf("\n");
printf("&pVTbl[i]\t&VTbl[i]\tVTbl[i]\t\tFunction Call Through Pointer\n");
printf("=============================================================================\n");
for(i=0;i<=1;i++)
{
VTbl=(unsigned int*)pVTbl[i]; //Call...
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[0],VTbl[0]);
ptrQueryInterface=(HRESULT(__stdcall*)(int, const IID&, void**)) VTbl[0];
ptrQueryInterface((int)&pVTbl[i],IID_Junk,(void**)&pIUnk); //QueryInterface()
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[1],VTbl[1]);
ptrAddRef=(ULONG(__stdcall*)(int)) VTbl[1];
ptrAddRef((int)&pVTbl[i]); //AddRef()
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[2],VTbl[2]);
ptrRelease=(ULONG(__stdcall*)(int)) VTbl[2];
ptrRelease((int)&pVTbl[i]); //Release()
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[3],VTbl[3]);
pIFn=(void(__stdcall*)(int,int)) VTbl[3];
pIFn((int)&pVTbl[i],i); //Fx1() / Fy1()
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[4],VTbl[4]);
pIFn=(void(__stdcall*)(int,int)) VTbl[4];
pIFn((int)&pVTbl[i],i); //Fx2() / Fy2()
printf("\n");
}
ptrRelease=(ULONG(__stdcall*)(int)) VTbl[2];
ptrRelease((int)&pVTbl[1]);
}
CoUninitialize();
getchar();
}
return 0;
}
/*
Called CA::AddRef()
Called CA::AddRef()
Called CA::Release()
Called CA::AddRef()
Called CA::Release()
CoCreateInstance() For IUnknown Succeeded!
pVTbl = 10355664
&pVTbl[i] &VTbl[i] VTbl[i] Function Call Through Pointer
=============================================================================
10355664 268464396 268439696 Called CA::QueryInterface()
10355664 268464400 268439840 Called CA::AddRef()
10355664 268464404 268439872 Called CA::Release()
10355664 268464408 268439936 Called Fx1() : iNum = 0
10355664 268464412 268439968 Called Fx2() : iNum = 0
10355668 268464376 268440448 Called CA::QueryInterface()
10355668 268464380 268440464 Called CA::AddRef()
10355668 268464384 268440480 Called CA::Release()
10355668 268464388 268440000 Called Fy1() : iNum = 1
10355668 268464392 268440032 Called Fy2() : iNum = 1
Called CA::Release()
*/
Type SomeType
A As Integer
B As Integer
C As Integer
End Type
Type Another
BasicInterface As SomeType
D As Integer
E As Integer
End Type
Class CA
Interface I_X : Inherit IUnknown '...function can be used to obtain the
Method Fx1() 'address of each interface's VTbl. Where
Print "Called Fx1()" 'PowerBASIC seems to differ somewhat from
End Method 'C++ is that in this situation in C++ the
'Sizeof(CA) would be 8 and those 8 bytes
Method Fx2() 'would be two contiguous VTable pointers.
Print "Called Fx2()" 'PowerBASIC will return two interface
End Method 'pointers also but they do not appear to
End Interface 'be contiguous. Below the I_X pVTbl is
'1280208 and the I_Y interface pointer is
Interface I_Y : Inherit IUnknown 'at 1280340 - not 1280212. Nontheless
Method Fy1() 'they each can be used to obtain the
Print "Called Fy1()" 'address of each interface's VTable, and
End Method 'the function pointers held in the VTables
'can be used to call the interface
Method Fy2() 'functions. This probably isn't really
Print "Called Fy2()" 'recommended but this exercise at least
End Method 'shows the memory layout.
End Interface
End Class
interface I_X : IUnknown
{
virtual HRESULT __stdcall Fx1(int)=0;
virtual HRESULT __stdcall Fx2(int)=0;
};
interface I_Y : IUnknown
{
virtual HRESULT __stdcall Fy1(int)=0;
virtual HRESULT __stdcall Fy2(int)=0;
};
PowerBASIC: Interface I_X : Inherit IUnknown
C++: interface I_X : IUnknown
Type IUnknown
QueryInterface As Dword Ptr
AddRef As Dword Ptr
Release As Dword Ptr
End Type
VTbl=@pVTbl ‘Get the base address of the virtual function table stored in a Vtable pointer
For i=0 To 4
Call Dword @VTbl[i] Using SomeModelFunctionDefinition To hResult
Next I
CA::CA()
{
m_lRef=0;
InterlockedIncrement(&g_lObjs);
}
CA::CA()
{
m_lRef=0;
InterlockedIncrement(&g_lObjs);
printf("sizeof(CA) = %u\n",sizeof(CA));
printf("this = %u\n",this);
}
#include <objbase.h> //CAClient5
#include <stdio.h> //IID_IClassFactory={00000001-0000-0000-C000-000000000046};
const CLSID CLSID_CA ={0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}}; //Class ID of Class CA, ie., Class A
const IID IID_I_X ={0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}}; //Interface X
const IID IID_I_Y ={0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06}}; //Interface Y
const IID IID_Junk ={0x12345678,0x9876,0x5432,{0x12,0x34,0x56,0x78,0x98,0x76,0x54,0x32}}; //Junk Number So QueryInterface() Fails
HRESULT (__stdcall* ptrQueryInterface) (int, const IID&, void**);
ULONG (__stdcall* ptrAddRef) (int);
ULONG (__stdcall* ptrRelease) (int);
void (__stdcall* pIFn) (int,int);
interface I_X : IUnknown
{
virtual HRESULT __stdcall Fx1(int)=0;
virtual HRESULT __stdcall Fx2(int)=0;
};
interface I_Y : IUnknown
{
virtual HRESULT __stdcall Fy1(int)=0;
virtual HRESULT __stdcall Fy2(int)=0;
};
int main(void)
{
IUnknown* pIUnk=NULL;
IClassFactory* pCF=NULL;
unsigned int* pVTbl=0;
unsigned int* VTbl=0;
CoInitialize(NULL);
CoGetClassObject(CLSID_CA,CLSCTX_INPROC_SERVER,NULL,IID_IClassFactory,(void**)&pCF);
pCF->CreateInstance(NULL,IID_IUnknown,(void**)&pVTbl);
pCF->Release();
printf("pVTbl = %u\n",pVTbl);
printf("\n");
printf("&pVTbl[i]\t&VTbl[i]\tVTbl[i]\t\tFunction Call Through Pointer\n");
printf("=============================================================================\n");
for(unsigned int i=0;i<=1;i++)
{
VTbl=(unsigned int*)pVTbl[i]; //Call...
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[0],VTbl[0]);
ptrQueryInterface=(HRESULT(__stdcall*)(int, const IID&, void**)) VTbl[0];
ptrQueryInterface((int)&pVTbl[i],IID_Junk,(void**)&pIUnk); //QueryInterface()
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[1],VTbl[1]);
ptrAddRef=(ULONG(__stdcall*)(int)) VTbl[1];
ptrAddRef((int)&pVTbl[i]); //AddRef()
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[2],VTbl[2]);
ptrRelease=(ULONG(__stdcall*)(int)) VTbl[2];
ptrRelease((int)&pVTbl[i]); //Release()
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[3],VTbl[3]);
pIFn=(void(__stdcall*)(int,int)) VTbl[3];
pIFn((int)&pVTbl[i],i); //Fx1() / Fy1()
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[4],VTbl[4]);
pIFn=(void(__stdcall*)(int,int)) VTbl[4];
pIFn((int)&pVTbl[i],i); //Fx2() / Fy2()
printf("\n");
}
ptrRelease=(ULONG(__stdcall*)(int)) VTbl[2];
ptrRelease((int)&pVTbl[0]);
CoUninitialize();
getchar();
return 0;
}
/*
Called CA::AddRef()
pVTbl = 10355664
&pVTbl[i] &VTbl[i] VTbl[i] Function Call Through Pointer
=============================================================================
10355664 268464396 268439696 Called CA::QueryInterface()
10355664 268464400 268439840 Called CA::AddRef()
10355664 268464404 268439872 Called CA::Release()
10355664 268464408 268439936 Called Fx1() : iNum = 0
10355664 268464412 268439968 Called Fx2() : iNum = 0
10355668 268464376 268440448 Called CA::QueryInterface()
10355668 268464380 268440464 Called CA::AddRef()
10355668 268464384 268440480 Called CA::Release()
10355668 268464388 268440000 Called Fy1() : iNum = 1
10355668 268464392 268440032 Called Fy2() : iNum = 1
Called CA::Release()
*/
STDAPI CoGetClassObject
(
REFCLSID rclsid, //CLSID associated with the class object
DWORD dwClsContext, //Context for running executable code
COSERVERINFO* pServerInfo, //Pointer to machine on which the object is to be instantiated
REFIID riid, //Reference to the identifier of the interface
LPVOID* ppv //Address of output variable that receives the interface pointer requested in riid
);
#Compile Exe "CAClient.exe"
#Dim All
#Include "Win32Api.inc"
#Include "ObjBase.inc"
%CLSCTX_INPROC_SERVER =&H1???
$IID_IUnknown =Guid$("{00000000-0000-0000-C000-000000000046}") 'Microsoft Defined - IUnknown
$IID_IClassFactory =Guid$("{00000001-0000-0000-C000-000000000046}") 'Microsoft Defined - IClassFactory
$CLSID_CA =Guid$("{20000000-0000-0000-0000-000000000004}") 'Class ID of Class CA, ie., Class A
$IID_IX =Guid$("{20000000-0000-0000-0000-000000000005}") 'Interface X
$IID_IY =Guid$("{20000000-0000-0000-0000-000000000006}") 'Interface Y
$IID_Junk =Guid$("{12345678-9876-5432-1012-345678901234}") 'Junk Number So QueryInterface() Fails
Declare Function ptrCreateInstance (Byval this As Dword, Byval pUnknown As DWord, Byref iid As Guid, Byref pVTbl As Any) As Long
Declare Function ptrQueryInterface (Byval this As Dword, Byref iid As Guid, Byref pUnknown As Any) As Long
Declare Function ptrAddRef (Byval this As Dword) As Dword
Declare Function ptrRelease (Byval this As Dword) As Dword
Declare Function ptrFn (Byval this As Dword, ByVal iNum As Long) As Long
Interface I_X $IID_IX : Inherit IUnknown
Method Fx1(ByVal iNum As Long) As Long
Method Fx2(ByVal iNum As Long) As Long
End Interface
Interface I_Y $IID_IY : Inherit IUnknown
Method Fy1(ByVal iNum As Long) As Long
Method Fy2(ByVal iNum As Long) As Long
End Interface
Function PBMain() As Long
Local pVTbl,VTbl,pCF,CFVTbl,pUnk As Dword Ptr
Local hResult As Long
Register i As Long
hResult=CoGetClassObject($CLSID_CA, %CLSCTX_INPROC_SERVER, Byval %NULL, $IID_IClassFactory, pCF)
If SUCCEEDED(hResult) Then
Print "CoGetClassObject() Succeeded!"
Print "pCF = " pCF
CFVTbl=@pCF[0] '@CFVTbl[3] is the address of CAClassFactory::CreateInstance(...)
Call Dword @CFVTbl[3] Using ptrCreateInstance(pCF,pUnk,$IID_IUnknown,pVTbl) To hResult
If SUCCEEDED(hResult) Then 'If we get inside this If the class factory has alreadt created class CA
Print "pCF->CreateInstance() Succeeded!" 'so we can do a pCF->Release(). Release() is in slot #2
Call DWord @CFVTbl[2] Using ptrRelease(pCF) To hResult 'Release() CAClassFactory
Print "pVTbl = " pVTbl 'We now have the same VTbl Ptr ( pVTbl ) we originally got from
Print 'CoCreateInstance(), so go to town.....
Print "Varptr(@pVTbl[i]) Varptr(@VTbl[i]) @VTbl[i] Function Call With Call Dword"
Print "==============================================================================="
For i=0 To 1
VTbl=@pVTbl[i] 'Call...
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[0]) Tab(37)@VTbl[0] " ";
Call DWord @VTbl[0] Using ptrQueryInterface(Varptr(@pVTbl[i]), $IID_Junk, pUnk) To hResult 'QueryInterface()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[1]) Tab(37)@VTbl[1] " ";
Call DWord @VTbl[1] Using ptrAddRef(Varptr(@pVTbl[i])) To hResult 'AddRef()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[2]) Tab(37)@VTbl[2] " ";
Call DWord @VTbl[2] Using ptrRelease(Varptr(@pVTbl[i])) To hResult 'Release()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[3]) Tab(37)@VTbl[3] " ";
Call DWord @VTbl[3] Using ptrFn(Varptr(@pVTbl[i]),i) To hResult 'Fx1() / Fy1()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[4]) Tab(37)@VTbl[4] " ";
Call DWord @VTbl[4] Using ptrFn(Varptr(@pVTbl[i]),i) To hResult 'Fy1() / Fy2()
Print
Next i
Call DWord @VTbl[2] Using ptrRelease(pVTbl) To hResult
End If
End If
Waitkey$
PBMain=0
End Function
'Called CAClassFactory::AddRef()
'Called CAClassFactory::AddRef()
'Called CAClassFactory::Release()
'Called CAClassFactory::AddRef()
'Called CAClassFactory::Release()
'CoGetClassObject() Succeeded!
'pCF = 14484944
'this = 14484880
'sizeof(CA) = 12
'Called CA::AddRef()
'pCF->CreateInstance() Succeeded!
'Called CAClassFactory::Release()
'pVTbl = 14484880
'
'Varptr(@pVTbl[i]) Varptr(@VTbl[i]) @VTbl[i] Function Call With Call Dword
'===============================================================================
'14484880 14381324 14356624 Called CA::QueryInterface()
'14484880 14381328 14356768 Called CA::AddRef()
'14484880 14381332 14356800 Called CA::Release()
'14484880 14381336 14356864 Called Fx1() : iNum = 0
'14484880 14381340 14356896 Called Fx2() : iNum = 0
'
'14484884 14381304 14357392 Called CA::QueryInterface()
'14484884 14381308 14357408 Called CA::AddRef()
'14484884 14381312 14357424 Called CA::Release()
'14484884 14381316 14356928 Called Fy1() : iNum = 1
'14484884 14381320 14356960 Called Fy2() : iNum = 1
'
'Called CA::Release()
#Compile Exe "CAClient.exe"
#Dim All
#Include "Win32Api.inc"
'#Include "ObjBase.inc"
$CLSID_CA =Guid$("{20000000-0000-0000-0000-000000000004}") 'Class ID of Class CA, ie., Class A
$IID_IX =Guid$("{20000000-0000-0000-0000-000000000005}") 'Interface X
$IID_IY =Guid$("{20000000-0000-0000-0000-000000000006}") 'Interface Y
Interface I_X $IID_IX : Inherit IUnknown
Method Fx1(ByVal iNum As Long) As Long
Method Fx2(ByVal iNum As Long) As Long
End Interface
Interface I_Y $IID_IY : Inherit IUnknown
Method Fy1(ByVal iNum As Long) As Long
Method Fy2(ByVal iNum As Long) As Long
End Interface
Function PBMain() As Long 'Important Note! I had originally made
Local hResult As Long 'a mistake in my original posting of this
Local ix As I_X 'little program that Jose caught! In
Local iy As I_Y 'order to call the I_Y interface functions...
ix=NewCom Clsid $CLSID_CA 'I had done this > iy=NewCom("ComObject.CA")
hResult=ix.Fx1(25) 'That isn't necessary! PowerBASIC does,
hResult=ix.Fx2(50) 'behind the scenes, so to speak, a
iy=ix ''iy=NewCom("ComObject.CA") 'QueryInterface() on I_Y using I_X exactly
hResult=iy.Fy1(75) 'as I had done in the C++ program below!
hResult=iy.Fy2(100) 'This is actually one of the fundamental
Set ix = Nothing 'rules of COM. If you have an interface
Set iy = Nothing 'on an object you should be able to get
Waitkey$ 'any other interface (if you have its IID).
PBMain=0
End Function
'===Output==================
'Called CA::AddRef()
'Called CA::AddRef()
'Called CA::Release()
'Called CA::AddRef()
'Called CA::Release()
'Called Fx1() : iNum = 25
'Called Fx2() : iNum = 50
'Called CA::AddRef()
'Called Fy1() : iNum = 75
'Called Fy2() : iNum = 100
'Called CA::Release()
'Called CA::Release()
#include <windows.h> //CAClient6
#include <stdio.h>
static const CLSID CLSID_CA = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}};
static const IID IID_I_X = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}};
static const IID IID_I_Y = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06}};
interface I_X : IUnknown
{
virtual HRESULT __stdcall Fx1(int)=0;
virtual HRESULT __stdcall Fx2(int)=0;
};
interface I_Y : IUnknown
{
virtual HRESULT __stdcall Fy1(int)=0;
virtual HRESULT __stdcall Fy2(int)=0;
};
int main(void)
{
I_X* pIX=NULL;
I_Y* pIY=NULL;
HRESULT hr;
hr=CoInitialize(NULL);
hr=CoCreateInstance(CLSID_CA, NULL, CLSCTX_INPROC_SERVER, IID_I_X, (void**)&pIX);
hr=pIX->Fx1(25);
hr=pIX->Fx2(50);
hr=pIX->QueryInterface(IID_I_Y,(void**)&pIY);
hr=pIY->Fy1(75);
hr=pIY->Fy2(100);
hr=pIX->Release();
hr=pIY->Release();
CoUninitialize();
return 0;
}
/*===Output=================
sizeof(CA) = 12
this = 10355696
Called CA::AddRef()
Called CA::AddRef()
Called CA::Release()
Called CA::AddRef()
Called CA::Release()
Called Fx1() : iNum = 25
Called Fx2() : iNum = 50
Called CA::AddRef()
Called Fy1() : iNum = 75
Called Fy2() : iNum = 100
Called CA::Release()
Called CA::Release()
*/
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv)
{
if(iid==IID_IX)
*ppv=static_cast<IX*>(this);
else if(iid==IID_IY)
*ppv=static_cast<IY*>(this);
else if(iid==IID_IUnknown)
*ppv=static_cast<IX*>(this);
else
{
*ppv=NULL;
return E_NOINTERFACE;
}
static_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
' ========================================================================================
' Loads the specified library and creates an instance of an object.
' If it succeeds, returns a reference to the requested interface; otherwise, it returns null.
' Note: Do not use FreeLibrary to unload the library once you have got a valid reference
' to an interface or your application will GPF. Before calling FreeLibrary, all the
' interface references must be released. If you don't need to unload the library until
' the application ends, then you don't need to call FreeLibrary because PB calls
' CoUninitialize under the hood, that closes the COM library on the current thread,
' unloads all DLLs loaded by the thread, frees any other resources that the thread
' maintains, and forces all RPC connections on the thread to close.
' ========================================================================================
FUNCTION CreateInstanceFromDll ( _
BYVAL strLibName AS STRING _ ' // [in] Library name and path
, BYREF rclsid AS GUID _ ' // [in] CLSID that will associate the correct data and code
, BYREF riid AS GUID _ ' // [in] IID of the interface to be used to communicate with the newly created objec
, OPTIONAL BYVAL strLicKey AS STRING _ ' // [in] License key (ansi string)
) AS IUnknown ' // [out] The interface pointer requested in riid
LOCAL hr AS LONG ' // HRESULT
LOCAL hLib AS DWORD ' // Library handle
LOCAL pProc AS DWORD ' // Procedure address
LOCAL pIClassFactory AS IClassFactory ' // IClassFactory interface
LOCAL pIClassFactory2 AS IClassFactory2 ' // IClassFactory2 interface
LOCAL ppv AS IUnknown ' // The requested interface pointer
' // See if the library is already loaded in the address space
hLib = GetModuleHandle(BYCOPY strLibName)
' // If it is not loaded, load it
IF hLib = %NULL THEN hLib = LoadLibrary(BYCOPY strLibName)
' // If it fails, abort
IF ISFALSE hLib THEN EXIT FUNCTION
' // Retrieve the address of the exported function DllGetClassObject
pProc = GetProcAddress(hLib, "DllGetClassObject")
IF ISFALSE pProc THEN
FreeLibrary hLib
EXIT FUNCTION
END IF
IF LEN(strLicKey) = 0 THEN
' // Request a reference to the IClassFactory interface
CALL DWORD pProc USING DllGetClassObject(rclsid, $IID_IClassFactory, pIClassFactory) TO hr
IF hr <> %S_OK THEN
FreeLibrary hLib
EXIT FUNCTION
END IF
' // Create an instance of the server or control
hr = pIClassFactory.CreateInstance(%NULL, riid, BYVAL VARPTR(ppv))
IF hr <> %S_OK THEN EXIT FUNCTION
ELSE
' // Request a reference to the IClassFactory2 interface
CALL DWORD pProc USING DllGetClassObject(rclsid, $IID_IClassFactory2, pIClassFactory2) TO hr
IF hr <> %S_OK THEN
FreeLibrary hLib
EXIT FUNCTION
END IF
' // Create a licensed instance of the server or control
strLicKey = UCODE$(strLicKey)
hr = pIClassFactory2.CreateInstanceLic(NOTHING, NOTHING, riid, strLicKey, ppv)
IF hr <> %S_OK THEN EXIT FUNCTION
END IF
FUNCTION = ppv
END FUNCTION
//CAClient3.cpp
#include <windows.h> //CAClient
#include <stdio.h> //IID_IClassFactory={00000001-0000-0000-C000-000000000046};
const CLSID CLSID_CA ={0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}}; //Class ID of Class CA, ie., Class A
const IID IID_I_X ={0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}}; //Interface X
const IID IID_I_Y ={0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06}}; //Interface Y
const IID IID_Junk ={0x12345678,0x9876,0x5432,{0x12,0x34,0x56,0x78,0x98,0x76,0x54,0x32}}; //Junk Number So QueryInterface() Fails
HRESULT (__stdcall* ptrDllGetClassObject) (const CLSID&, const IID&, void**);
HRESULT (__stdcall* ptrQueryInterface) (int, const IID&, void**);
ULONG (__stdcall* ptrAddRef) (int);
ULONG (__stdcall* ptrRelease) (int);
void (__stdcall* pIFn) (int,int);
interface I_X : IUnknown
{
virtual HRESULT __stdcall Fx1(int)=0;
virtual HRESULT __stdcall Fx2(int)=0;
};
interface I_Y : IUnknown
{
virtual HRESULT __stdcall Fy1(int)=0;
virtual HRESULT __stdcall Fy2(int)=0;
};
int main(void)
{
IClassFactory* pCF=NULL;
HMODULE hDll=NULL;
BOOL blnFree =FALSE;
IUnknown* pIUnk=NULL;
unsigned int* pVTbl=0;
unsigned int* VTbl=0;
HRESULT hr;
hDll=LoadLibrary("C:\\Code\\VStudio\\VC++6\\Projects\\COM\\ComObjects\\CA\\Release\\CA.dll");
printf("hDll=%u\n",hDll);
if(hDll)
{
ptrDllGetClassObject=(HRESULT (__stdcall*)(REFCLSID, REFIID, void**))GetProcAddress(hDll,"DllGetClassObject");
printf("ptrDllGetClassObject = %u\n",ptrDllGetClassObject);
hr=ptrDllGetClassObject(CLSID_CA,IID_IClassFactory,(void**)&pCF);
if(SUCCEEDED(hr))
{
puts("Worked!");
pCF->CreateInstance(NULL,IID_IUnknown,(void**)&pVTbl);
pCF->Release();
printf("pVTbl = %u\n",pVTbl);
printf("\n");
printf("&pVTbl[i]\t&VTbl[i]\tVTbl[i]\t\tFunction Call Through Pointer\n");
printf("=============================================================================\n");
for(unsigned int i=0;i<=1;i++)
{
VTbl=(unsigned int*)pVTbl[i]; //Call...
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[0],VTbl[0]);
ptrQueryInterface=(HRESULT(__stdcall*)(int, const IID&, void**)) VTbl[0];
ptrQueryInterface((int)&pVTbl[i],IID_Junk,(void**)&pIUnk); //QueryInterface()
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[1],VTbl[1]);
ptrAddRef=(ULONG(__stdcall*)(int)) VTbl[1];
ptrAddRef((int)&pVTbl[i]); //AddRef()
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[2],VTbl[2]);
ptrRelease=(ULONG(__stdcall*)(int)) VTbl[2];
ptrRelease((int)&pVTbl[i]); //Release()
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[3],VTbl[3]);
pIFn=(void(__stdcall*)(int,int)) VTbl[3];
pIFn((int)&pVTbl[i],i); //Fx1() / Fy1()
printf("%u\t%u\t%u\t",&pVTbl[i],&VTbl[4],VTbl[4]);
pIFn=(void(__stdcall*)(int,int)) VTbl[4];
pIFn((int)&pVTbl[i],i); //Fx2() / Fy2()
printf("\n");
}
ptrRelease=(ULONG(__stdcall*)(int)) VTbl[2];
ptrRelease((int)&pVTbl[0]);
getchar();
}
blnFree=FreeLibrary(hDll);
printf("blnFree=%u\n",blnFree);
}
return 0;
}
#Compile Exe "CAClient3.exe"
#Dim All
#Include "Win32Api.inc"
#Include "ObjBase.inc"
%CLSCTX_INPROC_SERVER =&H1???
$IID_IUnknown =Guid$("{00000000-0000-0000-C000-000000000046}") 'Microsoft Defined - IUnknown
$IID_IClassFactory =Guid$("{00000001-0000-0000-C000-000000000046}") 'Microsoft Defined - IClassFactory
$CLSID_CA =Guid$("{20000000-0000-0000-0000-000000000004}") 'Class ID of Class CA, ie., Class A
$IID_IX =Guid$("{20000000-0000-0000-0000-000000000005}") 'Interface X
$IID_IY =Guid$("{20000000-0000-0000-0000-000000000006}") 'Interface Y
$IID_Junk =Guid$("{12345678-9876-5432-1012-345678901234}") 'Junk Number So QueryInterface() Fails
Declare Function DllGetClassObject (Byref Clsid As Guid, Byref iid As Guid, Byref pIUnknown As Any) As Long
Declare Function ptrCreateInstance (Byval this As Dword, Byref pUnknown As Any, Byref iid As Guid, Byref pVTbl As Any) As Long
Declare Function ptrQueryInterface (Byval this As Dword, Byref iid As Guid, Byref pUnknown As Any) As Long
Declare Function ptrAddRef (Byval this As Dword) As Dword
Declare Function ptrRelease (Byval this As Dword) As Dword
Declare Function ptrFn (Byval this As Dword, ByVal iNum As Long) As Long
Interface I_X $IID_IX : Inherit IUnknown
Method Fx1(ByVal iNum As Long) As Long
Method Fx2(ByVal iNum As Long) As Long
End Interface
Interface I_Y $IID_IY : Inherit IUnknown
Method Fy1(ByVal iNum As Long) As Long
Method Fy2(ByVal iNum As Long) As Long
End Interface
Function PBMain() As Long
Local pVTbl,VTbl,pCF,CFVTbl,pUnk,pDllProc As Dword Ptr
Local pSerInfo As COSERVERINFO
Local hResult As Long
Local hDll As DWord
Register i As Long
hDll=LoadLibrary("C:\Code\VStudio\VC++6\Projects\COM\ComObjects\CA\Release\CA.dll") 'Change This Line!!!!
'hDll=LoadLibrary("C:\Code\DevC++\CA\CA.dll")
If hDll Then
Print "hDll = " hDll
pDllProc=GetProcAddress(hDll,"DllGetClassObject")
If pDllProc Then
Print "pDllProc = " pDllProc
Call DWord pDllProc Using DllGetClassObject($CLSID_CA, $IID_IClassFactory, pCF) To hResult
'hResult=CoGetClassObject($CLSID_CA, %CLSCTX_INPROC_SERVER, pSerInfo, $IID_IClassFactory, pCF)
If SUCCEEDED(hResult) Then
Print "Successfully Loaded CA.dll And Succeeded In DllGetClassObject() Call!"
Print "pCF = " pCF
CFVTbl=@pCF[0] '@CFVTbl[3] is the address of CAClassFactory::CreateInstance(...)
Call Dword @CFVTbl[3] Using ptrCreateInstance(pCF,pUnk,$IID_IUnknown,pVTbl) To hResult
If SUCCEEDED(hResult) Then 'If we get inside this If the class factory has alreadt created class CA
Print "pCF->CreateInstance() Succeeded!" 'so we can do a pCF->Release(). Release() is in slot #2
Call DWord @CFVTbl[2] Using ptrRelease(pCF) To hResult 'Release() CAClassFactory
Print "pVTbl = " pVTbl 'We now have the same VTbl Ptr ( pVTbl ) we originally got from
Print 'CoCreateInstance(), so go to town.....
Print "Varptr(@pVTbl[i]) Varptr(@VTbl[i]) @VTbl[i] Function Call With Call Dword"
Print "==============================================================================="
For i=0 To 1
VTbl=@pVTbl[i] 'Call...
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[0]) Tab(37)@VTbl[0] " ";
Call DWord @VTbl[0] Using ptrQueryInterface(Varptr(@pVTbl[i]), $IID_Junk, pUnk) To hResult 'QueryInterface()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[1]) Tab(37)@VTbl[1] " ";
Call DWord @VTbl[1] Using ptrAddRef(Varptr(@pVTbl[i])) To hResult 'AddRef()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[2]) Tab(37)@VTbl[2] " ";
Call DWord @VTbl[2] Using ptrRelease(Varptr(@pVTbl[i])) To hResult 'Release()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[3]) Tab(37)@VTbl[3] " ";
Call DWord @VTbl[3] Using ptrFn(Varptr(@pVTbl[i]),i) To hResult 'Fx1() / Fy1()
Print LTrim$(Str$(Varptr(@pVTbl[i]))) Tab(19)Varptr(@VTbl[4]) Tab(37)@VTbl[4] " ";
Call DWord @VTbl[4] Using ptrFn(Varptr(@pVTbl[i]),i) To hResult 'Fy1() / Fy2()
Print
Next i
Call DWord @VTbl[2] Using ptrRelease(pVTbl) To hResult
End If
End If
FreeLibrary(hDll)
End If
End If
Waitkey$
PBMain=0
End Function
'hDll = 268435456
'pDllProc = 268441664
'
'Entering DllGetClassObject()
'Called CAClassFactory Constructor!
'Called CAClassFactory::QueryInterface()
'Called CAClassFactory::AddRef()
'Leaving DllGetClassObject()
'
'Successfully Loaded CA.dll And Succeeded In DllGetClassObject() Call!
'pCF = 8521248
'Called CAClassFactory::CreateInstance()
'this = 8521216
'sizeof(CA) = 12
'Called CA::AddRef()
'pCF->CreateInstance() Succeeded!
'Called CAClassFactory::Release()
'Called CAClassFactory Destructor!
'pVTbl = 8521216
'
'Varptr(@pVTbl[i]) Varptr(@VTbl[i]) @VTbl[i] Function Call With Call Dword
'===============================================================================
'8521216 268464396 268439696 Called CA::QueryInterface()
'8521216 268464400 268439840 Called CA::AddRef()
'8521216 268464404 268439872 Called CA::Release()
'8521216 268464408 268439936 Called Fx1() : iNum = 0
'8521216 268464412 268439968 Called Fx2() : iNum = 0
'
'8521220 268464376 268440528 Called CA::QueryInterface()
'8521220 268464380 268440544 Called CA::AddRef()
'8521220 268464384 268440560 Called CA::Release()
'8521220 268464388 268440000 Called Fy1() : iNum = 1
'8521220 268464392 268440032 Called Fy2() : iNum = 1
'
'Called CA::Release()
#include <windows.h> //CAClient6
#include <stdio.h>
static const CLSID CLSID_CA = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}};
static const IID IID_I_X = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}};
static const IID IID_I_Y = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06}};
HRESULT (__stdcall* ptrDllGetClassObject) (const CLSID&, const IID&, void**);
interface I_X : IUnknown
{
virtual HRESULT __stdcall Fx1(int)=0;
virtual HRESULT __stdcall Fx2(int)=0;
};
interface I_Y : IUnknown
{
virtual HRESULT __stdcall Fy1(int)=0;
virtual HRESULT __stdcall Fy2(int)=0;
};
int main(void)
{
I_X* pIX=NULL;
I_Y* pIY=NULL;
HRESULT hr;
IClassFactory* pCF=NULL;
HMODULE hDll=NULL;
BOOL blnFree =FALSE;
hr=CoInitialize(NULL);
hDll=LoadLibrary("D:\\ComTutorial1\\Server\\bin\\CA.dll");
ptrDllGetClassObject=(HRESULT (__stdcall*)(REFCLSID, REFIID, void**))GetProcAddress(hDll,"DllGetClassObject");
printf("ptrDllGetClassObject = %u\n",ptrDllGetClassObject);
hr=ptrDllGetClassObject(CLSID_CA,IID_IClassFactory,(void**)&pCF);
if(SUCCEEDED(hr))
{
pCF->CreateInstance(NULL,IID_I_X,(void**)&pIX);
// is this needed ??
pCF->Release();
hr=pIX->Fx1(25);
hr=pIX->Fx2(50);
hr=pIX->QueryInterface(IID_I_Y,(void**)&pIY);
hr=pIY->Fy1(75);
hr=pIY->Fy2(100);
hr=pIX->Release();
hr=pIY->Release();
}
CoUninitialize();
blnFree=FreeLibrary(hDll);
getchar();
return 0;
}
#include <windows.h> //CAClient9
#include <stdio.h>
static const CLSID CLSID_CA = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}};
static const IID IID_I_X = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}};
static const IID IID_I_Y = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06}};
HRESULT (__stdcall* ptrDllGetClassObject) (const CLSID&, const IID&, void**);
interface I_X : IUnknown
{
virtual HRESULT __stdcall Fx1(int)=0;
virtual HRESULT __stdcall Fx2(int)=0;
};
interface I_Y : IUnknown
{
virtual HRESULT __stdcall Fy1(int)=0;
virtual HRESULT __stdcall Fy2(int)=0;
};
int main(void)
{
I_X* pIX=NULL;
I_Y* pIY=NULL;
HRESULT hr;
IClassFactory* pCF=NULL;
HMODULE hDll=NULL;
hDll=LoadLibrary("C:\\Code\\VStudio\\VC++6\\Projects\\COM\\ComObjects\\CA\\Release\\CA.dll");
//hDll=LoadLibrary("C:\\Code\\VStudio\\CA\\Release\\CA.dll");
ptrDllGetClassObject=(HRESULT (__stdcall*)(REFCLSID, REFIID, void**))GetProcAddress(hDll,"DllGetClassObject");
printf("ptrDllGetClassObject = %u\n",ptrDllGetClassObject);
hr=ptrDllGetClassObject(CLSID_CA,IID_IClassFactory,(void**)&pCF);
if(SUCCEEDED(hr))
{
pCF->CreateInstance(NULL,IID_I_X,(void**)&pIX);
// is this needed ??
pCF->Release();
hr=pIX->Fx1(25);
hr=pIX->Fx2(50);
hr=pIX->QueryInterface(IID_I_Y,(void**)&pIY);
hr=pIY->Fy1(75);
hr=pIY->Fy2(100);
hr=pIX->Release();
hr=pIY->Release();
}
FreeLibrary(hDll);
getchar();
return 0;
}
/*
====Output Including pCF->Release=======
========================================
ptrDllGetClassObject = 268441664
Entering DllGetClassObject()
Called CAClassFactory Constructor!
Called CAClassFactory::QueryInterface()
Called CAClassFactory::AddRef()
Leaving DllGetClassObject()
Called CAClassFactory::CreateInstance()
this = 10421168
sizeof(CA) = 12
Called CA::AddRef()
Called CAClassFactory::Release()
Called CAClassFactory Destructor!
Called Fx1() : iNum = 25
Called Fx2() : iNum = 50
Called CA::AddRef()
Called Fy1() : iNum = 75
Called Fy2() : iNum = 100
Called CA::Release()
Called CA::Release()
*/
/*
====Output With No pCF->Release()========
=========================================
ptrDllGetClassObject = 268441664
Entering DllGetClassObject()
Called CAClassFactory Constructor!
Called CAClassFactory::QueryInterface()
Called CAClassFactory::AddRef()
Leaving DllGetClassObject()
Called CAClassFactory::CreateInstance()
this = 10421168
sizeof(CA) = 12
Called CA::AddRef()
Called Fx1() : iNum = 25
Called Fx2() : iNum = 50
Called CA::AddRef()
Called Fy1() : iNum = 75
Called Fy2() : iNum = 100
Called CA::Release()
Called CA::Release()
*/
'SED_PBWIN
#COMPILE DLL "PBCA.DLL"
#DIM ALL
#INCLUDE ONCE "Windows.inc"
$CLSID_CA =GUID$("{AB2D3628-5A59-4719-970B-1D6D70761AE8}")
'0xab2d3628, 0x5a59, 0x4719, 0x97, 0xb, 0x1d, 0x6d, 0x70, 0x76, 0x1a, 0xe8);
$IID_I_X = GUID$("{77E3ACD0-E12B-428c-A8E8-E32526F14DD4}")
'0x77e3acd0, 0xe12b, 0x428c, 0xa8, 0xe8, 0xe3, 0x25, 0x26, 0xf1, 0x4d, 0xd4);
$IID_I_Y = GUID$("{68DDC584-EC29-4214-A907-0A3FAD7D7E32}")
'0x68ddc584, 0xec29, 0x4214, 0xa9, 0x7, 0xa, 0x3f, 0xad, 0x7d, 0x7e, 0x32);
CLASS CA $CLSID_CA AS COM
CLASS METHOD CREATE
STDOUT "Constructor Called"
END METHOD
CLASS METHOD DESTROY
STDOUT "Destructor Called"
END METHOD
INTERFACE I_X $IID_I_X : INHERIT IUNKNOWN
METHOD Fx1(BYVAL iNum AS LONG)
STDOUT "Called Fx1 iNum = " + FORMAT$(iNum)
END METHOD
METHOD Fx2(BYVAL iNum AS LONG)
STDOUT "Called Fx2 iNum = " + FORMAT$(iNum)
END METHOD
END INTERFACE
INTERFACE I_Y $IID_I_Y : INHERIT IUNKNOWN
METHOD Fy1(BYVAL iNum AS LONG)
STDOUT "Called Fy1 iNum = " + FORMAT$(iNum)
END METHOD
METHOD Fy2(BYVAL iNum AS LONG)
STDOUT "Called Fy2 iNum = " + FORMAT$(iNum)
END METHOD
END INTERFACE
END CLASS
'==============================================================================
FUNCTION STDOUT (Z AS STRING) AS LONG
' returns TRUE (non-zero) on success
LOCAL hStdOut AS LONG, nCharsWritten AS LONG
LOCAL w AS STRING
hStdOut = GetStdHandle (%STD_OUTPUT_HANDLE)
IF hSTdOut = -1& or hStdOut = 0& THEN ' invalid handle value, coded in line to avoid
' casting differences in Win32API.INC
' %NULL test added for Win/XP
AllocConsole
hStdOut = GetStdHandle (%STD_OUTPUT_HANDLE)
END IF
w = Z & $CRLF
FUNCTION = WriteFile(hStdOut, BYVAL STRPTR(W), LEN(W), nCharsWritten, BYVAL %NULL)
END FUNCTION
'==============================================================================
#include <windows.h>
#include <stdio.h>
static const CLSID CLSID_CA = {0xab2d3628, 0x5a59, 0x4719,{ 0x97, 0xb, 0x1d, 0x6d, 0x70, 0x76, 0x1a, 0xe8}};
static const IID IID_I_X = {0x77e3acd0, 0xe12b, 0x428c,{ 0xa8, 0xe8, 0xe3, 0x25, 0x26, 0xf1, 0x4d, 0xd4}};
static const IID IID_I_Y = {0x68ddc584, 0xec29, 0x4214,{0xa9, 0x7, 0xa, 0x3f, 0xad, 0x7d, 0x7e, 0x32}};
HRESULT (__stdcall* ptrDllGetClassObject) (const CLSID&, const IID&, void**);
interface I_X : IUnknown
{
virtual HRESULT __stdcall Fx1(int)=0;
virtual HRESULT __stdcall Fx2(int)=0;
};
interface I_Y : IUnknown
{
virtual HRESULT __stdcall Fy1(int)=0;
virtual HRESULT __stdcall Fy2(int)=0;
};
int main(void)
{
I_X* pIX=NULL;
I_Y* pIY=NULL;
HRESULT hr;
IClassFactory* pCF=NULL;
HMODULE hDll=NULL;
BOOL blnFree =FALSE;
//Change Path Here
hDll=LoadLibrary("D:\\ComTutorial1A\\Server\\PbSource\\PBCA.DLL");
ptrDllGetClassObject=(HRESULT (__stdcall*)(REFCLSID, REFIID, void**))GetProcAddress(hDll,"DllGetClassObject");
printf("ptrDllGetClassObject = %u\n",ptrDllGetClassObject);
hr=ptrDllGetClassObject(CLSID_CA,IID_IClassFactory,(void**)&pCF);
if(SUCCEEDED(hr))
{
pCF->CreateInstance(NULL,IID_I_X,(void**)&pIX);
// is this needed ??
pCF->Release();
hr=pIX->Fx1(25);
hr=pIX->Fx2(50);
hr=pIX->QueryInterface(IID_I_Y,(void**)&pIY);
hr=pIY->Fy1(75);
hr=pIY->Fy2(100);
hr=pIX->Release();
hr=pIY->Release();
}
blnFree=FreeLibrary(hDll);
getchar();
return 0;
}
'SED_PBWIN
#COMPILE DLL "PBCTEST01.DLL"
#DIM ALL
#INCLUDE ONCE "WIN32API.INC"
$CLSID_cTest01 =GUID$("{EEDFBD9E-8CD7-43ae-8B58-6676EE2B1E72}")
$IID_iTest1 = GUID$("{7E58490E-8445-4b61-9CED-611846F835D7}")
CLASS cTest01 $CLSID_cTest01 AS COM
INSTANCE S1 AS STRING, iNum2 AS LONG
CLASS METHOD CREATE
STDOUT "Constructor Called #1"
iNum2 = 17
S1 = "James"
END METHOD
CLASS METHOD DESTROY
STDOUT "Destructor Called"
END METHOD
INTERFACE iTest1 $IID_iTest1 : INHERIT IUNKNOWN
METHOD Fx1(BYVAL iNum AS LONG)
STDOUT "Called Fx1 iNum = " + FORMAT$(iNum)
END METHOD
METHOD Fx2(BYVAL iNum AS LONG)
STDOUT "Called Fx2 iNum = " + FORMAT$(iNum)
END METHOD
METHOD iNum2_Get(iNum1 AS LONG)
iNum1 = iNum2
STDOUT "Called iNum2_Get = " + FORMAT$(iNum1)
END METHOD
METHOD iNum2_Set(BYVAL iNum AS LONG)
iNum2 = iNum
STDOUT "Called iNum2_Set = " + FORMAT$(iNum)
END METHOD
METHOD S1_Get(Param AS STRING)
Param = S1
END METHOD
METHOD S1_Set(Param AS STRING)
S1 = Param
STDOUT "Called S1_Set -> "+ S1
END METHOD
END INTERFACE
END CLASS
'==============================================================================
'MCM code
'------------------------------------------------------------------------------
FUNCTION STDOUT (Z AS STRING) AS LONG
' returns TRUE (non-zero) on success
LOCAL hStdOut AS LONG, nCharsWritten AS LONG
LOCAL w AS STRING
hStdOut = GetStdHandle (%STD_OUTPUT_HANDLE)
IF hSTdOut = -1& or hStdOut = 0& THEN ' invalid handle value, coded in line to avoid
' casting differences in Win32API.INC
' %NULL test added for Win/XP
AllocConsole
hStdOut = GetStdHandle (%STD_OUTPUT_HANDLE)
END IF
w = Z & $CRLF
FUNCTION = WriteFile(hStdOut, BYVAL STRPTR(W), LEN(W), nCharsWritten, BYVAL %NULL)
END FUNCTION
'==============================================================================
#include <windows.h>
#include<OLEAUTO.H>
#include <stdio.h>
static const CLSID CLSID_cTest01 = {0xeedfbd9e, 0x8cd7, 0x43ae,{0x8b, 0x58, 0x66, 0x76, 0xee, 0x2b, 0x1e, 0x72}};
static const IID IID_iTest01 = {0x7e58490e, 0x8445, 0x4b61,{0x9c, 0xed, 0x61, 0x18, 0x46, 0xf8, 0x35, 0xd7}};
HRESULT (__stdcall* ptrDllGetClassObject) (const CLSID&, const IID&, void**);
interface iTest1 : IUnknown
{
virtual HRESULT __stdcall Fx1(int)=0;
virtual HRESULT __stdcall Fx2(int)=0;
virtual HRESULT __stdcall iNum2_Get(int*);
virtual HRESULT __stdcall iNum2_Set(int)=0;
virtual HRESULT __stdcall S1_Get(BSTR*);
virtual HRESULT __stdcall S1_Set(BSTR*);
};
int main(void)
{
iTest1* piTest01=NULL;
HRESULT hr;
IClassFactory* pCF=NULL;
HMODULE hDll=NULL;
int iNum2;
BSTR str1;
//Change Path Here
hDll=LoadLibrary("D:\\ComTutorial1A\\Server\\PbSource\\PBCTEST01.DLL");
ptrDllGetClassObject=(HRESULT (__stdcall*)(REFCLSID, REFIID, void**))GetProcAddress(hDll,"DllGetClassObject");
printf("ptrDllGetClassObject = %u\n",ptrDllGetClassObject);
hr=ptrDllGetClassObject(CLSID_cTest01,IID_IClassFactory,(void**)&pCF);
if(SUCCEEDED(hr))
{
pCF->CreateInstance(NULL,IID_iTest01,(void**)&piTest01);
pCF->Release();
hr=piTest01->Fx1(25);
hr=piTest01->Fx2(50);
hr=piTest01->iNum2_Get(&iNum2);
printf("iNum2 = %u\n",iNum2);
hr=piTest01->iNum2_Set(22);
hr=piTest01->iNum2_Get(&iNum2);
printf("iNum2 = %u\n",iNum2);
hr=piTest01->S1_Get(&str1);
printf("str1 = %s\n",str1);
SysFreeString(str1);
str1 = SysAllocStringByteLen("Fuller",6);
hr=piTest01->S1_Set(&str1);
SysFreeString(str1);
hr=piTest01->S1_Get(&str1);
printf("str1 = %s\n",str1);
SysFreeString(str1);
hr=piTest01->Release();
}
FreeLibrary(hDll);
getchar();
return 0;
}
I needed to edit the idl file to remove the .dll
// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: <could not determine filename>
[
uuid(7273541F-287F-4E32-92D4-4E25F501389E),
version(1.0),
helpstring("COM Library")
]
library PBCTEST04
{
// TLib : // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole32.tlb");
// Forward declare all types defined in this typelib
interface IDISPLAYOPENFILE;
[
odl,
uuid(B72CDD37-5349-46B7-8A27-592D23B34FE3),
helpstring("IDISPLAYOPENFILE is a custom interface for Direct VTable access."),
nonextensible
]
interface IDISPLAYOPENFILE : IUnknown {
[propput]
void _stdcall FOLDER([in] BSTR rhs);
[propput]
void _stdcall FILTER([in] BSTR rhs);
[propput]
void _stdcall HPARENT([in] unsigned long rhs);
[propput]
void _stdcall DFLEXT([in] BSTR rhs);
[propput]
void _stdcall START([in] BSTR rhs);
[propput]
void _stdcall TITLE([in] BSTR rhs);
[propput]
void _stdcall FLAGS([in] unsigned long rhs);
BSTR _stdcall GETNAME();
};
[
uuid(1B0F486F-9CCA-47BA-A338-8F7146B73C26)
]
coclass CDISPLAYOPENFILE {
[default] interface IDISPLAYOPENFILE;
};
};
D:\ComTutorial1A\Server\PbSource>midl TLIB04.IDL
Microsoft (R) 32b/64b MIDL Compiler Version 7.00.0555
Copyright (c) Microsoft Corporation. All rights reserved.
Processing .\TLIB04.IDL
TLIB04.IDL
Processing C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\oaidl.idl
oaidl.idl
Processing C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\objidl.id
l
objidl.idl
Processing C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\unknwn.id
l
unknwn.idl
Processing C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\wtypes.id
l
wtypes.idl
Processing C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\basetsd.h
basetsd.h
Processing C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\guiddef.h
guiddef.h
Processing C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\oaidl.acf
oaidl.acf
D:\ComTutorial1A\Server\PbSource>
When designing COM interfaces, we should always return HRESULTs as the physical return value of the method...
import "oaidl.idl";
[object, uuid(B72CDD37-5349-46B7-8A27-592D23B34FE3), helpstring("IDISPLAYOPENFILE is a custom interface for Direct VTable access."), nonextensible]
interface IDISPLAYOPENFILE : IUnknown
{
HRESULT _stdcall FOLDER ([in] BSTR rhs );
HRESULT _stdcall FILTER ([in] BSTR rhs );
HRESULT _stdcall HPARENT ([in] unsigned long rhs );
HRESULT _stdcall DFLEXT ([in] BSTR rhs );
HRESULT _stdcall START ([in] BSTR rhs );
HRESULT _stdcall TITLE ([in] BSTR rhs );
HRESULT _stdcall FLAGS ([in] unsigned long rhs );
HRESULT _stdcall GETNAME ([out, retval] BSTR* strName );
};
[uuid(7273541F-287F-4E32-92D4-4E25F501389E), version(1.0), helpstring("COM Library")]
library PBCTEST04
{
importlib("stdole32.tlb");
// Forward declare all types defined in this typelib
interface IDISPLAYOPENFILE;
[uuid(1B0F486F-9CCA-47BA-A338-8F7146B73C26)]
coclass CDISPLAYOPENFILE
{
[default] interface IDISPLAYOPENFILE;
};
};
C:\Code\VStudio\VC++6\Projects\PBCTES04>midl pbctes04.idl
Microsoft (R) MIDL Compiler Version 5.01.0164
Copyright (c) Microsoft Corp 1991-1997. All rights reserved.
Processing .\pbctes04.idl
pbctes04.idl
Processing C:\Program Files\Microsoft Visual Studio\VC98\include\oaidl.idl
oaidl.idl
Processing C:\Program Files\Microsoft Visual Studio\VC98\include\objidl.idl
objidl.idl
Processing C:\Program Files\Microsoft Visual Studio\VC98\include\unknwn.idl
unknwn.idl
Processing C:\Program Files\Microsoft Visual Studio\VC98\include\wtypes.idl
wtypes.idl
C:\Code\VStudio\VC++6\Projects\PBCTES04>dir
Volume in drive C is Main
Volume Serial Number is 881C-5BB1
Directory of C:\Code\VStudio\VC++6\Projects\PBCTES04
05/17/2011 11:29a <DIR> .
05/17/2011 11:29a <DIR> ..
05/17/2011 11:29a 811 dlldata.c
05/17/2011 10:35a 74 PBCTES04.bat
05/17/2011 11:29a 9,571 pbctes04.h
05/17/2011 11:29a 962 PBCTES04.idl
05/17/2011 11:29a 2,192 pbctes04.tlb
05/17/2011 11:29a 1,128 pbctes04_i.c
05/17/2011 11:29a 37,104 pbctes04_p.c
8 File(s) 52,799 bytes
2 Dir(s) 48,632,020,992 bytes free
C:\Code\VStudio\VC++6\Projects\PBCTES04>
#COMPILE DLL "PBTEST10_UNK.DLL"
#DIM ALL
#COM TLIB ON
#COM NAME "PBTEST10_UNK"
#COM GUID GUID$ ("{B3723C2A-7DCF-437A-AF59-42F19122B39B}")
#RESOURCE TYPELIB,1,"PBTEST10_UNK.TLB"
#INCLUDE ONCE "WIN32API.INC"
MACRO PropGet(PropName,PropType)=PROPERTY GET PropName() AS PropType:PROPERTY=PropName:END PROPERTY
MACRO PropSet(PropName,PropType)=PROPERTY SET PropName(BYVAL param AS PropType):PropName=param:END PROPERTY
$cPbTest10Guid = GUID$("{0D7051A6-456A-4631-9878-1B7FA5433539}")
$iPbTest10Guid = GUID$("{EAA6ED6B-B73D-44B6-832E-1B4BE67032D3}")
CLASS cPbTest10 $cPbTest10Guid AS COM
INSTANCE p1 AS LONG
CLASS METHOD CREATE
p1 = 77
STDOUT "Hello From the pbtest10_unk com server create method"
END METHOD
INTERFACE iPbTest10 $iPbTest10Guid : INHERIT IUNKNOWN
PropGet(p1,LONG)
PropSet(p1,LONG)
END INTERFACE
END CLASS
'==============================================================================
'MCM code
'------------------------------------------------------------------------------
FUNCTION STDOUT (Z AS STRING) AS LONG
' returns TRUE (non-zero) on success
LOCAL hStdOut AS LONG, nCharsWritten AS LONG
LOCAL w AS STRING
hStdOut = GetStdHandle (%STD_OUTPUT_HANDLE)
IF hSTdOut = -1& OR hStdOut = 0& THEN ' invalid handle value, coded in line to avoid
' casting differences in Win32API.INC
' %NULL test added for Win/XP
AllocConsole
hStdOut = GetStdHandle (%STD_OUTPUT_HANDLE)
END IF
w = Z & $CRLF
FUNCTION = WriteFile(hStdOut, BYVAL STRPTR(W), LEN(W), nCharsWritten, BYVAL %NULL)
END FUNCTION
'==============================================================================
// *********************************************************************
// Created with BCX32 - BASIC To C/C++ Translator (V) 8.7.0.0 (2011/05/11)
// BCX (c) 1999 - 2009 by Kevin Diggins
// *********************************************************************
// Translated for compiling with a C++ Compiler
// *********************************************************************
// Additional lines may be needed
#if defined( __cplusplus )
using namespace std;
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
typedef std::string stdstr;
#endif
#include <windows.h> // Win32 Header File
#include <windowsx.h> // Win32 Header File
#include <commctrl.h> // Win32 Header File
#include <commdlg.h> // Win32 Header File
#include <mmsystem.h> // Win32 Header File
#include <shellapi.h> // Win32 Header File
#include <shlobj.h> // Win32 Header File
#include <richedit.h> // Win32 Header File
#include <wchar.h> // Win32 Header File
#include <objbase.h> // Win32 Header File
#include <ocidl.h> // Win32 Header File
#include <winuser.h> // Win32 Header File
#include <olectl.h> // Win32 Header File
#include <oaidl.h> // Win32 Header File
#include <ole2.h> // Win32 Header File
#include <oleauto.h> // Win32 Header File
#include <winsock.h> // Win32 Header File
#include <process.h> // dos
#include <conio.h> // dos
#include <direct.h> // dos
#include <io.h> // dos
#include <ctype.h> // dos/linux
#include <fcntl.h> // dos/linux
#include <math.h> // dos/linux
#include <stdio.h> // dos/linux
#include <string.h> // dos/linux
#include <stddef.h> // dos/linux
#include <stdlib.h> // dos/linux
#include <setjmp.h> // dos/linux
#include <time.h> // dos/linux
#include <stdarg.h> // dos/linux
// ***************************************************
// Compiler Defines
// ***************************************************
// C++
#if defined( __cplusplus )
#define overloaded
#define C_EXPORT EXTERN_C __declspec(dllexport)
#define C_IMPORT EXTERN_C __declspec(dllimport)
#else
#define C_EXPORT __declspec(dllexport)
#define C_IMPORT __declspec(dllimport)
#endif
// Open Watcom defs
#if defined( __WATCOM_CPLUSPLUS__ ) || defined( __TINYC__ )
#define atanl atan
#define sinl sin
#define cosl cos
#define tanl tan
#define asinl asin
#define acosl acos
#define log10l log10
#define logl log
#define _fcloseall fcloseall
#endif
// Borland C++ 5.5.1 defs - bcc32.exe
#if defined( __BCPLUSPLUS__ )
// ===== Borland Libraries ==========
#include <dos.h>
#pragma comment(lib,"import32.lib")
#pragma comment(lib,"cw32.lib")
// ==================================
#endif
// Microsoft VC++
#ifndef DECLSPEC_UUID
#if (_MSC_VER >= 1100) && defined ( __cplusplus )
#define DECLSPEC_UUID(x) __declspec(uuid(x))
#else
#define DECLSPEC_UUID(x)
#endif
#endif
// *************************************************
#ifndef __cplusplus
#error A C++ compiler is required
#endif
#if !defined( __LCC__ )
// *************************************************
// Instruct Linker to Search Object/Import Libraries
// *************************************************
#pragma comment(lib,"kernel32.lib")
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")
#pragma comment(lib,"comctl32.lib")
#pragma comment(lib,"advapi32.lib")
#pragma comment(lib,"winspool.lib")
#pragma comment(lib,"shell32.lib")
#pragma comment(lib,"ole32.lib")
#pragma comment(lib,"oleaut32.lib")
#pragma comment(lib,"uuid.lib")
#pragma comment(lib,"odbc32.lib")
#pragma comment(lib,"odbccp32.lib")
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"comdlg32.lib")
#pragma comment(lib,"imagehlp.lib")
#pragma comment(lib,"version.lib")
#else
#pragma lib <winspool.lib>
#pragma lib <shell32.lib>
#pragma lib <ole32.lib>
#pragma lib <oleaut32.lib>
#pragma lib <uuid.lib>
#pragma lib <odbc32.lib>
#pragma lib <odbccp32.lib>
#pragma lib <winmm.lib>
#pragma lib <imagehlp.lib>
#pragma lib <version.lib>
// *************************************************
// End of Object/Import Libraries To Search
// *************************************************
#endif
// *************************************************
// User Defined Constants
// *************************************************
#define cSizeOfDefaultString 2048
#define GetClassObj(dll) (HRESULT(__stdcall*)(REFCLSID,REFIID,void**))GetProcAddress(hDll,"DllGetClassObject")
// *************************************************
// Standard Prototypes
// *************************************************
void Pause (void);
// *************************************************
// User Defined Types And Unions
// *************************************************
class IPbTest10: public IUnknown
{
public:
virtual long __stdcall p1_get();
virtual void __stdcall p1_set(long);
};
// *************************************************
// User Global Variables
// *************************************************
// *************************************************
// User Prototypes
// *************************************************
int main (int,PCHAR*);
// *************************************************
// User Global Initialized Arrays
// *************************************************
static const CLSID CLSID_cPbTest10Guid={0x0D7051A6,0x456A,0x4631,{0x98,0x78,0x1B,0x7F,0xA5,0x43,0x35,0x39}};
static const IID IID_iPbTest10Guid={0xEAA6ED6B,0xB73D,0x44B6,{0x83,0x2E,0x1B,0x4B,0xE6,0x70,0x32,0xD3}};
// *************************************************
// Runtime Functions
// *************************************************
void Pause(void)
{
printf("\n%s\n","Press any key to continue . . .");
_getch();
}
HRESULT( __stdcall*ptrDllGetClassObject)(const CLSID&,const IID&,void**);
// ************************************
// User Subs and Functions
// ************************************
int main (int argc,PCHAR* argv)
{
IPbTest10* pPbt=NULL;
HRESULT hr;
IClassFactory* pCF=NULL;
HMODULE hDll=NULL;
BSTR str1;
long l;
static char stemp[cSizeOfDefaultString];
hDll=LoadLibrary("D:\\ComTutorial1A\\Server\\PbSource\\PBTEST10_UNK.DLL");
if(!hDll )
{
MessageBox (GetActiveWindow(),"Bad Load","",0);
return 0;
}
ptrDllGetClassObject=GetClassObj(hDll);
hr=ptrDllGetClassObject(CLSID_cPbTest10Guid,IID_IClassFactory,(void**)&pCF);
if((SUCCEEDED(hr)))
{
pCF->CreateInstance(NULL,IID_iPbTest10Guid,(void**)&pPbt);
pCF->Release();
l=pPbt->p1_get();
cout<<" l = "<<l<<endl;
pPbt->p1_set(128);
l=pPbt->p1_get();
cout<<" l = "<<l<<endl;
hr=pPbt->Release();
}
if(hDll )
{
FreeLibrary(hDll);
}
Pause();
return 0;
}
#COMPILE DLL "PBTEST10_DUAL.DLL"
#DIM ALL
#COM TLIB ON
#COM NAME "PBTEST10_DUAL"
#COM GUID GUID$("{F86AA908-0A93-4F64-8E36-549A4850AA64}")
#RESOURCE TYPELIB,1,"PBTEST10_DUAL.TLB"
#INCLUDE ONCE "WIN32API.INC"
MACRO PropGet(PropName,PropType)=PROPERTY GET PropName() AS PropType:PROPERTY=PropName:END PROPERTY
MACRO PropSet(PropName,PropType)=PROPERTY SET PropName(BYVAL param AS PropType):PropName=param:END PROPERTY
$cPbTest10Guid = GUID$("{F455D1C8-37A2-40DD-901D-59D8EE7C33D2}")
$iPbTest10Guid = GUID$("{DDD0F77A-A178-4B88-A115-B80DD9FD7AED}")
CLASS cPbTest10 $cPbTest10Guid AS COM
INSTANCE p1 AS LONG
CLASS METHOD CREATE
p1 = 77
STDOUT "Hello From the pbtest10_dual com server create method"
END METHOD
INTERFACE iPbTest10 $iPbTest10Guid : INHERIT DUAL
'PropGet(p1,LONG)
'PropSet(p1,LONG)
METHOD p1_get() AS LONG
METHOD = p1
END METHOD
METHOD p1_set(p AS LONG)
p1 = p
END METHOD
END INTERFACE
END CLASS
'==============================================================================
'MCM code
'------------------------------------------------------------------------------
FUNCTION STDOUT (Z AS STRING) AS LONG
' returns TRUE (non-zero) on success
LOCAL hStdOut AS LONG, nCharsWritten AS LONG
LOCAL w AS STRING
hStdOut = GetStdHandle (%STD_OUTPUT_HANDLE)
IF hSTdOut = -1& OR hStdOut = 0& THEN ' invalid handle value, coded in line to avoid
' casting differences in Win32API.INC
' %NULL test added for Win/XP
AllocConsole
hStdOut = GetStdHandle (%STD_OUTPUT_HANDLE)
END IF
w = Z & $CRLF
FUNCTION = WriteFile(hStdOut, BYVAL STRPTR(W), LEN(W), nCharsWritten, BYVAL %NULL)
END FUNCTION
'==============================================================================
// *********************************************************************
// Created with BCX32 - BASIC To C/C++ Translator (V) 8.7.0.0 (2011/05/11)
// BCX (c) 1999 - 2009 by Kevin Diggins
// *********************************************************************
// Translated for compiling with a C++ Compiler
// *********************************************************************
// Additional lines may be needed
#if defined( __cplusplus )
using namespace std;
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
typedef std::string stdstr;
#endif
#include <windows.h> // Win32 Header File
#include <windowsx.h> // Win32 Header File
#include <commctrl.h> // Win32 Header File
#include <commdlg.h> // Win32 Header File
#include <mmsystem.h> // Win32 Header File
#include <shellapi.h> // Win32 Header File
#include <shlobj.h> // Win32 Header File
#include <richedit.h> // Win32 Header File
#include <wchar.h> // Win32 Header File
#include <objbase.h> // Win32 Header File
#include <ocidl.h> // Win32 Header File
#include <winuser.h> // Win32 Header File
#include <olectl.h> // Win32 Header File
#include <oaidl.h> // Win32 Header File
#include <ole2.h> // Win32 Header File
#include <oleauto.h> // Win32 Header File
#include <winsock.h> // Win32 Header File
#include <process.h> // dos
#include <conio.h> // dos
#include <direct.h> // dos
#include <io.h> // dos
#include <ctype.h> // dos/linux
#include <fcntl.h> // dos/linux
#include <math.h> // dos/linux
#include <stdio.h> // dos/linux
#include <string.h> // dos/linux
#include <stddef.h> // dos/linux
#include <stdlib.h> // dos/linux
#include <setjmp.h> // dos/linux
#include <time.h> // dos/linux
#include <stdarg.h> // dos/linux
// ***************************************************
// Compiler Defines
// ***************************************************
// C++
#if defined( __cplusplus )
#define overloaded
#define C_EXPORT EXTERN_C __declspec(dllexport)
#define C_IMPORT EXTERN_C __declspec(dllimport)
#else
#define C_EXPORT __declspec(dllexport)
#define C_IMPORT __declspec(dllimport)
#endif
// Open Watcom defs
#if defined( __WATCOM_CPLUSPLUS__ ) || defined( __TINYC__ )
#define atanl atan
#define sinl sin
#define cosl cos
#define tanl tan
#define asinl asin
#define acosl acos
#define log10l log10
#define logl log
#define _fcloseall fcloseall
#endif
// Borland C++ 5.5.1 defs - bcc32.exe
#if defined( __BCPLUSPLUS__ )
// ===== Borland Libraries ==========
#include <dos.h>
#pragma comment(lib,"import32.lib")
#pragma comment(lib,"cw32.lib")
// ==================================
#endif
// Microsoft VC++
#ifndef DECLSPEC_UUID
#if (_MSC_VER >= 1100) && defined ( __cplusplus )
#define DECLSPEC_UUID(x) __declspec(uuid(x))
#else
#define DECLSPEC_UUID(x)
#endif
#endif
// *************************************************
#ifndef __cplusplus
#error A C++ compiler is required
#endif
#if !defined( __LCC__ )
// *************************************************
// Instruct Linker to Search Object/Import Libraries
// *************************************************
#pragma comment(lib,"kernel32.lib")
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")
#pragma comment(lib,"comctl32.lib")
#pragma comment(lib,"advapi32.lib")
#pragma comment(lib,"winspool.lib")
#pragma comment(lib,"shell32.lib")
#pragma comment(lib,"ole32.lib")
#pragma comment(lib,"oleaut32.lib")
#pragma comment(lib,"uuid.lib")
#pragma comment(lib,"odbc32.lib")
#pragma comment(lib,"odbccp32.lib")
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"comdlg32.lib")
#pragma comment(lib,"imagehlp.lib")
#pragma comment(lib,"version.lib")
#else
#pragma lib <winspool.lib>
#pragma lib <shell32.lib>
#pragma lib <ole32.lib>
#pragma lib <oleaut32.lib>
#pragma lib <uuid.lib>
#pragma lib <odbc32.lib>
#pragma lib <odbccp32.lib>
#pragma lib <winmm.lib>
#pragma lib <imagehlp.lib>
#pragma lib <version.lib>
// *************************************************
// End of Object/Import Libraries To Search
// *************************************************
#endif
// *************************************************
// User Defined Constants
// *************************************************
#define cSizeOfDefaultString 2048
#define GetClassObj(dll) (HRESULT(__stdcall*)(REFCLSID,REFIID,void**))GetProcAddress(hDll,"DllGetClassObject")
// *************************************************
// Standard Prototypes
// *************************************************
char* BCX_TmpStr(size_t,size_t= 128,int= 1);
char* curdir (void);
void Pause (void);
// *************************************************
// User Defined Types And Unions
// *************************************************
class IPbTest10: public IDispatch
{
public:
virtual long __stdcall p1_get();
virtual void __stdcall p1_set(long);
};
// *************************************************
// System Variables
// *************************************************
// *************************************************
// User Global Variables
// *************************************************
// *************************************************
// User Prototypes
// *************************************************
int main (int,PCHAR*);
// *************************************************
// User Global Initialized Arrays
// *************************************************
static const CLSID CLSID_cPbTest10Guid={0xF455D1C8,0x37A2,0x40DD,{0x90,0x1D,0x59,0xD8,0xEE,0x7C,0x33,0xD2}};
static const IID IID_iPbTest10Guid={0xDDD0F77A,0xA178,0x4B88,{0xA1,0x15,0xB8,0x0D,0xD9,0xFD,0x7A,0xED}};
// *************************************************
// Runtime Functions
// *************************************************
#ifndef BCXTmpStrSize
#define BCXTmpStrSize 2048
#endif
char *BCX_TmpStr (size_t Bites,size_t iPad,int iAlloc)
{
static int StrCnt;
static char *StrFunc[BCXTmpStrSize];
StrCnt=(StrCnt + 1) & (BCXTmpStrSize-1);
if(StrFunc[StrCnt]) {free (StrFunc[StrCnt]); StrFunc[StrCnt] = NULL;}
#if defined BCX_MAX_VAR_SIZE
if(Bites*sizeof(char)>BCX_MAX_VAR_SIZE)
{
printf("Buffer Overflow caught in BCX_TmpStr - requested space of %d EXCEEDS %d\n",(int)(Bites*sizeof(char)),BCX_MAX_VAR_SIZE);
abort();
}
#endif
if(iAlloc) StrFunc[StrCnt]=(char*)calloc(Bites+128,sizeof(char));
return StrFunc[StrCnt];
}
char *curdir (void)
{
register char *strtmp = BCX_TmpStr(2048);
GetCurrentDirectory (1024,strtmp);
return strtmp;
}
void Pause(void)
{
printf("\n%s\n","Press any key to continue . . .");
_getch();
}
HRESULT( __stdcall*ptrDllGetClassObject)(const CLSID&,const IID&,void**);
// ************************************
// User Subs and Functions
// ************************************
int main (int argc,PCHAR* argv)
{
IPbTest10* pPbt=NULL;
HRESULT hr;
IClassFactory* pCF=NULL;
HMODULE hDll=NULL;
BSTR str1;
long l;
static char stemp[cSizeOfDefaultString];
strcpy(stemp,curdir());
hDll=LoadLibrary("D:\\ComTutorial1A\\Server\\PbSource\\PBTEST10_DUAL.DLL");
if(!hDll )
{
MessageBox (GetActiveWindow(),"Bad Load","",0);
return 0;
}
ptrDllGetClassObject=GetClassObj(hDll);
hr=ptrDllGetClassObject(CLSID_cPbTest10Guid,IID_IClassFactory,(void**)&pCF);
if((SUCCEEDED(hr)))
{
pCF->CreateInstance(NULL,IID_iPbTest10Guid,(void**)&pPbt);
pCF->Release();
l=pPbt->p1_get();
cout<<" l = "<<l<<endl;
pPbt->p1_set(128);
l=pPbt->p1_get();
cout<<" l = "<<l<<endl;
}
if(hDll )
{
FreeLibrary(hDll);
}
Pause();
return 0;
}
'Console Compiler 6
#Compile Exe
#Dim All
$CLSID_CPBTEST10 = Guid$("{F455D1C8-37A2-40DD-901D-59D8EE7C33D2}")
$IID_IPBTEST10 = Guid$("{DDD0F77A-A178-4B88-A115-B80DD9FD7AED}")
' Interface Name : IPBTEST10
' Description : IPBTEST10 is a dual interface with VTable/Dispatch access.
' Class Name : CPBTEST10
' ClassID : $CLSID_CPBTEST10
Interface IPBTEST10 $IID_IPBTEST10 : Inherit IDispatch
Method P1_GET <257> () As Long
Method P1_SET <258> (ByRef InOut P As Long)
End Interface
Function PBMain() As Long
Local pIPbTest10 As IPBTEST10
pIPbTest10=NewCom(ProgId$($CLSID_CPBTEST10))
If IsObject(pIPbTest10) Then
Print "pWhatever Is An Object!"
pIPbTest10.p1_Set(25)
Print "pIPbTest10.p1_Get() = " pIPbTest10.p1_Get()
Set pIPbTest10=Nothing
Else
Print "pWhatever Ain't Crap!"
End If
Con.WaitKey$
PBMain=0
End Function
'Hello From the pbtest10_dual com server create method
'pWhatever Is An Object!
'pIPbTest10.p1_Get() = 25
#include <windows.h>
#include <stdio.h>
const CLSID CLSID_CPBTEST10 = {0xF455D1C8,0x37A2,0x40DD,{0x90,0x1D,0x59,0xD8,0xEE,0x7C,0x33,0xD2}};
const IID IID_IPBTEST10 = {0xDDD0F77A,0xA178,0x4B88,{0xA1,0x15,0xB8,0x0D,0xD9,0xFD,0x7A,0xED}};
interface IPBTest : IDispatch
{
virtual HRESULT __stdcall p1_Get(int* pInt);
virtual HRESULT __stdcall p1_Set(int* pNum);
};
int main(void)
{
IPBTest* pTest=NULL;
int iNumber=0;
HRESULT hr;
OleInitialize(NULL);
hr=CoCreateInstance(CLSID_CPBTEST10,NULL,CLSCTX_INPROC_SERVER,IID_IPBTEST10,(void**)&pTest);
if(SUCCEEDED(hr))
{
printf("CoCreateInstance() Succeeded!\n");
hr=pTest->p1_Get(&iNumber);
if(SUCCEEDED(hr))
printf("iNumber = %d\n",iNumber);
pTest->Release();
}
OleUninitialize();
getchar();
return 0;
}
/*
Hello From the pbtest10_dual com server create method
CoCreateInstance() Succeeded!
iNumber = 77
*/