【问题标题】:How to translate RETRIEVAL_POINTERS_BUFFER structure to Delphi?如何将 RETRIEVAL_POINTERS_BUFFER 结构转换为 Delphi?
【发布时间】:2012-10-06 20:25:41
【问题描述】:

我正在使用 Windows API,并且必须在 Delphi record 中重新创建 a structure。我想我记错了,但这个有点令人困惑,我需要确保我做对了。

这是原始的 C++ 结构:

typedef struct RETRIEVAL_POINTERS_BUFFER {
  DWORD         ExtentCount;
  LARGE_INTEGER StartingVcn;
  struct {
    LARGE_INTEGER NextVcn;
    LARGE_INTEGER Lcn;
  } Extents[1];
} RETRIEVAL_POINTERS_BUFFER, *PRETRIEVAL_POINTERS_BUFFER;

请注意,此结构中有一个数组结构。这就是我迷路的地方。如果我没记错的话,Delphi 版本应该是这样的:

  TExtent = record
    NextVcn: Integer;
    Lcn: Integer;
  end;

  TExtents = array of TExtent;

  PRETRIEVAL_POINTERS_BUFFER = ^TRETRIEVAL_POINTERS_BUFFER;
  TRETRIEVAL_POINTERS_BUFFER = record
    ExtentCount: DWORD;
    StartingVcn: Integer;
    Extents: TExtents;
  end;

当我在 Windows API 中使用此结构时,它似乎确实有效。但是,由于结构内部的这个结构数组,我有点犹豫我是否正确地做到了这一点。这看起来对吗?

【问题讨论】:

  • 几乎所有内容都已经翻译好了by JEDI。
  • @TLama,我认为这实际上可能是我的答案,只要“几乎”不是一个因素。
  • 我的意思是几乎所有来自 Windows API 的东西。你需要什么is of course complete 那里。

标签: delphi winapi struct delphi-xe2 code-conversion


【解决方案1】:

Extents 字段是一个内联在结构体中的可变长度数组。实际的结构将具有 ExtentCount 元素。你不能在这里使用 Delphi 动态数组。事实上,你永远不能在互操作中使用 Delphi 动态数组。

所以,就像 C 代码一样,将其声明为 array [0..0]。为了访问它,您需要禁用范围检查。此记录的实际实例将在索引0..ExtentCount-1 中包含有效数据。

对于您的整数类型,将 C 中的 DWORD 映射到 Delphi 中的 DWORD。以及 C 中的 LARGE_INTEGER 到 Delphi 中的 LARGE_INTEGER。这些都与 Delphi Integer 不同。前者是无符号的,后者是64位宽。

PRetrievalPointersBuffer = ^TRetrievalPointersBuffer;
TRetrievalPointersBuffer = record
  ExtentCount: DWORD;
  StartingVcn: LARGE_INTEGER;
  Extents: array [0..0] of record
    NextVcn: LARGE_INTEGER;
    Lcn: LARGE_INTEGER;
  end;
end;

LARGE_INTEGER 类型很难使用。您可能更愿意将这些字段声明为 Int64。


这种类型的结构总是堆分配的。堆分配代码必须计算出适合可变长度数组中的ElementCount 项所需的大小。如果您正在分配缓冲区,那么您将需要单独定义类型的内部记录,以便您可以方便地将其命名为传递给SizeOf。如果 API 分配,那么你就可以如上所述。

【讨论】:

  • +1,特别适合您的编辑。我几乎总是给内部记录一个单独定义的类型。它使很多事情变得非常容易。随着记录方法的引入,我将在 TRetrievalPointersBuffer 类型上添加一个方法,用于计算给定 ExtentCount 的总大小。
  • @jeroen 在此我将在外部记录中定义内部类型。
  • 当您知道数组的上限时,您可以通过相应地声明数组将其放入堆栈。不适用于这种特定情况,但假设您有 WCHAR Name[1] 并且您知道它最多 255 个字符,那么您可以将字段定义为 Name: WCHAR[0..254]。
  • 我将尝试重述 -1... 可能知道最大可能的元素数量,或者可能不关心实际信息但只想知道元素的数量,或者一个仅当元素计数小于定义的总数时才可能关心信息。声明这种结构具有一定数量的大于 1 的数组元素并因此将其放在堆栈中并没有错。这对于 api 来说不是问题,因为接受这种结构的 api 不关心传递的大小是否适合 api 标头,而是实际使用的缓冲区的大小。
  • @Sertac 在这种情况下,您可能可以使用堆栈分配并在遇到 ERROR_MORE_DATA 时一次又一次地调用。不过我会堆分配。
【解决方案2】:

将TExtents 定义为array of TExtent 是错误的。那就是将它声明为一个动态数组,一种托管引用类型。你需要的是一个有界数组,比如array [x..y] of TExtent。

不过,这个 C 声明相当奇怪,因为它被声明为 只有一个元素的数组。 如果你想完全复制它,你应该将它声明为 array [0..0] of TExtent。 p>

【讨论】:

  • 这是一个变长数组。但是你不能这样声明。实际的数组有 ExtentCount 元素。
【解决方案3】:

StartingVcn、NextVcn 和 Lcn 定义为 LARGE_INTEGER,在 winnt.h 中定义如下:

typedef union _LARGE_INTEGER {
    struct {
        DWORD LowPart;
        LONG HighPart;
    } DUMMYSTRUCTNAME;
    struct {
        DWORD LowPart;
        LONG HighPart;
    } u;
    LONGLONG QuadPart;
} LARGE_INTEGER;

根据您使用的 Delphi 版本,您定义的结构可能不起作用。 LARGE_INTEGER 应声明如下:

LARGE_INTEGER = record
  case Integer of
    0: ( LowPart: DWORD;
      HighPart: Longint; );
    1: ( QuadPart: LONGLONG);
end;

LONGLONG 实际上只是一个 Int64。您可以使用 LowPart 和 Highpart 或 QuadPart 访问此结构。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-27
    • 1970-01-01
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    相关资源
    最近更新 更多