Mega Search
23.2 Million


Sign Up

Make a donation  
How do I select file(s) in Explorer folder with SHOpenFolder  
News Group: embarcadero.public.delphi.nativeapi

I'm running a 32-bit app and attempting to use the code below to launch a Windows Explorer window and the select a file within a folder,
but it always fails to select the file.   I also tried using the optional 3rd parameter with a PITemIDList for the file, and then setting the first parameter's PITemIDList to be based on just the file's path itself, and set the 2nd parameter to 1, but that also failed.   The error I've been getting is:  $80004002  (-2147467262).  

Oddly, if I set the 2nd parameter to 1, when using Nil for the 3rd parameter, and still having the first PItemIDList be based on the filename, then it launches Media Player and plays the file (which in my case is a .WAV file).

File names passed to this are fully qualified.

It fails whether or not CoInitialize is called. 

Any ideas what I am doing wrong or what I can do to launch Explorer and select file(s).  (and hopefully have it work under WinXp and better)   I'm currently testing with Win7, 64-bit.

Thanks.

Jeff 
_____________________________________________
const
  OFASI_EDIT = $0001;
  OFASI_OPENDESKTOP = $0002;

{$IFDEF UNICODE}
function ILCreateFromPath(pszPath: PChar): PItemIDList stdcall; external shell32
  name 'ILCreateFromPathW';
{$ELSE}
function ILCreateFromPath(pszPath: PChar): PItemIDList stdcall; external shell32
  name 'ILCreateFromPathA';
{$ENDIF}
procedure ILFree(pidl: PItemIDList) stdcall; external shell32;
function SHOpenFolderAndSelectItems(pidlFolder: PItemIDList; cidl: Cardinal;
  apidl: pointer; dwFlags: DWORD): HRESULT; stdcall; external shell32;

function OpenFolderAndSelectFile(FileName: string): boolean;
var
  IIDL: PItemIDList;       TheValue:HResult;
begin
  result := false;
  CoInitialize(Nil);
  IIDL := ILCreateFromPath(PChar(FileName));
  if (IIDL <> nil) then
    try
      TheValue := SHOpenFolderAndSelectItems(IIDL, 0, Nil, 0);
      If TheValue <> S_OK then NumberMessageBox(TheValue);
      result := TheValue = S_OK;
    finally
      ILFree(IIDL);
    end;
    CoUninitialize;
end;
_________________________

Edited by: Jeff Yankauer on Sep 30, 2014 2:55 PM

Edited by: Jeff Yankauer on Sep 30, 2014 2:56 PM

Vote for best question.
Score: 0  # Vote:  0
Date Posted: 30-Sep-2014, at 2:57 PM EST
From: Jeff Yankauer
 
Re: How do I select file(s) in Explorer folder withSHOpenFol  
News Group: embarcadero.public.delphi.nativeapi
Here's the current version of the code that I'm using:

const
  OFASI_EDIT = $0001;
  OFASI_OPENDESKTOP = $0002;

{$IFDEF UNICODE}
function ILCreateFromPath(pszPath: PChar): PItemIDList stdcall; external shell32
  name 'ILCreateFromPathW';
{$ELSE}
function ILCreateFromPath(pszPath: PChar): PItemIDList stdcall; external shell32
  name 'ILCreateFromPathA';
{$ENDIF}
procedure ILFree(pidl: PItemIDList) stdcall; external shell32;
function SHOpenFolderAndSelectItems(pidlFolder: PItemIDList; cidl: Uint;
  apidl: pItemIDList; dwFlags: DWORD): HRESULT; stdcall; external shell32;

function OpenFolderAndSelectFile(FileName: string): boolean;
var
  DidInitCOM: Boolean;
  IIDL: PItemIDList;
  TheValue:HResult;
begin
  Result := False;
  DidInitCOM := False;
  try
    IIDL := ILCreateFromPath(PChar(FileName));
    if (IIDL <> nil) then
    try
      TheValue := SHOpenFolderAndSelectItems(IIDL, 0, Nil, 0);
      If TheValue <> S_OK then
      begin
        If TheValue = $800401F0{CO_E_NOTINITIALIZED} then
        begin
          DidInitCOM := Succeeded(CoInitialize(nil));
          if DidInitCOM then TheValue := SHOpenFolderAndSelectItems(IIDL,
0, nil, 0);
        end;
      end;
      If TheValue <> S_OK then NumberMessageBox(TheValue);
      Result := TheValue = S_OK;
    finally
      ILFree(IIDL);
    end;
  finally
    if DidInitCOM then CoUninitialize;
  end;
end;

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 1-Oct-2014, at 10:18 AM EST
From: Jeff Yankauer
 
Re: How do I select file(s) in Explorer folder withSHOpenFol  
News Group: embarcadero.public.delphi.nativeapi
> The full path and filename, not just the filename by itself, right?
> 

Yes, full path and filename;

> On a side note, the second parameter of SHOpenFolderAndSelectItems() should 
> be declared as UINT instead of Cardinal, and the third parameter should be 
> declared as PItemIDList instead of Pointer:

