【问题标题】:Pass a complex struct to the Windows API将复杂结构传递给 Windows API
【发布时间】:2019-08-21 21:20:28
【问题描述】:

我正在尝试使用 Windows API 中的 GetConsoleScreenBufferInfo(HANDLE, PCONSOLE_SCREEN_BUFFER_INFO) 函数,使用 Perl 6 和(当然)NativeCall。

我想我已经正确设置了函数所需的 CONSOLE_SCREEN_BUFFER_INFO 结构,但是当我尝试转储其内容时,代码在调用后崩溃。

这是演示问题的最短(不完全但接近)方法:

use NativeCall;

constant \HANDLE            := Pointer[void];
constant \SHORT             := int16;
constant \USHORT            := uint16;
constant \WORD              := uint16;
constant \DWORD             := uint32;
constant \BOOL              := int32;
constant \STD_OUTPUT_HANDLE := -11;
constant \STD_INPUT_HANDLE  := -10;

class COORD is repr('CStruct')            {
  has SHORT $.X;
  has SHORT $.Y;
}

class SMALL_RECT is repr("CStruct")            {
  has SHORT $.Left;
  has SHORT $.Top;
  has SHORT $.Right;
  has SHORT $.Bottom;
};

class CONSOLE_SCREEN_BUFFER_INFO is repr("CStruct")            {
  has COORD $.dwSize;
  has COORD $.dwCursorPosition;
  has WORD $.wAttributes;
  has SMALL_RECT $.srWindow;
  has COORD $.dwMaximumWindowSize;

  submethod TWEAK {
    $!dwSize := COORD.new;
    $!dwCursorPosition := COORD.new;
    $!srWindow := SMALL_RECT.new;
    $!dwMaximumWindowSize := COORD.new;
  }
}

# C: BOOL WINAPI GetConsoleScreenBufferInfo(_In_  HANDLE hConsoleOutput, _Out_ PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);
sub GetConsoleScreenBufferInfo(HANDLE, CONSOLE_SCREEN_BUFFER_INFO is rw) is native("Kernel32.dll") returns BOOL { * };
sub GetStdHandle(DWORD) is native('Kernel32') returns Pointer[void]  { * };

my CONSOLE_SCREEN_BUFFER_INFO
  $info = CONSOLE_SCREEN_BUFFER_INFO.new;

my HANDLE
  $handle-o = GetStdHandle( STD_OUTPUT_HANDLE );

dd $info;
say "GetConsoleScreenBufferInfo ", GetConsoleScreenBufferInfo( $handle-o, $info );
say "Will I live?";
dd $info; #crashes without notice

非常欢迎任何有关崩溃发生原因以及如何修复它的提示。

【问题讨论】:

  • 我一尝试访问任何东西,它就会崩溃。 dd 只是模范。
  • constant \STD_INPUT_HANDLE := -10; 可能将Intis repr('P6Int') 绑定到STD_INPUT_HANDLE。在 GetStdHandle( STD_OUTPUT_HANDLE ) 中,它习惯于绑定到 32 位 DWORD。 Rakudo 是否会自动强制执行或必须采取任何措施才能使其发挥作用?
  • 是的,这是透明的。我使用以相同方式获得的另一个句柄进行输入,并且效果很好。问题一定出在 GetConsoleScreenBufferInfo
  • 我可能需要以某种方式使用“指针”。我明天再研究一下。
  • 你真的需要TWEAK方法吗?整个结构被GetConsoleScreenBufferInfo 覆盖。我不知道 Perl 在内部是如何工作的,也许它添加了被 API 调用覆盖的 vtable。例如,在 C++ 中,您不能添加虚拟方法,因为它们可能需要额外的存储空间来存储 vtable 指针。

标签: winapi raku kernel32 nativecall


【解决方案1】:

对于CONSOLE_SCREEN_BUFFER_INFO 的成员,您需要使用HAS 而不是has,因为它们是嵌入的而不是由指针引用的结构(这是Perl6 的默认设置)。

一旦你这样做了,你也可以删除TWEAK,这样代码就会被读取

class CONSOLE_SCREEN_BUFFER_INFO is repr("CStruct") {
  HAS COORD $.dwSize;
  HAS COORD $.dwCursorPosition;
  has WORD $.wAttributes;
  HAS SMALL_RECT $.srWindow;
  HAS COORD $.dwMaximumWindowSize;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 2019-09-19
    • 1970-01-01
    • 2016-01-29
    • 2014-04-01
    相关资源
    最近更新 更多