tags:

views:

222

answers:

2

What's the best way to package the activex dll with the delphi application? If I just compile it, when I send it to somebody else it gives them errors because they don't have the ActiveX dll registered.

+3  A: 

What you ought to do is create an installer. There are several programs that will let you do that. I prefer InnoSetup, which is open-source, written in Delphi, and works really well. Just put your ActiveX DLL into the install package with your EXE and tell InnoSetup where it needs to go, (in the same folder as your app, in Sys32, or in a handful of other predefined locations,) and it takes care of the rest for you.

Mason Wheeler
+1  A: 

When I was creating COM servers at run-time I used sth. like the below. The idea is to catch the "class not registered" exception and attempt to register the server on the fly. With some search, you'll also find examples that read the registry for the class identifier to find out if an activex server is registered... I adapted the example to some 'MS Rich Text Box' (richtx32.ocx) but it wouldn't make a difference.

uses
  comobj;

function RegisterServer(ServerDll: PChar): Boolean;
const
  REGFUNC          = 'DllRegisterServer';
  UNABLETOREGISTER = '''%s'' in ''%s'' failed.';
  FUNCTIONNOTFOUND = '%s: ''%s'' in ''%s''.';
  UNABLETOLOADLIB  = 'Unable to load library (''%s''): ''%s''.';
var
  LibHandle: HMODULE;
  DllRegisterFunction: function: Integer;
begin
  Result := False;
  LibHandle := LoadLibrary(ServerDll);
  if LibHandle <> 0 then begin
    try
      @DllRegisterFunction := GetProcAddress(LibHandle, REGFUNC);
      if @DllRegisterFunction <> nil then begin
        if DllRegisterFunction = S_OK then
          Result := True
        else
          raise EOSError.CreateFmt(UNABLETOREGISTER, [REGFUNC, ServerDll]);
      end else
        raise EOSError.CreateFmt(FUNCTIONNOTFOUND,
            [SysErrorMessage(GetLastError), ServerDll, REGFUNC]);
    finally
      FreeLibrary(LibHandle);
    end;
  end else
    raise EOSError.CreateFmt(UNABLETOLOADLIB, [ServerDll,
        SysErrorMessage(GetLastError)]);
end;

function GetRichTextBox(Owner: TComponent): TRichTextBox;
begin
  Result := nil;
  try
    Result := TRichTextBox.Create(Owner);
  except on E: EOleSysError do
    if E.ErrorCode = HRESULT($80040154) then begin
      if RegisterServer('richtx32.ocx') then
        Result := TRichTextBox.Create(Owner);
    end else
      raise;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  [...]
  RichTextBox := GetRichTextBox(Self);
  RichTextBox.SetBounds(20, 20, 100, 40);
  RichTextBox.Parent := Self;
  [...]
end;
Sertac Akyuz
That will not provide the activex dll to its users, just register it on the fly if not already done when installing.
François
@Francois: It seems to me that this was precisely what the OP wanted remedied? He'd prefer not having to distribute the dll, but if he does, he'd like to avoid the "dll not registered" error on his users' machines. And that is what Sertac's code does... Of course, using an installer would be another option, but also requires more maintenance (install script etc).
Marjan Venema
@François - Well, yes.. Perhaps I misunderstood the question?...
Sertac Akyuz
The user starting the application better have enough rights to write into the Local Machine registry. Simple users do not have this right.
Lars Truijens
@Lars - Indeed, good point.. In that case the function will raise an exception: "'DllRegisterServer' in [somefile] failed". One can advise users running with admin privileges for such case, or one can include such advise in the error message, or one can test for the privileges before attempting to register and show a message...
Sertac Akyuz