Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
delphiunicode和控制台_Delphi - Fatal编程技术网

delphiunicode和控制台

delphiunicode和控制台,delphi,Delphi,我正在编写一个与一对硬件传感器接口的C#应用程序。不幸的是,设备上唯一公开的接口需要一个用Delphi编写的dll 我正在编写一个Delphi可执行包装器,它为DLL调用必要的函数,并通过stout返回传感器数据。但是,此数据的返回类型是PWideChar(或PChar),我无法将其转换为ansi以便在命令行上打印 如果我直接将数据传递给WriteLn,则每个字符都会得到“?”。如果我查看字符数组,并尝试通过Ansi转换一次打印一个字符,则只打印少数字符(虽然它们确实确认了数据),而且它们通常会

我正在编写一个与一对硬件传感器接口的C#应用程序。不幸的是,设备上唯一公开的接口需要一个用Delphi编写的dll

我正在编写一个Delphi可执行包装器,它为DLL调用必要的函数,并通过stout返回传感器数据。但是,此数据的返回类型是PWideChar(或PChar),我无法将其转换为ansi以便在命令行上打印

如果我直接将数据传递给WriteLn,则每个字符都会得到“?”。如果我查看字符数组,并尝试通过Ansi转换一次打印一个字符,则只打印少数字符(虽然它们确实确认了数据),而且它们通常会按顺序打印。(打印时只需简单地跳转索引即可。)我还尝试将PWideChar转换为整数直线:“I”对应21321。我可能会计算出所有的转换,但有些数据有很多值

我不确定dll使用的是什么版本的Delphi,但我相信它是4。绝对在7之前

感谢您的帮助

TLDR:需要将UTF-16 PWideChar转换为AnsiString进行打印

示例应用程序:

program SensorReadout;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Windows,
  SysUtils,
  dllFuncUnit in 'dllFuncUnit.pas'; //This is my dll interface.

var  state: integer;
     answer: PChar;
     I: integer;
     J: integer;
     output: string;
     ch: char;

begin
  try
    for I := 0 to 9 do
    begin
      answer:= GetDeviceChannelInfo_HSI(1, Ord('a'), I, state); //DLL Function, returns a PChar with the results.  See example in comments.

      if state = HSI_NO_ERRORCODE then
      begin
        output:= '';
        for J := 0 to length(answer) do
        begin
          ch:= answer[J]; //This copies the char. Originally had an AnsiChar convert here.
          output:= output + ch;
        end;
        WriteLn(output);
      end;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  ReadLn(I);
end.`

问题是PAnsiChar必须是来自DLL的函数的返回类型。

要将
PWideChar
转换为
AnsiString

function WideCharToAnsiString(P: PWideChar): AnsiString;
begin
  Result := P;
end;
代码从UTF-16、以null结尾的PWideChar转换为
AnsiString
。如果您在输出中得到问号,那么您的输入不是UTF-16,或者它包含无法在ANSI代码页中编码的字符

我猜实际发生的是,您的Delphi DLL是使用Unicode之前的Delphi创建的,因此使用ANSI文本。但是现在您正试图从一个后Unicode Delphi链接到它,
PChar
具有不同的含义。我相信Rob在你的另一个问题中向你解释了这一点。因此,您只需将DLL导入声明为返回
PAnsiChar
,而不是
PChar
,即可解决此问题。像这样:

function GetDeviceChannelInfo_HSI(PortNumber, Address, ChNumber: Integer;
  var State: Integer): PAnsiChar; stdcall; external DLL_FILENAME;
当你这样做了,你可以像我上面描述的那样,以类似的方式分配给一个字符串变量

您需要了解的是,在旧版本的Delphi中,
PChar
PAnsiChar
的别名。在现代Delphi中,它是
PWideChar
的别名。这种不匹配可以解释你所报告的一切


在我看来,将Delphi包装器写入DLL并通过stdout与C#app通信是一种非常迂回的方法。我只是直接从C代码p/调用DLL。你似乎认为这是不可能的,但这很简单

[DllImport(@"mydll.dll")]
static extern IntPtr GetDeviceChannelInfo_HSI(
    int PortNumber, 
    int Address, 
    int ChNumber,
    ref int State
);
按如下方式调用函数:

IntPtr ptr = GetDeviceChannelInfo_HSI(Port, Addr, Channel, ref State);
string str = Marshal.PtrToStringUni(ptr);
string str = Marshal.PtrToStringAnsi(ptr);
如果函数返回一个UTF-16字符串(这似乎是可疑的),那么您可以如下转换
IntPtr

IntPtr ptr = GetDeviceChannelInfo_HSI(Port, Addr, Channel, ref State);
string str = Marshal.PtrToStringUni(ptr);
string str = Marshal.PtrToStringAnsi(ptr);
或者,如果它实际上是一个ANSI字符串,在我看来很有可能,那么您可以这样做:

IntPtr ptr = GetDeviceChannelInfo_HSI(Port, Addr, Channel, ref State);
string str = Marshal.PtrToStringUni(ptr);
string str = Marshal.PtrToStringAnsi(ptr);

当然,如果返回给您的字符串指针是在堆上分配的,那么您会想调用DLL来释放它。

我改变了对该注释的看法-我将给出一个答案:)

根据该代码,如果“state”是一个代码HSI_NO_ERRORCODE,并且没有异常,那么它将把未初始化的字符串“output”写入控制台。可能是任何东西,包括意外显示“S”和“4”以及一系列1个或多个问号

答案类型(变量)为PChar。对字符串变量使用长度函数。 使用strlen而不是length

 for J := 0 to StrLen(answer)-1 do

PChar(char*)的可访问范围也是0..n-1

不幸的是,这导致我的字符串从???变为????单身?字符。编辑TLDR以更好地反映。感谢您对该问题的尝试。该函数输出一个PChar(PWideChar),它确实包含我需要的文本,但字符编码似乎与Delphi的WriteLn不兼容。所以呢???。根据这些值,它似乎是UTF16的一种形式。您的转换方法无法将UTF16转换为Ansi以供使用。@大卫:我怀疑@Jonneh可能是对的。通常不使用
^
后缀运算符。没有它,您的代码工作得更好@大卫:嗯,我甚至试过了,它在简单的赋值(
Result:=P
)下也能正常工作,但是如果你坚持执行
Result:=P^
,那么
Result
将只包含
P
的第一个字符。这几乎是有道理的,因为如果
P
PWideChar
,那么
P^
WideChar
,也就是说,一个字符。试试看!您希望输出的文本是什么样子的?也许它不能表示为一个AnsiString?例如,Unicode字符串
⌬‽∫∇❦∴φ┶无法“转换”为AnsiString。文本显示为???。一个示例的预期输出是:“ISO 4190250”,但我得到的是“??”。如果我一个字符一个字符地转换,我会得到S和a 4,但是其他的要么是空的,要么会引起奇怪的IO问题。可能是某个地方有一些微妙的错误。我认为您需要显示一个最小的项目(带有代码)来显示这个问题。在我看来是可以的。你只是不知道如何解释结果。你声称你得到了一个PWideChar,但我不认为你真的得到了。您说第一个字符的数值为21321。当解释为两个Ansichar时,即
。您得到的是一个
PAnsiChar
,而不是
PWideChar
。你不需要转换任何东西。您只需修复导入单元即可使用正确的类型,即
PAnsiChar
,而不是
PChar
。制造商为您提供了为Delphi 4编写的代码。在Delphi4中,
PChar
PAnsiChar
相同,因此该版本中的代码是正确的。您正在使用Delphi XE2编译Delphi 4代码,
PChar
的含义是