tags:

views:

64

answers:

3

Also in the following code, which is more efficient?

if (Length(ParamStr(1)) <> 0) then

or

if (ParamStr(1) <> '') then

{$A8,B-,C-,D-,E-,F-,G+,H+,I-,J-,K-,L-,M-,N+,O+,P+,Q-,R-,S-,T-,U-,V-,W-,X+,Y-,Z1}

program LaunchUAC;

uses
    Windows, ShellAPI;

{$R 'MANIFEST.RES'}
(*
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (c) eyeClaxton Software (www.eyeclaxton.com) -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity
        processorArchitecture="x86"
        version="1.0.0.0"
        name="eyeClaxton.asInvoker.LaunchUAC" type="win32" />
    <description>asInvoker LaunchUAC</description>
    <dependency>
    <dependentAssembly>
    <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        publicKeyToken="6595b64144ccf1df"
        language="*"
        processorArchitecture="x86"/>
    </dependentAssembly>
    </dependency>
    <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"&gt;true&lt;/dpiAware&gt;
    </windowsSettings>
    </application>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
        <requestedPrivileges>
            <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
        </requestedPrivileges>
    </security>
    </trustInfo>
</assembly>
*)

function IsMinimumVista(): Boolean;
var
    OSVerInfo: TOSVersionInfo;
begin
    OSVerInfo.dwOSVersionInfoSize := SizeOf(OSVerInfo);
    Result := Windows.GetVersionEx(OSVerInfo) and (OSVerInfo.dwMajorVersion > 5);
end;

procedure RunAsAdmin(theHandle: hWnd; theFilename: string;
    theParams: string; theShow: Integer; bWaitFor: Boolean = True);
var
    ShellExInfo: TShellExecuteInfo;
    hHandle: DWORD;
    Msg: TMsg;
    MsgResult: LongBool;
begin
    Windows.ZeroMemory(@ShellExInfo, SizeOf(ShellExInfo));
    ShellExInfo.cbSize := SizeOf(TShellExecuteInfo);
    ShellExInfo.Wnd := theHandle;
    ShellExInfo.fMask := SEE_MASK_FLAG_DDEWAIT;
    if bWaitFor then
        ShellExInfo.fMask := ShellExInfo.fMask or SEE_MASK_NOCLOSEPROCESS;
    if (Launch.IsMinimumVista()) then
        ShellExInfo.lpVerb := PChar('runas');
    ShellExInfo.lpFile := PChar(theFilename);
    if (Length(theParams) <> 0) then
        ShellExInfo.lpParameters := PChar(theParams);
    ShellExInfo.nShow := theShow;

    hHandle := 0;
    if ShellAPI.ShellExecuteEx(@ShellExInfo) then
    try
        hHandle := ShellExInfo.hProcess;
        if bWaitFor then
        begin
            while (Windows.WaitForSingleObject(hHandle, 50) <> WAIT_OBJECT_0) do
                repeat
                    MsgResult := PeekMessage(Msg, ShellExInfo.Wnd, 0, 0, PM_REMOVE);
                    if MsgResult then
                    begin
                        Windows.TranslateMessage(Msg);
                        Windows.DispatchMessage(Msg);
                    end;
                until (not (MsgResult));
        end;
    finally
        if (hHandle <> 0) then
            Windows.CloseHandle(hHandle);
    end;
end;

begin
    if (Length(ParamStr(1)) <> 0) then
        Launch.RunAsAdmin(0, ParamStr(1), ParamStr(2), SW_SHOWNORMAL)
    else
        Windows.MessageBeep(MB_ICONERROR);
end.
+1  A: 

If you're determined to avoid threads, I would suggest using MsgWaitForMultipleObjects but only have your spawned process handle in the array. Once you get a return value of WAIT_OBJECT_0, you can call GetExitCodeProcess.

At a guess,since you're using Pascal strings which have a pre-calculated length, checking the length should be more efficient than doing a compare against an empty string, but it's entirely possible the compiler may convert one into the other anyway, if it's smart enough to spot the compare against ''.

Bob Moore
Thank's I'll try this,if (WAIT_OBJECT_0 = Windows.MsgWaitForMultipleObjects(1, hHandle, False, INFINITE, QS_PAINT or QS_SENDMESSAGE)) then Windows.GetExitCodeProcess(hHandle, Result);
Jerry Claxton
+1  A: 

There are few issues with your code. Do you understand what it does or you just copy&paste it?

  1. If you want to call GetExitCodeProcess - just call it: right before calling CloseHandle in your case.
  2. You don't need to pump messages, just call WaitForSingleObject for infinite period (possible DDE initialization is handled inside ShellExecute).
  3. You check that hHandle <> 0 for CloseHandle, but not for WaitForSingleObject. Either do it for both or none.
  4. Use ShellExInfo.lpParameters := Pointer(theParams); instead of if (Length(theParams) <> 0) then ShellExInfo.lpParameters := PChar(theParams);.
  5. Use ShellExInfo.lpVerb := 'runas'; instead of ShellExInfo.lpVerb := PChar('runas');.
  6. Your parameter passing is wrong: you not only ignore all parameters, except first, but also doesn't enclose param to quotes.
  7. Unused theHandle: hWnd parameter is clear indication that you just grabbed first piece of code, without realizing how it works.
  8. May be something else, but I'm bored already...
Alexander
A: 

Also in the following code, which is more efficient?

"Premature optimization is the root of all evil" - Donald Knuth.

Alexander
"He who stand on toilet high on pot." - Confucius
Jerry Claxton