1

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?

20
  • 2
    cacls is not DOS command Commented Dec 3, 2010 at 14:58
  • 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. Commented Dec 3, 2010 at 14:59
  • Also, you should use SW_SHOWNORMAL. Commented Dec 3, 2010 at 15:03
  • 2
    Well, it would be far better off not to go screwing around with permissions in ProgramData and follow the platform guidelines! Commented Dec 3, 2010 at 17:04
  • 1
    @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. Commented Dec 3, 2010 at 21:58

3 Answers 3

3

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

Sign up to request clarification or add additional context in comments.

Comments

2

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 ;)

Comments

2

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;

1 Comment

Hi there did you verify if post XP OSes needed admin privs to run with commnad line arguments? Just curious as my users may not have logged into an Admin account.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.