Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Problems calling DLL

Status
Not open for further replies.

djjd47130

Programmer
Nov 1, 2010
480
US
I'm not a genius when it comes to DLL's or Handles, but I have a project which involves both put together. The projects include an EXE and a DLL. The EXE is used to manage installing, in particular installing a Windows Service. The DLL inclues all the necessary functionality to manage Windows Services. I have the functions in the DLL which perform the actual install/uninstall, start/stop, check if installed, check if running, etc. This is all to make it easy to implement in one app, as well as re-use it across multiple apps. If possible, I'd like to make sure it's compatible with other development languages too.

My problem is passing a Handle (HWND) as a parameter in one of the DLL functions. I need to execute a windows command line, and the method I'm using requires it. It worked perfectly when this function was together in the main app, but since I moved it into the DLL, it is giving access violation.

On the other hand, I have another function in the DLL which for sure is supposed to return True, but always returns False. Please let me know if I'm doing anything wrong here...

WinSvc32Lib.dll:

Code:
library WinSvc32Lib;

uses
  ShareMem,
  Windows,
  SysUtils,
  Classes,
  Messages,
  Forms,
  Dialogs,
  StrUtils,
  Registry,
  ShellAPI,
  Controls;

{$R *.res}

//----------------------------------------------------------------------------------------------------------
//This function is always returning false, even though in previous code returns true properly
//Could it have to do with using PChar? I'm using PChar instead of String to be compatible with other languages.
function svc_ServiceIsInstalled(Filename: PChar): Bool; StdCall;
var
  Reg: TRegistry;
  L: TStringList;
  Key, N: PChar;
  X: Integer;
