Delphi Firebird UDF 仅返回一个字符

标签 delphi delphi-xe2 user-defined-functions firebird2.5

我使用的是 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';

仅用于测试。真正的代码在这一行之前。

但不起作用。

有人能给我建议吗?

错在哪里?

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

谢谢

拉兹万

<小时/>

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

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

该函数与之前的函数完全相同,但多了一个数字参数。

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

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';

最佳答案

您选择了错误的数据类型 clown 。

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

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

  • 在 Delphi 2009+ 中:UnicodeStringPWideCharWideChar
  • 默认情况下,在 Unicode 之前的 32 位 Delphi 中:AnsiStringPAnsiCharAnsiChar
  • 在 16 位 Delphi 中或具有兼容性设置:ShortStringPAnsiCharAnsiChar

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

WideCharUnicodeString 使用 UTF-16 字符集,对于非 Unicode 应用程序(或对于协议(protocol)期望非 Unicode 数据的应用程序)来说,它看起来为零 -交错字符串,如(2009 年以前的 Delphi 术语)'a'^@'b'^@'c'^@ 而不是 'abc'。根据 ASCIIZ (C) 字符串约定,这意味着字符串在第一个字符之后结束。

因此,您应该使 DLL 接口(interface)在双方上都匹配:您的来源和 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

关于Delphi Firebird UDF 仅返回一个字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16003652/

相关文章:

r - 我可以在用户定义的函数中使用 ggplot() 在单个图中绘制多个函数曲线吗?

ColdFusion - 替换值以格式化段落的最佳方法是什么?

windows - Windows 7 上的 DataSnapXE2 正常断开连接

mysql - Mysql存储函数和groupwise min

delphi - 如何将 DLL 中的表单嵌入到 Inno Setup 向导页面中?

delphi - Delphi TLabel 标题中制表符的行为是否已定义?

delphi - T图像未显示

multithreading - 将事件从主线程传递到工作线程并等待它是否安全?

delphi - Delphi IDE导致CPU过热

delphi - 如何保存 Tlistview 布局