forked from Travis-Sun/pywin32
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathPyFactory.cpp
More file actions
182 lines (156 loc) · 4.3 KB
/
Copy pathPyFactory.cpp
File metadata and controls
182 lines (156 loc) · 4.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
** Implementation for the CPyFactory class
*/
#include "stdafx.h"
#include <import.h> /* for PyImport_ImportModule() */
#include "PythonCOM.h"
#include "PyFactory.h"
#include "PythonCOMServer.h"
// Class Factories do not count against the DLLs total reference count.
static LONG factoryRefCount = 0;
CPyFactory::CPyFactory(REFCLSID guidClassID) :
m_guidClassID(guidClassID),
m_cRef(1)
{
InterlockedIncrement(&factoryRefCount);
}
CPyFactory::~CPyFactory()
{
InterlockedDecrement(&factoryRefCount);
}
STDMETHODIMP CPyFactory::QueryInterface(REFIID iid, void **ppv)
{
*ppv = NULL;
if ( IsEqualIID(iid, IID_IUnknown) ||
IsEqualIID(iid, IID_IClassFactory) )
{
*ppv = this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CPyFactory::AddRef(void)
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CPyFactory::Release(void)
{
LONG cRef = InterlockedDecrement(&m_cRef);
if ( cRef == 0 )
delete this;
return cRef;
}
STDMETHODIMP CPyFactory::CreateInstance(
IUnknown *punkOuter,
REFIID riid,
void **ppv
)
{
// LogF("in CPyFactory::CreateInstance");
if ( ppv == NULL )
return E_POINTER;
*ppv = NULL;
if ( punkOuter != NULL )
return CLASS_E_NOAGGREGATION;
// Add a temporary reference to the main DLL, so that the Python
// Init/Finalize semantics work correctly.
// If we ignore Factory reference counts, there is a possibility
// that the DLL global ref count will transition 1->0->1 during the
// creation process. To prevent this, we add an artificial lock
// and remove it when done.
HRESULT hr;
PyCom_DLLAddRef();
{ // scope to ensure CEnterLeave destructs before (possibly final) PyCom_DLLReleaseRef
CEnterLeavePython celp;
PyObject *pNewInstance = NULL;
hr = CreateNewPythonInstance(m_guidClassID, riid, &pNewInstance);
if ( FAILED(hr) )
{
PyCom_LoggerException(NULL, "CPyFactory::CreateInstance failed to create instance. (%lx)", hr);
}
else
{
// CreateInstance now returns an object already all wrapped
// up (giving more flexibility to the Python programmer.
if (!PyCom_InterfaceFromPyObject(pNewInstance, riid, ppv, FALSE)) {
PyCom_LoggerException(NULL, "CPyFactory::CreateInstance failed to get gateway to returned object");
hr = E_FAIL;
}
}
Py_XDECREF(pNewInstance); // Dont need it any more.
}
PyCom_DLLReleaseRef();
return hr;
}
STDMETHODIMP CPyFactory::LockServer(BOOL fLock)
{
if ( fLock )
PyCom_DLLAddRef();
else
PyCom_DLLReleaseRef();
return S_OK;
}
// NOTE NOTE: CreateNewPythonInstance assumes that you have the Python thread lock
// already acquired.
STDMETHODIMP CPyFactory::CreateNewPythonInstance(REFCLSID rclsid, REFCLSID rReqiid, PyObject **ppNewInstance)
{
extern BOOL LoadGatewayModule(PyObject **);
PyObject *pPyModule;
if ( ppNewInstance == NULL )
return E_INVALIDARG;
if ( !LoadGatewayModule(&pPyModule) )
return E_FAIL;
// zap any existing errors so we can reliably check for errors
// after object creation.
PyErr_Clear();
PyObject *obiid = PyWinObject_FromIID(rclsid);
PyObject *obReqiid = PyWinObject_FromIID(rReqiid);
if ( !obiid || !obReqiid)
{
Py_XDECREF(pPyModule);
Py_XDECREF(obiid);
Py_XDECREF(obReqiid);
PyErr_Clear(); // nothing Python can do!
return E_OUTOFMEMORY;
}
*ppNewInstance = PyObject_CallMethod(pPyModule, "CreateInstance",
"OO", obiid, obReqiid);
// Check the error state before DECREFs, otherwise they may
// change the error state.
if ( !*ppNewInstance )
PyCom_LoggerException(NULL, "ERROR: server.policy could not create an instance.");
HRESULT hr = PyCom_SetCOMErrorFromPyException(IID_IClassFactory);
Py_DECREF(obiid);
Py_DECREF(obReqiid);
Py_DECREF(pPyModule);
return hr;
}
/*
** Load our C <-> Python gateway module if needed
NOTE: Assumes the Python lock already acquired for us by our caller.
*/
BOOL LoadGatewayModule(PyObject **ppModule)
{
PyObject *pPyModule = NULL;
pPyModule = PyImport_ImportModule("win32com.server.policy");
if ( !pPyModule )
{
PyCom_LoggerException(NULL, "PythonCOM Server - The 'win32com.server.policy' module could not be loaded.");
/* ### propagate the exception? */
PyErr_Clear();
return FALSE;
}
*ppModule = pPyModule;
return TRUE;
}
void FreeGatewayModule(void)
{
/*****
if ( g_pPyModule != NULL )
{
Py_DECREF(g_pPyModule);
g_pPyModule = NULL;
}
*****/
}