首页 文章

Delphi Firebird UDF只返回一个char

提问于
浏览
3

我正在使用Firebird 2.5 .

我正在尝试编写一个Delphi XE2 UDF来从一些输入参数返回一些字符串 .

这是Delphi中的函数:

function  FormatRasaSingle(var formatRasa : PChar; var aDenumire : PChar; var aCod : PChar; var aSimbol : PChar; var aTulpina : PChar) : PChar;
var tmpString  : String;
    tmpInteger : Integer;
begin
  tmpString := formatRasa;
  tmpString := StringReplace(tmpString, '#DENUMIRE', aDenumire, [rfReplaceAll, rfIgnoreCase]);
  tmpString := StringReplace(tmpString, '#COD', aCod, [rfReplaceAll, rfIgnoreCase]);
  tmpString := StringReplace(tmpString, '#SIMBOL', aSimbol, [rfReplaceAll, rfIgnoreCase]);
  tmpString := StringReplace(tmpString, '#TULPINA', aTulpina, [rfReplaceAll, rfIgnoreCase]);
  tmpString := 'MAMA';
  tmpInteger := Length(tmpString) + 1;
  Result     := ib_util_malloc(tmpInteger);
  StrPCopy(Result, tmpString);
end;

udf声明是:

DECLARE EXTERNAL FUNCTION FORMATRASASINGLE
    CSTRING(255),
    CSTRING(255),
    CSTRING(255),
    CSTRING(255),
    CSTRING(255)
RETURNS CSTRING(255) FREE_IT
ENTRY_POINT 'FormatRasaSingle' MODULE_NAME 'eliteSoftFirebird';

当我试图测试功能结果时只有第一个字母“M” .

线条

tmpString := 'MAMA';

仅供测试 . 真正的代码就在这一行之前 .

但是没有用 .

有人可以建议我吗?

哪里出错了?

此外,当我尝试输入一个参数时,我收到一个很大的错误,例如“从连接中读取数据时出错” .

TKS

勒兹万


这个函数必须假设双参数是数字(5,2)?

function  FormatRasaMultiple(const formatRasa, aDenumire, aCod, aSimbol, aTulpina : PAnsiChar; aProcent : Double) : PAnsiChar; cdecl; export;

该函数与previos完全相同但是还有一个数字参数 .

到目前为止(我的旧UDF Firebird 1.5)我使用声明为“var aProcent:Double”,但是当我返回时它没有任何 Value .

UDF声明如下:

DECLARE EXTERNAL FUNCTION FORMATRASAMULTIPLE
    CSTRING(255),
    CSTRING(255),
    CSTRING(255),
    CSTRING(255),
    CSTRING(255),
    NUMERIC(5, 2)
RETURNS CSTRING(255) FREE_IT
ENTRY_POINT 'FormatRasaMultiple' MODULE_NAME 'eliteSoftFirebird';

2 回答

  • 0

    您选择了错误的数据类型jokers .

    StringPCharChar 不是Delphi中的数据类型,而是某些实际数据类型的别名 .

    根据Delphi版本,有时在编译器设置上,这些可以是类型的快捷方式,例如:

    在Delphi 2009中

    • UnicodeStringPWideCharWideChar

    • 默认情况下在Unicode前32位Delphi中: AnsiStringPAnsiCharAnsiChar
      _169_在16位Delphi中或兼容性设置: ShortStringPAnsiCharAnsiChar

    因此,在类型不安全的DLL项目中使用类型别名,您可以认为Delphi编译器会为您选择合适的数据类型 . 这次赌注失败了 .

    WideCharUnicodeString 使用UTF-16字符集,对于非Unicode应用程序(或对于应用程序,通过协议期望非Unicode数据)将看起来像零隔行扫描字符串(在2009年之前的Delphi术语中) 'a'^@'b'^@'c'^@ 而不是 'abc' . 根据ASCIIZ(C)字符串约定,这意味着字符串在第一个字符后结束 .

    因此,您应该在两侧使DLL接口匹配:您的源和Firebird期望 .

    • 如果可能,您可以尝试说Firebird这些字段和结果使用UTF-16字符集,但我怀疑Firebird是否支持它 CSTRING .

    • 您可以使用数据类型 AnsiStringPAnsiCharAnsiChar 根据Firebird DLL期望编写DLL代码

    我还强烈建议你阅读Delphi 2009中有关Unicode的Delphi帮助及其对兼容性的影响,特别是对DLL和指针数学等低级类型不安全的东西 . Google中的主题文章也很少 .

    使用DLL可以删除Delphi编译器的类型安全检查,因此您负责确保DLL APi两侧的相同二进制数据表示 . 类型别名如 stringcharPChar 会使其非常脆弱且容易出错 .


    另外,我看不到您为DLL入口点函数选择的调用约定 . 您是否使用 cdecl 关键字或 stdcallregister 标记了您的功能?通过 c:\Program Files (x86)\Firebird\Firebird_2_1\include\ib_util.pas 判断cdecl约定最有可能是正确的,但您应该查看关于此主题的Firebird手册 .

    http://en.wikipedia.org/wiki/Calling_convention#x86

    这是针对32位代码,但对于64位UDF,可能会要求另外一种约定 .


    现在,更奇怪的是你选择的参数模式 . 您的函数具有 var xxx:pointer 等参数,这意味着双重间接 . 你的函数需要指针 - >指针 - >到字符,这似乎不正确或理性 . 我在函数参数定义中将 var 限定符更改为 const .

    这个样本 - 虽然它被抛弃并且质量有问题(它受到上面提到的头晕别名问题的困扰)也支持 VAR 限定符在这里错误的想法:http://fireudflib.cvs.sourceforge.net/viewvc/fireudflib/src/EMail.pas?view=markup


    把这些点放在一起,我想你的功能应该是这样的

    function FormatRasaSingle(const formatRasa, aDenumire, aCod, aSimbol, aTulpina : PAnsiChar) : PAnsiChar; cdecl; export;
    var tmpString  : AnsiString;
        tmpInteger : Integer;
    begin
      tmpString := 'MAMA';
    
      Assert( SizeOf(tmpString[1]) = SizeOf(byte) );
    
      tmpInteger := Length(tmpString);
    
      Result     := ib_util_malloc(tmpInteger + 1);
      StrPLCopy(Result, tmpString, tmpInteger);
    end;
    

    http://docwiki.embarcadero.com/Libraries/XE3/en/System.SysUtils.StrPLCopy

  • 1

    AFAIR,CSTRING表示空终止的类C字符串,因此您不能使用UTF16相关的数据类型 . 请尝试使用ANSI类型 .

相关问题