1
votes

I am trying to run a command-line command from inside my Delphi application.

ShellExecute(Form1.Handle, 
             'open', 
             'cmd.exe',
             'icacls "C:\ProgramData\My Program\File" /grant Users:F',
             nil,
             SW_NORMAL);

Note: The command its self works perfectly.

However when I run this code in Delphi I get the command window popping up but the command I want to execute doesn't run or even appear in the command window.

Any idea as to what I am missing?

3
cacls is not DOS commandFree Consulting
And not even "dir" is. DOS is not a part of a modern Windows system. "dir" is a command-line command, or system command, though.Andreas Rejbrand
Also, you should use SW_SHOWNORMAL.Andreas Rejbrand
Well, it would be far better off not to go screwing around with permissions in ProgramData and follow the platform guidelines!David Heffernan
@Tim: you were not setting "write" ("M", modify) permission. You were setting "full control" ("F") permission. Again, it looks you don't know the difference. If the file is shared across users, it is even more important to avoid one user could damage a file that will be used by another. You also changed permission on a file because "not all have access to HKLM", but you can also set permissions on registry keys (although, as with files and directories, you should be very careful to change permissions on them). Allowing unrestricted write access to <program files> is bad as well.user160694

3 Answers

3
votes

The command string needs something in front of it.

/c - will cause it to run

/k - will cause it to run and not disappear when done

2
votes

You have no need to create a shell to run such a command. It is console executable, and you can run it directly with CreateProcess(). Invoking a shell just mean to invoke an executable (cmd.exe) and have it invoke the other more or less the same way you would have invoked it directly. You just spend time creating two processes instead of one. IMHO that's a bad programing practice, and just shows the caller has not a clue on how Windows works ;)

2
votes

Which OS are you using? I'm pretty sure a command like this requires elevation on any Windows platform after XP.

Here's the code I use for elevating a process under Vista/Windows 7

uses
  Windows, ShellAPI, Registry;

type
  TExecuteFileOption = (
    eoHide,
    eoWait,
    eoElevate
  );
  TExecuteFileOptions = set of TExecuteFileOption;

...

function IsUACActive: Boolean;
var
  Reg: TRegistry;
begin
  Result := FALSE;

  if CheckWin32Version(6, 0) then
  begin
    Result := FALSE;

    Reg := TRegistry.Create;
    try
      Reg.RootKey := HKEY_LOCAL_MACHINE;

      if Reg.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System') then
      begin
        if (Reg.ValueExists('EnableLUA')) and (Reg.ReadBool('EnableLUA')) then
          Result := TRUE;
      end;
    finally
      FreeAndNil(Reg);
    end;
  end;
end;

function ExecuteFile(Handle: HWND; const Filename, Paramaters: String; Options: TExecuteFileOptions): Integer;
var
  ShellExecuteInfo: TShellExecuteInfo;
  ExitCode: DWORD;
begin
  Result := -1;

  ZeroMemory(@ShellExecuteInfo, SizeOf(ShellExecuteInfo));
  ShellExecuteInfo.cbSize := SizeOf(TShellExecuteInfo);
  ShellExecuteInfo.Wnd := Handle;
  ShellExecuteInfo.fMask := SEE_MASK_NOCLOSEPROCESS;

  if (eoElevate in Options) and (IsUACActive) then
    ShellExecuteInfo.lpVerb := PChar('runas');

  ShellExecuteInfo.lpFile := PChar(Filename);

  if Paramaters <> '' then
    ShellExecuteInfo.lpParameters := PChar(Paramaters);

  // Show or hide the window
  if eoHide in Options then
    ShellExecuteInfo.nShow := SW_HIDE
  else
    ShellExecuteInfo.nShow := SW_SHOWNORMAL;

  if ShellExecuteEx(@ShellExecuteInfo) then
    Result := 0;

  if (Result = 0) and (eoWait in Options) then
  begin
    GetExitCodeProcess(ShellExecuteInfo.hProcess, ExitCode);

    while (ExitCode = STILL_ACTIVE) and
          (not Application.Terminated) do
    begin
      sleep(50);

      GetExitCodeProcess(ShellExecuteInfo.hProcess, ExitCode);
    end;

    Result := ExitCode;
  end;
end;