begin
  Result:= False;
  Reg:= TRegistry.Create(KEY_READ or KEY_WRITE);
  L:= TStringList.Create;
  try
    Reg.RootKey:= HKEY_LOCAL_MACHINE;
    Key:= 'System\CurrentControlSet\Services';
    Reg.OpenKey(Key, False);
      Reg.GetKeyNames(L);
    Reg.CloseKey;
    for X:= 0 to L.Count - 1 do begin
      N:= PChar(L[X]);
      Reg.OpenKey(Key+'\'+N, False);
        if Reg.ValueExists('ImagePath') then begin
          if UpperCase(Filename) = UpperCase(Reg.ReadString('ImagePath')) then
            Result:= True;
        end;
      Reg.CloseKey;
    end;
  finally
    Reg.Free;
    L.Free;
  end;
end;

function svc_ServiceIsRunning(Filename: PChar): Bool; StdCall;
begin

end;

//----------------This function is raising an Access Violation----------------
function svc_InstallService(Filename: PChar; Handle: HWND): Bool; StdCall;
var
  L: TStringList;
  Dir: String;
  FN: String;
  sei: TShellExecuteInfo;
begin
  Result:= True;
  Dir:= ExtractFilePath(Filename);
  FN:= ExtractFileName(Filename);
  if RightStr(Dir, 1) <> '\' then Dir:= Dir + '\';
  L:= TStringList.Create;
  try
    L.Append(FN+' /install');
    L.SaveToFile(Dir+'_InstSvc.bat');
    try
      ZeroMemory(@sei, sizeof(sei));
      with sei do
      begin
        cbSize:= SizeOf(sei);
        fMask:= SEE_MASK_INVOKEIDLIST;
        Wnd:= Handle;
        lpVerb:= 'open';
        lpFile:= PChar('_InstSvc.bat');
        lpDirectory := PChar(Dir);
        nShow := SW_HIDE;
      end;
      ShellExecuteEX(@sei);
    except
      on e: exception do begin
        Result:= False;
        MessageDlg('Failed to install service: '+e.Message, mtError, [mbOK], 0);
      end;
    end;
  finally
    L.Free;
  end;
end;

//----------------This function is raising an Access Violation----------------
function svc_UninstallService(Filename: PChar; Handle: HWND): Bool; StdCall;
var
  L: TStringList;
  Dir: String;
  FN: String;
  sei: TShellExecuteInfo;
begin
  Result:= True;
  Dir:= ExtractFilePath(Filename);
  FN:= ExtractFileName(Filename);
  if RightStr(Dir, 1) <> '\' then Dir:= Dir + '\';
  L:= TStringList.Create;
  try
    L.Append(FN+' /uninstall');
    L.SaveToFile(Dir+'_InstSvc.bat');
    try
      ZeroMemory(@sei, sizeof(sei));
      with sei do
      begin
        cbSize:= SizeOf(sei);
        fMask:= SEE_MASK_INVOKEIDLIST;
        Wnd:= Handle;
        lpVerb:= 'open';
        lpFile:= PChar('_InstSvc.bat');
        lpDirectory := PChar(Dir);
        nShow := SW_HIDE;
      end;
      ShellExecuteEX(@sei);
    except
      on e: exception do begin
        Result:= False;
        MessageDlg('Failed to uninstall service: '+e.Message, mtError, [mbOK], 0);
      end;
    end;
  finally
    L.Free;
  end;
end;

function svc_StartService(Filename: PChar; Handle: HWND): Bool; StdCall;
begin

end;

function svc_StopService(Filename: PChar; Handle: HWND): Bool; StdCall;
begin

end;

exports
  svc_ServiceIsInstalled,
  svc_ServiceIsRunning,
  svc_InstallService,
  svc_UninstallService,
  svc_StartService,
  svc_StopService;

begin

end.

WinSvc32.exe:

Code:
unit uMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, XPMan, Registry, StrUtils, ShellAPI, ExtCtrls;

type
  TfrmWinSvc32 = class(TForm)
    txtFilename: TEdit;
    Label2: TLabel;
    cmdBrowse: TBitBtn;
    dlgOpen: TOpenDialog;
    XPManifest1: TXPManifest;
    cmdInstall: TBitBtn;
    cmdAbout: TBitBtn;
    Panel1: TPanel;
    Label1: TLabel;
    procedure cmdBrowseClick(Sender: TObject);
    procedure cmdInstallClick(Sender: TObject);
    procedure cmdAboutClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    //function SvcInstalled(Filename: String): Bool;
    procedure AcceptFiles(var msg: TMessage);
      message WM_DROPFILES;
  end;

var
  frmWinSvc32: TfrmWinSvc32;

  function svc_ServiceIsInstalled(Filename: PChar): Bool;
    External 'WinSvc32Lib.dll';
  function svc_ServiceIsRunning(Filename: PChar): Bool;
    External 'WinSvc32Lib.dll';
  function svc_InstallService(Filename: PChar; Handle: HWND): Bool;
    External 'WinSvc32Lib.dll';
  function svc_UninstallService(Filename: PChar; Handle: HWND): Bool;
    External 'WinSvc32Lib.dll';
  function svc_StartService(Filename: PChar; Handle: HWND): Bool;
    External 'WinSvc32Lib.dll';
  function svc_StopService(Filename: PChar; Handle: HWND): Bool;
    External 'WinSvc32Lib.dll';

implementation

uses uAbout;

{$R *.dfm}
       
procedure TfrmWinSvc32.AcceptFiles(var msg: TMessage);
const
  cnMaxFileNameLen = 255;
var
  i, nCount: integer;
  acFileName: array [0..cnMaxFileNameLen] of char;
begin
  try
    try
      nCount:= DragQueryFile(msg.WParam, $FFFFFFFF, acFileName, cnMaxFileNameLen);
      if nCount = 1 then begin
        //for i := 0 to nCount-1 do
        //begin
          i:= 0;
          DragQueryFile(msg.WParam, i, acFileName, cnMaxFileNameLen);
          //ShowMessage(acFileName);
          if UpperCase(RightStr(acFileName, 4)) = '.EXE' then begin
            if FileExists(acFileName) then begin
              dlgOpen.FileName:= acFileName;
              txtFilename.Text:= acFileName;
              if svc_ServiceIsInstalled(acFileName) then begin
                cmdInstall.Caption:= 'Uninstall';
                cmdInstall.Hint:= 'Uninstall selected service';
              end else begin
                cmdInstall.Caption:= 'Install';   
                cmdInstall.Hint:= 'Install selected service';
              end;
              cmdInstall.Enabled:= True;
            end else begin
              raise Exception.Create('Specified file does not exist.');
            end;
          end else begin
            raise Exception.Create('Only executable (.exe) files can be installed.');
          end;
        //end;
      end else begin
        raise Exception.Create('Only one service can be installed at a time.');
      end;
    except
      on e: exception do begin
        MessageDlg('Error opening file(s): '+e.Message, mtError, [mbOK], 0);
      end;
    end;
  finally
    DragFinish(msg.WParam);
  end;
end;

procedure TfrmWinSvc32.cmdBrowseClick(Sender: TObject);
var
  Inst: Bool;
begin
  if dlgOpen.Execute then begin
    if FileExists(dlgOpen.FileName) then begin
      txtFilename.Text:= dlgOpen.FileName;
      Inst:= svc_ServiceIsInstalled(PChar(dlgOpen.FileName));
      if Inst then begin
        cmdInstall.Caption:= 'Uninstall';
        cmdInstall.Hint:= 'Uninstall selected service';
      end else begin
        cmdInstall.Caption:= 'Install';    
        cmdInstall.Hint:= 'Install selected service';
      end;
      cmdInstall.Enabled:= True;
    end;
  end;
end;

procedure TfrmWinSvc32.cmdInstallClick(Sender: TObject);
var
  Dir: String;
  FN: String;
  sei: TShellExecuteInfo;
  Res: Bool;
begin
  Dir:= ExtractFilePath(txtFilename.Text);
  FN:= ExtractFileName(txtFilename.Text);    
  if RightStr(Dir, 1) <> '\' then Dir:= Dir + '\';  
  try   
    if cmdInstall.Caption = 'Install' then begin
      Res:= svc_InstallService(PChar(FN), Handle);
    end else begin
      Res:= svc_UninstallService(PChar(FN), Handle);
    end;
  finally
    cmdInstall.Caption:= 'Install';
    cmdInstall.Enabled:= False;
    cmdBrowse.Enabled:= True;
    txtFilename.Enabled:= True;
    txtFilename.Clear;
    txtFilename.SetFocus;
  end;
end;
  
procedure TfrmWinSvc32.cmdAboutClick(Sender: TObject);
begin
  frmAbout.ShowModal;
  {ShowMessage('This utility is used to install or uninstall windows services.'+#10+
    'First, browse and select the Service Executable (.exe) you wish to use.'+#10+
    'If service is installed, it will offer to Uninstall.'+#10+
    'If service is not installed, it will offer to Install.');    }
end;

procedure TfrmWinSvc32.FormCreate(Sender: TObject);
begin
  DragAcceptFiles(Handle, True);
end;

end.


JD Solutions
 
Code:
function svc_ServiceIsInstalled(Filename: PChar): Bool;
    External 'WinSvc32Lib.dll';
  function svc_ServiceIsRunning(Filename: PChar): Bool;
    External 'WinSvc32Lib.dll';
  function svc_InstallService(Filename: PChar; Handle: HWND): Bool;
    External 'WinSvc32Lib.dll';
  function svc_UninstallService(Filename: PChar; Handle: HWND): Bool;
    External 'WinSvc32Lib.dll';
  function svc_StartService(Filename: PChar; Handle: HWND): Bool;
    External 'WinSvc32Lib.dll';
  function svc_StopService(Filename: PChar; Handle: HWND): Bool;
    External 'WinSvc32Lib.dll';

These need defined with Stdcall for them to work properly.

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
Holy crap, I knew I was forgetting something stupid, thanks man.

JD Solutions
 
Ok, I got that fixed, and the one function is properly returning False, and the other function is not raising an Access Violation. However, it does not actually install/uninstall the service, or do much of anything rather. I'm sure it has to do with the Handle. Any advice?

JD Solutions
 
Finally got it...

It wasn't a DLL call problem, I was missing the full directory when passing the filename... LMAO!


JD Solutions
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top