【问题标题】:Passing binary data from Qt/C++ DLL into Delphi host application将二进制数据从 Qt/C++ DLL 传递到 Delphi 主机应用程序
【发布时间】:2012-09-07 06:37:36
【问题描述】:

在我想在 Delphi 中使用 QImage.bits() 的程序中。因此,在 Qt 中,我创建了一个 dll。下面列出的dll源代码:

test.h:

  #ifndef TEST_H
    #define TEST_H

    #include "test_global.h"


    extern "C"{
    TESTSHARED_EXPORT uchar* testFunc();
    }


    #endif // TEST_H

test.cpp:

 #include "test.h"
#include <QtGui>

QImage image;

uchar* testFunc(){
    image.load("c:\\1.png","PNG");
    return (uchar*)image.constBits();
}

在 Delphi 端,我使用此代码来使用 Qt dll:

    function testFunc(): PByteArray; external 'test.dll';
// ...

procedure TForm3.Button1Click(Sender: TObject);
var
  bStream: TBytesStream;
  P: PByteArray;
  Size: Cardinal;
begin
  P := testFunc;
  Size := Length(PAnsiChar(P)); // AnsiChar = 1 Byte
  bStream := TBytesStream.Create();
  try
    bStream.Write(P[0], Size); // Works Fine (^_^)
    bStream.Position := 0;
    bStream.SaveToFile('c:\scr.txt');
  finally
    bStream.Free;
  end;
end;

当我调用 dll 函数时没有返回任何数据! 你能帮帮我吗?

更新 1: 在实际情况下,我的 Qt 函数非常复杂,由于多种原因,我无法在 Delphi 中编写它。事实上,原始函数从设备中获取屏幕截图并在主内存中处理它。因此,我想将此图像字节发送到 Delphi,以便在 TImage 上显示它,而不将它保存在硬盘和类似的内存上。在本主题中,我刚刚创建了一个简单的类似函数,用于简单的调试和可测试性。是否可以通过为这个问题编写一个真正简单的代码来帮助我?非常感谢你。 (-_-)

【问题讨论】:

  • 这里不需要 Qt。你可以从 Delphi 读取 PNG 文件。
  • 为什么会弄乱 TByteStream ?为什么不直接使用 TFileStream 呢?
  • 回答“Arioch The”问题:但在实际情况下,不存在从设备返回的任何 png 图像文件和图像。因此,为了减少响应时间,我不能使用任何文件,并且我的应用程序必须使用主内存来加载图像数据并显示它。我的 Qt 函数非常复杂,我无法将其转换为 delphi 源代码。
  • 回答“大卫赫弗南”:我知道。但是这个源代码是对我真正问题的简单模拟。
  • 好的,那么您只需要正确调用约定并将uchar* 映射到PByte。就是这样。

标签: c++ delphi qt dll qimage


【解决方案1】:

更直接的方法是使用 PByte aka ^Byte,而不是 PByteArray。 虽然 TByteArray 是静态类型,但仍然使用数组会增加随机拼写错误的风险,就像使用动态数组一样。


不要使用 PChar - 它会在第一个零字节处停止。图片不是字符串,它可以包含数百个零。

您应该将长度作为单独的变量/函数发送。 int QImage::byteCount () 常量 http://qt-project.org/doc/qt-4.8/qimage.html#byteCount


请编辑您的问题。你问的是 bits 还是 constbits ?这些是不同的属性!


还有:

您应该了解编译器、C++ 和 Pascal 中的“调用约定”。 您最好能够在汇编程序级别对其进行跟踪。

尝试在 Pascal 代码中使用“cdecl”指令标记该过程,或者在 C 和 Pascal 代码中使用“stdcall”指令。

尝试使用 FreePascal 的 h2pas 实用程序进行自动转换。


现在最重要的是 - 将 Qt 放在这里。仅仅为了读取 PNG 文件而制作 Qt 桥是非常奇怪和脆弱的。有许多支持 PNG 的原生 Delphi 库。几个例子:

