【问题标题】:Calling SHGetSetSettings from Delphi从 Delphi 调用 SHGetSetSettings
【发布时间】:2010-08-14 19:45:15
【问题描述】:

我刚刚阅读了this questionthis question,从那时起我一直尝试在Delphi 中调用SHGetSetSettings。这是shell32.dll的一个函数,但是ShlObj.pas中没有定义,所以我们需要自己写定义。

首先我们需要翻译SHELLSTATE 结构。现在我对C的经验有限,但我认为“:1”表示该结构的成员是单个位,即其中八个可以打包在一起一个字节。我还假设 DWORD = UINT = 32 位无符号整数,而 LONG = int 是 32 位有符号整数。但是我们遇到了一个问题:整个结构将占用 228 位,即 28.5 字节,这……相当不可能,至少在 Delphi 中,sizeof(SomeRecord) 必须是整数。

尽管如此,我试图通过在末尾添加四个虚拟位来解决它。 232 位 = 29 字节,这很好。

所以我尝试了

PShellState = ^TShellState;
TShellState = packed record
  Data1: cardinal;
  Data2: cardinal;
  Data3: cardinal;
  Data4: cardinal;
  Data5: cardinal;
  Data6: cardinal;
  Data7: cardinal;
  Data8: byte; // Actually a nibble would be sufficient
end;

然后我声明(为了以后方便)

const
  fShowAllObjects = 1;
  fShowExtensions = 2;
  fNoConfirmRecycle = 4;
  fShowSysFiles = 8;
  fShowCompColor = 16;
  fDoubleClickInWebView = 32;
  fDesktopHTML = 64;
  fWin95Classic = 128;
  fDontPrettyPath = 256;
  fShowAttribCol = 512;
  fMapNetDrvButton = 1024;
  fShowInfoTip = 2048;
  fHideIcons = 4096;
  fWebView = 8192;
  fFilter = 16384;
  fShowSuperHidden = 32768;
  fNoNetCrawling = 65536;

现在我准备好定义了

interface
  procedure SHGetSetSettings(var ShellState: TShellState; Mask: cardinal; DoSet: boolean); stdcall;

implementation
  procedure SHGetSetSettings; external shell32 name 'SHGetSetSettings';

但在我尝试代码之前,我发现了一些非常奇怪的东西。我发现我声明的常量已经在这里声明了:SSF Constants。请注意SSF_HIDEICONS = 0x00004000 = 16384 ≠ fHideIcons = 4096。如果SSF_ 常量确实是与SHELLSTATE 一起使用的掩码,那么当SSF_HIDEICONS 是结构中的第13 位(并且它的掩码应该是2^12)时,将其定义为2^14 是没有意义的。因此,这两个 MSDN 参考页面似乎相互矛盾。

有人可以澄清一下这一切吗?

