0

I use ShellExecute to open a shortcut

Code :

ShellExecute(Handle, 'open', 'C:\Users\hi2012\AppData\Roaming\Microsoft\Windows\Recent\xxx.gif.lnk', nil, nil, SW_SHOWNORMAL)

if xxx.gif exist that code can open it , if not it don't give anything.

but , when I open it with windows explorer it will show this:

enter image description here

I want when I use code to open a not nonexistent shortcut it also can show that , what can I do ?

is this a wrong way to use ShellExecute to open a shortcut ?

Hanlin
  • 835
  • 10
  • 26

3 Answers3

3

ShellExecute doesn't show dialogs when it fails. And it will not offer to delete files on your behalf. That dialog is shown by the Explorer app.

In order to handle errors you need to check the return value of the call to ShellExecute. If that return value is greater than 32 then the call succeeded. Otherwise there was an error. The possible reported errors are listed in the documentation.

For better error handling, use ShellExecuteEx. If a call to ShellExecuteEx fails then you can obtain an error code by calling GetLastError.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
1

You should use IShellLink::Resolve to resolve the shortcut yourself. IShellLink::Resolve offers flags to control whether to show search UI.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
  • I try my best to do that , but it doesn't work , could you please show me how to do that? – Hanlin Nov 06 '12 at 05:15
  • @ONion: See http://msdn.microsoft.com/en-us/library/windows/desktop/bb776891.aspx#Shellink_Resolving_Shortcut for sample code. – jamesdlin Nov 06 '12 at 08:31
0

You can invoke "open" from context popup menu on .lnk file. This will give you the same behaviour as double-clicking .lnk file in Explorer:

function SHBindToParent(pidl: PItemIDList; const riid: TIID; out ppv; out ppidlLast: PItemIDList): HResult; stdcall; external 'shell32.dll' name 'SHBindToParent';

procedure ExecuteFile(const AWnd: HWND; const AFileName: String);

  function GetUIObjectOfFile(wnd: HWND; const pszPath: WideString; const riid: TGUID; out ppv): HRESULT;
  var
    pidl: PItemIDList;
    sfgao: DWord;
    psf: IShellFolder;
    pidlChild: PItemIDList;
  begin
    DWord(ppv) := 0;
    Result := SHParseDisplayName(PWideChar(pszPath), nil, pidl, 0, sfgao);
    if SUCCEEDED(Result) then
    try
      Result := SHBindToParent(pidl, IID_IShellFolder, psf, pidlChild);
      if SUCCEEDED(Result) then
      try
        Result := psf.GetUIObjectOf(wnd, 1, pidlChild, riid, nil, ppv);
      finally
        psf := nil;
      end;
    finally
      CoTaskMemFree(pidl);
    end;
  end;

const
  SCRATCH_QCM_FIRST = 1;
  SCRATCH_QCM_LAST  = $7FFF;
var
  pcm: IContextMenu;
  Menu: HMENU;
  Info: TCMInvokeCommandInfo;
  Id: UINT;
begin
  if SUCCEEDED(GetUIObjectOfFile(AWnd, PChar(AFileName), IID_IContextMenu, pcm)) then
  try
    Menu := CreatePopupMenu;
    if Menu <> 0 then
    try
      if SUCCEEDED(pcm.QueryContextMenu(Menu, 0, SCRATCH_QCM_FIRST, SCRATCH_QCM_LAST, CMF_DEFAULTONLY)) then
      begin
        Id := GetMenuDefaultItem(Menu, 0, 0);
        if Id <> UINT(-1) then
        begin
          FillChar(Info, SizeOf(Info), 0);
          Info.cbSize := SizeOf(info);
          Info.hwnd := Handle;
          Info.lpVerb := MAKEINTRESOURCEA(Id - SCRATCH_QCM_FIRST);
          SetLastError(pcm.InvokeCommand(Info));
          if GetLastError <> 0 then
            RaiseLastOSError;
        end;
      end;
    finally
      DestroyMenu(Menu);
    end;
  finally
    pcm := nil;
  end;
end;

The same should be archieved by calling ShellExecuteEx with SEE_MASK_INVOKEIDLIST flag.

Alex
  • 5,477
  • 2
  • 36
  • 56