使用Delphi查找特殊驱动器

时间:2014-05-30 19:34:53

标签: windows delphi windows-shell

我正在尝试在Delphi 2007中编写一个小程序,以便在插入Windows 7计算机时访问便携式USB驱动器中的文件。此驱动器不会显示为标准驱动器号。它出现在Windows资源管理器中的便携设备下。我编写了以下代码来枚举“计算机”下的所有项目:

Procedure TfrmMain.ComputerChanged(Var Msg: TMessage);
Var
  Enum: IEnumIDList;
  Fetched: Longword;
  Item: PItemIDList;
  Path: String;
  Computer: IShellFolder;
  StrRet: TSTRRET;
Begin
  Status('Computer changed...  Checking folders.');
  fDesktop.BindToObject(fCompPidl, Nil, IID_IShellFolder, Computer);
  If Assigned(Computer) And
     (Computer.EnumObjects(Self.Handle, SHCONTF_FOLDERS, Enum) = NOERROR) Then
  Begin
    While (Enum.Next(1, Item, Fetched) = NOERROR) Do
    Begin
      FillChar(StrRet, SizeOf(StrRet), #0);
      Computer.GetDisplayNameOf(Item, SHGDN_FORADDRESSBAR or SHGDN_NORMAL, StrRet);
      Path := StrRetToStr(StrRet, Item);
      Status(Path);
    End;
  End;
End;

(注意:Status过程只是向TMemo输出一条消息。)

每当我的应用程序收到Windows shell子系统的更改通知时,都会调用此方法。它列举了所有本地驱动器和网络驱动器,但没有其他内容(iCloud Photos驱动器也缺失)。

有谁知道如何访问这些虚拟驱动器上的文件?

2 个答案:

答案 0 :(得分:4)

您很可能无法正确初始化COM。如果你不打电话给CoInitializeEx或者你打电话给它的价值不好,你的代码将会按原样运行,但便携式设备驱动程序需要使用公寓线程才能正常工作。

根据您的代码,这是一个正常运行并展示便携式设备的示例应用。如果您注释掉CoInitializeEx / CoUninitialize来电或传入COINIT_MULTITHREADED,它仍会有效,但它只会显示驱动器。

program ListMyComputer;

{$APPTYPE CONSOLE}

uses
  ComObj, ShlObj, ShellApi, ShLwApi, ActiveX, Windows, SysUtils;

var
  Enum: IEnumIDList;
  Fetched: Longword;
  CompPidl, Item: PItemIDList;
  Path: PWideChar;
  Desktop, Computer: IShellFolder;
  StrRet: TSTRRET;
begin
  CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
  try
    WriteLn('Computer changed...  Checking folders.');
    SHGetDesktopFolder(Desktop);
    SHGetFolderLocation(0, CSIDL_DRIVES, 0, 0, CompPidl);
    Desktop.BindToObject(CompPidl, Nil, IID_IShellFolder, Computer);
    CoTaskMemFree(CompPidl);
    If Assigned(Computer) And
       (Computer.EnumObjects(0, SHCONTF_FOLDERS, Enum) = NOERROR) Then
    Begin
      While (Enum.Next(1, Item, Fetched) = NOERROR) Do
      Begin
        FillChar(StrRet, SizeOf(StrRet), #0);
        Computer.GetDisplayNameOf(Item, SHGDN_FORADDRESSBAR or SHGDN_NORMAL, StrRet);
        StrRetToStr(@StrRet, Item, Path);
        WriteLn(Path);
        CoTaskMemFree(Path);
      End;
    End;
    WriteLn('Enumeration complete');
    ReadLn;
  finally
    CoUninitialize
  end;
end.

答案 1 :(得分:2)

感谢@SertacAkyuz指出需要使用Windows Portable Device API,这导致我this Experts Exchange question讨论相同的事情。 Sinisa Vuk提供了一个很棒的代码示例来回答我已经链接的这个问题(这个问题太长了,无法嵌入)这里有权限:http://pastebin.com/0hSWv5pE