-
-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding the source files for a simple out of process COM-server under
'source/OutProcSrv'. The COM-server implements a dual interface and the corresponding dispinterface with currently just a single method 'InitRecord' for testing record pointer parameters. The added unittest 'test_dispifc_recordptr.py' passes a record by reference and also as a record pointer to the 'InitRecord' method of the dispinterface and checks the initialized records.
- Loading branch information
Showing
15 changed files
with
2,036 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# coding: utf-8 | ||
|
||
import unittest | ||
|
||
from comtypes import CLSCTX_LOCAL_SERVER | ||
from comtypes.client import CreateObject, GetModule | ||
from ctypes import byref, pointer | ||
|
||
ComtypesTestLib_GUID = "07D2AEE5-1DF8-4D2C-953A-554ADFD25F99" | ||
ProgID = "ComtypesTest.COM.Server" | ||
|
||
try: | ||
GetModule([f"{{{ComtypesTestLib_GUID}}}", 1, 0, 0]) | ||
import comtypes.gen.ComtypesTestLib as ComtypesTestLib | ||
|
||
IMPORT_FAILED = False | ||
except (ImportError, OSError): | ||
IMPORT_FAILED = True | ||
|
||
|
||
@unittest.skipIf(IMPORT_FAILED, "This depends on the out of process COM-server.") | ||
class Test(unittest.TestCase): | ||
"""Test dispmethods with record pointer parameters.""" | ||
|
||
def test(self): | ||
# Explicitely ask for the dispinterface of the COM-server. | ||
dispifc = CreateObject( | ||
ProgID, clsctx=CLSCTX_LOCAL_SERVER, interface=ComtypesTestLib.IComtypesTest | ||
) | ||
|
||
# Test passing a record by reference. | ||
test_record = ComtypesTestLib.T_TEST_RECORD() | ||
self.assertEqual(test_record.question, None) | ||
self.assertEqual(test_record.answer, 0) | ||
self.assertEqual(test_record.needs_clarification, False) | ||
dispifc.InitRecord(byref(test_record)) | ||
self.assertEqual( | ||
test_record.question, "The meaning of life, the universe and everything?" | ||
) | ||
self.assertEqual(test_record.answer, 42) | ||
self.assertEqual(test_record.needs_clarification, True) | ||
|
||
# Test passing a record pointer. | ||
test_record = ComtypesTestLib.T_TEST_RECORD() | ||
self.assertEqual(test_record.question, None) | ||
self.assertEqual(test_record.answer, 0) | ||
self.assertEqual(test_record.needs_clarification, False) | ||
test_record_pointer = pointer(test_record) | ||
dispifc.InitRecord(test_record_pointer) | ||
self.assertEqual( | ||
test_record.question, "The meaning of life, the universe and everything?" | ||
) | ||
self.assertEqual(test_record.answer, 42) | ||
self.assertEqual(test_record.needs_clarification, True) | ||
|
||
|
||
if __name__ == "__main__": | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,281 @@ | ||
/* | ||
This code is based on example code to the book: | ||
Inside COM | ||
by Dale E. Rogerson | ||
Microsoft Press 1997 | ||
ISBN 1-57231-349-8 | ||
*/ | ||
|
||
/////////////////////////////////////////////////////////// | ||
// | ||
// CFactory | ||
// - Base class for reusing a single class factory for | ||
// all components in a DLL | ||
// | ||
#include <objbase.h> | ||
|
||
#include "Registry.h" | ||
#include "CFactory.h" | ||
|
||
/////////////////////////////////////////////////////////// | ||
// | ||
// Static variables | ||
// | ||
LONG CFactory::s_cServerLocks = 0 ; // Count of locks | ||
|
||
HMODULE CFactory::s_hModule = NULL ; // DLL module handle | ||
|
||
DWORD CFactory::s_dwThreadID = 0 ; | ||
|
||
/////////////////////////////////////////////////////////// | ||
// | ||
// CFactory implementation | ||
// | ||
|
||
CFactory::CFactory(const CFactoryData* pFactoryData) | ||
: m_cRef(1) | ||
{ | ||
m_pFactoryData = pFactoryData ; | ||
} | ||
|
||
// | ||
// IUnknown implementation | ||
// | ||
HRESULT __stdcall CFactory::QueryInterface(REFIID iid, void** ppv) | ||
{ | ||
IUnknown* pI ; | ||
if ((iid == IID_IUnknown) || (iid == IID_IClassFactory)) | ||
{ | ||
pI = this ; | ||
} | ||
else | ||
{ | ||
*ppv = NULL; | ||
return E_NOINTERFACE; | ||
} | ||
pI->AddRef() ; | ||
*ppv = pI ; | ||
return S_OK; | ||
} | ||
|
||
ULONG __stdcall CFactory::AddRef() | ||
{ | ||
return ::InterlockedIncrement(&m_cRef) ; | ||
} | ||
|
||
ULONG __stdcall CFactory::Release() | ||
{ | ||
if (::InterlockedDecrement(&m_cRef) == 0) | ||
{ | ||
delete this; | ||
return 0 ; | ||
} | ||
return m_cRef; | ||
} | ||
|
||
// | ||
// IClassFactory implementation | ||
// | ||
|
||
HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter, | ||
const IID& iid, | ||
void** ppv) | ||
{ | ||
|
||
// Aggregate only if the requested IID is IID_IUnknown. | ||
if ((pUnknownOuter != NULL) && (iid != IID_IUnknown)) | ||
{ | ||
return CLASS_E_NOAGGREGATION ; | ||
} | ||
|
||
// Create the component. | ||
CUnknown* pNewComponent ; | ||
HRESULT hr = m_pFactoryData->CreateInstance(pUnknownOuter, | ||
&pNewComponent) ; | ||
if (FAILED(hr)) | ||
{ | ||
return hr ; | ||
} | ||
|
||
// Initialize the component. | ||
hr = pNewComponent->Init(); | ||
if (FAILED(hr)) | ||
{ | ||
// Initialization failed. Release the component. | ||
pNewComponent->NondelegatingRelease() ; | ||
return hr ; | ||
} | ||
|
||
// Get the requested interface. | ||
hr = pNewComponent->NondelegatingQueryInterface(iid, ppv) ; | ||
|
||
// Release the reference held by the class factory. | ||
pNewComponent->NondelegatingRelease() ; | ||
return hr ; | ||
} | ||
|
||
// LockServer | ||
HRESULT __stdcall CFactory::LockServer(BOOL bLock) | ||
{ | ||
if (bLock) | ||
{ | ||
::InterlockedIncrement(&s_cServerLocks) ; | ||
} | ||
else | ||
{ | ||
::InterlockedDecrement(&s_cServerLocks) ; | ||
} | ||
// If this is an out-of-proc server, check to see | ||
// whether we should shut down. | ||
CloseExe() ; //@local | ||
|
||
return S_OK ; | ||
} | ||
|
||
|
||
/////////////////////////////////////////////////////////// | ||
// | ||
// GetClassObject | ||
// - Create a class factory based on a CLSID. | ||
// | ||
HRESULT CFactory::GetClassObject(const CLSID& clsid, | ||
const IID& iid, | ||
void** ppv) | ||
{ | ||
if ((iid != IID_IUnknown) && (iid != IID_IClassFactory)) | ||
{ | ||
return E_NOINTERFACE ; | ||
} | ||
|
||
// Traverse the array of data looking for this class ID. | ||
for (int i = 0; i < g_cFactoryDataEntries; i++) | ||
{ | ||
const CFactoryData* pData = &g_FactoryDataArray[i] ; | ||
if (pData->IsClassID(clsid)) | ||
{ | ||
|
||
// Found the ClassID in the array of components we can | ||
// create. So create a class factory for this component. | ||
// Pass the CFactoryData structure to the class factory | ||
// so that it knows what kind of components to create. | ||
*ppv = (IUnknown*) new CFactory(pData) ; | ||
if (*ppv == NULL) | ||
{ | ||
return E_OUTOFMEMORY ; | ||
} | ||
return NOERROR ; | ||
} | ||
} | ||
return CLASS_E_CLASSNOTAVAILABLE ; | ||
} | ||
|
||
// | ||
// Determine if the component can be unloaded. | ||
// | ||
HRESULT CFactory::CanUnloadNow() | ||
{ | ||
if (CUnknown::ActiveComponents() || IsLocked()) | ||
{ | ||
return S_FALSE ; | ||
} | ||
else | ||
{ | ||
return S_OK ; | ||
} | ||
} | ||
|
||
// | ||
// Register all components. | ||
// | ||
HRESULT CFactory::RegisterAll() | ||
{ | ||
for(int i = 0 ; i < g_cFactoryDataEntries ; i++) | ||
{ | ||
RegisterServer(s_hModule, | ||
*(g_FactoryDataArray[i].m_pCLSID), | ||
g_FactoryDataArray[i].m_RegistryName, | ||
g_FactoryDataArray[i].m_szVerIndProgID, | ||
g_FactoryDataArray[i].m_szProgID, | ||
*(g_FactoryDataArray[i].m_pLIBID)) ; | ||
} | ||
return S_OK ; | ||
} | ||
|
||
HRESULT CFactory::UnregisterAll() | ||
{ | ||
for(int i = 0 ; i < g_cFactoryDataEntries ; i++) | ||
{ | ||
UnregisterServer(*(g_FactoryDataArray[i].m_pCLSID), | ||
g_FactoryDataArray[i].m_szVerIndProgID, | ||
g_FactoryDataArray[i].m_szProgID) ; | ||
} | ||
return S_OK ; | ||
} | ||
|
||
|
||
// | ||
// Start factories | ||
// | ||
BOOL CFactory::StartFactories() | ||
{ | ||
CFactoryData* pStart = &g_FactoryDataArray[0] ; | ||
const CFactoryData* pEnd = | ||
&g_FactoryDataArray[g_cFactoryDataEntries - 1] ; | ||
|
||
for(CFactoryData* pData = pStart ; pData <= pEnd ; pData++) | ||
{ | ||
// Initialize the class factory pointer and cookie. | ||
pData->m_pIClassFactory = NULL ; | ||
pData->m_dwRegister = NULL ; | ||
|
||
// Create the class factory for this component. | ||
IClassFactory* pIFactory = new CFactory(pData) ; | ||
|
||
// Register the class factory. | ||
DWORD dwRegister ; | ||
HRESULT hr = ::CoRegisterClassObject( | ||
*pData->m_pCLSID, | ||
static_cast<IUnknown*>(pIFactory), | ||
CLSCTX_LOCAL_SERVER, | ||
REGCLS_MULTIPLEUSE, | ||
// REGCLS_MULTI_SEPARATE, //@Multi | ||
&dwRegister) ; | ||
if (FAILED(hr)) | ||
{ | ||
pIFactory->Release() ; | ||
return FALSE ; | ||
} | ||
|
||
// Set the data. | ||
pData->m_pIClassFactory = pIFactory ; | ||
pData->m_dwRegister = dwRegister ; | ||
} | ||
return TRUE ; | ||
} | ||
|
||
// | ||
// Stop factories | ||
// | ||
void CFactory::StopFactories() | ||
{ | ||
CFactoryData* pStart = &g_FactoryDataArray[0] ; | ||
const CFactoryData* pEnd = | ||
&g_FactoryDataArray[g_cFactoryDataEntries - 1] ; | ||
|
||
for (CFactoryData* pData = pStart ; pData <= pEnd ; pData++) | ||
{ | ||
// Get the magic cookie and stop the factory from running. | ||
DWORD dwRegister = pData->m_dwRegister ; | ||
if (dwRegister != 0) | ||
{ | ||
::CoRevokeClassObject(dwRegister) ; | ||
} | ||
|
||
// Release the class factory. | ||
IClassFactory* pIFactory = pData->m_pIClassFactory ; | ||
if (pIFactory != NULL) | ||
{ | ||
pIFactory->Release() ; | ||
} | ||
} | ||
} |
Oops, something went wrong.