home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 March / pcp161b.iso / full / delphi / INSTALL / data.z / COMSERV.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-08-04  |  9.1 KB  |  371 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Delphi Runtime Library                          }
  5. {                                                       }
  6. {       Copyright (C) 1997 Borland International        }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit ComServ;
  11.  
  12. {$DENYPACKAGEUNIT}
  13.  
  14. interface
  15.  
  16. uses Windows, ActiveX, SysUtils, ComObj;
  17.  
  18. type
  19.  
  20. { Application start mode }
  21.  
  22.   TStartMode = (smStandalone, smAutomation, smRegServer, smUnregServer);
  23.  
  24. { Class manager event types }
  25.  
  26.   TLastReleaseEvent = procedure(var Shutdown: Boolean) of object;
  27.  
  28. { TComServer }
  29.  
  30.   TComServer = class(TComServerObject)
  31.   private
  32.     FObjectCount: Integer;
  33.     FFactoryCount: Integer;
  34.     FTypeLib: ITypeLib;
  35.     FServerName: string;
  36.     FHelpFileName: string;
  37.     FIsInprocServer: Boolean;
  38.     FStartMode: TStartMode;
  39.     FRegister: Boolean;
  40.     FOnLastRelease: TLastReleaseEvent;
  41.     procedure FactoryFree(Factory: TComObjectFactory);
  42.     procedure FactoryRegisterClassObject(Factory: TComObjectFactory);
  43.     procedure FactoryUpdateRegistry(Factory: TComObjectFactory);
  44.     procedure LastReleased;
  45.   protected
  46.     function CountObject(Created: Boolean): Integer; override;
  47.     function CountFactory(Created: Boolean): Integer; override;
  48.     function GetHelpFileName: string; override;
  49.     function GetServerFileName: string; override;
  50.     function GetServerKey: string; override;
  51.     function GetServerName: string; override;
  52.     function GetTypeLib: ITypeLib; override;
  53.   public
  54.     constructor Create;
  55.     destructor Destroy; override;
  56.     procedure Initialize;
  57.     procedure LoadTypeLib;
  58.     procedure SetServerName(const Name: string);
  59.     procedure UpdateRegistry(Register: Boolean);
  60.     property IsInprocServer: Boolean read FIsInprocServer write FIsInprocServer;
  61.     property ObjectCount: Integer read FObjectCount;
  62.     property StartMode: TStartMode read FStartMode;
  63.     property OnLastRelease: TLastReleaseEvent read FOnLastRelease write FOnLastRelease;
  64.   end;
  65.  
  66. var
  67.   ComServer: TComServer;
  68.  
  69. function DllGetClassObject(const CLSID, IID: TGUID; var Obj): HResult; stdcall;
  70. function DllCanUnloadNow: HResult; stdcall;
  71. function DllRegisterServer: HResult; stdcall;
  72. function DllUnregisterServer: HResult; stdcall;
  73.  
  74. implementation
  75.  
  76. {$I ComServ.inc}
  77.  
  78. { Find command-line switch }
  79.  
  80. function FindCmdLineSwitch(const Switch: string): Boolean;
  81. var
  82.   I: Integer;
  83.   S: string;
  84. begin
  85.   for I := 1 to ParamCount do
  86.   begin
  87.     S := ParamStr(I);
  88.     if (S[1] in ['-', '/']) and
  89.       (CompareText(Copy(S, 2, Maxint), Switch) = 0) then
  90.     begin
  91.       Result := True;
  92.       Exit;
  93.     end;
  94.   end;
  95.   Result := False;
  96. end;
  97.  
  98. function GetModuleFileName: string;
  99. var
  100.   Buffer: array[0..261] of Char;
  101. begin
  102.   SetString(Result, Buffer, Windows.GetModuleFileName(HInstance,
  103.     Buffer, SizeOf(Buffer)));
  104. end;
  105.  
  106. function GetModuleName: string;
  107. begin
  108.   Result := ChangeFileExt(ExtractFileName(GetModuleFileName), '');
  109. end;
  110.  
  111. function LoadTypeLibrary(const ModuleName: string): ITypeLib;
  112. begin
  113.   OleCheck(LoadTypeLib(PWideChar(WideString(ModuleName)), Result));
  114. end;
  115.  
  116. procedure RegisterTypeLibrary(TypeLib: ITypeLib; const ModuleName: string);
  117. var
  118.   Name: WideString;
  119. begin
  120.   Name := ModuleName;
  121.   OleCheck(RegisterTypeLib(TypeLib, PWideChar(Name), PWideChar(Name)));
  122. end;
  123.  
  124. procedure UnregisterTypeLibrary(TypeLib: ITypeLib);
  125. type
  126.   TUnregisterProc = function(const GUID: TGUID; VerMajor, VerMinor: Word;
  127.     LCID: TLCID; SysKind: TSysKind): HResult stdcall;
  128. var
  129.   Handle: THandle;
  130.   UnregisterProc: TUnregisterProc;
  131.   LibAttr: PTLibAttr;
  132. begin
  133.   Handle := GetModuleHandle('OLEAUT32.DLL');
  134.   if Handle <> 0 then
  135.   begin
  136.     @UnregisterProc := GetProcAddress(Handle, 'UnRegisterTypeLib');
  137.     if @UnregisterProc <> nil then
  138.     begin
  139.       OleCheck(ComServer.TypeLib.GetLibAttr(LibAttr));
  140.       with LibAttr^ do
  141.         UnregisterProc(guid, wMajorVerNum, wMinorVerNum, lcid, syskind);
  142.       ComServer.TypeLib.ReleaseTLibAttr(LibAttr);
  143.     end;
  144.   end;
  145. end;
  146.  
  147. function GetTypeLibName(TypeLib: ITypeLib): string;
  148. var
  149.   Name: WideString;
  150. begin
  151.   OleCheck(TypeLib.GetDocumentation(-1, @Name, nil, nil, nil));
  152.   Result := Name;
  153. end;
  154.  
  155. function DllGetClassObject(const CLSID, IID: TGUID; var Obj): HResult;
  156. var
  157.   Factory: TComObjectFactory;
  158. begin
  159.   Factory := ComClassManager.GetFactoryFromClassID(CLSID);
  160.   if Factory <> nil then
  161.     if Factory.GetInterface(IID, Obj) then
  162.       Result := S_OK
  163.     else
  164.       Result := E_NOINTERFACE
  165.   else
  166.   begin
  167.     Pointer(Obj) := nil;
  168.     Result := CLASS_E_CLASSNOTAVAILABLE;
  169.   end;
  170. end;
  171.  
  172. function DllCanUnloadNow: HResult;
  173. begin
  174.   if (ComServer = nil) or
  175.     ((ComServer.FObjectCount = 0) and (ComServer.FFactoryCount = 0)) then
  176.     Result := S_OK
  177.   else
  178.     Result := S_FALSE;
  179. end;
  180.  
  181. function DllRegisterServer: HResult;
  182. begin
  183.   Result := S_OK;
  184.   try
  185.     ComServer.UpdateRegistry(True);
  186.   except
  187.     Result := E_FAIL;
  188.   end;
  189. end;
  190.  
  191. function DllUnregisterServer: HResult;
  192. begin
  193.   Result := S_OK;
  194.   try
  195.     ComServer.UpdateRegistry(False);
  196.   except
  197.     Result := E_FAIL;
  198.   end;
  199. end;
  200.  
  201. { Automation TerminateProc }
  202.  
  203. function AutomationTerminateProc: Boolean;
  204. begin
  205.   Result := True;
  206.   // Does StartMode matter?
  207.   if (ComServer.StartMode = smAutomation) and not ((ComServer = nil) or
  208.     (ComServer.ObjectCount = 0)) then
  209.   begin
  210.     Result := MessageBox(0, PChar(SNoCloseActiveServer1 + SNoCloseActiveServer2),
  211.       PChar(SAutomationWarning), MB_YESNO or MB_TASKMODAL or
  212.       MB_ICONWARNING or MB_DEFBUTTON2) = IDYES;
  213.   end;
  214. end;
  215.  
  216. { TComServer }
  217.  
  218. constructor TComServer.Create;
  219. begin
  220.   FTypeLib := nil;
  221.   FIsInprocServer := ModuleIsLib;
  222.   if FindCmdLineSwitch('AUTOMATION') or FindCmdLineSwitch('EMBEDDING') then
  223.     FStartMode := smAutomation
  224.   else if FindCmdLineSwitch('REGSERVER') then
  225.     FStartMode := smRegServer
  226.   else if FindCmdLineSwitch('UNREGSERVER') then
  227.     FStartMode := smUnregServer;
  228. end;
  229.  
  230. destructor TComServer.Destroy;
  231. begin
  232.   ComClassManager.ForEachFactory(Self, FactoryFree);
  233. end;
  234.  
  235. function TComServer.CountObject(Created: Boolean): Integer;
  236. begin
  237.   if Created then Inc(FObjectCount) else
  238.   begin
  239.     Dec(FObjectCount);
  240.     if FObjectCount = 0 then LastReleased;
  241.   end;
  242.   Result := FObjectCount;
  243. end;
  244.  
  245. function TComServer.CountFactory(Created: Boolean): Integer;
  246. begin
  247.   if Created then Inc(FFactoryCount) else Dec(FFactoryCount);
  248.   Result := FFactoryCount;
  249. end;
  250.  
  251. procedure TComServer.FactoryFree(Factory: TComObjectFactory);
  252. begin
  253.   Factory.Free;
  254. end;
  255.  
  256. procedure TComServer.FactoryRegisterClassObject(Factory: TComObjectFactory);
  257. begin
  258.   Factory.RegisterClassObject;
  259. end;
  260.  
  261. procedure TComServer.FactoryUpdateRegistry(Factory: TComObjectFactory);
  262. begin
  263.   if Factory.Instancing <> ciInternal then
  264.     Factory.UpdateRegistry(FRegister);
  265. end;
  266.  
  267. function TComServer.GetHelpFileName: string;
  268. begin
  269.   Result := FHelpFileName;
  270. end;
  271.  
  272. function TComServer.GetServerFileName: string;
  273. begin
  274.   Result := GetModuleFileName;
  275. end;
  276.  
  277. function TComServer.GetServerKey: string;
  278. begin
  279.   if FIsInprocServer then
  280.     Result := 'InprocServer32' else
  281.     Result := 'LocalServer32';
  282. end;
  283.  
  284. function TComServer.GetServerName: string;
  285. begin
  286.   if FServerName <> '' then
  287.     Result := FServerName
  288.   else
  289.     if FTypeLib <> nil then
  290.       Result := GetTypeLibName(FTypeLib)
  291.     else
  292.       Result := GetModuleName;
  293. end;
  294.  
  295. procedure TComServer.SetServerName(const Name: string);
  296. begin
  297.   if FTypeLib = nil then
  298.     FServerName := Name;
  299. end;
  300.  
  301. function TComServer.GetTypeLib: ITypeLib;
  302. begin
  303.   LoadTypeLib;
  304.   Result := FTypeLib;
  305. end;
  306.  
  307. procedure TComServer.Initialize;
  308. begin
  309.   UpdateRegistry(FStartMode <> smUnregServer);
  310.   if FStartMode in [smRegServer, smUnregServer] then Halt;
  311.   ComClassManager.ForEachFactory(Self, FactoryRegisterClassObject);
  312. end;
  313.  
  314. procedure TComServer.LastReleased;
  315. var
  316.   Shutdown: Boolean;
  317. begin
  318.   if not FIsInprocServer then
  319.   begin
  320.     Shutdown := FStartMode = smAutomation;
  321.     if Assigned(FOnLastRelease) then FOnLastRelease(Shutdown);
  322.     if Shutdown then PostQuitMessage(0);
  323.   end;
  324. end;
  325.  
  326. procedure TComServer.LoadTypeLib;
  327. begin
  328.   if FTypeLib = nil then FTypeLib := LoadTypeLibrary(GetModuleFileName);
  329. end;
  330.  
  331. procedure TComServer.UpdateRegistry(Register: Boolean);
  332. begin
  333.   if FTypeLib <> nil then
  334.     if Register then
  335.       RegisterTypeLibrary(FTypeLib, GetModuleFileName) else
  336.       UnregisterTypeLibrary(FTypeLib);
  337.   FRegister := Register;
  338.   ComClassManager.ForEachFactory(Self, FactoryUpdateRegistry);
  339. end;
  340.  
  341. var
  342.   SaveInitProc: Pointer = nil;
  343.   OleAutHandle: Integer;
  344.  
  345. procedure InitComServer;
  346. begin
  347.   if SaveInitProc <> nil then TProcedure(SaveInitProc);
  348.   ComServer.Initialize;
  349. end;
  350.  
  351. initialization
  352. begin
  353.   OleAutHandle := LoadLibrary('OLEAUT32.DLL');
  354.   ComServer := TComServer.Create;
  355.   if not ModuleIsLib then
  356.   begin
  357.     SaveInitProc := InitProc;
  358.     InitProc := @InitComServer;
  359.     AddTerminateProc(@AutomationTerminateProc);
  360.   end;
  361. end;
  362.  
  363. finalization
  364. begin
  365.   ComServer.Free;
  366.   ComServer := nil;
  367.   FreeLibrary(OleAutHandle);
  368. end;
  369.  
  370. end.
  371.