-
Notifications
You must be signed in to change notification settings - Fork 0
/
ClassFactory.cs
243 lines (206 loc) · 8.21 KB
/
ClassFactory.cs
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
using System;
using System.Collections;
using System.Runtime.InteropServices;
namespace ASCOM.LocalServer
{
#region C# Definition of IClassFactory
/// <summary>
/// Reproduce the definition of the COM IClassFactory interface.
/// </summary>
[ComImport] // This interface originated from COM.
[ComVisible(false)] // Must not be exposed to COM!!!
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] // Indicate that this interface is not IDispatch-based.
[Guid("00000001-0000-0000-C000-000000000046")] // This GUID is the actual GUID of IClassFactory.
public interface IClassFactory
{
void CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);
void LockServer(bool fLock);
}
#endregion
/// <summary>
/// Universal ClassFactory. Given a type as a parameter of the constructor, it implements IClassFactory for any interface that the class implements. Magic!!!
/// </summary>
public class ClassFactory : IClassFactory
{
#region Access to ole32.dll functions for class factories
// Define two common GUID objects for public usage.
public static Guid IID_IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}");
public static Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}");
[Flags]
private enum CLSCTX : uint
{
CLSCTX_INPROC_SERVER = 0x1,
CLSCTX_INPROC_HANDLER = 0x2,
CLSCTX_LOCAL_SERVER = 0x4,
CLSCTX_INPROC_SERVER16 = 0x8,
CLSCTX_REMOTE_SERVER = 0x10,
CLSCTX_INPROC_HANDLER16 = 0x20,
CLSCTX_RESERVED1 = 0x40,
CLSCTX_RESERVED2 = 0x80,
CLSCTX_RESERVED3 = 0x100,
CLSCTX_RESERVED4 = 0x200,
CLSCTX_NO_CODE_DOWNLOAD = 0x400,
CLSCTX_RESERVED5 = 0x800,
CLSCTX_NO_CUSTOM_MARSHAL = 0x1000,
CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000,
CLSCTX_NO_FAILURE_LOG = 0x4000,
CLSCTX_DISABLE_AAA = 0x8000,
CLSCTX_ENABLE_AAA = 0x10000,
CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000,
CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
CLSCTX_ALL = CLSCTX_SERVER | CLSCTX_INPROC_HANDLER
}
[Flags]
private enum REGCLS : uint
{
REGCLS_SINGLEUSE = 0,
REGCLS_MULTIPLEUSE = 1,
REGCLS_MULTI_SEPARATE = 2,
REGCLS_SUSPENDED = 4,
REGCLS_SURROGATE = 8
}
/// <summary>
/// Register a Class Factory into COM's internal table of Class Factories.
/// </summary>
[DllImport("ole32.dll")]
static extern int CoRegisterClassObject([In] ref Guid rclsid, [MarshalAs(UnmanagedType.IUnknown)] object pUnk, uint dwClsContext, uint flags, out uint lpdwRegister);
/// <summary>
/// Called by a COM EXE Server that can register multiple class objects to inform COM about all registered classes, and permits activation requests for those class objects.
/// </summary>
/// <remarks>
/// This function causes OLE to inform the SCM about all the registered classes, and begins letting activation requests into the server process.
/// </remarks>
[DllImport("ole32.dll")]
static extern int CoResumeClassObjects();
/// <summary>
/// Prevents new activation requests from the SCM on all class objects registered within the process.
/// </summary>
/// <remarks>
/// Even though a process may call this API, the process still must call CoRevokeClassObject for each CLSID it has registered, in the apartment it registered in.
/// </remarks>
[DllImport("ole32.dll")]
static extern int CoSuspendClassObjects();
/// <summary>
/// Unregister a Class Factory from COM's internal table of Class Factories.
/// </summary>
[DllImport("ole32.dll")]
static extern int CoRevokeClassObject(uint dwRegister);
#endregion
#region Private ClassFactory Data
protected Type classType;
protected Guid classId;
protected ArrayList interfaceTypes;
protected uint classContext;
protected uint flags;
protected UInt32 locked = 0;
protected uint cookie;
protected string progId;
#endregion
#region Constructor
/// <summary>
/// Initialises the class factory interface for the supplied type
/// </summary>
/// <param name="type">Type for which to add class factory functionality</param>
public ClassFactory(Type type)
{
classType = type ?? throw new ArgumentNullException("type");
progId = Marshal.GenerateProgIdForType(type);
classId = Marshal.GenerateGuidForType(type);
classContext = (uint)CLSCTX.CLSCTX_LOCAL_SERVER; // Default
flags = (uint)REGCLS.REGCLS_MULTIPLEUSE | (uint)REGCLS.REGCLS_SUSPENDED;
interfaceTypes = new ArrayList();
// Save all of the implemented interfaces
foreach (Type T in type.GetInterfaces())
{
interfaceTypes.Add(T);
}
}
#endregion
#region Common ClassFactory Methods
public uint ClassContext
{
get { return classContext; }
set { classContext = value; }
}
public Guid ClassId
{
get { return classId; }
set { classId = value; }
}
public uint Flags
{
get { return flags; }
set { flags = value; }
}
public bool RegisterClassObject()
{
// Register the class factory
int i = CoRegisterClassObject(ref classId, this, classContext, flags, out cookie);
return (i == 0);
}
public bool RevokeClassObject()
{
int i = CoRevokeClassObject(cookie);
return (i == 0);
}
public static bool ResumeClassObjects()
{
int i = CoResumeClassObjects();
return (i == 0);
}
public static bool SuspendClassObjects()
{
int i = CoSuspendClassObjects();
return (i == 0);
}
#endregion
#region IClassFactory Implementations
/// <summary>
///Implement creation of the type and interface.
/// </summary>
void IClassFactory.CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject)
{
IntPtr nullPtr = new IntPtr(0);
ppvObject = nullPtr;
// Handle specific requests for implemented interfaces
foreach (Type iType in interfaceTypes)
{
if (riid == Marshal.GenerateGuidForType(iType))
{
ppvObject = Marshal.GetComInterfaceForObject(Activator.CreateInstance(classType), iType);
return;
}
}
// Handle requests for IDispatch or IUnknown on the class
if (riid == IID_IDispatch)
{
ppvObject = Marshal.GetIDispatchForObject(Activator.CreateInstance(classType));
return;
}
else if (riid == IID_IUnknown)
{
ppvObject = Marshal.GetIUnknownForObject(Activator.CreateInstance(classType));
}
else
{
// Oops, some interface that the class doesn't implement
throw new COMException("No interface", unchecked((int)0x80004002));
}
}
void IClassFactory.LockServer(bool incrementLockCount)
{
if (incrementLockCount)
{
Server.IncrementServerLockCount();
}
else
{
Server.DecrementServerLockLock();
}
// Check whether we need to shutdown the server application.
Server.ExitIf();
}
#endregion
}
}