Ole2auto.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:33k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {         OLE2 Automation Controller                    }
  5. {                                                       }
  6. {         Copyright (c) 1995, 1996 AO ROSNO             }
  7. {         Copyright (c) 1997 Master-Bank                }
  8. {                                                       }
  9. {*******************************************************}
  10. unit Ole2Auto;
  11. interface
  12. {$I RX.INC}
  13. {$IFDEF WIN32}
  14. uses Windows, SysUtils, {$IFDEF RX_D3} ActiveX, ComObj {$ELSE}
  15.   Ole2, OleAuto, OleCtl {$ENDIF};
  16. {$ELSE}
  17. uses WinTypes, WinProcs, SysUtils, Ole2, Dispatch;
  18. {$ENDIF}
  19. const { Maximum number of dispatch arguments }
  20. {$IFDEF RX_D3}
  21.   MaxDispArgs = 64;
  22. {$ELSE}
  23.   MaxDispArgs = 32;
  24. {$ENDIF}
  25. {$IFNDEF WIN32}
  26. type
  27.   TDispID = DISPID;
  28.   PDispID = ^TDispID;
  29.   TDispParams = DISPPARAMS;
  30.   TLCID = LCID;
  31.   TExcepInfo = EXCEPINFO;
  32.   PDispIDList = ^TDispIDList;
  33.   TDispIDList = array[0..MaxDispArgs] of TDispID;
  34.   EOleError = class(Exception);
  35. {$ENDIF WIN32}
  36. {$IFNDEF RX_D3}
  37. type
  38.   EPropReadOnly = class(EOleError);
  39.   EPropWriteOnly = class(EOleError);
  40. {$ENDIF}
  41. {$IFNDEF WIN32}
  42. const
  43. { Primary language IDs. }
  44.   LANG_NEUTRAL                     = $00;
  45.   LANG_AFRIKAANS                   = $36;
  46.   LANG_ALBANIAN                    = $1C;
  47.   LANG_ARABIC                      = $01;
  48.   LANG_BASQUE                      = $2D;
  49.   LANG_BELARUSIAN                  = $23;
  50.   LANG_BULGARIAN                   = $02;
  51.   LANG_CATALAN                     = $03;
  52.   LANG_CHINESE                     = $04;
  53.   LANG_CROATIAN                    = $1A;
  54.   LANG_CZECH                       = $05;
  55.   LANG_DANISH                      = $06;
  56.   LANG_DUTCH                       = $13;
  57.   LANG_ENGLISH                     = $09;
  58.   LANG_ESTONIAN                    = $25;
  59.   LANG_FAEROESE                    = $38;
  60.   LANG_FARSI                       = $29;
  61.   LANG_FINNISH                     = $0B;
  62.   LANG_FRENCH                      = $0C;
  63.   LANG_GERMAN                      = $07;
  64.   LANG_GREEK                       = $08;
  65.   LANG_HEBREW                      = $0D;
  66.   LANG_HUNGARIAN                   = $0E;
  67.   LANG_ICELANDIC                   = $0F;
  68.   LANG_INDONESIAN                  = $21;
  69.   LANG_ITALIAN                     = $10;
  70.   LANG_JAPANESE                    = $11;
  71.   LANG_KOREAN                      = $12;
  72.   LANG_LATVIAN                     = $26;
  73.   LANG_LITHUANIAN                  = $27;
  74.   LANG_NORWEGIAN                   = $14;
  75.   LANG_POLISH                      = $15;
  76.   LANG_PORTUGUESE                  = $16;
  77.   LANG_ROMANIAN                    = $18;
  78.   LANG_RUSSIAN                     = $19;
  79.   LANG_SERBIAN                     = $1A;
  80.   LANG_SLOVAK                      = $1B;
  81.   LANG_SLOVENIAN                   = $24;
  82.   LANG_SPANISH                     = $0A;
  83.   LANG_SWEDISH                     = $1D;
  84.   LANG_THAI                        = $1E;
  85.   LANG_TURKISH                     = $1F;
  86.   LANG_UKRAINIAN                   = $22;
  87.   LANG_VIETNAMESE                  = $2A;
  88. { Sublanguage IDs. }
  89.   SUBLANG_NEUTRAL                  = $00;    { language neutral }
  90.   SUBLANG_DEFAULT                  = $01;    { user default }
  91.   SUBLANG_SYS_DEFAULT              = $02;    { system default }
  92.   SUBLANG_CHINESE_TRADITIONAL      = $01;    { Chinese (Taiwan) }
  93.   SUBLANG_CHINESE_SIMPLIFIED       = $02;    { Chinese (PR China) }
  94.   SUBLANG_CHINESE_HONGKONG         = $03;    { Chinese (Hong Kong) }
  95.   SUBLANG_CHINESE_SINGAPORE        = $04;    { Chinese (Singapore) }
  96.   SUBLANG_DUTCH                    = $01;    { Dutch }
  97.   SUBLANG_DUTCH_BELGIAN            = $02;    { Dutch (Belgian) }
  98.   SUBLANG_ENGLISH_US               = $01;    { English (USA) }
  99.   SUBLANG_ENGLISH_UK               = $02;    { English (UK) }
  100.   SUBLANG_ENGLISH_AUS              = $03;    { English (Australian) }
  101.   SUBLANG_ENGLISH_CAN              = $04;    { English (Canadian) }
  102.   SUBLANG_ENGLISH_NZ               = $05;    { English (New Zealand) }
  103.   SUBLANG_ENGLISH_EIRE             = $06;    { English (Irish) }
  104.   SUBLANG_FRENCH                   = $01;    { French }
  105.   SUBLANG_FRENCH_BELGIAN           = $02;    { French (Belgian) }
  106.   SUBLANG_FRENCH_CANADIAN          = $03;    { French (Canadian) }
  107.   SUBLANG_FRENCH_SWISS             = $04;    { French (Swiss) }
  108.   SUBLANG_GERMAN                   = $01;    { German }
  109.   SUBLANG_GERMAN_SWISS             = $02;    { German (Swiss) }
  110.   SUBLANG_GERMAN_AUSTRIAN          = $03;    { German (Austrian) }
  111.   SUBLANG_ITALIAN                  = $01;    { Italian }
  112.   SUBLANG_ITALIAN_SWISS            = $02;    { Italian (Swiss) }
  113.   SUBLANG_NORWEGIAN_BOKMAL         = $01;    { Norwegian (Bokmal) }
  114.   SUBLANG_NORWEGIAN_NYNORSK        = $02;    { Norwegian (Nynorsk) }
  115.   SUBLANG_PORTUGUESE               = $02;    { Portuguese }
  116.   SUBLANG_PORTUGUESE_BRAZILIAN     = $01;    { Portuguese (Brazilian) }
  117.   SUBLANG_SPANISH                  = $01;    { Spanish (Castilian) }
  118.   SUBLANG_SPANISH_MEXICAN          = $02;    { Spanish (Mexican) }
  119.   SUBLANG_SPANISH_MODERN           = $03;    { Spanish (Modern) }
  120. { Default System and User IDs for language and locale. }
  121.   LANG_SYSTEM_DEFAULT   = (SUBLANG_SYS_DEFAULT shl 10) or LANG_NEUTRAL;
  122.   LANG_USER_DEFAULT     = (SUBLANG_DEFAULT shl 10) or LANG_NEUTRAL;
  123.   LOCALE_SYSTEM_DEFAULT = (0 shl 16) or LANG_SYSTEM_DEFAULT;
  124.   LOCALE_USER_DEFAULT   = (0 shl 16) or LANG_USER_DEFAULT;
  125. { OLE control status codes }
  126.   CTL_E_ILLEGALFUNCTIONCALL       = $800A0000 + 5;
  127.   CTL_E_OVERFLOW                  = $800A0000 + 6;
  128.   CTL_E_OUTOFMEMORY               = $800A0000 + 7;
  129.   CTL_E_DIVISIONBYZERO            = $800A0000 + 11;
  130.   CTL_E_OUTOFSTRINGSPACE          = $800A0000 + 14;
  131.   CTL_E_OUTOFSTACKSPACE           = $800A0000 + 28;
  132.   CTL_E_BADFILENAMEORNUMBER       = $800A0000 + 52;
  133.   CTL_E_FILENOTFOUND              = $800A0000 + 53;
  134.   CTL_E_BADFILEMODE               = $800A0000 + 54;
  135.   CTL_E_FILEALREADYOPEN           = $800A0000 + 55;
  136.   CTL_E_DEVICEIOERROR             = $800A0000 + 57;
  137.   CTL_E_FILEALREADYEXISTS         = $800A0000 + 58;
  138.   CTL_E_BADRECORDLENGTH           = $800A0000 + 59;
  139.   CTL_E_DISKFULL                  = $800A0000 + 61;
  140.   CTL_E_BADRECORDNUMBER           = $800A0000 + 63;
  141.   CTL_E_BADFILENAME               = $800A0000 + 64;
  142.   CTL_E_TOOMANYFILES              = $800A0000 + 67;
  143.   CTL_E_DEVICEUNAVAILABLE         = $800A0000 + 68;
  144.   CTL_E_PERMISSIONDENIED          = $800A0000 + 70;
  145.   CTL_E_DISKNOTREADY              = $800A0000 + 71;
  146.   CTL_E_PATHFILEACCESSERROR       = $800A0000 + 75;
  147.   CTL_E_PATHNOTFOUND              = $800A0000 + 76;
  148.   CTL_E_INVALIDPATTERNSTRING      = $800A0000 + 93;
  149.   CTL_E_INVALIDUSEOFNULL          = $800A0000 + 94;
  150.   CTL_E_INVALIDFILEFORMAT         = $800A0000 + 321;
  151.   CTL_E_INVALIDPROPERTYVALUE      = $800A0000 + 380;
  152.   CTL_E_INVALIDPROPERTYARRAYINDEX = $800A0000 + 381;
  153.   CTL_E_SETNOTSUPPORTEDATRUNTIME  = $800A0000 + 382;
  154.   CTL_E_SETNOTSUPPORTED           = $800A0000 + 383;
  155.   CTL_E_NEEDPROPERTYARRAYINDEX    = $800A0000 + 385;
  156.   CTL_E_SETNOTPERMITTED           = $800A0000 + 387;
  157.   CTL_E_GETNOTSUPPORTEDATRUNTIME  = $800A0000 + 393;
  158.   CTL_E_GETNOTSUPPORTED           = $800A0000 + 394;
  159.   CTL_E_PROPERTYNOTFOUND          = $800A0000 + 422;
  160.   CTL_E_INVALIDCLIPBOARDFORMAT    = $800A0000 + 460;
  161.   CTL_E_INVALIDPICTURE            = $800A0000 + 481;
  162.   CTL_E_PRINTERERROR              = $800A0000 + 482;
  163.   CTL_E_CANTSAVEFILETOTEMP        = $800A0000 + 735;
  164.   CTL_E_SEARCHTEXTNOTFOUND        = $800A0000 + 744;
  165.   CTL_E_REPLACEMENTSTOOLONG       = $800A0000 + 746;
  166.   CTL_E_CUSTOM_FIRST              = $800A0000 + 600;
  167. {$ENDIF WIN32}
  168. type
  169. { OLE2 Automation Controller }
  170.   TOleController = class(TObject)
  171.   private
  172.     FLocale: TLCID;
  173.     FObject: Variant;
  174.     FRetValue: Variant;
  175.     function CallMethod(ID: TDispID; const Params: array of const;
  176.       NeedResult: Boolean): PVariant;
  177.     function CallMethodNamedParams(const IDs: TDispIDList;
  178.       const Params: array of const; Cnt: Byte; NeedResult: Boolean): PVariant;
  179.     function CallMethodNoParams(ID: TDispID; NeedResult: Boolean): PVariant;
  180.     function Invoke(dispidMember: TDispID; wFlags: Word;
  181.       var pdispparams: TDispParams; Res: PVariant): PVariant;
  182.     function NameToDispID(const AName: string): TDispID;
  183.     function NameToDispIDs(const AName: string;
  184.       const AParams: array of string; Dest: PDispIDList): PDispIDList;
  185.   protected
  186.     procedure ClearObject; virtual;
  187.   public
  188.     constructor Create;
  189.     destructor Destroy; override;
  190.     { create or assign OLE objects }
  191.     procedure CreateObject(const ClassName: string); virtual;
  192.     procedure AssignIDispatch(V: Variant); virtual;
  193.     procedure GetActiveObject(const ClassName: string); virtual;
  194.     { get/set properties of OLE object by ID }
  195.     function GetPropertyByID(ID: TDispID): PVariant;
  196.     procedure SetPropertyByID(ID: TDispID; const Prop: array of const);
  197.     { get/set properties of OLE object }
  198.     function GetProperty(const AName: string): PVariant;
  199.     procedure SetProperty(const AName: string; const Prop: array of const);
  200.     { call OLE functions by IDs }
  201.     function CallFunctionByID(ID: TDispID; const Params: array of const): PVariant;
  202.     function CallFunctionByIDsNamedParams(const IDs: TDispIDList;
  203.       const Params: array of const; Cnt: Byte): PVariant;
  204.     function CallFunctionNoParamsByID(ID: TDispID): PVariant;
  205.     { call OLE procedures by ID }
  206.     procedure CallProcedureByID(ID: TDispID; const Params: array of const);
  207.     procedure CallProcedureByIDsNamedParams(const IDs: TDispIDList;
  208.       const Params: array of const; Cnt: Byte);
  209.     procedure CallProcedureNoParamsByID(ID: TDispID);
  210.     { call OLE functions }
  211.     function CallFunction(const AName: string; const Params: array of const): PVariant;
  212.     function CallFunctionNamedParams(const AName: string; const Params: array of const;
  213.       const ParamNames: array of string): PVariant;
  214.     function CallFunctionNoParams(const AName: string): PVariant;
  215.     { call OLE procedures }
  216.     procedure CallProcedure(const AName: string; const Params: array of const);
  217.     procedure CallProcedureNamedParams(const AName: string; const Params: array of const;
  218.       const ParamNames: array of string);
  219.     procedure CallProcedureNoParams(const AName: string);
  220.     { locale }
  221.     procedure SetLocale(PrimaryLangID, SubLangID: Word);
  222.     property Locale: TLCID read FLocale write FLocale;
  223.     property OleObject: Variant read FObject;
  224.   end;
  225. procedure InitOLE;
  226. procedure DoneOLE;
  227. function OleInitialized: Boolean;
  228. function MakeLangID(PrimaryLangID, SubLangID: Word): Word;
  229. function MakeLCID(LangID: Word): TLCID;
  230. function CreateLCID(PrimaryLangID, SubLangID: Word): TLCID;
  231. function ExtractLangID(LCID: TLCID): Word;
  232. function ExtractSubLangID(LCID: TLCID): Word;
  233. {$IFNDEF WIN32}
  234. procedure OleCheck(OleResult: HResult);
  235. { OLE string support }
  236. function OleStrToString(Source: BSTR): string;
  237. function StringToOleStr(const Source: string): BSTR;
  238. function StringToClassID(const S: string): CLSID;
  239. function ClassIDToString(const CLSID: CLSID): string;
  240. { Create or get active OLE object for a given a class name }
  241. function CreateOleObject(const ClassName: string): Variant;
  242. function GetActiveOleObject(const ClassName: string): Variant;
  243. {$ENDIF WIN32}
  244. implementation
  245. uses Forms;
  246. {$IFDEF RX_D3}
  247. resourcestring
  248. {$ELSE}
  249. const
  250. {$ENDIF}
  251.   SOleInvalidVer   = 'Invalid OLE library version';
  252.   SOleInitFailed   = 'OLE Library initialization failed. Error code: %.8xH';
  253.   SOleNotInit      = 'OLE2 Library not initialized';
  254.   SOleInvalidParam = 'Invalid parameter value';
  255.   SOleNotSupport   = 'Method or property %s not supported by OLE object';
  256.   SOleNotReference = 'Variant does not reference an OLE automation object';
  257. {$IFNDEF RX_D3}
  258.   SOleError        = 'OLE2 error occured. Error code: %.8xH';
  259. {$ENDIF}
  260. const
  261.   FOleInitialized: Boolean = False;
  262. const
  263. { OLE2 Version }
  264.   RMJ =   0;
  265.   RMM =  23;
  266.   RUP = 639;
  267. const
  268.   DISPATCH_METHODNOPARAM = DISPATCH_METHOD or DISPATCH_PROPERTYGET;
  269.   DISPATCH_METHODPARAMS = DISPATCH_METHOD
  270.     {$IFDEF WIN32} or DISPATCH_PROPERTYGET {$ENDIF};
  271. {$IFDEF WIN32}
  272. function FailedHR(hr: HResult): Boolean;
  273. begin
  274.   Result := Failed(hr);
  275. end;
  276. {$ELSE WIN32}
  277. { Standard OLE class pathes }
  278. type
  279.   IDispatch = class(IUnknown)
  280.     function GetTypeInfoCount(var pctinfo: Integer): HResult; virtual; cdecl; export; abstract;
  281.     function GetTypeInfo(itinfo: Integer; TLCID: TLCID; var pptinfo: ITypeInfo): HResult; virtual; cdecl; export; abstract;
  282.     function GetIDsOfNames(const riid: IID; var rgszNames: PChar;
  283.       cNames: Integer; TLCID: TLCID; rgdispid: PDispID): HResult; virtual; cdecl; export; abstract;
  284.     function Invoke(dispidMember: TDispID; const riid: IID; TLCID: TLCID;
  285.       wFlags: Word; var pdispparams: TDispParams; pvarResult: PVARIANT;
  286.       var pexcepinfo: TExcepInfo; var puArgErr: Integer): HResult; virtual; cdecl; export; abstract;
  287.   end;
  288. function DispInvoke(_this: Pointer; ptinfo: ITypeInfo; dispidMember: TDispID;
  289.   wFlags: Word; var pparams: TDispParams; pvarResult: PVARIANT;
  290.   var pexcepinfo: TExcepInfo; var puArgErr: Integer): HResult; far; external 'ole2disp';
  291. function DispGetIDsOfNames(ptinfo: ITypeInfo; var rgszNames: PChar;
  292.   cNames: Integer; rgdispid: PDispID): HResult; far; external 'ole2disp';
  293. function GUID_NULL: GUID;
  294. begin
  295.   Result := IID_NULL;
  296. end;
  297. {$ENDIF WIN32}
  298. { Standard OLE Library initialization code }
  299. procedure InitOLE;
  300. var
  301.   dwVer: Longint;
  302.   HRes: HResult;
  303. begin
  304.   if FOleInitialized then Exit;
  305.   dwVer := Longint(CoBuildVersion);
  306.   if (RMM <> HiWord(dwVer)) or (RUP > LoWord(dwVer)) then
  307.     raise EOleError.Create(SOleInvalidVer)
  308.   else begin
  309.     HRes := OleInitialize(nil);
  310.     if FailedHR(HRes) then
  311.       raise EOleError.CreateFmt(SOleInitFailed, [Longint(HRes)])
  312.     else FOleInitialized := True;
  313.   end;
  314. end;
  315. { Standard OLE Library exit code }
  316. procedure DoneOLE;
  317. begin
  318.   if FOleInitialized then OleUninitialize;
  319.   FOleInitialized := False;
  320. end;
  321. function OleInitialized: Boolean;
  322. begin
  323.   Result := FOleInitialized;
  324. end;
  325. procedure CheckOleInitialized;
  326. begin
  327.   if not FOleInitialized then raise EOleError.Create(SOleNotInit);
  328. end;
  329. {$IFNDEF RX_D3}
  330. function OleErrorMsg(ErrorCode: HResult): string;
  331. begin
  332.   FmtStr(Result, SOleError, [Longint(ErrorCode)]);
  333. end;
  334. {$ENDIF}
  335. {$IFNDEF WIN32}
  336. procedure OleError(ErrorCode: HResult);
  337. begin
  338.   raise EOleError.Create(OleErrorMsg(ErrorCode));
  339. end;
  340. { Raise EOleError exception if result code indicates an error }
  341. procedure OleCheck(OleResult: HResult);
  342. begin
  343.   if FailedHR(OleResult) then OleError(OleResult);
  344. end;
  345. {$ENDIF WIN32}
  346. { Raise exception given an OLE return code and TExcepInfo structure }
  347. procedure DispInvokeError(Status: HResult; const ExcepInfo: TExcepInfo);
  348. {$IFDEF RX_D3}
  349. begin
  350.   DispatchInvokeError(Status, ExcepInfo);
  351. {$ELSE}
  352. var
  353.   EClass: ExceptClass;
  354.   Message: string;
  355. begin
  356.   EClass := EOleError;
  357.   if Longint(Status) <> DISP_E_EXCEPTION then
  358.     Message := OleErrorMsg(Status)
  359.   else
  360.     with ExcepInfo do
  361.     begin
  362.       try
  363.         if (scode = CTL_E_SETNOTSUPPORTED) or
  364.           (scode = CTL_E_SETNOTSUPPORTEDATRUNTIME) then
  365.             EClass := EPropReadOnly
  366.         else if (scode = CTL_E_GETNOTSUPPORTED) or
  367.           (scode = CTL_E_GETNOTSUPPORTEDATRUNTIME) then
  368.             EClass := EPropWriteOnly;
  369.         if bstrDescription <> nil then begin
  370.           Message := OleStrToString(bstrDescription);
  371.           while (Length(Message) > 0) and
  372.             (Message[Length(Message)] in [#0..#32, '.']) do
  373.             Delete(Message, Length(Message), 1);
  374.         end;
  375.       finally
  376.         if bstrSource <> nil then SysFreeString(bstrSource);
  377.         if bstrDescription <> nil then SysFreeString(bstrDescription);
  378.         if bstrHelpFile <> nil then SysFreeString(bstrHelpFile);
  379.       end;
  380.     end;
  381.   if Message = '' then Message := OleErrorMsg(Status);
  382.   raise EClass.Create(Message);
  383. {$ENDIF RX_D3}
  384. end;
  385. {$IFNDEF WIN32}
  386. { Convert a string to a class ID }
  387. function StringToClassID(const S: string): CLSID;
  388. var
  389.   CharBuf: array[0..64] of Char;
  390. begin
  391.   OleCheck(CLSIDFromString(StrPLCopy(CharBuf, S, SizeOf(CharBuf) - 1),
  392.     Result));
  393. end;
  394. { Convert a class ID to a string }
  395. function ClassIDToString(const CLSID: CLSID): string;
  396. var
  397.   P: PChar;
  398.   Malloc: IMalloc;
  399. begin
  400.   OleCheck(CoGetMalloc(MEMCTX_TASK, Malloc));
  401.   OleCheck(StringFromCLSID(CLSID, P));
  402.   Result := StrPas(P);
  403.   Malloc.Free(P);
  404. end;
  405. { Create an OLE object variant given an IDispatch }
  406. function VarFromInterface(Unknown: IUnknown): Variant;
  407. var
  408.   Disp: IDispatch;
  409. begin
  410.   VariantClear(VARIANTARG(Result));
  411.   VariantInit(VARIANTARG(Result));
  412.   try
  413.     if Unknown <> nil then begin
  414.       OleCheck(Unknown.QueryInterface(IID_IDispatch, Disp));
  415.       Result.VT := VT_DISPATCH;
  416.       Result.pdispVal := Dispatch.IDispatch(Disp);
  417.     end;
  418.   except
  419.     VariantClear(VARIANTARG(Result));
  420.     raise;
  421.   end;
  422. end;
  423. { Return OLE object stored in a variant }
  424. function VarToInterface(const V: Variant): IDispatch;
  425. begin
  426.   Result := nil;
  427.   if V.VT = VT_DISPATCH then
  428.     Result := IDispatch(V.pdispVal)
  429.   else if V.VT = (VT_DISPATCH or VT_BYREF) then
  430.     Result := IDispatch(V.ppdispVal^);
  431.   if Result = nil then raise EOleError.Create(SOleNotReference);
  432. end;
  433. { Create an OLE object variant given a class name }
  434. function CreateOleObject(const ClassName: string): Variant;
  435. var
  436.   Unknown: IUnknown;
  437.   ClassID: CLSID;
  438.   CharBuf: array[0..127] of Char;
  439. begin
  440.   StrPLCopy(CharBuf, ClassName, SizeOf(CharBuf) - 1);
  441.   OleCheck(CLSIDFromProgID(@CharBuf, ClassID));
  442.   OleCheck(CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or
  443.     CLSCTX_LOCAL_SERVER, IID_IUnknown, Unknown));
  444.   try
  445.     Result := VarFromInterface(Unknown);
  446.   finally
  447.     Unknown.Release;
  448.   end;
  449. end;
  450. { Get active OLE object for a given class name }
  451. function GetActiveOleObject(const ClassName: string): Variant;
  452. var
  453.   Unknown: IUnknown;
  454.   ClassID: CLSID;
  455.   CharBuf: array[0..127] of Char;
  456. begin
  457.   StrPLCopy(CharBuf, ClassName, SizeOf(CharBuf) - 1);
  458.   OleCheck(CLSIDFromProgID(@CharBuf, ClassID));
  459.   OleCheck(GetActiveObject(ClassID, nil, Unknown));
  460.   try
  461.     Result := VarFromInterface(Unknown);
  462.   finally
  463.     Unknown.Release;
  464.   end;
  465. end;
  466. { OLE string support }
  467. function OleStrToString(Source: BSTR): string;
  468. begin
  469.   Result := StrPas(Source);
  470. end;
  471. function StringToOleStr(const Source: string): BSTR;
  472. var
  473.   SourceLen: Integer;
  474.   CharBuf: array[0..255] of Char;
  475. begin
  476.   SourceLen := Length(Source);
  477.   if SourceLen > 0 then begin
  478.     StrPLCopy(CharBuf, Source, SizeOf(CharBuf) - 1);
  479.     Result := SysAllocStringLen(CharBuf, SourceLen);
  480.   end
  481.   else Result := nil;
  482. end;
  483. {$ELSE}
  484.  {$IFDEF RX_D3}
  485. { Return OLE object stored in a variant }
  486. function VarToInterface(const V: Variant): IDispatch;
  487. begin
  488.   Result := nil;
  489.   if TVarData(V).VType = varDispatch then
  490.     Result := IDispatch(TVarData(V).VDispatch)
  491.   else if TVarData(V).VType = (varDispatch or varByRef) then
  492.     Result := IDispatch(Pointer(TVarData(V).VPointer^));
  493.   if Result = nil then raise EOleError.Create(SOleNotReference);
  494. end;
  495.  {$ENDIF}
  496. {$ENDIF}
  497. { Assign Variant }
  498. procedure AssignVariant(
  499.   var Dest: {$IFDEF WIN32} TVariantArg; {$ELSE} Variant; {$ENDIF}
  500.   const Value: TVarRec);
  501. begin
  502. {$IFNDEF WIN32}
  503.   VariantInit(VARIANTARG(Dest));
  504.   try
  505. {$ENDIF}
  506.     with Value do
  507.       case VType of
  508.         vtInteger:
  509.           begin
  510.             Dest.vt := VT_I4;
  511.             Dest.lVal := VInteger;
  512.           end;
  513.         vtBoolean:
  514.           begin
  515.             Dest.vt := VT_BOOL;
  516.             Dest.vbool := VBoolean;
  517.           end;
  518.         vtChar:
  519.           begin
  520.             Dest.vt := VT_BSTR;
  521.             Dest.bstrVal := StringToOleStr(VChar);
  522.           end;
  523.         vtExtended:
  524.           begin
  525.             Dest.vt := VT_R8;
  526.             Dest.dblVal := VExtended^;
  527.           end;
  528.         vtString:
  529.           begin
  530.             Dest.vt := VT_BSTR;
  531.             Dest.bstrVal := StringToOleStr(VString^);
  532.           end;
  533.         vtPointer:
  534.           if VPointer = nil then begin
  535.             Dest.vt := VT_NULL;
  536.             Dest.byRef := nil;
  537.           end
  538.           else begin
  539.             Dest.vt := VT_BYREF;
  540.             Dest.byRef := VPointer;
  541.           end;
  542.         vtPChar:
  543.           begin
  544.             Dest.vt := VT_BSTR;
  545.             Dest.bstrVal := StringToOleStr(StrPas(VPChar));
  546.           end;
  547.         vtObject:
  548.           begin
  549.             Dest.vt := VT_BYREF;
  550.             Dest.byRef := VObject;
  551.           end;
  552. {$IFDEF WIN32}
  553.         vtClass:
  554.           begin
  555.             Dest.vt := VT_BYREF;
  556.             Dest.byRef := VClass;
  557.           end;
  558.         vtWideChar:
  559.           begin
  560.             Dest.vt := VT_BSTR;
  561.             Dest.bstrVal := @VWideChar;
  562.           end;
  563.         vtPWideChar:
  564.           begin
  565.             Dest.vt := VT_BSTR;
  566.             Dest.bstrVal := VPWideChar;
  567.           end;
  568.         vtAnsiString:
  569.           begin
  570.             Dest.vt := VT_BSTR;
  571.             Dest.bstrVal := StringToOleStr(string(VAnsiString));
  572.           end;
  573.         vtCurrency:
  574.           begin
  575.             Dest.vt := VT_CY;
  576.             Dest.cyVal := VCurrency^;
  577.           end;
  578.         vtVariant:
  579.           begin
  580.             Dest.vt := VT_BYREF or VT_VARIANT;
  581.             Dest.pvarVal := VVariant;
  582.           end;
  583. {$ENDIF WIN32}
  584. {$IFDEF RX_D4}
  585.         vtInterface:
  586.           begin
  587.             Dest.vt := VT_UNKNOWN or VT_BYREF;
  588.             Dest.byRef := VInterface;
  589.           end;
  590.         vtInt64:
  591.           begin
  592.             Dest.vt := VT_I8 or VT_BYREF;
  593.             Dest.byRef := VInt64;
  594.           end;
  595. {$ENDIF RX_D4}
  596.         else raise EOleError.Create(SOleInvalidParam);
  597.       end;
  598. {$IFNDEF WIN32}
  599.   except
  600.     VariantClear(VARIANTARG(Dest));
  601.     raise;
  602.   end;
  603. {$ENDIF}
  604. end;
  605. { TOleController }
  606. constructor TOleController.Create;
  607. begin
  608.   inherited Create;
  609. {$IFDEF WIN32}
  610.   FLocale := GetThreadLocale;
  611. {$ELSE}
  612.   FLocale := LOCALE_SYSTEM_DEFAULT;
  613. {$ENDIF}
  614.   try
  615.     InitOLE;
  616.   except
  617.     Application.HandleException(Self);
  618.   end;
  619. end;
  620. destructor TOleController.Destroy;
  621. begin
  622.   if FOleInitialized then ClearObject;
  623.   inherited Destroy;
  624. end;
  625. procedure TOleController.CreateObject(const ClassName: string);
  626. begin
  627.   CheckOleInitialized;
  628.   ClearObject;
  629.   FObject := CreateOleObject(ClassName);
  630. end;
  631. procedure TOleController.GetActiveObject(const ClassName: string);
  632. begin
  633.   CheckOleInitialized;
  634.   ClearObject;
  635.   FObject := GetActiveOleObject(ClassName);
  636. end;
  637. procedure TOleController.AssignIDispatch(V: Variant);
  638. begin
  639.   CheckOleInitialized;
  640.   ClearObject;
  641.   VarToInterface(V);
  642. {$IFDEF WIN32}
  643.   VarCopy(FObject, V);
  644. {$ELSE}
  645.   VariantCopy(VARIANTARG(FObject), V);
  646. {$ENDIF}
  647. end;
  648. procedure TOleController.ClearObject;
  649. begin
  650. {$IFDEF WIN32}
  651.   VarClear(FRetValue);
  652.   VarClear(FObject);
  653. {$ELSE}
  654.   VariantClear(VARIANTARG(FRetValue));
  655.   VariantClear(VARIANTARG(FObject));
  656. {$ENDIF}
  657. end;
  658. function TOleController.NameToDispID(const AName: string): TDispID;
  659. var
  660. {$IFDEF WIN32}
  661.   CharBuf: array[0..255] of WideChar;
  662.   P: array[0..0] of PWideChar;
  663. {$ELSE}
  664.   CharBuf: array[0..255] of Char;
  665.   P: PChar;
  666. {$ENDIF}
  667. begin
  668.   CheckOleInitialized;
  669. {$IFDEF WIN32}
  670.   StringToWideChar(AName, @CharBuf, 256);
  671.   P[0] := @CharBuf[0];
  672. {$ELSE}
  673.   StrPLCopy(CharBuf, AName, SizeOf(CharBuf) - 1);
  674.   P := @CharBuf;
  675. {$ENDIF}
  676.   if FailedHR(VarToInterface(FObject).GetIDsOfNames(GUID_NULL,
  677.     {$IFDEF WIN32} @P, {$ELSE} P, {$ENDIF} 1, FLocale, @Result)) then
  678.     raise EOleError.CreateFmt(SOleNotSupport, [AName]);
  679. end;
  680. function TOleController.NameToDispIDs(const AName: string;
  681.   const AParams: array of string; Dest: PDispIDList): PDispIDList;
  682. var
  683. {$IFDEF WIN32}
  684.   CharBuf: array[0..MaxDispArgs] of PWideChar;
  685.   Size: Integer;
  686. {$ELSE}
  687.   CharBuf: array[0..MaxDispArgs] of PChar;
  688. {$ENDIF}
  689.   I: Byte;
  690. begin
  691.   Result := Dest;
  692.   CheckOleInitialized;
  693. {$IFDEF WIN32}
  694.   Size := Length(AName) + 1;
  695.   GetMem(CharBuf[0], Size * SizeOf(WideChar));
  696.   StringToWideChar(AName, CharBuf[0], Size);
  697.   for I := 0 to High(AParams) do begin
  698.     Size := Length(AParams[I]) + 1;
  699.     GetMem(CharBuf[I + 1], Size * SizeOf(WideChar));
  700.     StringToWideChar(AParams[I], CharBuf[I + 1], Size);
  701.   end;
  702. {$ELSE}
  703.   CharBuf[0] := StrPCopy(StrAlloc(Length(AName) + 1), AName);
  704.   for I := 0 to High(AParams) do
  705.     CharBuf[I + 1] := StrPCopy(StrAlloc(Length(AParams[I]) + 1), AParams[I]);
  706. {$ENDIF}
  707.   try
  708.     if FailedHR(VarToInterface(FObject).GetIDsOfNames(GUID_NULL,
  709.       {$IFDEF WIN32} @CharBuf, {$ELSE} CharBuf[0], {$ENDIF}
  710.       High(AParams) + 2, FLocale, @Result^[0]))
  711.     then
  712.       raise EOleError.CreateFmt(SOleNotSupport, [AName]);
  713.   finally
  714. {$IFDEF WIN32}
  715.     for I := 0 to High(AParams) + 1 do FreeMem(CharBuf[I]);
  716. {$ELSE}
  717.     for I := 0 to High(AParams) + 1 do StrDispose(CharBuf[I]);
  718. {$ENDIF}
  719.   end;
  720. end;
  721. function TOleController.Invoke(dispidMember: TDispID; wFlags: Word;
  722.   var pdispparams: TDispParams; Res: PVariant): PVariant;
  723. var
  724.   pexcepinfo: TExcepInfo;
  725.   puArgErr: Integer;
  726.   HRes: HResult;
  727. begin
  728. {$IFDEF WIN32}
  729.   if Res <> nil then VarClear(Res^);
  730.   try
  731.     HRes := VarToInterface(FObject).Invoke(dispidMember, GUID_NULL,
  732.       FLocale, wFlags, pdispparams, Res, @pexcepinfo, @puArgErr);
  733.   except
  734.     if Res <> nil then VarClear(Res^);
  735.     raise;
  736.   end;
  737. {$ELSE}
  738.   if Res <> nil then begin
  739.     VariantClear(VARIANTARG(Res^));
  740.     VariantInit(VARIANTARG(Res^));
  741.   end;
  742.   try
  743.     HRes := VarToInterface(FObject).Invoke(dispidMember, GUID_NULL,
  744.       FLocale, wFlags, pdispparams, Res, pexcepinfo, puArgErr);
  745.   except
  746.     if Res <> nil then VariantClear(VARIANTARG(Res^));
  747.     raise;
  748.   end;
  749. {$ENDIF}
  750.   if FailedHR(HRes) then DispInvokeError(HRes, pexcepinfo);
  751.   Result := Res;
  752. end;
  753. function TOleController.CallMethodNoParams(ID: TDispID;
  754.   NeedResult: Boolean): PVariant;
  755. const
  756.   Disp: TDispParams = (rgvarg: nil; rgdispidNamedArgs: nil; cArgs: 0;
  757.     cNamedArgs: 0);
  758. begin
  759.   CheckOleInitialized;
  760.   if NeedResult then
  761.     Result := Invoke(ID, DISPATCH_METHODNOPARAM, Disp, @FRetValue)
  762.   else
  763.     Result := Invoke(ID, DISPATCH_METHODNOPARAM, Disp, nil);
  764. end;
  765. function TOleController.CallMethod(ID: TDispID; const Params: array of const;
  766.   NeedResult: Boolean): PVariant;
  767. var
  768.   Disp: TDispParams;
  769.   ArgCnt, I: Integer;
  770. {$IFDEF WIN32}
  771.   Args: array[0..MaxDispArgs - 1] of TVariantArg;
  772. {$ELSE}
  773.   Args: array[0..MaxDispArgs - 1] of Variant;
  774. {$ENDIF}
  775. begin
  776.   CheckOleInitialized;
  777.   ArgCnt := 0;
  778.   try
  779.     for I := 0 to High(Params) do begin
  780.       AssignVariant(Args[I], Params[I]);
  781.       Inc(ArgCnt);
  782.       if ArgCnt >= MaxDispArgs then Break;
  783.     end;
  784.     with Disp do begin
  785.       if ArgCnt = 0 then rgvarg := nil
  786.       else rgvarg := @Args;
  787.       rgdispidNamedArgs := nil;
  788.       cArgs := ArgCnt;
  789.       cNamedArgs := 0;
  790.     end;
  791.     if NeedResult then
  792.       Result := Invoke(ID, DISPATCH_METHODPARAMS, Disp, @FRetValue)
  793.     else
  794.       Result := Invoke(ID, DISPATCH_METHODPARAMS, Disp, nil);
  795.   finally
  796. {$IFNDEF WIN32}
  797.     for I := 0 to ArgCnt - 1 do VariantClear(VARIANTARG(Args[I]));
  798. {$ENDIF}
  799.   end;
  800. end;
  801. function TOleController.CallMethodNamedParams(const IDs: TDispIDList;
  802.   const Params: array of const; Cnt: Byte; NeedResult: Boolean): PVariant;
  803. var
  804.   Disp: TDispParams;
  805.   ArgCnt, I: Integer;
  806. {$IFDEF WIN32}
  807.   Args: array[0..MaxDispArgs - 1] of TVariantArg;
  808. {$ELSE}
  809.   Args: array[0..MaxDispArgs - 1] of Variant;
  810. {$ENDIF}
  811. begin
  812.   CheckOleInitialized;
  813.   ArgCnt := 0;
  814.   try
  815.     for I := 0 to High(Params) do begin
  816.       AssignVariant(Args[I], Params[I]);
  817.       Inc(ArgCnt);
  818.       if ArgCnt >= MaxDispArgs then Break;
  819.     end;
  820.     with Disp do begin
  821.       if ArgCnt = 0 then rgvarg := nil
  822.       else rgvarg := @Args;
  823.       if Cnt = 0 then rgdispidNamedArgs := nil
  824.       else rgdispidNamedArgs := @IDs[1];
  825.       cArgs := ArgCnt;
  826.       cNamedArgs := Cnt;
  827.     end;
  828.     if NeedResult then
  829.       Result := Invoke(IDs[0], DISPATCH_METHODPARAMS, Disp, @FRetValue)
  830.     else
  831.       Result := Invoke(IDs[0], DISPATCH_METHODPARAMS, Disp, nil);
  832.   finally
  833. {$IFNDEF WIN32}
  834.     for I := 0 to ArgCnt - 1 do VariantClear(VARIANTARG(Args[I]));
  835. {$ENDIF}
  836.   end;
  837. end;
  838. procedure TOleController.SetPropertyByID(ID: TDispID; const Prop: array of const);
  839. const
  840.   NameArg: TDispID = DISPID_PROPERTYPUT;
  841. var
  842.   Disp: TDispParams;
  843.   ArgCnt, I: Integer;
  844. {$IFDEF WIN32}
  845.   Args: array[0..MaxDispArgs - 1] of TVariantArg;
  846. {$ELSE}
  847.   Args: array[0..MaxDispArgs - 1] of Variant;
  848. {$ENDIF}
  849. begin
  850.   CheckOleInitialized;
  851.   ArgCnt := 0;
  852.   try
  853.     for I := 0 to High(Prop) do begin
  854.       AssignVariant(Args[I], Prop[I]);
  855.       Inc(ArgCnt);
  856.       if ArgCnt >= MaxDispArgs then Break;
  857.     end;
  858.     with Disp do begin
  859.       rgvarg := @Args;
  860.       rgdispidNamedArgs := @NameArg;
  861.       cArgs := ArgCnt;
  862.       cNamedArgs := 1;
  863.     end;
  864.     Invoke(ID, DISPATCH_PROPERTYPUT, Disp, nil);
  865.   finally
  866. {$IFNDEF WIN32}
  867.     for I := 0 to ArgCnt - 1 do VariantClear(VARIANTARG(Args[I]));
  868. {$ENDIF}
  869.   end;
  870. end;
  871. function TOleController.GetPropertyByID(ID: TDispID): PVariant;
  872. const
  873.   Disp: TDispParams = (rgvarg: nil; rgdispidNamedArgs: nil;
  874.     cArgs: 0; cNamedArgs: 0);
  875. begin
  876.   CheckOleInitialized;
  877.   Result := Invoke(ID, DISPATCH_PROPERTYGET, Disp, @FRetValue);
  878. end;
  879. procedure TOleController.CallProcedureByID(ID: TDispID; const Params: array of const);
  880. begin
  881.   CallMethod(ID, Params, False);
  882. end;
  883. function TOleController.CallFunctionByID(ID: TDispID;
  884.   const Params: array of const): PVariant;
  885. begin
  886.   Result := CallMethod(ID, Params, True);
  887. end;
  888. procedure TOleController.CallProcedureByIDsNamedParams(const IDs: TDispIDList;
  889.   const Params: array of const; Cnt: Byte);
  890. begin
  891.   CallMethodNamedParams(IDs, Params, Cnt, False);
  892. end;
  893. function TOleController.CallFunctionByIDsNamedParams(const IDs: TDispIDList;
  894.   const Params: array of const; Cnt: Byte): PVariant;
  895. begin
  896.   Result := CallMethodNamedParams(IDs, Params, Cnt, True);
  897. end;
  898. procedure TOleController.CallProcedureNoParamsByID(ID: TDispID);
  899. begin
  900.   CallMethodNoParams(ID, False);
  901. end;
  902. function TOleController.CallFunctionNoParamsByID(ID: TDispID): PVariant;
  903. begin
  904.   Result := CallMethodNoParams(ID, True);
  905. end;
  906. procedure TOleController.SetProperty(const AName: string;
  907.   const Prop: array of const);
  908. begin
  909.   SetPropertyByID(NameToDispID(AName), Prop);
  910. end;
  911. function TOleController.GetProperty(const AName: string): PVariant;
  912. begin
  913.   Result := GetPropertyByID(NameToDispID(AName));
  914. end;
  915. procedure TOleController.CallProcedure(const AName: string;
  916.   const Params: array of const);
  917. begin
  918.   CallProcedureByID(NameToDispID(AName), Params);
  919. end;
  920. function TOleController.CallFunction(const AName: string;
  921.   const Params: array of const): PVariant;
  922. begin
  923.   Result := CallFunctionByID(NameToDispID(AName), Params);
  924. end;
  925. procedure TOleController.CallProcedureNamedParams(const AName: string;
  926.   const Params: array of const; const ParamNames: array of string);
  927. var
  928.   DispIDs: array[0..MaxDispArgs] of TDispID;
  929. begin
  930.   CallProcedureByIDsNamedParams(NameToDispIDs(AName, ParamNames, @DispIDs)^,
  931.     Params, High(ParamNames) + 1);
  932. end;
  933. function TOleController.CallFunctionNamedParams(const AName: string;
  934.   const Params: array of const; const ParamNames: array of string): PVariant;
  935. var
  936.   DispIDs: array[0..MaxDispArgs] of TDispID;
  937. begin
  938.   Result := CallFunctionByIDsNamedParams(NameToDispIDs(AName, ParamNames,
  939.     @DispIDs)^, Params, High(ParamNames) + 1);
  940. end;
  941. procedure TOleController.CallProcedureNoParams(const AName: string);
  942. begin
  943.   CallProcedureNoParamsByID(NameToDispID(AName));
  944. end;
  945. function TOleController.CallFunctionNoParams(const AName: string): PVariant;
  946. begin
  947.   Result := CallFunctionNoParamsByID(NameToDispID(AName));
  948. end;
  949. procedure TOleController.SetLocale(PrimaryLangID, SubLangID: Word);
  950. begin
  951.   FLocale := CreateLCID(PrimaryLangID, SubLangID);
  952. end;
  953. { Utility routines }
  954. function MakeLangID(PrimaryLangID, SubLangID: Word): Word;
  955. begin
  956.   Result := (SubLangID shl 10) or PrimaryLangID;
  957. end;
  958. function MakeLCID(LangID: Word): TLCID;
  959. begin
  960.   Result := TLCID(LangID or (Longint(0) shl 16));
  961. end;
  962. function CreateLCID(PrimaryLangID, SubLangID: Word): TLCID;
  963. begin
  964.   Result := MakeLCID(MakeLangID(PrimaryLangID, SubLangID));
  965. end;
  966. function ExtractLangID(LCID: TLCID): Word;
  967. begin
  968.   Result := LCID and $FF;
  969. end;
  970. function ExtractSubLangID(LCID: TLCID): Word;
  971. begin
  972.   Result := LCID and ($FF shl 10) shr 10;
  973. end;
  974. {$IFDEF WIN32}
  975. initialization
  976. finalization
  977.   DoneOLE;
  978. {$ELSE}
  979. initialization
  980.   AddExitProc(DoneOLE);
  981. {$ENDIF}
  982. end.