【讨论】:

  • 你对PByteArray的理解是错误的。它不是指向记录的指针。它是一个指向普通数组的指针。 声明表示指向的数组包含 MaxInt 元素,但这实际上只是为了满足编译器可能发出的范围检查代码,这对于那种数组指针没有用处。实际上,数组可以有任意长度。该问题不涉及动态数组。
  • 我认为我的回答比 Arioch 的回答要好。但我无法将自己的答案作为最终结果。所以我检查了 Arioch 的帖子作为最终答案。
  • @Rob 好吧,然后我的记忆欺骗了我。是的,它不是动态数组。但是为什么“没有返回任何数据”?这应该意味着最多的第一个字节已经为零?即使我们跳过 PNG 标头——我真的对 Qt 一无所知,而 topicstarter 混合了两个不同的属性——第一个像素正好为 0 的概率似乎并不大。
  • @Shuhin_Ashayeri 您可以在几天内检查自己的答案。 AFAIR 应该写在你的尝试上。您的回答显示了要做什么,但既没有说明发生了什么变化,也没有说明原因。想象一下对 C++ 和 Pascal 知之甚少的人。他是否能够检查所有几乎完全重做的代码并了解哪些更改很重要以及为什么它们很重要?我怀疑。坦率地说,我们的回答是免费的。如果您要突出显示并解释代码中的更改,那将是最有用的答案。
【解决方案2】:

问题解决了。 (^_^)

为了解决它:

在 Qt 端:

test.h:

#ifndef TEST_H
#define TEST_H

#include "test_global.h"


extern "C"{
TESTSHARED_EXPORT char* testFunc(int &a);
}


#endif // TEST_H

test.cpp:

#include "test.h"
#include <QtGui>

QImage image;
QByteArray ba;


char* testFunc(int &a){
    image.load("c:\\2.png","PNG");
    QBuffer buffer(&ba);
    buffer.open(QIODevice::WriteOnly);
    image.save(&buffer,"PNG");
    a = ba.size();
    return ba.data();
}

在德尔福方面:

function testFunc(var aByteCount: DWORD): PByte;cdecl external 'test.dll';

// ...
var
  bStream: TBytesStream;
  Size: DWORD;
procedure TForm3.Button1Click(Sender: TObject);
var
  P: PByte;
  s: TStringList;
begin
  Caption := '0';
  P := testFunc(Size);
  bStream := TBytesStream.Create();
  try
    bStream.Write(P[0], Size);
    bStream.Position := 0;
    bStream.SaveToFile('c:\my.png');
  finally
    Caption := IntToStr(Size);
  end;
end;

再次感谢“Arioch The”和“David Heffernan”。 (^_^)

【讨论】:

  • @David 他的回答具有作为工作代码的价值。虽然我同意 SO 精神这样的代码示例最好在原始问题中作为更新 2 附加,而不是独立答案。
  • @Arioch'The 显然 Shuhin 还没有完全了解 SO 的工作原理。我正在尝试帮助他/她如何接受答案。
  • 不,@Arioch,它不属于问题的更新。这不是问题的一部分。它属于一个答案。由于您没有在 your 答案中放入工作代码来解决问题,因此 Shuhin 将其放入他自己的答案中。如果能证明这一点,您的答案会更好,因为原始代码中唯一真正的问题是确定缓冲区长度的方法。
  • @Rob,Ahem,绝对错误的数据类型,可能会导致 AV 或(如果尝试就地编辑)内存损坏 - 这对您来说不算重要问题?嗯,是。答案由“如何”和“什么”组成。我更喜欢“如何”部分。我不太关心复制粘贴猴子,并认为制作你自己的实现比复制粘贴更能教你。但我同意代码示例也有其价值。我也从未使用过 Qt,所以我既不能测试代码,也不能依赖我的经验。并将可能仅根据常识起作用的假设代码发布为“答案”,不
  • @Rob 在Q中的代码中,存在调用约定不匹配、类型不匹配、缺少数据长度参数。 Arioch 明白了一切,即使文字本可以更清晰。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
  • 2011-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多