1165 lines
32 KiB
ObjectPascal
1165 lines
32 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: JvOle2Auto.PAS, released on 2002-07-04.
|
|
|
|
The Initial Developers of the Original Code are: Fedor Koshevnikov, Igor Pavluk and Serge Korolev
|
|
Copyright (c) 1997, 1998 Fedor Koshevnikov, Igor Pavluk and Serge Korolev
|
|
Copyright (c) 2001,2002 SGB Software
|
|
All Rights Reserved.
|
|
|
|
Last Modified: 2002-07-04
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
|
|
located at http://jvcl.sourceforge.net
|
|
|
|
Known Issues:
|
|
-----------------------------------------------------------------------------}
|
|
|
|
{$I JVCL.INC}
|
|
|
|
unit JvOle2Auto;
|
|
|
|
interface
|
|
|
|
{$IFDEF WIN32}
|
|
uses
|
|
Windows, SysUtils,
|
|
{$IFDEF COMPILER3_UP}
|
|
ActiveX, ComObj;
|
|
{$ELSE}
|
|
Ole2, OleAuto, OleCtl;
|
|
{$ENDIF}
|
|
{$ELSE}
|
|
uses
|
|
WinTypes, WinProcs, SysUtils, Ole2, Dispatch;
|
|
{$ENDIF}
|
|
|
|
const
|
|
{ Maximum number of dispatch arguments }
|
|
{$IFDEF COMPILER3_UP}
|
|
MaxDispArgs = 64;
|
|
{$ELSE}
|
|
MaxDispArgs = 32;
|
|
{$ENDIF}
|
|
|
|
{$IFNDEF WIN32}
|
|
type
|
|
TDispID = DISPID;
|
|
PDispID = ^TDispID;
|
|
TDispParams = DISPPARAMS;
|
|
TLCID = LCID;
|
|
TExcepInfo = EXCEPINFO;
|
|
PDispIDList = ^TDispIDList;
|
|
TDispIDList = array [0..MaxDispArgs] of TDispID;
|
|
EOleError = class(EJVCLException);
|
|
{$ENDIF WIN32}
|
|
|
|
{$IFNDEF COMPILER3_UP}
|
|
type
|
|
EPropReadOnly = class(EOleError);
|
|
EPropWriteOnly = class(EOleError);
|
|
{$ENDIF}
|
|
|
|
{$IFNDEF WIN32}
|
|
const
|
|
{ Primary language IDs. }
|
|
LANG_NEUTRAL = $00;
|
|
|
|
LANG_AFRIKAANS = $36;
|
|
LANG_ALBANIAN = $1C;
|
|
LANG_ARABIC = $01;
|
|
LANG_BASQUE = $2D;
|
|
LANG_BELARUSIAN = $23;
|
|
LANG_BULGARIAN = $02;
|
|
LANG_CATALAN = $03;
|
|
LANG_CHINESE = $04;
|
|
LANG_CROATIAN = $1A;
|
|
LANG_CZECH = $05;
|
|
LANG_DANISH = $06;
|
|
LANG_DUTCH = $13;
|
|
LANG_ENGLISH = $09;
|
|
LANG_ESTONIAN = $25;
|
|
LANG_FAEROESE = $38;
|
|
LANG_FARSI = $29;
|
|
LANG_FINNISH = $0B;
|
|
LANG_FRENCH = $0C;
|
|
LANG_GERMAN = $07;
|
|
LANG_GREEK = $08;
|
|
LANG_HEBREW = $0D;
|
|
LANG_HUNGARIAN = $0E;
|
|
LANG_ICELANDIC = $0F;
|
|
LANG_INDONESIAN = $21;
|
|
LANG_ITALIAN = $10;
|
|
LANG_JAPANESE = $11;
|
|
LANG_KOREAN = $12;
|
|
LANG_LATVIAN = $26;
|
|
LANG_LITHUANIAN = $27;
|
|
LANG_NORWEGIAN = $14;
|
|
LANG_POLISH = $15;
|
|
LANG_PORTUGUESE = $16;
|
|
LANG_ROMANIAN = $18;
|
|
LANG_RUSSIAN = $19;
|
|
LANG_SERBIAN = $1A;
|
|
LANG_SLOVAK = $1B;
|
|
LANG_SLOVENIAN = $24;
|
|
LANG_SPANISH = $0A;
|
|
LANG_SWEDISH = $1D;
|
|
LANG_THAI = $1E;
|
|
LANG_TURKISH = $1F;
|
|
LANG_UKRAINIAN = $22;
|
|
LANG_VIETNAMESE = $2A;
|
|
|
|
{ Sublanguage IDs. }
|
|
SUBLANG_NEUTRAL = $00; { language neutral }
|
|
SUBLANG_DEFAULT = $01; { user default }
|
|
SUBLANG_SYS_DEFAULT = $02; { system default }
|
|
|
|
SUBLANG_CHINESE_TRADITIONAL = $01; { Chinese (Taiwan) }
|
|
SUBLANG_CHINESE_SIMPLIFIED = $02; { Chinese (PR China) }
|
|
SUBLANG_CHINESE_HONGKONG = $03; { Chinese (Hong Kong) }
|
|
SUBLANG_CHINESE_SINGAPORE = $04; { Chinese (Singapore) }
|
|
SUBLANG_DUTCH = $01; { Dutch }
|
|
SUBLANG_DUTCH_BELGIAN = $02; { Dutch (Belgian) }
|
|
SUBLANG_ENGLISH_US = $01; { English (USA) }
|
|
SUBLANG_ENGLISH_UK = $02; { English (UK) }
|
|
SUBLANG_ENGLISH_AUS = $03; { English (Australian) }
|
|
SUBLANG_ENGLISH_CAN = $04; { English (Canadian) }
|
|
SUBLANG_ENGLISH_NZ = $05; { English (New Zealand) }
|
|
SUBLANG_ENGLISH_EIRE = $06; { English (Irish) }
|
|
SUBLANG_FRENCH = $01; { French }
|
|
SUBLANG_FRENCH_BELGIAN = $02; { French (Belgian) }
|
|
SUBLANG_FRENCH_CANADIAN = $03; { French (Canadian) }
|
|
SUBLANG_FRENCH_SWISS = $04; { French (Swiss) }
|
|
SUBLANG_GERMAN = $01; { German }
|
|
SUBLANG_GERMAN_SWISS = $02; { German (Swiss) }
|
|
SUBLANG_GERMAN_AUSTRIAN = $03; { German (Austrian) }
|
|
SUBLANG_ITALIAN = $01; { Italian }
|
|
SUBLANG_ITALIAN_SWISS = $02; { Italian (Swiss) }
|
|
SUBLANG_NORWEGIAN_BOKMAL = $01; { Norwegian (Bokmal) }
|
|
SUBLANG_NORWEGIAN_NYNORSK = $02; { Norwegian (Nynorsk) }
|
|
SUBLANG_PORTUGUESE = $02; { Portuguese }
|
|
SUBLANG_PORTUGUESE_BRAZILIAN = $01; { Portuguese (Brazilian) }
|
|
SUBLANG_SPANISH = $01; { Spanish (Castilian) }
|
|
SUBLANG_SPANISH_MEXICAN = $02; { Spanish (Mexican) }
|
|
SUBLANG_SPANISH_MODERN = $03; { Spanish (Modern) }
|
|
|
|
{ Default System and User IDs for language and locale. }
|
|
LANG_SYSTEM_DEFAULT = (SUBLANG_SYS_DEFAULT shl 10) or LANG_NEUTRAL;
|
|
LANG_USER_DEFAULT = (SUBLANG_DEFAULT shl 10) or LANG_NEUTRAL;
|
|
LOCALE_SYSTEM_DEFAULT = (0 shl 16) or LANG_SYSTEM_DEFAULT;
|
|
LOCALE_USER_DEFAULT = (0 shl 16) or LANG_USER_DEFAULT;
|
|
|
|
{ OLE control status codes }
|
|
CTL_E_ILLEGALFUNCTIONCALL = $800A0000 + 5;
|
|
CTL_E_OVERFLOW = $800A0000 + 6;
|
|
CTL_E_OUTOFMEMORY = $800A0000 + 7;
|
|
CTL_E_DIVISIONBYZERO = $800A0000 + 11;
|
|
CTL_E_OUTOFSTRINGSPACE = $800A0000 + 14;
|
|
CTL_E_OUTOFSTACKSPACE = $800A0000 + 28;
|
|
CTL_E_BADFILENAMEORNUMBER = $800A0000 + 52;
|
|
CTL_E_FILENOTFOUND = $800A0000 + 53;
|
|
CTL_E_BADFILEMODE = $800A0000 + 54;
|
|
CTL_E_FILEALREADYOPEN = $800A0000 + 55;
|
|
CTL_E_DEVICEIOERROR = $800A0000 + 57;
|
|
CTL_E_FILEALREADYEXISTS = $800A0000 + 58;
|
|
CTL_E_BADRECORDLENGTH = $800A0000 + 59;
|
|
CTL_E_DISKFULL = $800A0000 + 61;
|
|
CTL_E_BADRECORDNUMBER = $800A0000 + 63;
|
|
CTL_E_BADFILENAME = $800A0000 + 64;
|
|
CTL_E_TOOMANYFILES = $800A0000 + 67;
|
|
CTL_E_DEVICEUNAVAILABLE = $800A0000 + 68;
|
|
CTL_E_PERMISSIONDENIED = $800A0000 + 70;
|
|
CTL_E_DISKNOTREADY = $800A0000 + 71;
|
|
CTL_E_PATHFILEACCESSERROR = $800A0000 + 75;
|
|
CTL_E_PATHNOTFOUND = $800A0000 + 76;
|
|
CTL_E_INVALIDPATTERNSTRING = $800A0000 + 93;
|
|
CTL_E_INVALIDUSEOFNULL = $800A0000 + 94;
|
|
CTL_E_INVALIDFILEFORMAT = $800A0000 + 321;
|
|
CTL_E_INVALIDPROPERTYVALUE = $800A0000 + 380;
|
|
CTL_E_INVALIDPROPERTYARRAYINDEX = $800A0000 + 381;
|
|
CTL_E_SETNOTSUPPORTEDATRUNTIME = $800A0000 + 382;
|
|
CTL_E_SETNOTSUPPORTED = $800A0000 + 383;
|
|
CTL_E_NEEDPROPERTYARRAYINDEX = $800A0000 + 385;
|
|
CTL_E_SETNOTPERMITTED = $800A0000 + 387;
|
|
CTL_E_GETNOTSUPPORTEDATRUNTIME = $800A0000 + 393;
|
|
CTL_E_GETNOTSUPPORTED = $800A0000 + 394;
|
|
CTL_E_PROPERTYNOTFOUND = $800A0000 + 422;
|
|
CTL_E_INVALIDCLIPBOARDFORMAT = $800A0000 + 460;
|
|
CTL_E_INVALIDPICTURE = $800A0000 + 481;
|
|
CTL_E_PRINTERERROR = $800A0000 + 482;
|
|
CTL_E_CANTSAVEFILETOTEMP = $800A0000 + 735;
|
|
CTL_E_SEARCHTEXTNOTFOUND = $800A0000 + 744;
|
|
CTL_E_REPLACEMENTSTOOLONG = $800A0000 + 746;
|
|
CTL_E_CUSTOM_FIRST = $800A0000 + 600;
|
|
{$ENDIF WIN32}
|
|
|
|
type
|
|
{ OLE2 Automation Controller }
|
|
TJvOleController = class(TObject)
|
|
private
|
|
FLocale: TLCID;
|
|
FObject: Variant;
|
|
FRetValue: Variant;
|
|
function CallMethod(ID: TDispID; const Params: array of const;
|
|
NeedResult: Boolean): PVariant;
|
|
function CallMethodNamedParams(const IDs: TDispIDList;
|
|
const Params: array of const; Cnt: Byte; NeedResult: Boolean): PVariant;
|
|
function CallMethodNoParams(ID: TDispID; NeedResult: Boolean): PVariant;
|
|
function Invoke(DispIdMember: TDispID; WFlags: Word;
|
|
var DispParams: TDispParams; Res: PVariant): PVariant;
|
|
function NameToDispID(const AName: string): TDispID;
|
|
function NameToDispIDs(const AName: string;
|
|
const AParams: array of string; Dest: PDispIDList): PDispIDList;
|
|
protected
|
|
procedure ClearObject; virtual;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
{ create or assign OLE objects }
|
|
procedure CreateObject(const ClassName: string); virtual;
|
|
procedure AssignIDispatch(V: Variant); virtual;
|
|
procedure GetActiveObject(const ClassName: string); virtual;
|
|
{ get/set properties of OLE object by ID }
|
|
function GetPropertyByID(ID: TDispID): PVariant;
|
|
procedure SetPropertyByID(ID: TDispID; const Prop: array of const);
|
|
{ get/set properties of OLE object }
|
|
function GetProperty(const AName: string): PVariant;
|
|
procedure SetProperty(const AName: string; const Prop: array of const);
|
|
{ call OLE functions by IDs }
|
|
function CallFunctionByID(ID: TDispID; const Params: array of const): PVariant;
|
|
function CallFunctionByIDsNamedParams(const IDs: TDispIDList;
|
|
const Params: array of const; Cnt: Byte): PVariant;
|
|
function CallFunctionNoParamsByID(ID: TDispID): PVariant;
|
|
{ call OLE procedures by ID }
|
|
procedure CallProcedureByID(ID: TDispID; const Params: array of const);
|
|
procedure CallProcedureByIDsNamedParams(const IDs: TDispIDList;
|
|
const Params: array of const; Cnt: Byte);
|
|
procedure CallProcedureNoParamsByID(ID: TDispID);
|
|
{ call OLE functions }
|
|
function CallFunction(const AName: string; const Params: array of const): PVariant;
|
|
function CallFunctionNamedParams(const AName: string; const Params: array of const;
|
|
const ParamNames: array of string): PVariant;
|
|
function CallFunctionNoParams(const AName: string): PVariant;
|
|
{ call OLE procedures }
|
|
procedure CallProcedure(const AName: string; const Params: array of const);
|
|
procedure CallProcedureNamedParams(const AName: string; const Params: array of const;
|
|
const ParamNames: array of string);
|
|
procedure CallProcedureNoParams(const AName: string);
|
|
{ locale }
|
|
procedure SetLocale(PrimaryLangID, SubLangID: Word);
|
|
property Locale: TLCID read FLocale write FLocale;
|
|
property OleObject: Variant read FObject;
|
|
end;
|
|
|
|
procedure InitOLE;
|
|
procedure DoneOLE;
|
|
function OleInitialized: Boolean;
|
|
|
|
function MakeLangID(PrimaryLangID, SubLangID: Word): Word;
|
|
function MakeLCID(LangID: Word): TLCID;
|
|
function CreateLCID(PrimaryLangID, SubLangID: Word): TLCID;
|
|
function ExtractLangID(LCID: TLCID): Word;
|
|
function ExtractSubLangID(LCID: TLCID): Word;
|
|
|
|
{$IFNDEF WIN32}
|
|
|
|
procedure OleCheck(OleResult: HResult);
|
|
|
|
{ OLE string support }
|
|
function OleStrToString(Source: BSTR): string;
|
|
function StringToOleStr(const Source: string): BSTR;
|
|
function StringToClassID(const S: string): CLSID;
|
|
function ClassIDToString(const CLSID: CLSID): string;
|
|
|
|
{ Create or get active OLE object for a given a class name }
|
|
function CreateOleObject(const ClassName: string): Variant;
|
|
function GetActiveOleObject(const ClassName: string): Variant;
|
|
|
|
{$ENDIF WIN32}
|
|
|
|
implementation
|
|
|
|
uses
|
|
Forms;
|
|
|
|
{$IFDEF COMPILER3_UP}
|
|
resourcestring
|
|
{$ELSE}
|
|
const
|
|
{$ENDIF}
|
|
SOleInvalidVer = 'Invalid OLE library version';
|
|
SOleInitFailed = 'OLE Library initialization failed. Error code: %.8xH';
|
|
SOleNotInit = 'OLE2 Library not initialized';
|
|
SOleInvalidParam = 'Invalid parameter value';
|
|
SOleNotSupport = 'Method or property %s not supported by OLE object';
|
|
SOleNotReference = 'Variant does not reference an OLE automation object';
|
|
{$IFNDEF COMPILER3_UP}
|
|
SOleError = 'OLE2 error occured. Error code: %.8xH';
|
|
{$ENDIF}
|
|
|
|
// (rom) changed to var
|
|
var
|
|
FOleInitialized: Boolean = False;
|
|
|
|
const
|
|
{ OLE2 Version }
|
|
RMJ = 0;
|
|
RMM = 23;
|
|
RUP = 639;
|
|
|
|
const
|
|
DISPATCH_METHODNOPARAM = DISPATCH_METHOD or DISPATCH_PROPERTYGET;
|
|
DISPATCH_METHODPARAMS = DISPATCH_METHOD {$IFDEF WIN32} or DISPATCH_PROPERTYGET {$ENDIF};
|
|
|
|
{$IFDEF WIN32}
|
|
|
|
function FailedHR(hr: HResult): Boolean;
|
|
begin
|
|
Result := Failed(hr);
|
|
end;
|
|
|
|
{$ELSE WIN32}
|
|
|
|
{ Standard OLE class pathes }
|
|
type
|
|
IDispatch = class(IUnknown)
|
|
function GetTypeInfoCount(var PctInfo: Integer): HResult; virtual; cdecl; export; abstract;
|
|
function GetTypeInfo(ItInfo: Integer; TLCID: TLCID; var PTInfo: ITypeInfo): HResult; virtual; cdecl; export;
|
|
abstract;
|
|
function GetIDsOfNames(const Riid: IID; var rgszNames: PChar;
|
|
CNames: Integer; TLCID: TLCID; RgDispId: PDispID): HResult; virtual; cdecl; export; abstract;
|
|
function Invoke(DispIdMember: TDispID; const Riid: IID; TLCID: TLCID;
|
|
WFlags: Word; var DispParams: TDispParams; PVarResult: PVariant;
|
|
var ExcepInfo: TExcepInfo; var UArgErr: Integer): HResult; virtual; cdecl; export; abstract;
|
|
end;
|
|
|
|
function DispInvoke(_this: Pointer; PTInfo: ITypeInfo; DispIdMember: TDispID;
|
|
WFlags: Word; var pparams: TDispParams; PVarResult: PVariant;
|
|
var ExcepInfo: TExcepInfo; var UArgErr: Integer): HResult; far; external 'ole2disp';
|
|
|
|
function DispGetIDsOfNames(PTInfo: ITypeInfo; var rgszNames: PChar;
|
|
CNames: Integer; RgDispId: PDispID): HResult; far; external 'ole2disp';
|
|
|
|
function GUID_NULL: GUID;
|
|
begin
|
|
Result := IID_NULL;
|
|
end;
|
|
|
|
{$ENDIF WIN32}
|
|
|
|
{ Standard OLE Library initialization code }
|
|
|
|
procedure InitOLE;
|
|
var
|
|
dwVer: Longint;
|
|
HRes: HResult;
|
|
begin
|
|
if FOleInitialized then
|
|
Exit;
|
|
dwVer := Longint(CoBuildVersion);
|
|
if (RMM <> HiWord(dwVer)) or (RUP > LoWord(dwVer)) then
|
|
raise EOleError.Create(SOleInvalidVer)
|
|
else
|
|
begin
|
|
HRes := OleInitialize(nil);
|
|
if FailedHR(HRes) then
|
|
raise EOleError.CreateFmt(SOleInitFailed, [Longint(HRes)])
|
|
else
|
|
FOleInitialized := True;
|
|
end;
|
|
end;
|
|
|
|
{ Standard OLE Library exit code }
|
|
|
|
procedure DoneOLE;
|
|
begin
|
|
if FOleInitialized then
|
|
OleUninitialize;
|
|
FOleInitialized := False;
|
|
end;
|
|
|
|
function OleInitialized: Boolean;
|
|
begin
|
|
Result := FOleInitialized;
|
|
end;
|
|
|
|
procedure CheckOleInitialized;
|
|
begin
|
|
if not FOleInitialized then
|
|
raise EOleError.Create(SOleNotInit);
|
|
end;
|
|
|
|
{$IFNDEF COMPILER3_UP}
|
|
function OleErrorMsg(ErrorCode: HResult): string;
|
|
begin
|
|
FmtStr(Result, SOleError, [Longint(ErrorCode)]);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFNDEF WIN32}
|
|
|
|
procedure OleError(ErrorCode: HResult);
|
|
begin
|
|
raise EOleError.Create(OleErrorMsg(ErrorCode));
|
|
end;
|
|
|
|
{ Raise EOleError exception if result code indicates an error }
|
|
|
|
procedure OleCheck(OleResult: HResult);
|
|
begin
|
|
if FailedHR(OleResult) then
|
|
OleError(OleResult);
|
|
end;
|
|
|
|
{$ENDIF WIN32}
|
|
|
|
{ Raise exception given an OLE return code and TExcepInfo structure }
|
|
|
|
procedure DispInvokeError(Status: HResult; const ExcepInfo: TExcepInfo);
|
|
{$IFDEF COMPILER3_UP}
|
|
begin
|
|
DispatchInvokeError(Status, ExcepInfo);
|
|
end;
|
|
{$ELSE}
|
|
var
|
|
EClass: ExceptClass;
|
|
Msg: string;
|
|
begin
|
|
EClass := EOleError;
|
|
if Longint(Status) <> DISP_E_EXCEPTION then
|
|
Msg := OleErrorMsg(Status)
|
|
else
|
|
with ExcepInfo do
|
|
begin
|
|
try
|
|
if (scode = CTL_E_SETNOTSUPPORTED) or
|
|
(scode = CTL_E_SETNOTSUPPORTEDATRUNTIME) then
|
|
EClass := EPropReadOnly
|
|
else
|
|
if (scode = CTL_E_GETNOTSUPPORTED) or
|
|
(scode = CTL_E_GETNOTSUPPORTEDATRUNTIME) then
|
|
EClass := EPropWriteOnly;
|
|
if bstrDescription <> nil then
|
|
begin
|
|
Msg := OleStrToString(bstrDescription);
|
|
while (Length(Msg) > 0) and
|
|
(Msg[Length(Msg)] in [#0..#32, '.']) do
|
|
Delete(Msg, Length(Msg), 1);
|
|
end;
|
|
finally
|
|
if bstrSource <> nil then
|
|
SysFreeString(bstrSource);
|
|
if bstrDescription <> nil then
|
|
SysFreeString(bstrDescription);
|
|
if bstrHelpFile <> nil then
|
|
SysFreeString(bstrHelpFile);
|
|
end;
|
|
end;
|
|
if Msg = '' then
|
|
Msg := OleErrorMsg(Status);
|
|
raise EClass.Create(Msg);
|
|
end;
|
|
{$ENDIF COMPILER3_UP}
|
|
|
|
{$IFNDEF WIN32}
|
|
|
|
{ Convert a string to a class ID }
|
|
|
|
function StringToClassID(const S: string): CLSID;
|
|
var
|
|
CharBuf: array [0..64] of Char;
|
|
begin
|
|
OleCheck(CLSIDFromString(StrPLCopy(CharBuf, S, SizeOf(CharBuf) - 1), Result));
|
|
end;
|
|
|
|
{ Convert a class ID to a string }
|
|
|
|
function ClassIDToString(const CLSID: CLSID): string;
|
|
var
|
|
P: PChar;
|
|
Malloc: IMalloc;
|
|
begin
|
|
OleCheck(CoGetMalloc(MEMCTX_TASK, Malloc));
|
|
OleCheck(StringFromCLSID(CLSID, P));
|
|
Result := StrPas(P);
|
|
Malloc.Free(P);
|
|
end;
|
|
|
|
{ Create an OLE object variant given an IDispatch }
|
|
|
|
function VarFromInterface(Unknown: IUnknown): Variant;
|
|
var
|
|
Disp: IDispatch;
|
|
begin
|
|
VariantClear(VARIANTARG(Result));
|
|
VariantInit(VARIANTARG(Result));
|
|
try
|
|
if Unknown <> nil then
|
|
begin
|
|
OleCheck(Unknown.QueryInterface(IID_IDispatch, Disp));
|
|
Result.VT := VT_DISPATCH;
|
|
Result.pdispVal := Dispatch.IDispatch(Disp);
|
|
end;
|
|
except
|
|
VariantClear(VARIANTARG(Result));
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
{ Return OLE object stored in a variant }
|
|
|
|
function VarToInterface(const V: Variant): IDispatch;
|
|
begin
|
|
Result := nil;
|
|
if V.VT = VT_DISPATCH then
|
|
Result := IDispatch(V.pdispVal)
|
|
else
|
|
if V.VT = (VT_DISPATCH or VT_BYREF) then
|
|
Result := IDispatch(V.ppdispVal^);
|
|
if Result = nil then
|
|
raise EOleError.Create(SOleNotReference);
|
|
end;
|
|
|
|
{ Create an OLE object variant given a class name }
|
|
|
|
function CreateOleObject(const ClassName: string): Variant;
|
|
var
|
|
Unknown: IUnknown;
|
|
ClassID: CLSID;
|
|
CharBuf: array [0..127] of Char;
|
|
begin
|
|
StrPLCopy(CharBuf, ClassName, SizeOf(CharBuf) - 1);
|
|
OleCheck(CLSIDFromProgID(@CharBuf, ClassID));
|
|
OleCheck(CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or
|
|
CLSCTX_LOCAL_SERVER, IID_IUnknown, Unknown));
|
|
try
|
|
Result := VarFromInterface(Unknown);
|
|
finally
|
|
Unknown.Release;
|
|
end;
|
|
end;
|
|
|
|
{ Get active OLE object for a given class name }
|
|
|
|
function GetActiveOleObject(const ClassName: string): Variant;
|
|
var
|
|
Unknown: IUnknown;
|
|
ClassID: CLSID;
|
|
CharBuf: array [0..127] of Char;
|
|
begin
|
|
StrPLCopy(CharBuf, ClassName, SizeOf(CharBuf) - 1);
|
|
OleCheck(CLSIDFromProgID(@CharBuf, ClassID));
|
|
OleCheck(GetActiveObject(ClassID, nil, Unknown));
|
|
try
|
|
Result := VarFromInterface(Unknown);
|
|
finally
|
|
Unknown.Release;
|
|
end;
|
|
end;
|
|
|
|
{ OLE string support }
|
|
|
|
function OleStrToString(Source: BSTR): string;
|
|
begin
|
|
Result := StrPas(Source);
|
|
end;
|
|
|
|
function StringToOleStr(const Source: string): BSTR;
|
|
var
|
|
SourceLen: Integer;
|
|
CharBuf: array [0..255] of Char;
|
|
begin
|
|
SourceLen := Length(Source);
|
|
if SourceLen > 0 then
|
|
begin
|
|
StrPLCopy(CharBuf, Source, SizeOf(CharBuf) - 1);
|
|
Result := SysAllocStringLen(CharBuf, SourceLen);
|
|
end
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
{$ELSE}
|
|
|
|
{ Return OLE object stored in a variant }
|
|
|
|
{$IFDEF COMPILER3_UP}
|
|
function VarToInterface(const V: Variant): IDispatch;
|
|
begin
|
|
Result := nil;
|
|
if TVarData(V).VType = varDispatch then
|
|
Result := IDispatch(TVarData(V).VDispatch)
|
|
else
|
|
if TVarData(V).VType = (varDispatch or varByRef) then
|
|
Result := IDispatch(Pointer(TVarData(V).VPointer^));
|
|
if Result = nil then
|
|
raise EOleError.Create(SOleNotReference);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$ENDIF}
|
|
|
|
{ Assign Variant }
|
|
|
|
procedure AssignVariant(
|
|
var Dest: {$IFDEF WIN32} TVariantArg; {$ELSE} Variant; {$ENDIF}
|
|
const Value: TVarRec);
|
|
begin
|
|
{$IFNDEF WIN32}
|
|
VariantInit(VARIANTARG(Dest));
|
|
try
|
|
{$ENDIF}
|
|
with Value do
|
|
case VType of
|
|
vtInteger:
|
|
begin
|
|
Dest.vt := VT_I4;
|
|
Dest.lVal := VInteger;
|
|
end;
|
|
vtBoolean:
|
|
begin
|
|
Dest.vt := VT_BOOL;
|
|
Dest.vbool := VBoolean;
|
|
end;
|
|
vtChar:
|
|
begin
|
|
Dest.vt := VT_BSTR;
|
|
Dest.bstrVal := StringToOleStr(VChar);
|
|
end;
|
|
vtExtended:
|
|
begin
|
|
Dest.vt := VT_R8;
|
|
Dest.dblVal := VExtended^;
|
|
end;
|
|
vtString:
|
|
begin
|
|
Dest.vt := VT_BSTR;
|
|
Dest.bstrVal := StringToOleStr(VString^);
|
|
end;
|
|
vtPointer:
|
|
if VPointer = nil then
|
|
begin
|
|
Dest.vt := VT_NULL;
|
|
Dest.byRef := nil;
|
|
end
|
|
else
|
|
begin
|
|
Dest.vt := VT_BYREF;
|
|
Dest.byRef := VPointer;
|
|
end;
|
|
vtPChar:
|
|
begin
|
|
Dest.vt := VT_BSTR;
|
|
Dest.bstrVal := StringToOleStr(StrPas(VPChar));
|
|
end;
|
|
vtObject:
|
|
begin
|
|
Dest.vt := VT_BYREF;
|
|
Dest.byRef := VObject;
|
|
end;
|
|
{$IFDEF WIN32}
|
|
vtClass:
|
|
begin
|
|
Dest.vt := VT_BYREF;
|
|
Dest.byRef := VClass;
|
|
end;
|
|
vtWideChar:
|
|
begin
|
|
Dest.vt := VT_BSTR;
|
|
Dest.bstrVal := @VWideChar;
|
|
end;
|
|
vtPWideChar:
|
|
begin
|
|
Dest.vt := VT_BSTR;
|
|
Dest.bstrVal := VPWideChar;
|
|
end;
|
|
vtAnsiString:
|
|
begin
|
|
Dest.vt := VT_BSTR;
|
|
Dest.bstrVal := StringToOleStr(string(VAnsiString));
|
|
end;
|
|
vtCurrency:
|
|
begin
|
|
Dest.vt := VT_CY;
|
|
Dest.cyVal := VCurrency^;
|
|
end;
|
|
vtVariant:
|
|
begin
|
|
Dest.vt := VT_BYREF or VT_VARIANT;
|
|
Dest.pvarVal := VVariant;
|
|
end;
|
|
{$ENDIF WIN32}
|
|
{$IFDEF COMPILER4_UP}
|
|
vtInterface:
|
|
begin
|
|
Dest.vt := VT_UNKNOWN or VT_BYREF;
|
|
Dest.byRef := VInterface;
|
|
end;
|
|
vtInt64:
|
|
begin
|
|
Dest.vt := VT_I8 or VT_BYREF;
|
|
Dest.byRef := VInt64;
|
|
end;
|
|
{$ENDIF COMPILER4_UP}
|
|
else
|
|
raise EOleError.Create(SOleInvalidParam);
|
|
end;
|
|
{$IFNDEF WIN32}
|
|
except
|
|
VariantClear(VARIANTARG(Dest));
|
|
raise;
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
{ TJvOleController }
|
|
|
|
constructor TJvOleController.Create;
|
|
begin
|
|
inherited Create;
|
|
{$IFDEF WIN32}
|
|
FLocale := GetThreadLocale;
|
|
{$ELSE}
|
|
FLocale := LOCALE_SYSTEM_DEFAULT;
|
|
{$ENDIF}
|
|
try
|
|
InitOLE;
|
|
except
|
|
Application.HandleException(Self);
|
|
end;
|
|
end;
|
|
|
|
destructor TJvOleController.Destroy;
|
|
begin
|
|
if FOleInitialized then
|
|
ClearObject;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvOleController.CreateObject(const ClassName: string);
|
|
begin
|
|
CheckOleInitialized;
|
|
ClearObject;
|
|
FObject := CreateOleObject(ClassName);
|
|
end;
|
|
|
|
procedure TJvOleController.GetActiveObject(const ClassName: string);
|
|
begin
|
|
CheckOleInitialized;
|
|
ClearObject;
|
|
FObject := GetActiveOleObject(ClassName);
|
|
end;
|
|
|
|
procedure TJvOleController.AssignIDispatch(V: Variant);
|
|
begin
|
|
CheckOleInitialized;
|
|
ClearObject;
|
|
VarToInterface(V);
|
|
{$IFDEF WIN32}
|
|
VarCopy(FObject, V);
|
|
{$ELSE}
|
|
VariantCopy(VARIANTARG(FObject), V);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TJvOleController.ClearObject;
|
|
begin
|
|
{$IFDEF WIN32}
|
|
VarClear(FRetValue);
|
|
VarClear(FObject);
|
|
{$ELSE}
|
|
VariantClear(VARIANTARG(FRetValue));
|
|
VariantClear(VARIANTARG(FObject));
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TJvOleController.NameToDispID(const AName: string): TDispID;
|
|
var
|
|
{$IFDEF WIN32}
|
|
CharBuf: array [0..255] of WideChar;
|
|
P: array [0..0] of PWideChar;
|
|
{$ELSE}
|
|
CharBuf: array [0..255] of Char;
|
|
P: PChar;
|
|
{$ENDIF}
|
|
begin
|
|
CheckOleInitialized;
|
|
{$IFDEF WIN32}
|
|
StringToWideChar(AName, @CharBuf[0], 256);
|
|
P[0] := @CharBuf[0];
|
|
{$ELSE}
|
|
StrPLCopy(CharBuf, AName, SizeOf(CharBuf) - 1);
|
|
P := @CharBuf;
|
|
{$ENDIF}
|
|
if FailedHR(VarToInterface(FObject).GetIDsOfNames(GUID_NULL,
|
|
{$IFDEF WIN32} @P, {$ELSE} P, {$ENDIF} 1, FLocale, @Result)) then
|
|
raise EOleError.CreateFmt(SOleNotSupport, [AName]);
|
|
end;
|
|
|
|
function TJvOleController.NameToDispIDs(const AName: string;
|
|
const AParams: array of string; Dest: PDispIDList): PDispIDList;
|
|
var
|
|
{$IFDEF WIN32}
|
|
CharBuf: array [0..MaxDispArgs] of PWideChar;
|
|
Size: Integer;
|
|
{$ELSE}
|
|
CharBuf: array [0..MaxDispArgs] of PChar;
|
|
{$ENDIF}
|
|
I: Byte;
|
|
begin
|
|
Result := Dest;
|
|
CheckOleInitialized;
|
|
{$IFDEF WIN32}
|
|
Size := Length(AName) + 1;
|
|
GetMem(CharBuf[0], Size * SizeOf(WideChar));
|
|
StringToWideChar(AName, CharBuf[0], Size);
|
|
for I := 0 to High(AParams) do
|
|
begin
|
|
Size := Length(AParams[I]) + 1;
|
|
GetMem(CharBuf[I + 1], Size * SizeOf(WideChar));
|
|
StringToWideChar(AParams[I], CharBuf[I + 1], Size);
|
|
end;
|
|
{$ELSE}
|
|
CharBuf[0] := StrPCopy(StrAlloc(Length(AName) + 1), AName);
|
|
for I := 0 to High(AParams) do
|
|
CharBuf[I + 1] := StrPCopy(StrAlloc(Length(AParams[I]) + 1), AParams[I]);
|
|
{$ENDIF}
|
|
try
|
|
if FailedHR(VarToInterface(FObject).GetIDsOfNames(GUID_NULL,
|
|
{$IFDEF WIN32} @CharBuf, {$ELSE} CharBuf[0], {$ENDIF}
|
|
High(AParams) + 2, FLocale, @Result^[0])) then
|
|
raise EOleError.CreateFmt(SOleNotSupport, [AName]);
|
|
finally
|
|
{$IFDEF WIN32}
|
|
for I := 0 to High(AParams) + 1 do
|
|
FreeMem(CharBuf[I]);
|
|
{$ELSE}
|
|
for I := 0 to High(AParams) + 1 do
|
|
StrDispose(CharBuf[I]);
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
function TJvOleController.Invoke(DispIdMember: TDispID; WFlags: Word;
|
|
var DispParams: TDispParams; Res: PVariant): PVariant;
|
|
var
|
|
ExcepInfo: TExcepInfo;
|
|
UArgErr: Integer;
|
|
HRes: HResult;
|
|
begin
|
|
{$IFDEF WIN32}
|
|
if Res <> nil then
|
|
VarClear(Res^);
|
|
try
|
|
HRes := VarToInterface(FObject).Invoke(DispIdMember, GUID_NULL,
|
|
FLocale, WFlags, DispParams, Res, @ExcepInfo, @UArgErr);
|
|
except
|
|
if Res <> nil then
|
|
VarClear(Res^);
|
|
raise;
|
|
end;
|
|
{$ELSE}
|
|
if Res <> nil then
|
|
begin
|
|
VariantClear(VARIANTARG(Res^));
|
|
VariantInit(VARIANTARG(Res^));
|
|
end;
|
|
try
|
|
HRes := VarToInterface(FObject).Invoke(DispIdMember, GUID_NULL,
|
|
FLocale, WFlags, DispParams, Res, ExcepInfo, UArgErr);
|
|
except
|
|
if Res <> nil then
|
|
VariantClear(VARIANTARG(Res^));
|
|
raise;
|
|
end;
|
|
{$ENDIF}
|
|
if FailedHR(HRes) then
|
|
DispInvokeError(HRes, ExcepInfo);
|
|
Result := Res;
|
|
end;
|
|
|
|
function TJvOleController.CallMethodNoParams(ID: TDispID;
|
|
NeedResult: Boolean): PVariant;
|
|
var
|
|
Disp: TDispParams;
|
|
begin
|
|
FillChar(Disp, SizeOf(Disp), #0);
|
|
CheckOleInitialized;
|
|
if NeedResult then
|
|
Result := Invoke(ID, DISPATCH_METHODNOPARAM, Disp, @FRetValue)
|
|
else
|
|
Result := Invoke(ID, DISPATCH_METHODNOPARAM, Disp, nil);
|
|
end;
|
|
|
|
function TJvOleController.CallMethod(ID: TDispID; const Params: array of const;
|
|
NeedResult: Boolean): PVariant;
|
|
var
|
|
Disp: TDispParams;
|
|
ArgCnt, I: Integer;
|
|
{$IFDEF WIN32}
|
|
Args: array [0..MaxDispArgs - 1] of TVariantArg;
|
|
{$ELSE}
|
|
Args: array [0..MaxDispArgs - 1] of Variant;
|
|
{$ENDIF}
|
|
begin
|
|
CheckOleInitialized;
|
|
ArgCnt := 0;
|
|
try
|
|
for I := 0 to High(Params) do
|
|
begin
|
|
AssignVariant(Args[I], Params[I]);
|
|
Inc(ArgCnt);
|
|
if ArgCnt >= MaxDispArgs then
|
|
Break;
|
|
end;
|
|
with Disp do
|
|
begin
|
|
if ArgCnt = 0 then
|
|
rgvarg := nil
|
|
else
|
|
rgvarg := PVariantArgList(@Args[0]);
|
|
rgdispidNamedArgs := nil;
|
|
cArgs := ArgCnt;
|
|
cNamedArgs := 0;
|
|
end;
|
|
if NeedResult then
|
|
Result := Invoke(ID, DISPATCH_METHODPARAMS, Disp, @FRetValue)
|
|
else
|
|
Result := Invoke(ID, DISPATCH_METHODPARAMS, Disp, nil);
|
|
finally
|
|
{$IFNDEF WIN32}
|
|
for I := 0 to ArgCnt - 1 do
|
|
VariantClear(VARIANTARG(Args[I]));
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
function TJvOleController.CallMethodNamedParams(const IDs: TDispIDList;
|
|
const Params: array of const; Cnt: Byte; NeedResult: Boolean): PVariant;
|
|
var
|
|
Disp: TDispParams;
|
|
ArgCnt, I: Integer;
|
|
{$IFDEF WIN32}
|
|
Args: array [0..MaxDispArgs - 1] of TVariantArg;
|
|
{$ELSE}
|
|
Args: array [0..MaxDispArgs - 1] of Variant;
|
|
{$ENDIF}
|
|
begin
|
|
CheckOleInitialized;
|
|
ArgCnt := 0;
|
|
try
|
|
for I := 0 to High(Params) do
|
|
begin
|
|
AssignVariant(Args[I], Params[I]);
|
|
Inc(ArgCnt);
|
|
if ArgCnt >= MaxDispArgs then
|
|
Break;
|
|
end;
|
|
with Disp do
|
|
begin
|
|
if ArgCnt = 0 then
|
|
rgvarg := nil
|
|
else
|
|
rgvarg := PVariantArgList(@Args);
|
|
if Cnt = 0 then
|
|
rgdispidNamedArgs := nil
|
|
else
|
|
rgdispidNamedArgs := PDispIDList(@IDs[1]);
|
|
cArgs := ArgCnt;
|
|
cNamedArgs := Cnt;
|
|
end;
|
|
if NeedResult then
|
|
Result := Invoke(IDs[0], DISPATCH_METHODPARAMS, Disp, @FRetValue)
|
|
else
|
|
Result := Invoke(IDs[0], DISPATCH_METHODPARAMS, Disp, nil);
|
|
finally
|
|
{$IFNDEF WIN32}
|
|
for I := 0 to ArgCnt - 1 do
|
|
VariantClear(VARIANTARG(Args[I]));
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
procedure TJvOleController.SetPropertyByID(ID: TDispID; const Prop: array of const);
|
|
var
|
|
Disp: TDispParams;
|
|
ArgCnt, I: Integer;
|
|
{$IFDEF WIN32}
|
|
Args: array [0..MaxDispArgs - 1] of TVariantArg;
|
|
{$ELSE}
|
|
Args: array [0..MaxDispArgs - 1] of Variant;
|
|
{$ENDIF}
|
|
NameArg: TDispID;
|
|
begin
|
|
NameArg := DISPID_PROPERTYPUT;
|
|
CheckOleInitialized;
|
|
ArgCnt := 0;
|
|
try
|
|
for I := 0 to High(Prop) do
|
|
begin
|
|
AssignVariant(Args[I], Prop[I]);
|
|
Inc(ArgCnt);
|
|
if ArgCnt >= MaxDispArgs then
|
|
Break;
|
|
end;
|
|
with Disp do
|
|
begin
|
|
rgvarg := PVariantArgList(@Args[0]);
|
|
rgdispidNamedArgs := PDispIDList(@NameArg);
|
|
cArgs := ArgCnt;
|
|
cNamedArgs := 1;
|
|
end;
|
|
Invoke(ID, DISPATCH_PROPERTYPUT, Disp, nil);
|
|
finally
|
|
{$IFNDEF WIN32}
|
|
for I := 0 to ArgCnt - 1 do
|
|
VariantClear(VARIANTARG(Args[I]));
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
function TJvOleController.GetPropertyByID(ID: TDispID): PVariant;
|
|
var
|
|
Disp: TDispParams;
|
|
begin
|
|
FillChar(Disp, SizeOf(Disp), #0);
|
|
CheckOleInitialized;
|
|
Result := Invoke(ID, DISPATCH_PROPERTYGET, Disp, @FRetValue);
|
|
end;
|
|
|
|
procedure TJvOleController.CallProcedureByID(ID: TDispID; const Params: array of const);
|
|
begin
|
|
CallMethod(ID, Params, False);
|
|
end;
|
|
|
|
function TJvOleController.CallFunctionByID(ID: TDispID;
|
|
const Params: array of const): PVariant;
|
|
begin
|
|
Result := CallMethod(ID, Params, True);
|
|
end;
|
|
|
|
procedure TJvOleController.CallProcedureByIDsNamedParams(const IDs: TDispIDList;
|
|
const Params: array of const; Cnt: Byte);
|
|
begin
|
|
CallMethodNamedParams(IDs, Params, Cnt, False);
|
|
end;
|
|
|
|
function TJvOleController.CallFunctionByIDsNamedParams(const IDs: TDispIDList;
|
|
const Params: array of const; Cnt: Byte): PVariant;
|
|
begin
|
|
Result := CallMethodNamedParams(IDs, Params, Cnt, True);
|
|
end;
|
|
|
|
procedure TJvOleController.CallProcedureNoParamsByID(ID: TDispID);
|
|
begin
|
|
CallMethodNoParams(ID, False);
|
|
end;
|
|
|
|
function TJvOleController.CallFunctionNoParamsByID(ID: TDispID): PVariant;
|
|
begin
|
|
Result := CallMethodNoParams(ID, True);
|
|
end;
|
|
|
|
procedure TJvOleController.SetProperty(const AName: string;
|
|
const Prop: array of const);
|
|
begin
|
|
SetPropertyByID(NameToDispID(AName), Prop);
|
|
end;
|
|
|
|
function TJvOleController.GetProperty(const AName: string): PVariant;
|
|
begin
|
|
Result := GetPropertyByID(NameToDispID(AName));
|
|
end;
|
|
|
|
procedure TJvOleController.CallProcedure(const AName: string;
|
|
const Params: array of const);
|
|
begin
|
|
CallProcedureByID(NameToDispID(AName), Params);
|
|
end;
|
|
|
|
function TJvOleController.CallFunction(const AName: string;
|
|
const Params: array of const): PVariant;
|
|
begin
|
|
Result := CallFunctionByID(NameToDispID(AName), Params);
|
|
end;
|
|
|
|
procedure TJvOleController.CallProcedureNamedParams(const AName: string;
|
|
const Params: array of const; const ParamNames: array of string);
|
|
var
|
|
DispIDs: array [0..MaxDispArgs] of TDispID;
|
|
begin
|
|
CallProcedureByIDsNamedParams(NameToDispIDs(AName, ParamNames, PDispIDList(@DispIDs[0]))^,
|
|
Params, High(ParamNames) + 1);
|
|
end;
|
|
|
|
function TJvOleController.CallFunctionNamedParams(const AName: string;
|
|
const Params: array of const; const ParamNames: array of string): PVariant;
|
|
var
|
|
DispIDs: array [0..MaxDispArgs] of TDispID;
|
|
begin
|
|
Result := CallFunctionByIDsNamedParams(NameToDispIDs(AName, ParamNames,
|
|
PDispIDList(@DispIDs[0]))^, Params, High(ParamNames) + 1);
|
|
end;
|
|
|
|
procedure TJvOleController.CallProcedureNoParams(const AName: string);
|
|
begin
|
|
CallProcedureNoParamsByID(NameToDispID(AName));
|
|
end;
|
|
|
|
function TJvOleController.CallFunctionNoParams(const AName: string): PVariant;
|
|
begin
|
|
Result := CallFunctionNoParamsByID(NameToDispID(AName));
|
|
end;
|
|
|
|
procedure TJvOleController.SetLocale(PrimaryLangID, SubLangID: Word);
|
|
begin
|
|
FLocale := CreateLCID(PrimaryLangID, SubLangID);
|
|
end;
|
|
|
|
{ Utility routines }
|
|
|
|
function MakeLangID(PrimaryLangID, SubLangID: Word): Word;
|
|
begin
|
|
Result := (SubLangID shl 10) or PrimaryLangID;
|
|
end;
|
|
|
|
function MakeLCID(LangID: Word): TLCID;
|
|
begin
|
|
Result := TLCID(LangID or (Longint(0) shl 16));
|
|
end;
|
|
|
|
function CreateLCID(PrimaryLangID, SubLangID: Word): TLCID;
|
|
begin
|
|
Result := MakeLCID(MakeLangID(PrimaryLangID, SubLangID));
|
|
end;
|
|
|
|
function ExtractLangID(LCID: TLCID): Word;
|
|
begin
|
|
Result := LCID and $FF;
|
|
end;
|
|
|
|
function ExtractSubLangID(LCID: TLCID): Word;
|
|
begin
|
|
Result := LCID and ($FF shl 10) shr 10;
|
|
end;
|
|
|
|
{$IFDEF WIN32}
|
|
initialization
|
|
finalization
|
|
DoneOLE;
|
|
{$ELSE}
|
|
initialization
|
|
AddExitProc(DoneOLE);
|
|
{$ENDIF}
|
|
|
|
end.
|
|
|