2

我在使用 delphi 从 DEV_BROADCAST_PORT 获取友好名称 (dbcp_name) 时遇到问题。

我试过使用微软帮助文档,它说它是一个指向空终止字符串的指针,但是在那个页面上有一条注释表明它是一个可变长度结构,而 dbcp_name 是一个包含实际字符的数组端口名称。

我试图提取它,但我目前还没有找到一种方法,因为当我让它返回任何东西时,它完全是胡言乱语。

我使用的代码如下:

PDevBroadcastPort = ^DEV_BROADCAST_PORT;

DEV_BROADCAST_PORT = packed record
    dbcp_size : DWORD ;
    dbcp_devicetype : DWORD;
    dbcp_reserved : DWORD ;
    dbcp_name : array[0..0] of ansichar; //TCHAR dbcp_name[1]; not valid
end;

我为数组的长度尝试了不同的值,我在某处读到这是正确的声明,但我不完全确定。注释掉的行也是微软文档为 C++ 中的行提供的内容

要提取我尝试过的信息:

var
  PData: PDevBroadcastPort;

  FName: string;

  ...

  PData := PDevBroadcastPort(Msg.lParam);

  ShowMessage('Length '+Inttostr(length(PData^.dbcp_name)));

  FName := '';

  i:=0;

  while((PData^.dbcp_name[i]) <> #0) and (i < 100) do
      begin
          FName := FName + (PData.dbcp_name[i]);

          i := i +1;

          ShowMessage(FName); 
      end;

我尝试将 while 循环设置为在数据结构的长度处终止,但如果我不设置它,它就会变得很大。

感谢您提供任何帮助,如果我遗漏了此问题所需的任何代码,请告诉我,我会尽快获取。

谢谢

4

2 回答 2

4

文档并没有说它是指向以空字符结尾的字符串的指针。它说它一个以空字符结尾的字符串。这对于在长度仅为一个元素的记录末尾声明的数组来说是典型的。

在指定的记录大小之后实际上还有更多的内存,并且该内存保存了字符串的剩余字符。指向该记录字段的指针也是指向字符数据的指针。

FName := PAnsiChar(@PData.dbcp_name);

你的数组遍历代码也应该可以工作,假设你禁用了那段代码的边界检查(否则当程序检测到你读取超出数组的第一个元素时你会得到一个异常)。

这一切都假定这PData确实是一个指向Dev_Broadcast_Port结构的指针。你没有提供关于你正在传递什么信息的信息,所以我不知道你是否真的拥有你认为你拥有的东西。

如果您使用的是 Delphi 2009 或更高版本,则TCHARC 声明中的类型等同于 Delphi 的WideChar类型。将该字段解释为一个数组AnsiChar会得到错误的结果,尽管对于大多数端口名称,它可能看起来好像该数组是一个以空字符结尾的单字符字符串列表。除非您确定您有非 Unicode 数据,否则您应该只使用Charand PChar,并让 Delphi 版本确定您拥有的数据类型。

FName := PChar(@PData.dbcp_name);
于 2012-07-20T13:19:20.107 回答
0

dbcp_name字段包含实际字符。字符数据的长度减去空终止符后为dbcp_size - SizeOf(DEV_BROADCAST_PORT),因此您可以像这样获取名称:

type
  DEV_BROADCAST_PORTA = packed record
    dbcp_size : DWORD;
    dbcp_devicetype : DWORD;
    dbcp_reserved : DWORD;
    dbcp_name : array[0..0] of AnsiChar;
  end; 

  DEV_BROADCAST_PORTW = packed record
    dbcp_size : DWORD;
    dbcp_devicetype : DWORD;
    dbcp_reserved : DWORD;
    dbcp_name : array[0..0] of WideChar;
  end; 

  {$IFDEF UNICODE}
  DEV_BROADCAST_PORT = DEV_BROADCAST_PORTW;
  {$ELSE}
  DEV_BROADCAST_PORT = DEV_BROADCAST_PORTA;
  {$ENDIF}
  PDEV_BROADCAST_PORT = ^DEV_BROADCAST_PORT;

.

var
  PData: PDEV_BROADCAST_PORT;
  FName: string;

...
PData := PDEV_BROADCAST_PORT(Msg.lParam);
SetString(FName, PData^.dbcp_name, (PData^.dbcp_size - SizeOf(DEV_BROADCAST_PORT)) div SizeOf(Char));
ShowMessage(FName);
于 2012-07-20T20:00:02.340 回答