Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: How do I select file(s) in Explorer folder with SHOpenFolderAndSelectItems?


This question is not answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 3 - Last Post: Oct 1, 2014 10:18 AM Last Post By: Jeff Yankauer
Jeff Yankauer

Posts: 18
Registered: 6/9/06
How do I select file(s) in Explorer folder with SHOpenFolderAndSelectItems?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 30, 2014 2:55 PM
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
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: How do I select file(s) in Explorer folder withSHOpenFolderAndSelectItems? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 30, 2014 4:55 PM   in response to: Jeff Yankauer in response to: Jeff Yankauer
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:

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


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:

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;


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:

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;


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

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;


--
Remy Lebeau (TeamB)
Jeff Yankauer

Posts: 18
Registered: 6/9/06
Re: How do I select file(s) in Explorer folder withSHOpenFolderAndSelectItems? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 30, 2014 6:13 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
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 operating 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
Jeff Yankauer

Posts: 18
Registered: 6/9/06
Re: How do I select file(s) in Explorer folder withSHOpenFolderAndSelectItems? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 1, 2014 10:18 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
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;
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02