Thanks, I made those corrections, and I'm using the code that doesn't init COM unless necessary.   I still wind up getting the original error when the 1st parameter is based on the fully qualified filename and no 3rd parameter, or if I base the 1st parameter on the full path of the filename (without the filename included) and the 3rd parameter is based on either just the filename itself or a fully qualified filename.   Perhaps the selection routine has a bug when a 32-bit app calls this within a 64-it ope
rating system?   Even when it fails, it still does display the folder, just not selecting the file(s).  

Thanks,

Jeff

Edited by: Jeff Yankauer on Sep 30, 2014 6:13 PM

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 30-Sep-2014, at 6:14 PM EST
From: Jeff Yankauer
 
Re: How do I select file(s) in Explorer folder withSHOpenFol  
News Group: embarcadero.public.delphi.nativeapi
Jeff wrote:

> I also tried using the optional 3rd parameter with a PITemIDList for the
> file, and then setting the first parameter's PITemIDList to be based on
> just the file's path itself

To clarify, the first parameter is the absolute PIDL of the parent folder, 
and the third parameter is the relative PIDL of the file within the parent 
folder.

The error I've been getting is:  $80004002  (-2147467262).

That is E_NOINTERFACE, which likely means that SHOpenExplorerAndSelectItems() 
is internally creating a COM object and calling QueryInterface() on it, and 
that call is failing because the requested interface is not supported on 
that machine.  Hard to say without knowing what it actually being done internally.

> Oddly, if I set the 2nd parameter to 1, when using Nil for the 3rd
> parameter

That is not a valid combination.

> and still having the first PItemIDList be based on the filename

The full path and filename, not just the filename by itself, right?

> then it launches Media Player and plays the file (which in my case is a 
..WAV file).

That does not make sense, SHOpenFolderAndSelectItems() should not be invoking 
Media Player or any app other than Windows Explorer.

On a side note, the second parameter of SHOpenFolderAndSelectItems() should 
be declared as UINT instead of Cardinal, and the third parameter should be 
declared as PItemIDList instead of Pointer:

{code}
function SHOpenFolderAndSelectItems(pidlFolder: PItemIDList; cidl: UINT; 
apidl: PItemIDList; dwFlags: DWORD): HRESULT; stdcall; external shell32;
{code}

Also, you need to do error handling on CoInitialize() and only call CoUninitialize() 
if CoInitialize() succeeds, otherwise you may screw up COM for the calling 
thread:

{code}
function OpenFolderAndSelectFile(FileName: string): boolean;
var
  DidInitCOM: Boolean;
  IIDL: PItemIDList;
  TheValue:HResult;
begin
  Result := False;
  DidInitCOM := Succeeded(CoInitialize(nil));
  try
    IIDL := ILCreateFromPath(PChar(FileName));
    if (IIDL <> nil) then
    try
      TheValue := SHOpenFolderAndSelectItems(IIDL, 0, nil, 0);
      If TheValue <> S_OK then NumberMessageBox(TheValue);
      Result := TheValue = S_OK;
    finally
      ILFree(IIDL);
    end;
  finally
    if DidInitCOM then CoUninitialize;
  end;
end;
{code}

It is better not to call CoInitialize() in your function at all.  It should 
be called at thread startup instead.  The RTL usually does that for you during 
program startup:

{code}
function OpenFolderAndSelectFile(FileName: string): boolean;
var
  IIDL: PItemIDList;
  TheValue:HResult;
begin
  Result := False;
  IIDL := ILCreateFromPath(PChar(FileName));
  if (IIDL <> nil) then
  try
    TheValue := SHOpenFolderAndSelectItems(IIDL, 0, nil, 0);
    If TheValue <> S_OK then NumberMessageBox(TheValue);
    Result := TheValue = S_OK;
  finally
    ILFree(IIDL);
  end;
end;
{code}

If SHOpenFolderAndSelectItems() happens to fail with CO_E_NOTINITIALIZED 
($800401F0) then you could temporary call CoInitialize() and try again:

{code}
function OpenFolderAndSelectFile(FileName: string): boolean;
var
  DidInitCOM: Boolean;
  IIDL: PItemIDList;
  TheValue:HResult;
begin
  Result := False;
  DidInitCOM := False;
  try
    IIDL := ILCreateFromPath(PChar(FileName));
    if (IIDL <> nil) then
    try
      TheValue := SHOpenFolderAndSelectItems(IIDL, 0, nil, 0);
      If TheValue <> S_OK then
      begin
        If TheValue = $800401F0{CO_E_NOTINITIALIZED} then
        begin
          DidInitCOM := Succeeded(CoInitialize(nil));
          if DidInitCOM then TheValue := SHOpenFolderAndSelectItems(IIDL, 
0, nil, 0);
        end;
      end;
      If TheValue <> S_OK then NumberMessageBox(TheValue);
      Result := TheValue = S_OK;
    finally
      ILFree(IIDL);
    end;
  finally
    if DidInitCOM then CoUninitialize;
  end;
end;
{code}

--
Remy Lebeau (TeamB)

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 30-Sep-2014, at 4:55 PM EST
From: Remy Lebeau (TeamB)