【问题标题】:Use Delphi to Find Special Drives使用 Delphi 查找特殊驱动器
【发布时间】:2014-05-30 19:34:52
【问题描述】:

我正在尝试在 Delphi 2007 中编写一个小程序,以便在将便携式 USB 驱动器插入 Windows 7 机器时访问文件。但是,此驱动器并未显示为标准驱动器号。它出现在 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 驱动器也不见了)。

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

【问题讨论】:

  • 啊啊啊……太棒了。另一个完整的 API 来学习,而不仅仅是使用现有的 shell 函数。好吧,一旦我了解了 Windows 便携式设备 API,我发现有人编写了一个完整的示例程序,完全符合我的要求。不幸的是,它在 Experts Exchange 上,您需要一个帐户才能看到它。对于那些有的人,请在此处查看:www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_28303837.html
  • @SertacAkyuz:您能否发表您的评论作为答案,以便我将其标记为已关闭?
  • 请您自己发布一个答案,您已经比我了解更多了:)。
  • 通过谷歌搜索“Q_28303837 www.experts-exchange.com”,您将能够得到答案。有人发布了一个位于此处的程序:filedb.experts-exchange.com/incoming/2014/03_w12/840187/…

标签: windows delphi windows-shell


【解决方案1】:

您很可能没有正确初始化 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.

【讨论】:

  • @Ken:噢!固定的。我的原始版本只是泄露了所有内容,我在清理它以发布时尝试将其扔进去。
  • 没问题。无论如何我都赞成它,因为它的小修复工作。我只是想我会提到它。 :-)
  • @CraigPeterson:酷!谢谢。我确实认为普通的 shell 控件看不到便携式设备很奇怪。我从没想过初始化的东西,因为没有它一切都可以工作。
【解决方案2】:

感谢@SertacAkyuz 指出需要使用 Windows 便携式设备 API,这让我找到了 this Experts Exchange question 讨论同样的事情。 Sinisa Vuk 提供了一个很棒的代码示例来回答我在此处链接的问题(嵌入时间太长):http://pastebin.com/0hSWv5pE

【讨论】:

    猜你喜欢
    • 2012-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-25
    • 1970-01-01
    • 2011-12-18
    • 1970-01-01
    相关资源
    最近更新 更多