【问题讨论】:

    标签: c delphi winapi translation msdn


    【解决方案1】:

    我在这里阅读的帮助是在检索数据时为掩码指定了 SSF_ 常量。他们没有理由必须映射到 ShellState 结构中的位。

    如果他们这样做,fShowSysFiles 将映射到 8 (0x04),我们从帮助中知道 SSF_SHOWSYSFILES 是 0x20。没有直接映射。

    【讨论】:

    • 是的,他们当然没有映射到结构的位。但在当时看来是那么合理!
    • 但是另一个问题呢:C 结构是否有可能没有整数字节作为其大小?
    • 没有。查看声明,位字段被指定为在 BOOL 内,因此基础类型是 int。一目了然,我将该结构的大小设置为 36 个字节。当然,结构打包可以改变大小,但由于这里的所有内容(int、UINT、long、DWORD)在 32 位操作系统上都是 4 字节,我认为估计是合理安全的。当然,一些语言律师会跳进来证明我错了:-)。但请注意您是否使用 64 位编译器...该值会改变。
    • 那么,如果我在必要时添加一些虚拟位来“完成 BOOLS”,我对结构的解释是正确的?
    • 是的。我不经常使用 Delphi,但我相信打包的记录无论如何都只会是整数字节。您只需要确保使用足够的空间来在四字节边界上启动 dwWin95Unused。
    【解决方案2】:

    不幸的是,ShlObj.pas 中 SHELLSTATE 的 D2010 声明不正确,但第一组位 (17) 与 Data: DWORD; 正确匹配(您的确实没问题)。 可能有 18 个或 19 个都一样。那么我们应该为 2 个未使用的 Win95 再获得 2 个 DWORD/UINT,而不仅仅是 Data2。

    太糟糕了,因为 SSF 标志和 SHGetSetSettings 声明已经在那里完成并且正确。

    根据 MSDN 的正确声明应该是 IMO:

      tagSHELLSTATEW = record
        Data: DWORD;
    {   fShowAllObjects: BOOL:1;
        fShowExtensions: BOOL:1;
        fNoConfirmRecycle: BOOL:1;
        fShowSysFiles: BOOL:1;
        fShowCompColor: BOOL:1;
        fDoubleClickInWebView: BOOL:1;
        fDesktopHTML: BOOL:1;
        fWin95Classic: BOOL:1;
        fDontPrettyPath: BOOL:1;
        fShowAttribCol: BOOL:1;
        fMapNetDrvBtn: BOOL:1;
        fShowInfoTip: BOOL:1;
        fHideIcons: BOOL:1;
        fWebView: BOOL:1;
        fFilter: BOOL:1;
        fShowSuperHidden: BOOL:1;
        fNoNetCrawling: BOOL:1;}
    
        dwWin95Unused: DWORD;// Win95 only - no longer supported pszHiddenFileExts
        uWin95Unused: UINT; // Win95 only - no longer supported cbHiddenFileExts
    
        // Note: Not a typo!  This is a persisted structure so we cannot use LPARAM
        lParamSort: Integer;
        iSortDirection: Integer;
        version: UINT;
    
        // new for win2k. need notUsed var to calc the right size of ie4 struct
        // FIELD_OFFSET does not work on bit fields
        uNotUsed: UINT;// feel free to rename and use}
    
        Data2: DWORD;
    {   fSepProcess: BOOL:1;
    
        // new for Whistler.
        fStartPanelOn: BOOL:1;
        fShowStartPage: BOOL:1;
    
        // new for Windows Vista
        fAutoCheckSelect: BOOL:1;
        fIconsOnly: BOOL:1;
        fShowTypeOverlay: BOOL:1;
    
        // If you need a new flag, steal a bit from from fSpareFlags.
        // Also, keep SHELLFLAGSTATE and SHGetSettings in sync when adding new flags.
        fSpareFlag: UINT:13;}
      end;
    

    您可以通过以下方式验证这是否允许正确获取排序属性:

    var
      lpss: tagSHELLSTATEW;
    begin
      ZeroMemory(@lpss, SizeOf(lpss));
      SHGetSetSettings(lpss, SSF_SORTCOLUMNS, False);
    

    【讨论】:

      【解决方案3】:

      这是 Delphi 2010 中的 TShellState 定义:

      type
        tagSHELLSTATEW = record 
          Data: DWORD;
          Data2: UINT;
      {   fShowAllObjects: BOOL:1;
          fShowExtensions: BOOL:1;
          fNoConfirmRecycle: BOOL:1;
          fShowSysFiles: BOOL:1;
          fShowCompColor: BOOL:1;
          fDoubleClickInWebView: BOOL:1;
          fDesktopHTML: BOOL:1;
          fWin95Classic: BOOL:1;
          fDontPrettyPath: BOOL:1;
          fShowAttribCol: BOOL:1;
          fMapNetDrvBtn: BOOL:1;
          fShowInfoTip: BOOL:1;
          fHideIcons: BOOL:1;
          fWebView: BOOL:1;
          fFilter: BOOL:1;
          fShowSuperHidden: BOOL:1;
          fNoNetCrawling: BOOL:1;}
      
          //dwWin95Unused: DWORD;// Win95 only - no longer supported pszHiddenFileExts
          //uWin95Unused: UINT; // Win95 only - no longer supported cbHiddenFileExts
      
          // Note: Not a typo!  This is a persisted structure so we cannot use LPARAM
          lParamSort: Integer;
          iSortDirection: Integer;
          version: UINT;
      
          // new for win2k. need notUsed var to calc the right size of ie4 struct
          // FIELD_OFFSET does not work on bit fields
          uNotUsed: UINT;// feel free to rename and use
      {   fSepProcess: BOOL:1;
      
          // new for Whistler.
          fStartPanelOn: BOOL:1;
          fShowStartPage: BOOL:1;
      
          // new for Windows Vista
          fAutoCheckSelect: BOOL:1;
          fIconsOnly: BOOL:1;
          fShowTypeOverlay: BOOL:1;
      
          // If you need a new flag, steal a bit from from fSpareFlags.
          // Also, keep SHELLFLAGSTATE and SHGetSettings in sync when adding new flags.
          fSpareFlags: UINT:11;
      }
      
        end;
        {$EXTERNALSYM tagSHELLSTATEW}
        SHELLSTATEA = tagSHELLSTATEW;
        {$EXTERNALSYM SHELLSTATEA}
        SHELLSTATEW = tagSHELLSTATEW;
        {$EXTERNALSYM SHELLSTATEW}
        SHELLSTATE = SHELLSTATEW;
        {$EXTERNALSYM SHELLSTATE}
        TShellState = SHELLSTATE;
        PShellState = ^TShellState;
      
      const
        SHELLSTATEVERSION_IE4 = 9; 
        {$EXTERNALSYM SHELLSTATEVERSION_IE4}
        SHELLSTATEVERSION_WIN2K = 10; 
        {$EXTERNALSYM SHELLSTATEVERSION_WIN2K}
      

      不幸的是,这不是很有帮助。

      【讨论】:

      • 嗯,它实际上非常很有帮助。除其他外,这表示所有 BOOL:1 一起占用 8 个字节。不过有点奇怪,因为 17 位可以容纳三个字节,所以一个基数就足够了。顺便说一句:我假设 UINT 是一个无符号整数,即一个基数,就像 DWORD 一样。但是为什么要使用两个不同的“别名”呢?嗯...我似乎只有 24 个字节...
      【解决方案4】:

      C 中的 Afaik 位域是整数的子类型。有一些方法可以打包它,但在 C 中,在一堆单个位字段之后,将填充到下一个字节边界(甚至可能填充到下一个整数边界)。而且C的sizeof也不支持减半。

      所以可能是 sizeof(integer)= 32bytes 的 1+6+1 倍。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-15
        • 2012-05-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多