2 {*******************************************************}
4 { Borland Delphi Runtime Library }
7 { Copyright (C) 1997,99 Inprise Corporation }
9 {*******************************************************}
18 uses Windows
, ActiveX
, KOL
, err
{$IFDEF _D6orHigher}, Variants
{$ENDIF};
21 { Forward declarations }
23 TComObjectFactory
= class;
25 { COM server abstract base class }
27 TComServerObject
= class(TObject
)
29 function CountObject(Created
: Boolean): Integer; virtual; abstract;
30 function CountFactory(Created
: Boolean): Integer; virtual; abstract;
31 function GetHelpFileName
: string; virtual; abstract;
32 function GetServerFileName
: string; virtual; abstract;
33 function GetServerKey
: string; virtual; abstract;
34 function GetServerName
: string; virtual; abstract;
35 function GetStartSuspended
: Boolean; virtual; abstract;
36 function GetTypeLib
: ITypeLib
; virtual; abstract;
37 procedure SetHelpFileName(const Value
: string); virtual; abstract;
39 property HelpFileName
: string read GetHelpFileName write SetHelpFileName
;
40 property ServerFileName
: string read GetServerFileName
;
41 property ServerKey
: string read GetServerKey
;
42 property ServerName
: string read GetServerName
;
43 property TypeLib
: ITypeLib read GetTypeLib
;
44 property StartSuspended
: Boolean read GetStartSuspended
;
48 { TMultiReadExclusiveWriteSynchronizer minimizes thread serialization to gain
49 read access to a resource shared among threads while still providing complete
50 exclusivity to callers needing write access to the shared resource.
51 (multithread shared reads, single thread exclusive write)
52 Reading is allowed while owning a write lock.
53 Read locks can be promoted to write locks.}
56 TActiveThreadRecord
= record
58 RecursionCount
: Integer;
60 TActiveThreadArray
= array of TActiveThreadRecord
;
62 TMultiReadExclusiveWriteSynchronizer
= class
64 FLock
: TRTLCriticalSection
;
67 FSaveReadCount
: Integer;
68 FActiveThreads
: TActiveThreadArray
;
69 FWriteRequestorID
: Integer;
70 FReallocFlag
: Integer;
72 function WriterIsOnlyReader
: Boolean;
75 destructor Destroy
; override;
85 TFactoryProc
= procedure(Factory
: TComObjectFactory
) of object;
87 TComClassManager
= class(TObject
)
89 FFactoryList
: TComObjectFactory
;
91 FLock
: TMultiReadExclusiveWriteSynchronizer
;
93 procedure AddObjectFactory(Factory
: TComObjectFactory
);
94 procedure RemoveObjectFactory(Factory
: TComObjectFactory
);
97 destructor Destroy
; override;
98 procedure ForEachFactory(ComServer
: TComServerObject
;
99 FactoryProc
: TFactoryProc
);
100 function GetFactoryFromClass(ComClass
: TClass
): TComObjectFactory
;
101 function GetFactoryFromClassID(const ClassID
: TGUID
): TComObjectFactory
;
104 { IServerExceptionHandler }
105 { This interface allows you to report safecall exceptions that occur in a
106 TComObject server to a third party, such as an object that logs errors into
107 the system event log or a server monitor residing on another machine.
108 Obtain an interface from the error logger implementation and assign it
109 to your TComObject's ServerExceptionHandler property. Each TComObject
110 instance can have its own server exception handler, or all instances can
111 share the same handler. The server exception handler can override the
112 TComObject's default exception handling by setting Handled to True and
113 assigning an OLE HResult code to the HResult parameter.
116 IServerExceptionHandler
= interface
117 ['{6A8D432B-EB81-11D1-AAB1-00C04FB16FBC}']
118 procedure OnException(
119 const ServerClass
, ExceptionClass
, ErrorMessage
: WideString
;
120 ExceptAddr
: Integer; const ErrorIID
, ProgID
: WideString
;
121 var Handled
: Integer; var Result
: HResult
); dispid 2;
126 TComObject
= class(TObject
, IUnknown
, ISupportErrorInfo
)
128 FController
: Pointer;
129 FFactory
: TComObjectFactory
;
130 FNonCountedObject
: Boolean;
132 FServerExceptionHandler
: IServerExceptionHandler
;
133 function GetController
: IUnknown
;
136 function IUnknown
.QueryInterface
= ObjQueryInterface
;
137 function IUnknown
._AddRef
= ObjAddRef
;
138 function IUnknown
._Release
= ObjRelease
;
139 { IUnknown methods for other interfaces }
140 function QueryInterface(const IID
: TGUID
; out Obj
): HResult
; stdcall;
141 function _AddRef
: Integer; stdcall;
142 function _Release
: Integer; stdcall;
143 { ISupportErrorInfo }
144 function InterfaceSupportsErrorInfo(const iid
: TIID
): HResult
; stdcall;
147 constructor CreateAggregated(const Controller
: IUnknown
);
148 constructor CreateFromFactory(Factory
: TComObjectFactory
;
149 const Controller
: IUnknown
);
150 destructor Destroy
; override;
151 procedure Initialize
; virtual;
152 function ObjAddRef
: Integer; virtual; stdcall;
153 function ObjQueryInterface(const IID
: TGUID
; out Obj
): HResult
; virtual; stdcall;
154 function ObjRelease
: Integer; virtual; stdcall;
155 function SafeCallException(ExceptObject
: TObject
;
156 ExceptAddr
: Pointer): HResult
; override;
157 property Controller
: IUnknown read GetController
;
158 property Factory
: TComObjectFactory read FFactory
;
159 property RefCount
: Integer read FRefCount
;
160 property ServerExceptionHandler
: IServerExceptionHandler
161 read FServerExceptionHandler write FServerExceptionHandler
;
166 TComClass
= class of TComObject
;
168 { Instancing mode for COM classes }
170 TClassInstancing
= (ciInternal
, ciSingleInstance
, ciMultiInstance
);
172 { Threading model supported by COM classes }
174 TThreadingModel
= (tmSingle
, tmApartment
, tmFree
, tmBoth
);
176 { COM object factory }
181 TComObjectFactory
= class(TObject
, IUnknown
, IClassFactory
, IClassFactory2
)
183 FNext
: TComObjectFactory
;
184 FComServer
: TComServerObject
;
188 FDescription
: string;
190 FInstancing
: TClassInstancing
;
191 FLicString
: WideString
;
193 FShowErrors
: Boolean;
194 FSupportsLicensing
: Boolean;
195 FThreadingModel
: TThreadingModel
;
197 function GetProgID
: string; virtual;
198 function GetLicenseString
: WideString
; virtual;
199 function HasMachineLicense
: Boolean; virtual;
200 function ValidateUserLicense(const LicStr
: WideString
): Boolean; virtual;
202 function QueryInterface(const IID
: TGUID
; out Obj
): HResult
; stdcall;
203 function _AddRef
: Integer; stdcall;
204 function _Release
: Integer; stdcall;
206 function CreateInstance(const UnkOuter
: IUnknown
; const IID
: TGUID
;
207 out Obj
): HResult
; stdcall;
208 function LockServer(fLock
: BOOL
): HResult
; stdcall;
210 function GetLicInfo(var licInfo
: TLicInfo
): HResult
; stdcall;
211 function RequestLicKey(dwResrved
: Longint; out bstrKey
: WideString
): HResult
; stdcall;
212 function CreateInstanceLic(const unkOuter
: IUnknown
; const unkReserved
: IUnknown
;
213 const iid
: TIID
; const bstrKey
: WideString
; out vObject
): HResult
; stdcall;
215 constructor Create(ComServer
: TComServerObject
; ComClass
: TComClass
;
216 const ClassID
: TGUID
; const ClassName
, Description
: string;
217 Instancing
: TClassInstancing
; ThreadingModel
: TThreadingModel
{= tmSingle} );
218 destructor Destroy
; override;
219 function CreateComObject(const Controller
: IUnknown
): TComObject
; virtual;
220 procedure RegisterClassObject
;
221 procedure UpdateRegistry(Register: Boolean); virtual;
222 property ClassID
: TGUID read FClassID
;
223 property ClassName
: string read FClassName
;
224 property ComClass
: TClass read FComClass
;
225 property ComServer
: TComServerObject read FComServer
;
226 property Description
: string read FDescription
;
227 property ErrorIID
: TGUID read FErrorIID write FErrorIID
;
228 property LicString
: WideString read FLicString write FLicString
;
229 property ProgID
: string read GetProgID
;
230 property Instancing
: TClassInstancing read FInstancing
;
231 property ShowErrors
: Boolean read FShowErrors write FShowErrors
;
232 property SupportsLicensing
: Boolean read FSupportsLicensing write FSupportsLicensing
;
233 property ThreadingModel
: TThreadingModel read FThreadingModel
;
239 { COM objects intended to be aggregated / contained }
241 TAggregatedObject
= class
243 FController
: Pointer;
244 function GetController
: IUnknown
;
247 function QueryInterface(const IID
: TGUID
; out Obj
): HResult
; stdcall;
248 function _AddRef
: Integer; stdcall;
249 function _Release
: Integer; stdcall;
251 constructor Create(Controller
: IUnknown
);
252 property Controller
: IUnknown read GetController
;
255 TContainedObject
= class(TAggregatedObject
, IUnknown
)
258 function QueryInterface(const IID
: TGUID
; out Obj
): HResult
; virtual; stdcall;
261 { COM object with type information }
263 TTypedComObject
= class(TComObject
, IProvideClassInfo
)
265 { IProvideClassInfo }
266 function GetClassInfo(out TypeInfo
: ITypeInfo
): HResult
; stdcall;
269 TTypedComClass
= class of TTypedComObject
;
274 TTypedComObjectFactory
= class(TComObjectFactory
)
276 FClassInfo
: ITypeInfo
;
278 constructor Create(ComServer
: TComServerObject
;
279 TypedComClass
: TTypedComClass
; const ClassID
: TGUID
;
280 Instancing
: TClassInstancing
; ThreadingModel
: TThreadingModel
{= tmSingle} );
281 function GetInterfaceTypeInfo(TypeFlags
: Integer): ITypeInfo
;
282 procedure UpdateRegistry(Register: Boolean); override;
283 property ClassInfo
: ITypeInfo read FClassInfo
;
289 { OLE Automation object }
291 TConnectEvent
= procedure (const Sink
: IUnknown
; Connecting
: Boolean) of object;
293 TAutoObjectFactory
= class;
295 TAutoObject
= class(TTypedComObject
, IDispatch
)
297 FEventSink
: IUnknown
;
298 FAutoFactory
: TAutoObjectFactory
;
301 function GetIDsOfNames(const IID
: TGUID
; Names
: Pointer;
302 NameCount
, LocaleID
: Integer; DispIDs
: Pointer): HResult
; virtual; stdcall;
303 function GetTypeInfo(Index
, LocaleID
: Integer; out TypeInfo
): HResult
; virtual; stdcall;
304 function GetTypeInfoCount(out Count
: Integer): HResult
; virtual; stdcall;
305 function Invoke(DispID: Integer; const IID
: TGUID
; LocaleID
: Integer;
306 Flags
: Word; var Params
; VarResult
, ExcepInfo
, ArgErr
: Pointer): HResult
; virtual; stdcall;
308 procedure EventConnect(const Sink
: IUnknown
; Connecting
: Boolean);
309 procedure EventSinkChanged(const EventSink
: IUnknown
); virtual;
310 property AutoFactory
: TAutoObjectFactory read FAutoFactory
;
311 property EventSink
: IUnknown read FEventSink write FEventSink
;
313 procedure Initialize
; override;
316 { OLE Automation class }
318 TAutoClass
= class of TAutoObject
;
320 { OLE Automation object factory }
322 TAutoObjectFactory
= class(TTypedComObjectFactory
)
324 FDispTypeInfo
: ITypeInfo
;
325 FDispIntfEntry
: PInterfaceEntry
;
327 FEventTypeInfo
: ITypeInfo
;
329 constructor Create(ComServer
: TComServerObject
; AutoClass
: TAutoClass
;
330 const ClassID
: TGUID
; Instancing
: TClassInstancing
;
331 ThreadingModel
: TThreadingModel
{= tmSingle} );
332 function GetIntfEntry(Guid
: TGUID
): PInterfaceEntry
; virtual;
333 property DispIntfEntry
: PInterfaceEntry read FDispIntfEntry
;
334 property DispTypeInfo
: ITypeInfo read FDispTypeInfo
;
335 property EventIID
: TGUID read FEventIID
;
336 property EventTypeInfo
: ITypeInfo read FEventTypeInfo
;
339 TAutoIntfObject
= class(TInterfacedObject
, IDispatch
, ISupportErrorInfo
)
341 FDispTypeInfo
: ITypeInfo
;
342 FDispIntfEntry
: PInterfaceEntry
;
346 function GetIDsOfNames(const IID
: TGUID
; Names
: Pointer;
347 NameCount
, LocaleID
: Integer; DispIDs
: Pointer): HResult
; stdcall;
348 function GetTypeInfo(Index
, LocaleID
: Integer; out TypeInfo
): HResult
; stdcall;
349 function GetTypeInfoCount(out Count
: Integer): HResult
; stdcall;
350 function Invoke(DispID: Integer; const IID
: TGUID
; LocaleID
: Integer;
351 Flags
: Word; var Params
; VarResult
, ExcepInfo
, ArgErr
: Pointer): HResult
; stdcall;
352 { ISupportErrorInfo }
353 function InterfaceSupportsErrorInfo(const iid
: TIID
): HResult
; stdcall;
355 constructor Create(const TypeLib
: ITypeLib
; const DispIntf
: TGUID
);
356 function SafeCallException(ExceptObject
: TObject
;
357 ExceptAddr
: Pointer): HResult
; override;
358 property DispIntfEntry
: PInterfaceEntry read FDispIntfEntry
;
359 property DispTypeInfo
: ITypeInfo read FDispTypeInfo
;
360 property DispIID
: TGUID read FDispIID
;
363 { OLE exception classes }
365 EOleError
= Exception
; // class(Exception);
367 EOleSysError
= EOleError
; { class(EOleError)
371 constructor Create(const Message: string; ErrorCode: HRESULT;
372 HelpContext: Integer);
373 property ErrorCode: HRESULT read FErrorCode write FErrorCode;
376 EOleException
= EOleSysError
; { class(EOleSysError)
381 constructor Create(const Message: string; ErrorCode: HRESULT;
382 const Source, HelpFile: string; HelpContext: Integer);
383 property HelpFile: string read FHelpFile write FHelpFile;
384 property Source: string read FSource write FSource;
387 EOleRegistrationError
= EOleError
; { class(EOleError);}
389 { Dispatch call descriptor }
391 PCallDesc
= ^TCallDesc
;
392 TCallDesc
= packed record
396 ArgTypes
: array[0..255] of Byte;
399 PDispDesc
= ^TDispDesc
;
400 TDispDesc
= packed record
406 procedure DispatchInvoke(const Dispatch
: IDispatch
; CallDesc
: PCallDesc
;
407 DispIDs
: PDispIDList
; Params
: Pointer; Result
: PVariant
);
408 procedure DispatchInvokeError(Status
: Integer; const ExcepInfo
: TExcepInfo
);
410 {function HandleSafeCallException(ExceptObject: TObject;
411 ExceptAddr: Pointer; const ErrorIID: TGUID; const ProgID,
412 HelpFileName: WideString): HResult;}
414 function CreateComObject(const ClassID
: TGUID
): IUnknown
;
415 function CreateRemoteComObject(const MachineName
: WideString
; const ClassID
: TGUID
): IUnknown
;
416 function CreateOleObject(const ClassName
: string): IDispatch
;
417 function GetActiveOleObject(const ClassName
: string): IDispatch
;
419 procedure OleError(ErrorCode
: HResult
);
420 procedure OleCheck(Result
: HResult
);
422 function StringToGUID(const S
: string): TGUID
;
423 function GUIDToString(const ClassID
: TGUID
): string;
425 function ProgIDToClassID(const ProgID
: string): TGUID
;
426 function ClassIDToProgID(const ClassID
: TGUID
): string;
428 procedure CreateRegKey(const Key
, ValueName
, Value
: string);
429 procedure DeleteRegKey(const Key
: string);
430 function GetRegStringValue(const Key
, ValueName
: string): string;
432 function StringToLPOLESTR(const Source
: string): POleStr
;
434 procedure RegisterComServer(const DLLName
: string);
435 procedure RegisterAsService(const ClassID
, ServiceName
: string);
437 function CreateClassID
: string;
439 procedure InterfaceConnect(const Source
: IUnknown
; const IID
: TIID
;
440 const Sink
: IUnknown
; var Connection
: Longint);
441 procedure InterfaceDisconnect(const Source
: IUnknown
; const IID
: TIID
;
442 var Connection
: Longint);
445 TCoCreateInstanceExProc
= function (const clsid
: TCLSID
;
446 unkOuter
: IUnknown
; dwClsCtx
: Longint; ServerInfo
: PCoServerInfo
;
447 dwCount
: Longint; rgmqResults
: PMultiQIArray
): HResult
stdcall;
448 TCoInitializeExProc
= function (pvReserved
: Pointer;
449 coInit
: Longint): HResult
; stdcall;
450 TCoAddRefServerProcessProc
= function :Longint; stdcall;
451 TCoReleaseServerProcessProc
= function :Longint; stdcall;
452 TCoResumeClassObjectsProc
= function :HResult
; stdcall;
453 TCoSuspendClassObjectsProc
= function :HResult
; stdcall;
455 // COM functions that are only available on DCOM updated OSs
456 // These pointers may be nil on Win95 or Win NT 3.51 systems
458 CoCreateInstanceEx
: TCoCreateInstanceExProc
= nil;
459 CoInitializeEx
: TCoInitializeExProc
= nil;
460 CoAddRefServerProcess
: TCoAddRefServerProcessProc
= nil;
461 CoReleaseServerProcess
: TCoReleaseServerProcessProc
= nil;
462 CoResumeClassObjects
: TCoResumeClassObjectsProc
= nil;
463 CoSuspendClassObjects
: TCoSuspendClassObjectsProc
= nil;
466 { CoInitFlags determines the COM threading model of the application or current
467 thread. This bitflag value is passed to CoInitializeEx in ComServ initialization.
468 Assign COINIT_APARTMENTTHREADED or COINIT_MULTITHREADED to this variable before
469 Application.Initialize is called by the project source file to select a
470 threading model. Other CoInitializeEx flags (such as COINIT_SPEED_OVER_MEMORY)
471 can be OR'd in also. }
473 CoInitFlags
: Integer = -1; // defaults to no threading model, call CoInitialize()
475 function ComClassManager
: TComClassManager
;
480 SCreateRegKeyError
= 'Error creating system registry entry';
481 SOleError
= 'OLE error %.8x';
482 SObjectFactoryMissing
= 'Object factory for class %s missing';
483 STypeInfoMissing
= 'Type information missing for class %s';
484 SBadTypeInfo
= 'Incorrect type information for class %s';
485 SDispIntfMissing
= 'Dispatch interface missing from class %s';
486 SNoMethod
= 'Method ''%s'' not supported by automation object';
487 SVarNotObject
= 'Variant does not reference an automation object';
488 SDCOMNotInstalled
= 'DCOM not installed';
489 SDAXError
= 'DAX Error';
491 SAutomationWarning
= 'COM Server Warning';
492 SNoCloseActiveServer1
= 'There are still active COM objects in this ' +
493 'application. One or more clients may have references to these objects, ' +
494 'so manually closing ';
495 SNoCloseActiveServer2
= 'this application may cause those client ' +
496 'application(s) to fail.'#13#10#13#10'Are you sure you want to close this ' +
500 OleUninitializing
: Boolean;
502 { Handle a safe call exception }
504 {function HandleSafeCallException(ExceptObject: TObject;
505 ExceptAddr: Pointer; const ErrorIID: TGUID; const ProgID,
506 HelpFileName: WideString): HResult;
509 CreateError: ICreateErrorInfo;
510 ErrorInfo: IErrorInfo;
512 Result := E_UNEXPECTED;
514 if Succeeded(CreateErrorInfo(CreateError)) then
516 CreateError.SetGUID(ErrorIID);
517 if ProgID <> '' then CreateError.SetSource(PWideChar(ProgID));
518 if HelpFileName <> '' then CreateError.SetHelpFile(PWideChar(HelpFileName));
519 if E is Exception then
521 CreateError.SetDescription(PWideChar(WideString(Exception(E).Message)));
522 CreateError.SetHelpContext(Exception(E).HelpContext);
523 if (E is EOleSysError) and (EOleSysError(E).ErrorCode < 0) then
524 Result := EOleSysError(E).ErrorCode;
526 if CreateError.QueryInterface(IErrorInfo, ErrorInfo) = S_OK then
527 SetErrorInfo(0, ErrorInfo);
531 { TDispatchSilencer }
534 TDispatchSilencer
= class(TInterfacedObject
, IUnknown
, IDispatch
)
539 constructor Create(ADispatch
: IUnknown
; const ADispIntfIID
: TGUID
);
541 function QueryInterface(const IID
: TGUID
; out Obj
): HResult
; stdcall;
543 function GetTypeInfoCount(out Count
: Integer): HResult
; stdcall;
544 function GetTypeInfo(Index
, LocaleID
: Integer; out TypeInfo
): HResult
; stdcall;
545 function GetIDsOfNames(const IID
: TGUID
; Names
: Pointer;
546 NameCount
, LocaleID
: Integer; DispIDs
: Pointer): HResult
; stdcall;
547 function Invoke(DispID: Integer; const IID
: TGUID
; LocaleID
: Integer;
548 Flags
: Word; var Params
; VarResult
, ExcepInfo
, ArgErr
: Pointer): HResult
; stdcall;
551 constructor TDispatchSilencer
.Create(ADispatch
: IUnknown
;
552 const ADispIntfIID
: TGUID
);
555 DispIntfIID
:= ADispIntfIID
;
556 OleCheck(ADispatch
.QueryInterface(ADispIntfIID
, Dispatch
));
559 function TDispatchSilencer
.QueryInterface(const IID
: TGUID
; out Obj
): HResult
;
561 Result
:= inherited QueryInterface(IID
, Obj
);
562 if Result
= E_NOINTERFACE
then
563 if IsEqualGUID(IID
, DispIntfIID
) then
565 IDispatch(Obj
) := Self
;
569 Result
:= Dispatch
.QueryInterface(IID
, Obj
);
572 function TDispatchSilencer
.GetTypeInfoCount(out Count
: Integer): HResult
;
574 Result
:= Dispatch
.GetTypeInfoCount(Count
);
577 function TDispatchSilencer
.GetTypeInfo(Index
, LocaleID
: Integer; out TypeInfo
): HResult
;
579 Result
:= Dispatch
.GetTypeInfo(Index
, LocaleID
, TypeInfo
);
582 function TDispatchSilencer
.GetIDsOfNames(const IID
: TGUID
; Names
: Pointer;
583 NameCount
, LocaleID
: Integer; DispIDs
: Pointer): HResult
;
585 Result
:= Dispatch
.GetIDsOfNames(IID
, Names
, NameCount
, LocaleID
, DispIDs
);
588 function TDispatchSilencer
.Invoke(DispID: Integer; const IID
: TGUID
; LocaleID
: Integer;
589 Flags
: Word; var Params
; VarResult
, ExcepInfo
, ArgErr
: Pointer): HResult
;
591 { Ignore error since some containers, such as Internet Explorer 3.0x, will
592 return error when the method was not handled, or scripting errors occur }
593 Dispatch
.Invoke(DispID, IID
, LocaleID
, Flags
, Params
, VarResult
, ExcepInfo
,
599 { TMultiReadExclusiveWriteSynchronizer }
601 constructor TMultiReadExclusiveWriteSynchronizer
.Create
;
604 InitializeCriticalSection(FLock
);
605 FReadExit
:= CreateEvent(nil, True, True, nil); // manual reset, start signaled
606 SetLength(FActiveThreads
, 4);
609 destructor TMultiReadExclusiveWriteSynchronizer
.Destroy
;
613 CloseHandle(FReadExit
);
614 DeleteCriticalSection(FLock
);
617 function TMultiReadExclusiveWriteSynchronizer
.WriterIsOnlyReader
: Boolean;
622 if FWriteRequestorID
= 0 then Exit
;
623 // We know a writer is waiting for entry with the FLock locked,
624 // so FActiveThreads is stable - no BeginRead could be resizing it now
626 Len
:= High(FActiveThreads
);
628 ((FActiveThreads
[I
].ThreadID
= 0) or (FActiveThreads
[I
].ThreadID
= FWriteRequestorID
)) do
633 procedure TMultiReadExclusiveWriteSynchronizer
.BeginWrite
;
635 EnterCriticalSection(FLock
); // Block new read or write ops from starting
638 FWriteRequestorID
:= GetCurrentThreadID
; // Indicate that writer is waiting for entry
639 if not WriterIsOnlyReader
then // See if any other thread is reading
640 WaitForSingleObject(FReadExit
, INFINITE
); // Wait for current readers to finish
641 FSaveReadCount
:= FCount
; // record prior read recursions for this thread
643 FWriteRequestorID
:= 0;
646 Inc(FCount
); // allow read recursions during write without signalling FReadExit event
649 procedure TMultiReadExclusiveWriteSynchronizer
.EndWrite
;
654 FCount
:= FSaveReadCount
; // restore read recursion count
658 LeaveCriticalSection(FLock
);
661 procedure TMultiReadExclusiveWriteSynchronizer
.BeginRead
;
666 AlreadyInRead
: Boolean;
668 ThreadID
:= GetCurrentThreadID
;
669 // First, do a lightweight check to see if this thread already has a read lock
670 while InterlockedExchange(FReallocFlag
, ThreadID
) <> 0 do Sleep(0);
671 try // FActiveThreads array is now stable
673 while (I
< High(FActiveThreads
)) and (FActiveThreads
[I
].ThreadID
<> ThreadID
) do
675 AlreadyInRead
:= I
< High(FActiveThreads
);
676 if AlreadyInRead
then // This thread already has a read lock
677 begin // Don't grab FLock, since that could deadlock with
678 if not FWriting
then // a waiting BeginWrite
679 begin // Bump up ref counts and exit
680 InterlockedIncrement(FCount
);
681 Inc(FActiveThreads
[I
].RecursionCount
); // thread safe = unique to threadid
687 if not AlreadyInRead
then
688 begin // Ok, we don't already have a lock, so do the hard work of making one
689 EnterCriticalSection(FLock
);
693 // This will call ResetEvent more than necessary on win95, but still work
694 if InterlockedIncrement(FCount
) = 1 then
695 ResetEvent(FReadExit
); // Make writer wait until all readers are finished.
696 I
:= 0; // scan for empty slot in activethreads list
698 while (I
< High(FActiveThreads
)) and (FActiveThreads
[I
].ThreadID
<> ThreadID
) do
700 if (FActiveThreads
[I
].ThreadID
= 0) and (ZeroSlot
< 0) then ZeroSlot
:= I
;
703 if I
>= High(FActiveThreads
) then // didn't find our threadid slot
705 if ZeroSlot
< 0 then // no slots available. Grow array to make room
706 begin // spin loop. wait for EndRead to put zero back into FReallocFlag
707 while InterlockedExchange(FReallocFlag
, ThreadID
) <> 0 do Sleep(0);
709 SetLength(FActiveThreads
, High(FActiveThreads
) + 3);
714 else // use an empty slot
716 // no concurrency issue here. We're the only thread interested in this record.
717 FActiveThreads
[I
].ThreadID
:= ThreadID
;
718 FActiveThreads
[I
].RecursionCount
:= 1;
720 else // found our threadid slot.
721 Inc(FActiveThreads
[I
].RecursionCount
); // thread safe = unique to threadid
724 LeaveCriticalSection(FLock
);
729 procedure TMultiReadExclusiveWriteSynchronizer
.EndRead
;
731 I
, ThreadID
, Len
: Integer;
735 // Remove our threadid from the list of active threads
737 ThreadID
:= GetCurrentThreadID
;
738 // wait for BeginRead to finish any pending realloc of FActiveThreads
739 while InterlockedExchange(FReallocFlag
, ThreadID
) <> 0 do Sleep(0);
741 Len
:= High(FActiveThreads
);
742 while (I
< Len
) and (FActiveThreads
[I
].ThreadID
<> ThreadID
) do Inc(I
);
744 // no concurrency issues here. We're the only thread interested in this record.
745 Dec(FActiveThreads
[I
].RecursionCount
); // threadsafe = unique to threadid
746 if FActiveThreads
[I
].RecursionCount
= 0 then
747 FActiveThreads
[I
].ThreadID
:= 0; // must do this last!
751 if (InterlockedDecrement(FCount
) = 0) or WriterIsOnlyReader
then
752 SetEvent(FReadExit
); // release next writer
756 procedure FreeAndNil(var Obj
);
761 TObject(Obj
) := nil; // clear the reference before destroying the object
767 constructor TComClassManager
.Create
;
771 FLock
:= TMultiReadExclusiveWriteSynchronizer
.Create
;
775 destructor TComClassManager
.Destroy
;
783 procedure TComClassManager
.AddObjectFactory(Factory
: TComObjectFactory
);
789 Factory
.FNext
:= FFactoryList
;
790 FFactoryList
:= Factory
;
798 procedure TComClassManager
.ForEachFactory(ComServer
: TComServerObject
;
799 FactoryProc
: TFactoryProc
);
801 Factory
, Next
: TComObjectFactory
;
804 FLock
.BeginWrite
; // FactoryProc could add or delete factories from list
807 Factory
:= FFactoryList
;
808 while Factory
<> nil do
810 Next
:= Factory
.FNext
;
811 if Factory
.ComServer
= ComServer
then FactoryProc(Factory
);
821 function TComClassManager
.GetFactoryFromClass(ComClass
: TClass
): TComObjectFactory
;
827 Result
:= FFactoryList
;
828 while Result
<> nil do
830 if Result
.ComClass
= ComClass
then Exit
;
831 Result
:= Result
.FNext
;
833 raise EOleError
.CreateResFmt(e_Ole
, Integer( @SObjectFactoryMissing
), [ComClass
.ClassName
]);
841 function TComClassManager
.GetFactoryFromClassID(const ClassID
: TGUID
): TComObjectFactory
;
847 Result
:= FFactoryList
;
848 while Result
<> nil do
850 if IsEqualGUID(Result
.ClassID
, ClassID
) then Exit
;
851 Result
:= Result
.FNext
;
860 procedure TComClassManager
.RemoveObjectFactory(Factory
: TComObjectFactory
);
862 F
, P
: TComObjectFactory
;
874 if P
<> nil then P
.FNext
:= F
.FNext
else FFactoryList
:= F
.FNext
;
889 constructor TComObject
.Create
;
891 FNonCountedObject
:= True;
892 CreateFromFactory(ComClassManager
.GetFactoryFromClass(ClassType
), nil);
895 constructor TComObject
.CreateAggregated(const Controller
: IUnknown
);
897 FNonCountedObject
:= True;
898 CreateFromFactory(ComClassManager
.GetFactoryFromClass(ClassType
), Controller
);
901 constructor TComObject
.CreateFromFactory(Factory
: TComObjectFactory
;
902 const Controller
: IUnknown
);
906 FController
:= Pointer(Controller
);
907 if not FNonCountedObject
then FFactory
.ComServer
.CountObject(True);
912 destructor TComObject
.Destroy
;
914 if not OleUninitializing
then
916 if (FFactory
<> nil) and not FNonCountedObject
then
917 FFactory
.ComServer
.CountObject(False);
918 if FRefCount
> 0 then CoDisconnectObject(Self
, 0);
922 function TComObject
.GetController
: IUnknown
;
924 Result
:= IUnknown(FController
);
927 procedure TComObject
.Initialize
;
931 function TComObject
.SafeCallException(ExceptObject
: TObject
;
932 ExceptAddr
: Pointer): HResult
;
938 if ServerExceptionHandler
<> nil then
940 if ExceptObject
is Exception
then
941 Msg
:= Exception(ExceptObject
).Message;
943 ServerExceptionHandler
.OnException(ClassName
,
944 ExceptObject
.ClassName
, Msg
, Integer(ExceptAddr
),
945 WideString(GUIDToString(FFactory
.ErrorIID
)),
946 FFactory
.ProgID
, Handled
, Result
);
949 {Result := HandleSafeCallException(ExceptObject, ExceptAddr,
950 FFactory.ErrorIID, FFactory.ProgID, FFactory.ComServer.HelpFileName);}
953 { TComObject.IUnknown }
955 function TComObject
.ObjQueryInterface(const IID
: TGUID
; out Obj
): HResult
;
957 if GetInterface(IID
, Obj
) then Result
:= S_OK
else Result
:= E_NOINTERFACE
;
960 function TComObject
.ObjAddRef
: Integer;
962 Result
:= InterlockedIncrement(FRefCount
);
965 function TComObject
.ObjRelease
: Integer;
967 // InterlockedDecrement returns only 0 or 1 on Win95 and NT 3.51
968 // returns actual result on NT 4.0
969 Result
:= InterlockedDecrement(FRefCount
);
970 if Result
= 0 then Destroy
;
973 { TComObject.IUnknown for other interfaces }
975 function TComObject
.QueryInterface(const IID
: TGUID
; out Obj
): HResult
;
977 if FController
<> nil then
978 Result
:= IUnknown(FController
).QueryInterface(IID
, Obj
) else
979 Result
:= ObjQueryInterface(IID
, Obj
);
982 function TComObject
._AddRef
: Integer;
984 if FController
<> nil then
985 Result
:= IUnknown(FController
)._AddRef
else
989 function TComObject
._Release
: Integer;
991 if FController
<> nil then
992 Result
:= IUnknown(FController
)._Release
else
993 Result
:= ObjRelease
;
996 { TComObject.ISupportErrorInfo }
998 function TComObject
.InterfaceSupportsErrorInfo(const iid
: TIID
): HResult
;
1000 if GetInterfaceEntry(iid
) <> nil then
1005 { TComObjectFactory }
1007 constructor TComObjectFactory
.Create(ComServer
: TComServerObject
;
1008 ComClass
: TComClass
; const ClassID
: TGUID
; const ClassName
,
1009 Description
: string; Instancing
: TClassInstancing
;
1010 ThreadingModel
: TThreadingModel
);
1012 IsMultiThread
:= IsMultiThread
or (ThreadingModel
<> tmSingle
);
1013 if ThreadingModel
in [tmFree
, tmBoth
] then
1014 CoInitFlags
:= COINIT_MULTITHREADED
else
1015 if (ThreadingModel
= tmApartment
) and (CoInitFlags
<> COINIT_MULTITHREADED
) then
1016 CoInitFlags
:= COINIT_APARTMENTTHREADED
;
1017 ComClassManager
.AddObjectFactory(Self
);
1018 FComServer
:= ComServer
;
1019 FComClass
:= ComClass
;
1020 FClassID
:= ClassID
;
1021 FClassName
:= ClassName
;
1022 FDescription
:= Description
;
1023 FInstancing
:= Instancing
;
1024 FErrorIID
:= IUnknown
;
1025 FShowErrors
:= True;
1026 FThreadingModel
:= ThreadingModel
;
1030 destructor TComObjectFactory
.Destroy
;
1032 if FRegister
<> -1 then CoRevokeClassObject(FRegister
);
1033 ComClassManager
.RemoveObjectFactory(Self
);
1036 function TComObjectFactory
.CreateComObject(const Controller
: IUnknown
): TComObject
;
1038 Result
:= TComClass(FComClass
).CreateFromFactory(Self
, Controller
);
1041 function TComObjectFactory
.GetProgID
: string;
1043 if FClassName
<> '' then
1044 Result
:= FComServer
.ServerName
+ '.' + FClassName
else
1048 procedure TComObjectFactory
.RegisterClassObject
;
1050 RegFlags
: array[ciSingleInstance
..ciMultiInstance
] of Integer = (
1051 REGCLS_SINGLEUSE
, REGCLS_MULTIPLEUSE
);
1052 SuspendedFlag
: array[Boolean] of Integer = (0, REGCLS_SUSPENDED
);
1054 if FInstancing
<> ciInternal
then
1055 OleCheck(CoRegisterClassObject(FClassID
, Self
, CLSCTX_LOCAL_SERVER
,
1056 RegFlags
[FInstancing
] or SuspendedFlag
[FComServer
.StartSuspended
], FRegister
));
1059 procedure TComObjectFactory
.UpdateRegistry(Register: Boolean);
1061 ThreadStrs
: array[TThreadingModel
] of string =
1062 ('', 'Apartment', 'Free', 'Both');
1064 ClassID
, ProgID
, ServerKeyName
, ShortFileName
: string;
1066 if FInstancing
= ciInternal
then Exit
;
1067 ClassID
:= GUIDToString(FClassID
);
1068 ProgID
:= GetProgID
;
1069 ServerKeyName
:= 'CLSID\' + ClassID
+ '\' + FComServer
.ServerKey
;
1072 CreateRegKey('CLSID\' + ClassID
, '', Description
);
1073 ShortFileName
:= FComServer
.ServerFileName
;
1074 if {Ansi}Pos(' ', ShortFileName
) <> 0 then
1075 ShortFileName
:= ExtractShortPathName(ShortFileName
);
1076 CreateRegKey(ServerKeyName
, '', ShortFileName
);
1077 if (FThreadingModel
<> tmSingle
) and IsLibrary
then
1078 CreateRegKey(ServerKeyName
, 'ThreadingModel', ThreadStrs
[FThreadingModel
]);
1079 if ProgID
<> '' then
1081 CreateRegKey(ProgID
, '', Description
);
1082 CreateRegKey(ProgID
+ '\Clsid', '', ClassID
);
1083 CreateRegKey('CLSID\' + ClassID
+ '\ProgID', '', ProgID
);
1087 if ProgID
<> '' then
1089 DeleteRegKey('CLSID\' + ClassID
+ '\ProgID');
1090 DeleteRegKey(ProgID
+ '\Clsid');
1091 DeleteRegKey(ProgID
);
1093 DeleteRegKey(ServerKeyName
);
1094 DeleteRegKey('CLSID\' + ClassID
);
1098 function TComObjectFactory
.GetLicenseString
: WideString
;
1100 if FSupportsLicensing
then Result
:= FLicString
1104 function TComObjectFactory
.HasMachineLicense
: Boolean;
1109 function TComObjectFactory
.ValidateUserLicense(const LicStr
: WideString
): Boolean;
1111 Result
:= AnsiCompareText(LicStr
, FLicString
) = 0;
1114 { TComObjectFactory.IUnknown }
1116 function TComObjectFactory
.QueryInterface(const IID
: TGUID
; out Obj
): HResult
;
1118 if GetInterface(IID
, Obj
) then Result
:= S_OK
else Result
:= E_NOINTERFACE
;
1121 function TComObjectFactory
._AddRef
: Integer;
1123 Result
:= ComServer
.CountFactory(True);
1126 function TComObjectFactory
._Release
: Integer;
1128 Result
:= ComServer
.CountFactory(False);
1131 { TComObjectFactory.IClassFactory }
1133 function TComObjectFactory
.CreateInstance(const UnkOuter
: IUnknown
;
1134 const IID
: TGUID
; out Obj
): HResult
;
1136 Result
:= CreateInstanceLic(UnkOuter
, nil, IID
, '', Obj
);
1139 function TComObjectFactory
.LockServer(fLock
: BOOL
): HResult
;
1141 Result
:= CoLockObjectExternal(Self
, fLock
, True);
1142 // Keep com server alive until this class factory is unlocked
1143 ComServer
.CountObject(fLock
);
1146 { TComObjectFactory.IClassFactory2 }
1148 function TComObjectFactory
.GetLicInfo(var licInfo
: TLicInfo
): HResult
;
1154 cbLicInfo
:= SizeOf(licInfo
);
1155 fRuntimeKeyAvail
:= (not FSupportsLicensing
) or (GetLicenseString
<> '');
1156 fLicVerified
:= (not FSupportsLicensing
) or HasMachineLicense
;
1159 Result
:= E_UNEXPECTED
;
1163 function TComObjectFactory
.RequestLicKey(dwResrved
: Longint; out bstrKey
: WideString
): HResult
;
1165 // Can't give away a license key on an unlicensed machine
1166 if not HasMachineLicense
then
1168 Result
:= CLASS_E_NOTLICENSED
;
1171 bstrKey
:= FLicString
;
1175 function TComObjectFactory
.CreateInstanceLic(const unkOuter
: IUnknown
;
1176 const unkReserved
: IUnknown
; const iid
: TIID
; const bstrKey
: WideString
;
1177 out vObject
): HResult
; stdcall;
1179 ComObject
: TComObject
;
1181 // We can't write to a nil pointer. Duh.
1182 if @vObject
= nil then
1184 Result
:= E_POINTER
;
1187 // In case of failure, make sure we return at least a nil interface.
1188 Pointer(vObject
) := nil;
1189 // Check for licensing.
1190 if FSupportsLicensing
and
1191 ((bstrKey
<> '') and (not ValidateUserLicense(bstrKey
))) or
1192 ((bstrKey
= '') and (not HasMachineLicense
)) then
1194 Result
:= CLASS_E_NOTLICENSED
;
1197 // We can only aggregate if they are requesting our IUnknown.
1198 if (unkOuter
<> nil) and not (IsEqualIID(iid
, IUnknown
)) then
1200 Result
:= CLASS_E_NOAGGREGATION
;
1204 ComObject
:= CreateComObject(UnkOuter
);
1206 if FShowErrors
and (ExceptObject
is Exception
) then
1207 with Exception(ExceptObject
) do
1209 {if (Message <> '') and (AnsiLastChar(Message) > '.') then
1210 Message := Message + '.';}
1211 MessageBox(0, PChar(Message), PChar(SDAXError
), MB_OK
or MB_ICONSTOP
or
1214 Result
:= E_UNEXPECTED
;
1217 Result
:= ComObject
.ObjQueryInterface(IID
, vObject
);
1218 if ComObject
.RefCount
= 0 then ComObject
.Free
;
1221 { TAggregatedObject }
1223 constructor TAggregatedObject
.Create(Controller
: IUnknown
);
1225 FController
:= Pointer(Controller
);
1228 function TAggregatedObject
.GetController
: IUnknown
;
1230 Result
:= IUnknown(FController
);
1233 { TAggregatedObject.IUnknown }
1235 function TAggregatedObject
.QueryInterface(const IID
: TGUID
; out Obj
): HResult
;
1237 Result
:= IUnknown(FController
).QueryInterface(IID
, Obj
);
1240 function TAggregatedObject
._AddRef
: Integer;
1242 Result
:= IUnknown(FController
)._AddRef
;
1245 function TAggregatedObject
._Release
: Integer; stdcall;
1247 Result
:= IUnknown(FController
)._Release
;
1250 { TContainedObject.IUnknown }
1252 function TContainedObject
.QueryInterface(const IID
: TGUID
; out Obj
): HResult
;
1254 if GetInterface(IID
, Obj
) then Result
:= S_OK
else Result
:= E_NOINTERFACE
;
1257 { TTypedComObject.IProvideClassInfo }
1259 function TTypedComObject
.GetClassInfo(out TypeInfo
: ITypeInfo
): HResult
;
1261 TypeInfo
:= TTypedComObjectFactory(FFactory
).FClassInfo
;
1265 { TTypedComObjectFactory }
1267 constructor TTypedComObjectFactory
.Create(ComServer
: TComServerObject
;
1268 TypedComClass
: TTypedComClass
; const ClassID
: TGUID
;
1269 Instancing
: TClassInstancing
; ThreadingModel
: TThreadingModel
);
1271 ClassName
, Description
: WideString
;
1273 if ComServer
.TypeLib
.GetTypeInfoOfGUID(ClassID
, FClassInfo
) <> S_OK
then
1274 raise EOleError
.CreateResFmt(e_Ole
, Integer(@STypeInfoMissing
), [TypedComClass
.ClassName
]);
1275 OleCheck(FClassInfo
.GetDocumentation(MEMBERID_NIL
, @ClassName
,
1276 @Description
, nil, nil));
1277 inherited Create(ComServer
, TypedComClass
, ClassID
,
1278 ClassName
, Description
, Instancing
, ThreadingModel
);
1281 function TTypedComObjectFactory
.GetInterfaceTypeInfo(
1282 TypeFlags
: Integer): ITypeInfo
;
1284 FlagsMask
= IMPLTYPEFLAG_FDEFAULT
or IMPLTYPEFLAG_FSOURCE
;
1286 ClassAttr
: PTypeAttr
;
1287 I
, TypeInfoCount
, Flags
: Integer;
1290 OleCheck(FClassInfo
.GetTypeAttr(ClassAttr
));
1291 TypeInfoCount
:= ClassAttr
^.cImplTypes
;
1292 ClassInfo
.ReleaseTypeAttr(ClassAttr
);
1293 for I
:= 0 to TypeInfoCount
- 1 do
1295 OleCheck(ClassInfo
.GetImplTypeFlags(I
, Flags
));
1296 if Flags
and FlagsMask
= TypeFlags
then
1298 OleCheck(ClassInfo
.GetRefTypeOfImplType(I
, RefType
));
1299 OleCheck(ClassInfo
.GetRefTypeInfo(RefType
, Result
));
1306 procedure TTypedComObjectFactory
.UpdateRegistry(Register: Boolean);
1310 TLibAttr
: PTLibAttr
;
1312 ClassKey
:= 'CLSID\' + GUIDToString(FClassID
);
1315 inherited UpdateRegistry(Register);
1316 TypeLib
:= FComServer
.TypeLib
;
1317 OleCheck(TypeLib
.GetLibAttr(TLibAttr
));
1319 CreateRegKey(ClassKey
+ '\Version', '', Format('%d.%d',
1320 [TLibAttr
.wMajorVerNum
, TLibAttr
.wMinorVerNum
]));
1321 CreateRegKey(ClassKey
+ '\TypeLib', '', GUIDToString(TLibAttr
.guid
));
1323 TypeLib
.ReleaseTLibAttr(TLibAttr
);
1327 DeleteRegKey(ClassKey
+ '\TypeLib');
1328 DeleteRegKey(ClassKey
+ '\Version');
1329 inherited UpdateRegistry(Register);
1335 procedure TAutoObject
.EventConnect(const Sink
: IUnknown
;
1336 Connecting
: Boolean);
1340 OleCheck(Sink
.QueryInterface(FAutoFactory
.FEventIID
, FEventSink
));
1341 EventSinkChanged(TDispatchSilencer
.Create(Sink
, FAutoFactory
.FEventIID
));
1346 EventSinkChanged(nil);
1350 procedure TAutoObject
.EventSinkChanged(const EventSink
: IUnknown
);
1354 procedure TAutoObject
.Initialize
;
1356 FAutoFactory
:= Factory
as TAutoObjectFactory
;
1357 inherited Initialize
;
1360 { TAutoObject.IDispatch }
1362 function TAutoObject
.GetIDsOfNames(const IID
: TGUID
; Names
: Pointer;
1363 NameCount
, LocaleID
: Integer; DispIDs
: Pointer): HResult
;
1365 Result
:= DispGetIDsOfNames(FAutoFactory
.DispTypeInfo
,
1366 Names
, NameCount
, DispIDs
);
1369 function TAutoObject
.GetTypeInfo(Index
, LocaleID
: Integer;
1370 out TypeInfo
): HResult
;
1372 Pointer(TypeInfo
) := nil;
1375 Result
:= DISP_E_BADINDEX
;
1378 ITypeInfo(TypeInfo
) := TAutoObjectFactory(Factory
).DispTypeInfo
;
1382 function TAutoObject
.GetTypeInfoCount(out Count
: Integer): HResult
;
1388 function TAutoObject
.Invoke(DispID: Integer; const IID
: TGUID
; LocaleID
: Integer;
1389 Flags
: Word; var Params
; VarResult
, ExcepInfo
, ArgErr
: Pointer): HResult
;
1391 INVOKE_PROPERTYSET
= INVOKE_PROPERTYPUT
or INVOKE_PROPERTYPUTREF
;
1393 if Flags
and INVOKE_PROPERTYSET
<> 0 then Flags
:= INVOKE_PROPERTYSET
;
1394 Result
:= TAutoObjectFactory(Factory
).DispTypeInfo
.Invoke(Pointer(
1395 Integer(Self
) + TAutoObjectFactory(Factory
).DispIntfEntry
.IOffset
),
1396 DispID, Flags
, TDispParams(Params
), VarResult
, ExcepInfo
, ArgErr
);
1399 { TAutoObjectFactory }
1401 constructor TAutoObjectFactory
.Create(ComServer
: TComServerObject
;
1402 AutoClass
: TAutoClass
; const ClassID
: TGUID
;
1403 Instancing
: TClassInstancing
; ThreadingModel
: TThreadingModel
);
1405 TypeAttr
: PTypeAttr
;
1407 inherited Create(ComServer
, AutoClass
, ClassID
, Instancing
, ThreadingModel
);
1408 FDispTypeInfo
:= GetInterfaceTypeInfo(IMPLTYPEFLAG_FDEFAULT
);
1409 if FDispTypeInfo
= nil then
1410 raise EOleError
.CreateResFmt(e_Ole
, Integer(@SBadTypeInfo
), [AutoClass
.ClassName
]);
1411 OleCheck(FDispTypeInfo
.GetTypeAttr(TypeAttr
));
1412 FDispIntfEntry
:= GetIntfEntry(TypeAttr
^.guid
);
1413 FDispTypeInfo
.ReleaseTypeAttr(TypeAttr
);
1414 if FDispIntfEntry
= nil then
1415 raise EOleError
.CreateResFmt(e_Ole
, Integer(@SDispIntfMissing
),
1416 [AutoClass
.ClassName
]);
1417 FErrorIID
:= FDispIntfEntry
^.IID
;
1418 FEventTypeInfo
:= GetInterfaceTypeInfo(IMPLTYPEFLAG_FDEFAULT
or
1419 IMPLTYPEFLAG_FSOURCE
);
1420 if FEventTypeInfo
<> nil then
1422 OleCheck(FEventTypeInfo
.GetTypeAttr(TypeAttr
));
1423 FEventIID
:= TypeAttr
.guid
;
1424 FEventTypeInfo
.ReleaseTypeAttr(TypeAttr
);
1428 function TAutoObjectFactory
.GetIntfEntry(Guid
: TGUID
): PInterfaceEntry
;
1430 Result
:= FComClass
.GetInterfaceEntry(Guid
);
1435 constructor TAutoIntfObject
.Create(const TypeLib
: ITypeLib
; const DispIntf
: TGUID
);
1438 OleCheck(TypeLib
.GetTypeInfoOfGuid(DispIntf
, FDispTypeInfo
));
1439 FDispIntfEntry
:= GetInterfaceEntry(DispIntf
);
1442 { TAutoIntfObject.IDispatch }
1444 function TAutoIntfObject
.GetIDsOfNames(const IID
: TGUID
; Names
: Pointer;
1445 NameCount
, LocaleID
: Integer; DispIDs
: Pointer): HResult
;
1447 Result
:= DispGetIDsOfNames(FDispTypeInfo
, Names
, NameCount
, DispIDs
);
1450 function TAutoIntfObject
.GetTypeInfo(Index
, LocaleID
: Integer;
1451 out TypeInfo
): HResult
;
1453 Pointer(TypeInfo
) := nil;
1456 Result
:= DISP_E_BADINDEX
;
1459 ITypeInfo(TypeInfo
) := FDispTypeInfo
;
1463 function TAutoIntfObject
.GetTypeInfoCount(out Count
: Integer): HResult
;
1469 function TAutoIntfObject
.Invoke(DispID: Integer; const IID
: TGUID
;
1470 LocaleID
: Integer; Flags
: Word; var Params
; VarResult
, ExcepInfo
,
1471 ArgErr
: Pointer): HResult
;
1473 INVOKE_PROPERTYSET
= INVOKE_PROPERTYPUT
or INVOKE_PROPERTYPUTREF
;
1475 if Flags
and INVOKE_PROPERTYSET
<> 0 then Flags
:= INVOKE_PROPERTYSET
;
1476 Result
:= FDispTypeInfo
.Invoke(Pointer(Integer(Self
) +
1477 FDispIntfEntry
.IOffset
), DispID, Flags
, TDispParams(Params
), VarResult
,
1481 function TAutoIntfObject
.InterfaceSupportsErrorInfo(const iid
: TIID
): HResult
;
1483 if IsEqualGUID(DispIID
, iid
) then
1488 function TAutoIntfObject
.SafeCallException(ExceptObject
: TObject
;
1489 ExceptAddr
: Pointer): HResult
;
1491 Result
:= 0; { HandleSafeCallException(ExceptObject, ExceptAddr, DispIID, '', ''); }
1495 { Maximum number of dispatch arguments }
1497 MaxDispArgs
= 64; {!!!}
1499 { Special variant type codes }
1503 { Parameter type masks }
1509 {function TrimPunctuation(const S: string): string;
1514 P := AnsiLastChar(Result);
1515 while (Length(Result) > 0) and (P^ in [#0..#32, '.']) do
1517 SetLength(Result, P - PChar(Result));
1518 P := AnsiLastChar(Result);
1524 {constructor EOleSysError.Create(const Message: string;
1525 ErrorCode: HRESULT; HelpContext: Integer);
1532 S := SysErrorMessage(ErrorCode);
1533 if S = '' then FmtStr(S, SOleError, [ErrorCode]);
1535 inherited CreateHelp(S, HelpContext);
1536 FErrorCode := ErrorCode;
1541 {constructor EOleException.Create(const Message: string; ErrorCode: HRESULT;
1542 const Source, HelpFile: string; HelpContext: Integer);
1544 inherited Create(TrimPunctuation(Message), ErrorCode, HelpContext);
1546 FHelpFile := HelpFile;
1550 { Raise EOleSysError exception from an error code }
1552 procedure OleError(ErrorCode
: HResult
);
1554 raise EOleSysError
.Create(e_Ole
, 'OLE error: ' + Int2Str( ErrorCode
) );
1557 { Raise EOleSysError exception if result code indicates an error }
1559 procedure OleCheck(Result
: HResult
);
1561 if not Succeeded(Result
) then OleError(Result
);
1564 { Convert a string to a GUID }
1566 function StringToGUID(const S
: string): TGUID
;
1568 OleCheck(CLSIDFromString(PWideChar(WideString(S
)), Result
));
1571 { Convert a GUID to a string }
1573 function GUIDToString(const ClassID
: TGUID
): string;
1577 OleCheck(StringFromCLSID(ClassID
, P
));
1582 { Convert a programmatic ID to a class ID }
1584 function ProgIDToClassID(const ProgID
: string): TGUID
;
1586 OleCheck(CLSIDFromProgID(PWideChar(WideString(ProgID
)), Result
));
1589 { Convert a class ID to a programmatic ID }
1591 function ClassIDToProgID(const ClassID
: TGUID
): string;
1595 OleCheck(ProgIDFromCLSID(ClassID
, P
));
1600 { Create registry key }
1602 procedure CreateRegKey(const Key
, ValueName
, Value
: string);
1605 Status
, Disposition
: Integer;
1607 Status
:= RegCreateKeyEx(HKEY_CLASSES_ROOT
, PChar(Key
), 0, '',
1608 REG_OPTION_NON_VOLATILE
, KEY_READ
or KEY_WRITE
, nil, Handle
,
1612 Status
:= RegSetValueEx(Handle
, PChar(ValueName
), 0, REG_SZ
,
1613 PChar(Value
), Length(Value
) + 1);
1614 RegCloseKey(Handle
);
1616 if Status
<> 0 then raise EOleRegistrationError
.CreateResFmt(e_Registry
,
1617 Integer(@SCreateRegKeyError
), [ nil ] );
1620 { Delete registry key }
1622 procedure DeleteRegKey(const Key
: string);
1624 RegDeleteKey(HKEY_CLASSES_ROOT
, PChar(Key
));
1627 { Get registry value }
1629 function GetRegStringValue(const Key
, ValueName
: string): string;
1635 if RegOpenKey(HKEY_CLASSES_ROOT
, PChar(Key
), RegKey
) = ERROR_SUCCESS
then
1638 SetLength(Result
, Size
);
1639 if RegQueryValueEx(RegKey
, PChar(ValueName
), nil, nil, PByte(PChar(Result
)), @Size
) = ERROR_SUCCESS
then
1640 SetLength(Result
, Size
- 1) else
1643 RegCloseKey(RegKey
);
1647 function CreateComObject(const ClassID
: TGUID
): IUnknown
;
1649 OleCheck(CoCreateInstance(ClassID
, nil, CLSCTX_INPROC_SERVER
or
1650 CLSCTX_LOCAL_SERVER
, IUnknown
, Result
));
1653 function CreateRemoteComObject(const MachineName
: WideString
;
1654 const ClassID
: TGUID
): IUnknown
;
1656 LocalFlags
= CLSCTX_LOCAL_SERVER
or CLSCTX_REMOTE_SERVER
or CLSCTX_INPROC_SERVER
;
1657 RemoteFlags
= CLSCTX_REMOTE_SERVER
;
1660 ServerInfo
: TCoServerInfo
;
1661 IID_IUnknown
: TGuid
;
1663 LocalMachine
: array [0..MAX_COMPUTERNAME_LENGTH
] of char;
1665 if @CoCreateInstanceEx
= nil then
1666 raise Exception
.CreateResFmt(e_Com
, Integer(@SDCOMNotInstalled
), [nil]);
1667 FillChar(ServerInfo
, sizeof(ServerInfo
), 0);
1668 ServerInfo
.pwszName
:= PWideChar(MachineName
);
1669 IID_IUnknown
:= IUnknown
;
1670 MQI
.IID
:= @IID_IUnknown
;
1673 { If a MachineName is specified check to see if it the local machine.
1674 If it isn't, do not allow LocalServers to be used. }
1675 if Length(MachineName
) > 0 then
1677 Size
:= Sizeof(LocalMachine
); // Win95 is hypersensitive to size
1678 if GetComputerName(LocalMachine
, Size
) and
1679 (AnsiCompareText(LocalMachine
, MachineName
) = 0) then
1680 Flags
:= LocalFlags
else
1681 Flags
:= RemoteFlags
;
1683 Flags
:= LocalFlags
;
1684 OleCheck(CoCreateInstanceEx(ClassID
, nil, Flags
, @ServerInfo
, 1, @MQI
));
1689 function CreateOleObject(const ClassName
: string): IDispatch
;
1693 ClassID
:= ProgIDToClassID(ClassName
);
1694 OleCheck(CoCreateInstance(ClassID
, nil, CLSCTX_INPROC_SERVER
or
1695 CLSCTX_LOCAL_SERVER
, IDispatch
, Result
));
1698 function GetActiveOleObject(const ClassName
: string): IDispatch
;
1703 ClassID
:= ProgIDToClassID(ClassName
);
1704 OleCheck(GetActiveObject(ClassID
, nil, Unknown
));
1705 OleCheck(Unknown
.QueryInterface(IDispatch
, Result
));
1708 function StringToLPOLESTR(const Source
: string): POleStr
;
1713 SourceLen
:= Length(Source
);
1714 Buffer
:= CoTaskMemAlloc((SourceLen
+1) * sizeof(WideChar
));
1715 StringToWideChar( Source
, Buffer
, SourceLen
+1 );
1716 Result
:= POleStr( Buffer
);
1719 function CreateClassID
: string;
1724 CoCreateGuid(ClassID
);
1725 StringFromCLSID(ClassID
, P
);
1730 procedure RegisterComServer(const DLLName
: string);
1732 TRegProc
= function: HResult
; stdcall;
1734 RegProcName
= 'DllRegisterServer'; { Do not localize }
1740 Handle
:= LoadLibrary( PChar( DLLName
) );
1742 Handle
:= SafeLoadLibrary(DLLName
);
1744 if Handle
<= HINSTANCE_ERROR
then
1745 raise Exception
.CreateFmt( e_Com
, '%s: %s', [SysErrorMessage(GetLastError
), DLLName
]);
1747 RegProc
:= GetProcAddress(Handle
, RegProcName
);
1748 if Assigned(RegProc
) then OleCheck(RegProc
) else RaiseLastWin32Error
;
1750 FreeLibrary(Handle
);
1754 procedure RegisterAsService(const ClassID
, ServiceName
: string);
1756 CreateRegKey('AppID\' + ClassID
, 'LocalService', ServiceName
);
1757 CreateRegKey('CLSID\' + ClassID
, 'AppID', ClassID
);
1760 { Connect an IConnectionPoint interface }
1762 procedure InterfaceConnect(const Source
: IUnknown
; const IID
: TIID
;
1763 const Sink
: IUnknown
; var Connection
: Longint);
1765 CPC
: IConnectionPointContainer
;
1766 CP
: IConnectionPoint
;
1769 if Succeeded(Source
.QueryInterface(IConnectionPointContainer
, CPC
)) then
1770 if Succeeded(CPC
.FindConnectionPoint(IID
, CP
)) then
1771 CP
.Advise(Sink
, Connection
);
1774 { Disconnect an IConnectionPoint interface }
1776 procedure InterfaceDisconnect(const Source
: IUnknown
; const IID
: TIID
;
1777 var Connection
: Longint);
1779 CPC
: IConnectionPointContainer
;
1780 CP
: IConnectionPoint
;
1782 if Connection
<> 0 then
1783 if Succeeded(Source
.QueryInterface(IConnectionPointContainer
, CPC
)) then
1784 if Succeeded(CPC
.FindConnectionPoint(IID
, CP
)) then
1785 if Succeeded(CP
.Unadvise(Connection
)) then Connection
:= 0;
1788 procedure LoadComExProcs
;
1792 Ole32
:= GetModuleHandle('ole32.dll');
1795 @CoCreateInstanceEx
:= GetProcAddress(Ole32
, 'CoCreateInstanceEx');
1796 @CoInitializeEx
:= GetProcAddress(Ole32
, 'CoInitializeEx');
1797 @CoAddRefServerProcess
:= GetProcAddress(Ole32
, 'CoAddRefServerProcess');
1798 @CoReleaseServerProcess
:= GetProcAddress(Ole32
, 'CoReleaseServerProcess');
1799 @CoResumeClassObjects
:= GetProcAddress(Ole32
, 'CoResumeClassObjects');
1800 @CoSuspendClassObjects
:= GetProcAddress(Ole32
, 'CoSuspendClassObjects');
1804 procedure SafeCallError(ErrorCode
: Integer; ErrorAddr
: Pointer);
1806 ErrorInfo
: IErrorInfo
;
1807 Source
, Description
, HelpFile
: WideString
;
1808 HelpContext
: Longint;
1811 if GetErrorInfo(0, ErrorInfo
) = S_OK
then
1813 ErrorInfo
.GetSource(Source
);
1814 ErrorInfo
.GetDescription(Description
);
1815 ErrorInfo
.GetHelpFile(HelpFile
);
1816 ErrorInfo
.GetHelpContext(HelpContext
);
1818 raise EOleException
.Create(e_Ole
, Description
+ Int2Str( ErrorCode
) {, Source,
1819 HelpFile, HelpContext} ) at ErrorAddr
;
1822 { Call Invoke method on the given IDispatch interface using the given
1823 call descriptor, dispatch IDs, parameters, and result }
1825 procedure DispatchInvoke(const Dispatch
: IDispatch
; CallDesc
: PCallDesc
;
1826 DispIDs
: PDispIDList
; Params
: Pointer; Result
: PVariant
);
1829 TVarArg
= array[0..3] of DWORD
;
1830 TStringDesc
= record
1835 I
, J
, K
, ArgType
, ArgCount
, StrCount
, DispID, InvKind
, Status
: Integer;
1838 ArgPtr
, VarPtr
: PVarArg
;
1839 DispParams
: TDispParams
;
1840 ExcepInfo
: TExcepInfo
;
1841 Strings
: array[0..MaxDispArgs
- 1] of TStringDesc
;
1842 Args
: array[0..MaxDispArgs
- 1] of TVarArg
;
1846 ArgCount
:= CallDesc
^.ArgCount
;
1847 if ArgCount
<> 0 then
1850 ArgPtr
:= @Args
[ArgCount
];
1853 Dec(Integer(ArgPtr
), SizeOf(TVarData
));
1854 ArgType
:= CallDesc
^.ArgTypes
[I
] and atTypeMask
;
1855 VarFlag
:= CallDesc
^.ArgTypes
[I
] and atByRef
;
1856 if ArgType
= varError
then
1858 ArgPtr
^[0] := varError
;
1859 ArgPtr
^[2] := DWORD(DISP_E_PARAMNOTFOUND
);
1862 if ArgType
= varStrArg
then
1864 with Strings
[StrCount
] do
1865 if VarFlag
<> 0 then
1867 BStr
:= StringToOleStr(PString(ParamPtr
^)^);
1868 PStr
:= PString(ParamPtr
^);
1869 ArgPtr
^[0] := varOleStr
or varByRef
;
1870 ArgPtr
^[2] := Integer(@BStr
);
1873 BStr
:= StringToOleStr(PString(ParamPtr
)^);
1875 ArgPtr
^[0] := varOleStr
;
1876 ArgPtr
^[2] := Integer(BStr
);
1880 if VarFlag
<> 0 then
1882 if (ArgType
= varVariant
) and
1883 (PVarData(ParamPtr
^)^.VType
= varString
) then
1884 VarCast(PVariant(ParamPtr
^)^, PVariant(ParamPtr
^)^, varOleStr
);
1885 ArgPtr
^[0] := ArgType
or varByRef
;
1886 ArgPtr
^[2] := ParamPtr
^;
1888 if ArgType
= varVariant
then
1890 if PVarData(ParamPtr
)^.VType
= varString
then
1892 with Strings
[StrCount
] do
1894 BStr
:= StringToOleStr(string(PVarData(ParamPtr
^)^.VString
));
1896 ArgPtr
^[0] := varOleStr
;
1897 ArgPtr
^[2] := Integer(BStr
);
1902 VarPtr
:= PVarArg(ParamPtr
);
1903 ArgPtr
^[0] := VarPtr
^[0];
1904 ArgPtr
^[1] := VarPtr
^[1];
1905 ArgPtr
^[2] := VarPtr
^[2];
1906 ArgPtr
^[3] := VarPtr
^[3];
1907 Inc(Integer(ParamPtr
), 12);
1911 ArgPtr
^[0] := ArgType
;
1912 ArgPtr
^[2] := ParamPtr
^;
1913 if (ArgType
>= varDouble
) and (ArgType
<= varDate
) then
1915 Inc(Integer(ParamPtr
), 4);
1916 ArgPtr
^[3] := ParamPtr
^;
1919 Inc(Integer(ParamPtr
), 4);
1924 DispParams
.rgvarg
:= @Args
;
1925 DispParams
.rgdispidNamedArgs
:= @DispIDs
[1];
1926 DispParams
.cArgs
:= ArgCount
;
1927 DispParams
.cNamedArgs
:= CallDesc
^.NamedArgCount
;
1928 DispID := DispIDs
[0];
1929 InvKind
:= CallDesc
^.CallType
;
1930 if InvKind
= DISPATCH_PROPERTYPUT
then
1932 if Args
[0][0] and varTypeMask
= varDispatch
then
1933 InvKind
:= DISPATCH_PROPERTYPUTREF
;
1934 DispIDs
[0] := DISPID_PROPERTYPUT
;
1935 Dec(Integer(DispParams
.rgdispidNamedArgs
), SizeOf(Integer));
1936 Inc(DispParams
.cNamedArgs
);
1938 if (InvKind
= DISPATCH_METHOD
) and (ArgCount
= 0) and (Result
<> nil) then
1939 InvKind
:= DISPATCH_METHOD
or DISPATCH_PROPERTYGET
;
1940 Status
:= Dispatch
.Invoke(DispID, GUID_NULL
, 0, InvKind
, DispParams
,
1941 Result
, @ExcepInfo
, nil);
1942 if Status
<> 0 then DispatchInvokeError(Status
, ExcepInfo
);
1948 if PStr
<> nil then OleStrToStrVar(BStr
, PStr
^);
1955 SysFreeString(Strings
[K
].BStr
);
1960 { Call GetIDsOfNames method on the given IDispatch interface }
1962 procedure GetIDsOfNames(const Dispatch
: IDispatch
; Names
: PChar
;
1963 NameCount
: Integer; DispIDs
: PDispIDList
);
1965 procedure RaiseNameException
;
1967 raise EOleError
.CreateResFmt(e_Com
, Integer( @SNoMethod
), [Names
]);
1971 PNamesArray
= ^TNamesArray
;
1972 TNamesArray
= array[0..0] of PWideChar
;
1974 N
, SrcLen
, DestLen
: Integer;
1977 NameRefs
: PNamesArray
;
1987 SHL EAX, 2 // sizeof pointer
= 4
1993 SrcLen
:= StrLen(Src
);
1994 DestLen
:= MultiByteToWideChar(0, 0, Src
, SrcLen
, nil, 0) + 1;
1998 ADD EAX, 3 // round up to
4 byte boundary
2004 if N
= 0 then NameRefs
[0] := Dest
else NameRefs
[NameCount
- N
] := Dest
;
2005 MultiByteToWideChar(0, 0, Src
, SrcLen
, Dest
, DestLen
);
2006 Dest
[DestLen
-1] := #0;
2009 until N
= NameCount
;
2010 Temp
:= Dispatch
.GetIDsOfNames(GUID_NULL
, NameRefs
, NameCount
,
2011 GetThreadLocale
, DispIDs
);
2012 if Temp
= Integer(DISP_E_UNKNOWNNAME
) then RaiseNameException
else OleCheck(Temp
);
2018 { Central call dispatcher }
2020 procedure VarDispInvoke(Result
: PVariant
; const Instance
: Variant
;
2021 CallDesc
: PCallDesc
; Params
: Pointer); cdecl;
2023 procedure RaiseException
;
2025 raise EOleError
.CreateResFmt(e_Com
, Integer( @SVarNotObject
), [ nil ] );
2030 DispIDs
: array[0..MaxDispArgs
- 1] of Integer;
2032 if TVarData(Instance
).VType
= varDispatch
then
2033 Dispatch
:= TVarData(Instance
).VDispatch
2034 else if TVarData(Instance
).VType
= (varDispatch
or varByRef
) then
2035 Dispatch
:= Pointer(TVarData(Instance
).VPointer
^)
2036 else RaiseException
;
2037 GetIDsOfNames(IDispatch(Dispatch
), @CallDesc
^.ArgTypes
[CallDesc
^.ArgCount
],
2038 CallDesc
^.NamedArgCount
+ 1, @DispIDs
);
2039 if Result
<> nil then VarClear(Result
^);
2040 DispatchInvoke(IDispatch(Dispatch
), CallDesc
, @DispIDs
, @Params
, Result
);
2043 { Raise exception given an OLE return code and TExcepInfo structure }
2045 procedure DispCallError(Status
: Integer; var ExcepInfo
: TExcepInfo
;
2046 ErrorAddr
: Pointer; FinalizeExcepInfo
: Boolean);
2050 if Status
= Integer(DISP_E_EXCEPTION
) then
2053 E
:= EOleException
.Create(e_Com
, bstrDescription
{, scode, bstrSource,
2054 bstrHelpFile, dwHelpContext } );
2055 if FinalizeExcepInfo
then
2056 Finalize(ExcepInfo
);
2058 E
:= EOleSysError
.Create(e_com
, '' {, Status, 0});
2059 if ErrorAddr
<> nil then
2060 raise E at ErrorAddr
2065 { Raise exception given an OLE return code and TExcepInfo structure }
2067 procedure DispatchInvokeError(Status
: Integer; const ExcepInfo
: TExcepInfo
);
2069 DispCallError(Status
, PExcepInfo(@ExcepInfo
)^, nil, False);
2072 procedure ClearExcepInfo(var ExcepInfo
: TExcepInfo
);
2074 FillChar(ExcepInfo
, SizeOf(ExcepInfo
), 0);
2077 procedure DispCall(const Dispatch
: IDispatch
; CallDesc
: PCallDesc
;
2078 DispID: Integer; NamedArgDispIDs
, Params
, Result
: Pointer); stdcall;
2080 TExcepInfoRec
= record // mock type to avoid auto init and cleanup code
2083 bstrSource
: PWideChar
;
2084 bstrDescription
: PWideChar
;
2085 bstrHelpFile
: PWideChar
;
2086 dwHelpContext
: Longint;
2087 pvReserved
: Pointer;
2088 pfnDeferredFillIn
: Pointer;
2092 DispParams
: TDispParams
;
2093 ExcepInfo
: TExcepInfoRec
;
2101 MOVZX ECX,[EBX].TCallDesc.ArgCount
2102 MOV DispParams.cArgs
,ECX
2105 ADD EBX,OFFSET TCallDesc.ArgTypes
2107 @@1: MOVZX EAX,[EBX].
Byte
2116 PUSH [ESI].Integer
[4]
2117 PUSH [ESI].Integer
[0]
2122 @@2: PUSH [ESI].Integer
[12]
2123 PUSH [ESI].Integer
[8]
2124 PUSH [ESI].Integer
[4]
2125 PUSH [ESI].Integer
[0]
2128 @@3: AND AL,atTypeMask
2131 PUSH [ESI].Integer
[0]
2139 @@10: MOV DispParams.rgvarg
,ESP
2140 MOVZX EAX,[EBX].TCallDesc.NamedArgCount
2141 MOV DispParams.cNamedArgs
,EAX
2144 MOV ESI,NamedArgDispIDs
2145 @@11: PUSH [ESI].Integer
[EAX*4-4]
2148 @@12: MOVZX ECX,[EBX].TCallDesc.CallType
2149 CMP ECX,DISPATCH_PROPERTYPUT
2151 PUSH DISPID_PROPERTYPUT
2152 INC DispParams.cNamedArgs
2153 CMP [EBX].TCallDesc.ArgTypes.
Byte[0],varDispatch
2155 CMP [EBX].TCallDesc.ArgTypes.
Byte[0],varUnknown
2157 @@13: MOV ECX,DISPATCH_PROPERTYPUTREF
2158 @@20: MOV DispParams.rgdispidNamedArgs
,ESP
2161 PUSH EAX { ExcepInfo }
2167 PUSH Result
{ VarResult }
2171 PUSH EDX { LocaleID }
2172 PUSH OFFSET GUID_NULL
{ IID }
2173 PUSH DispID
{ DispID }
2177 CALL [EAX].Pointer
[24]
2191 procedure DispCallByID(Result
: Pointer; const Dispatch
: IDispatch
;
2192 DispDesc
: PDispDesc
; Params
: Pointer); cdecl;
2206 PUSH [EBX].TDispDesc.DispID
2207 LEA EAX,[EBX].TDispDesc.CallDesc
2211 MOVZX EAX,[EBX].TDispDesc.ResType
2213 JMP @ResultTable.Pointer
[EAX*4]
2244 FILD [ESP+8].Currency
2253 @@1: MOV EAX,[ESP+8]
2264 CALL [EAX].Pointer
[8]
2265 @@2: MOV EAX,[ESP+8]
2271 CALL System.
@VarClear
2298 ComClassManagerVar
: TObject
;
2299 SaveInitProc
: Pointer;
2300 NeedToUninitialize
: Boolean;
2302 function ComClassManager
: TComClassManager
;
2304 if ComClassManagerVar
= nil then
2305 ComClassManagerVar
:= TComClassManager
.Create
;
2306 Result
:= TComClassManager(ComClassManagerVar
);
2309 procedure InitComObj
;
2311 if SaveInitProc
<> nil then TProcedure(SaveInitProc
);
2312 if (CoInitFlags
<> -1) and Assigned(KOLComObj
.CoInitializeEx
) then
2314 NeedToUninitialize
:= Succeeded(KOLComObj
.CoInitializeEx(nil, CoInitFlags
));
2315 IsMultiThread
:= IsMultiThread
or
2316 ((CoInitFlags
and COINIT_APARTMENTTHREADED
) <> 0) or
2317 (CoInitFlags
= COINIT_MULTITHREADED
); // this flag has value zero
2320 NeedToUninitialize
:= Succeeded(CoInitialize(nil));
2327 VarDispProc
:= @VarDispInvoke
;
2328 DispCallByIDProc
:= @DispCallByID
;
2329 SafeCallErrorProc
:= @SafeCallError
;
2330 if not IsLibrary
then
2332 SaveInitProc
:= InitProc
;
2333 InitProc
:= @InitComObj
;
2339 OleUninitializing
:= True;
2340 ComClassManagerVar
.Free
;
2341 SafeCallErrorProc
:= nil;
2342 DispCallByIDProc
:= nil;
2344 if NeedToUninitialize
then CoUninitialize
;