天道酬勤,学无止境

How to call Delphi DLL WideString Parameters from C++ (including var parameters)

I have a Delphi DLL that works when called by delphi apps and exports a method declared as:

Procedure ProduceOutput(request,inputs:widestring; var ResultString:widestring);stdcall;

On the C++ side I have tried:

[DllImport( "ArgumentLab.dll", CallingConvention = CallingConvention.StdCall, CharSet=CharSet.WideString )];
 extern void ProduceOutput(WideString request, WideString inputs, WideString ResultString);

WideString arequest = WideString(ComboBox1->Text);
WideString ainput = "<xml> Input Text Goes Here </XML>";
WideString  aresultstring;
WideString &aresultstringpointer = aresultstring;
aresultstring = " ";
ProduceOutput(arequest, ainput, &aresultstringpointer);

Memo1->Lines->Text = aresultstring;

My console error reads:

 Unit1.cpp(13): candidate function not viable: no known conversion from 'BSTR *' (aka 'wchar_t **') to 'System::WideString' for 3rd argument;

I have built the DLL and the c++ test app using Rad Studio XE4 - it is a 64 bit DLL and APP

How should I have gone about doing this?

Best regards,

garry

评论

There is no DllImport in C++. That is for .NET PInvoke instead. So remove that.

The remainder of your C++ function declaration does not match the Delphi function declaration. The correct C++ declaration is as follows:

void __stdcall ProduceOutput(WideString request, WideString inputs, WideString &ResultString);

Don't forget to statically link to the DLL's import .LIB file (which you can create using C++Builder's command-line IMPLIB.EXE tool, if needed).

Then, in the app's code, you can call the DLL function like this:

WideString arequest = ComboBox1->Text;
WideString ainput = "<xml> Input Text Goes Here </XML>";
WideString aresultstring;
ProduceOutput(arequest, ainput, aresultstring);

Memo1->Lines->Text = aresultstring;

The reason you are getting the conversion error is because the WideString class overrides the & operator to return a pointer to its internal BSTR member. The reason for this is to allow WideString to act like a smart wrapper class for ActiveX/COM strings, eg:

HRESULT __stdcall SomeFuncThatReturnsABStr(BSTR** Output);

WideString output;
SomeFuncThatReturnsABStr(&output);

As such, it is not possible to obtain a pointer to a WideString itself using the & operator. Because of that, the only way (that I know of) to get a real WideString pointer is to dynamically allocate the WideString, eg:

WideString *pStr = new WideString;
...
delete pStr;

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 为什么不能将WideString用作互操作的函数返回值?(Why can a WideString not be used as a function return value for interop?)
    问题 我不止一次建议人们为互操作目的WideString类型的返回值。 访问Delphi DLL引发特殊异常返回PChar字符串时,ASP.NET Web应用程序在IIS Web服务器上调用Delphi DLL时被锁定为什么在不使用ShareMem的情况下Delphi DLL可以使用WideString? 这个想法是WideString与BSTR相同。 由于BSTR是在共享COM堆上分配的,因此在一个模块中分配和在另一个模块中取消分配是没有问题的。 这是因为各方都同意使用相同的堆,即COM堆。 但是,似乎WideString不能用作互操作的函数返回值。 考虑下面的Delphi DLL。 library WideStringTest; uses ActiveX; function TestWideString: WideString; stdcall; begin Result := 'TestWideString'; end; function TestBSTR: TBstr; stdcall; begin Result := SysAllocString('TestBSTR'); end; procedure TestWideStringOutParam(out str: WideString); stdcall; begin str :=
  • 将参数从 Delphi 5 传递到 Delphi DLL XE(Passing parameters from Delphi 5 to Delphi DLL XE)
    问题 我有一个 Delphi 5 应用程序,在应用程序代码中调用 DLL 中的一个函数,传递整数和字符串参数,这在以静态方式调用 DLL 时效果很好,当我尝试动态更改时不起作用。 传递参数以动态运行的正确方法是什么? 代码如下 主要应用 function Modulo_Pptos_Operacion(No_Orden : Integer; pathBD : string; PathBDConf : String) : Integer ; stdcall; external 'LIB_Pptos_Oper.dll'; Modulo_Pptos_Operacion(DmDatos.OrdenesNO_Orden.AsInteger, DmDatos.CiasPATHA.AsString, 'Alguna String'); 动态链接库 Modulo_Pptos_Operacion function (No_Orden: Integer; PathDB: AnsiString; PathDBConfig: AnsiString): Integer; StdCall; 动态碰撞主要应用 type TDLLPpto = function(No_Orden : Integer; PathDB : AnsiString; PathDBConfig : AnsiString) : Integer
  • Why can a WideString not be used as a function return value for interop?
    I have, on more than one occasion, advised people to use a return value of type WideString for interop purposes. Accessing Delphi DLL throwing ocasional exception ASP.NET web app calling Delphi DLL on IIS webserver, locks up when returning PChar string Why can Delphi DLLs use WideString without using ShareMem? The idea is that a WideString is the same as a BSTR. Because a BSTR is allocated on the shared COM heap then it is no problem to allocate in one module and deallocate in a different module. This is because all parties have agreed to use the same heap, the COM heap. However, it seems that
  • Delphi 和 C/C++ DLL Struct vs.Record(Delphi and C/C++ DLL Struct vs.Record)
    问题 我之前问过一个关于 delphi 和 C/C++ DLL 的问题。 我现在有另一个关于记录/结构的问题。 DLL 应该能够从 MainAPP 动态更改指针变量的值。 我的delphi MAINAPP有以下记录: type MyRec = record MyInteger : Pointer; MyWideString : pwidechar; MyString : pchar; MyBool : Pointer end; type TMyFunc = function ( p : pointer ): pointer; stdcall; procedure test; var MyFunction : TMyFunc; TheRecord : MyRec; AnInteger : Integer; AWideString : WideString; AString : String; ABool : Bool; begin AnInteger := 1234; AWideString := 'hello'; AString := 'hello2'; ABool := TRUE; TheRecord.MyInteger := @AnInteger; TheRecord.MyWideString := pwidechar(AWideString); TheRecord
  • Delphi:从导出接口/类的 vc++ dll 调用函数(Delphi: Calling a function from a vc++ dll that exports a interface / class)
    问题 我在访问用 vc++ 编写的导出接口的 dll 时遇到了一些麻烦。 首先我尝试使用类,但经过一些谷歌搜索后,我找到了解决方案,这是不可能的。 我只想确保可以使用其他语言(如 c++)访问插件界面。 德尔福界面 IPlugIn = interface function GetName: WideString; stdcall; end; Delphi 插件调用 procedure TForm1.Button5Click(Sender: TObject); var hLib: Cardinal; MLoadPlugIn: TLoadPlugIn; PlugIn: IPlugIn; begin hLib := LoadLibrary('PluginB.dll'); try if not(hLib = 0) then begin @MLoadPlugIn := GetProcAddress(hLib, 'LoadPlugIn'); if not(@MLoadPlugIn = nil) then begin if MLoadPlugIn(PlugIn) then try ShowMessage(PlugIn.GetName); // here i get the access-violation using the vc++ plugin finally // i get the
  • 在Delphi程序中托管.NET运行时(Hosting the .NET runtime in a Delphi Program)
    问题 我一直在寻找在Delphi程序中使用一些.NET代码的方法,我需要使用.net程序集和预定义的函数(我已经支持常规DLL)使程序具有可扩展性。 在网上进行了大量搜索之后,我找到了Managed-VCL,但是我还没有准备好为自己需要的东西支付250美元,我还发现一些新闻组的代码不完整且无法正常工作。 我正在使用Delphi 2007 for win32。 我可以使用什么从具有预定义参数的程序集中动态执行功能? 就像是: procedure ExecAssembly(AssemblyFileName:String; Parameters: Variant); 我只想补充一点,我需要能够加载任意程序集(也许所有程序集都位于特定文件夹中),因此创建C#包装器可能行不通。 回答1 在免费的Jedi代码库(JCL)中,有一个JclDotNet.pas,其中包含类TJclClrHost,它可能会执行您想要的操作: TJclClrHost = class(TJclClrBase, ICorRuntimeHost) private FDefaultInterface: ICorRuntimeHost; FAppDomains: TObjectList; procedure EnumAppDomains; function GetAppDomain(const Idx: Integer)
  • 在Freepascal编译的DLL和Delphi编译的EXE之间交换字符串(PChar)(Exchanging strings (PChar) between a Freepascal compiled DLL and a Delphi compiled EXE)
    问题 经过大量的实验,我找到了一种从FreePascal编译的DLL与Delphi编译的EXE交换PChar的方法。 我负责DLL和EXE源代码,但其中之一必须在FreePascal中,而另一则必须在Delphi中。 我的解决方案涉及DLL中的以下方法: function GetAString(): PChar; var aString: string; begin aString := 'My String'; result := StrAlloc(length(aString) + 1); StrPCopy(result, aString); end; procedure FreeString(aString: PChar); begin StrDispose(aString); end; 在Delphi EXE中,要调用GetAString方法,我需要调用GetAString方法,将PChar保存到实际的Delphi String中,然后调用FreeString方法。 这是用Delphi EXE从FreePascal DLL交换字符串的最佳方法吗? 我可以避免从Delphi调用FreeString吗? 最后,如果这是正确的解决方案,则默认情况下,它将与Delphi 2010和WideString一起表现如何:我也需要在FreePascal中强制WidePChar吗? 回答1
  • 调用Delphi dll函数时的PInvokeStackImbalance(PInvokeStackImbalance when calling Delphi dll function)
    问题 一个(非 COM)Delphi dll 有一个被导出的函数: function GetQuestions(Digit1, Digit2: string; CountryISO: string):string; 我已将此 dll 添加为 Visual Studio 2012 中的现有项目,并将其Build Action设置为None , Copy to Output Directory为Copy Always 。 包含DllImportAttribute的类: public class RefundLibrary { [DllImport("RefundLibrary.dll", EntryPoint = "GetQuestions", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr GetQuestions(string digit1, string digit2, string countryISO); } 当我在 WebForm 的Page_Load中调用此方法时(不确定是否相关),它会在以下指示的行上抛出PInvokeStackImbalance以表示可能的签名不匹配: protected void Page_Load
  • Call dotNET from Delphi and return a string
    How does a Delphi application call an exported function (non-COM) dotNET assembly and have the function return a string? COM is not a possible solution for my particular application. I have control over both ends of the call. What I have tried so far - Delphi client side type TStrProc = procedure( var x: widestring); stdcall; function TryIt: string; var Handle: THandle; Proc: TStrProc; InData: widestring; OutData: widestring; begin Handle := LoadLibrary( 'DelphiToDotNet.dll'); if Handle = 0 then exit; @Proc := GetProcAddress( Handle, 'StrProc'); if @Proc <> nil then begin InData := 'input'
  • 在 Delphi 中从 C++ DLL 调用函数(Calling functions from a c++ DLL in Delphi)
    问题 我在 VS2010 中创建了一个新的 c++ DLL 项目,它公开了 1 个函数 #include "stdafx.h" #define DllImport extern "C" __declspec( dllimport ) #define DllExport extern "C" __declspec( dllexport ) DllExport int DoMath( int a, int b) { return a + b ; } 然后我用 VS2010 创建了一个 C++ 应用程序来测试这个 DLL。 在VS2010中构建的测试应用程序可以调用c++ DLL并得到预期的结果。 #include "stdafx.h" #include <windows.h> typedef int (*DoMath)(int, int) ; int _tmain(int argc, _TCHAR* argv[]) { HMODULE hMod = LoadLibrary ("exampleDLL.dll"); if (NULL != hMod) { DoMath mf1 = (DoMath) GetProcAddress(hMod,"DoMath"); if( mf1 != NULL ) { printf ("DoMath(8,7)==%d \n", mf1(8,7) ); }
  • Why can Delphi DLLs use WideString without using ShareMem?
    David's answer to another question shows a Delphi DLL function returning a WideString. I never thought that was possible without the use of ShareMem. My test DLL: function SomeFunction1: Widestring; stdcall; begin Result := 'Hello'; end; function SomeFunction2(var OutVar: Widestring): BOOL; stdcall; begin OutVar := 'Hello'; Result := True; end; My caller program: function SomeFunction1: WideString; stdcall; external 'Test.dll'; function SomeFunction2(var OutVar: Widestring): BOOL; stdcall; external 'Test.dll'; procedure TForm1.Button1Click(Sender: TObject); var W: WideString; begin ShowMessage
  • Delphi communication with C++ dll (parameters)
    Hi I'm having quite some issues with integrating a DLL inside my Delphi 2007 application. i suspect that I'm doing something wrong with the parameters of the calls. At this moment i have 2 issues, but i think they are related to eachother. 1) First call with the DLL: from the .h file: extern "C" { __declspec(dllexport) HRESULT Startup(char* version); } This call should initialize the DLL and give me the version back of the DLL. HRESULT should be 0, and the version pointer should contain the version. My Delphi code: function Startup(var version: Pchar): HRESULT; cdecl; stdcall; external 'myDLL
  • Delphi's Sharemem - When it is not needed
    I know that when I share strings between a Delphi APP and a Delphi DLL I need to add Sharemem in both app and dll project source as the first unit in uses clause. But, if the dll exports function that accept only Pchars but inside some of the dll methods I use strings, should I use sharemem as well? Let me shown a sample code: procedure ShowMyCustomMessage(aMessage : Pchar); var vUselessString : string; begin vUselessString := aMessage; ShowMessage(vUselessString); end; exports ShowMyCustomMessage; In that simple and useless case, the dll is accepting a Pchar but inside the exported method the
  • 将记录作为函数结果从 Delphi DLL 传递到 C++(Passing record as a function result from Delphi DLL to C++)
    问题 我现在正在经历一些非常奇怪的事情。 当我将结构从 C++ 传递到 Delphi DLL 作为参数时,一切正常。 但是,一旦我想收到一条记录,我要么得到错误的值,要么得到异常。 我停用了记录的对齐方式,以便通过它们应该可以工作! 代码如下! 德尔福DLL: TSimpleRecord = packed record Nr1 : Integer; Nr2 : Integer; end; //... function TTest() : TSimpleRecord; cdecl; begin Result.Nr1 := 1; Result.Nr2 := 201; ShowMessage(IntToStr(SizeOf(Result))); end; C++ 调用: #pragma pack(1) struct TSimpleRecord { int Nr1; int Nr2; }; //... typedef TSimpleRecord (__cdecl TestFunc)(void); TestFunc* Function; HINSTANCE hInstLibrary = LoadLibrary("Reactions.dll"); if (hInstLibrary) { Function = (TestFunc*)GetProcAddress(hInstLibrary,
  • 在带有/不带有JCL的Delphi中托管CLR-示例(Hosting CLR in Delphi with/without JCL - example)
    问题 有人可以在这里发布示例如何在Delphi中托管CLR吗? 我在这里读过类似的问题,但是由于要在Delphi 5中托管它,所以无法使用JCL。谢谢。 编辑:这篇关于在Fox Pro中托管CLR的文章看起来很有希望,但我不知道如何从Delphi访问clrhost.dll。 编辑2:我放弃了Delphi 5的要求。 现在,我正在尝试使用Delphi 7进行JCL。但是,我再也找不到任何示例。 这是我到目前为止所拥有的: 我的C#程序集: namespace DelphiNET { public class NETAdder { public int Add3(int left) { return left + 3; } } } 我已经将其编译为DelphiNET.dll 。 现在,我想使用来自Delphi的该程序集: uses JclDotNet, mscorlib_TLB; procedure TForm1.Button1Click(Sender: TObject); var clr: TJclClrHost; ads: TJclClrAppDomainSetup; ad: TJclClrAppDomain; ass: TJclClrAssembly; obj: _ObjectHandle; ov: OleVariant; begin clr := TJclClrHost
  • 是否有必要在Delphi中将字符串转换为WideString?(Is it necessary to convert string to WideString in Delphi?)
    问题 我发现一个Windows API函数执行字符串的“自然比较”。 它的定义如下: int StrCmpLogicalW( LPCWSTR psz1, LPCWSTR psz2 ); 为了在Delphi中使用它,我这样声明: interface function StrCmpLogicalW(psz1, psz2: PWideChar): integer; stdcall; implementation function StrCmpLogicalW; external 'shlwapi.dll' name 'StrCmpLogicalW'; 因为它比较Unicode字符串,所以我不确定要比较ANSI字符串时如何调用它。 将字符串转换为WideString然后转换为PWideChar似乎就足够了,但是,我不知道这种方法是否正确: function AnsiNaturalCompareText(const S1, S2: string): integer; begin Result := StrCmpLogicalW(PWideChar(WideString(S1)), PWideChar(WideString(S2))); end; 我对字符编码了解得很少,所以这就是我提出问题的原因。 这个函数可以吗,还是我应该先转换两个比较的字符串? 回答1 请记住
  • Delphi的字符(Char),字符串(String),字符串指针(PChar),字符数组arrayofchar
    Delphi有三种类型的字符:AnsiChar这是标准的1字节的ANSI字符,程序员都对它比较熟悉。WideChar这是2字节的Unicode字符。Char在目前相当于AnsiChar,但在Delphi 2010 以后版本中相当于WideChar.记住因为一个字符在长度上并不表示一个字节,所以不能在应用程序中对字符长度进行硬编码,而应该使用Sizeof()函数。注意Sizeof()标准函数返回类型或实例的字节长度。Delphi有下列几种不同的字符串类型 String:ShortString保留该类型是为了向后兼容 Delphi1.0,它的长度限制在255个字符内。 ShortString[0] = len : $H- 代表 ShortStringAnsiString是Pascal缺省的字符串类型,它由AnsiChar字符组成,其长度没有限制,同时与null结束的字符串相兼容。<Delphi2.0开始引入> : $H+ 代表 AnsiStringWideString功能上类似于AnsiString,但它是由WideChar字符组成的。WideString没有引用计数,所以将一个WideString字符串赋值给另一个WideString字符串时,就需要从内存中的一个位置复制到另一个位置。这使得WideString在速度和内存的利用上不如AnsiString有效。缺省情况下
  • 我的班级实例中出现奇怪的内存覆盖问题(Strange memory overwrite problem in instance of my class)
    问题 这个问题与我之前问过的这个问题有关。 @RRUZ 提供的代码正在运行,但似乎不太正确,或者我做错了什么。 执行GetSharedFiles后, TMyObject实例中发生了奇怪的事情。 FMyEvent是(并且应该是)nil 的字段指向一些随机数据。 我在 5 分钟前发现的是,如果我关闭编译器选项中的优化,它在重建后工作正常。 所以也许这是一些编译器错误? 这是代码快照(Delphi 2009 Windows 7 64 位): unit Unit17; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm17 = class(TForm) btnetst: TButton; procedure btnTestClick(Sender: TObject); private { Private declarations } public { Public declarations } end; type TMyEvent = procedure(Sender: TObject) of object; type TMyObject = class(TObject) private FMyEvent
  • 托管调试助手 'PInvokeStackImbalance' 检测到一个......关于平凡的方法(Managed Debugging Assistant 'PInvokeStackImbalance' has detected a... on trivial method)
    问题 我从 C# 调用 Delphi 函数并得到错误: 托管调试助手“PInvokeStackImbalance”在...中检测到问题 我已经竭尽全力改变 .Net 代码以适应 Delphi 签名,为什么它不能与基本的整数一起工作让我难倒,有谁知道我哪里出错了? 即使是使用 2 个整数的最简单函数也会产生错误。 我的目标是 x86 并进行了几个小时的研究,但以下解决方案在这里、这里、这里和这个都没有帮助。 这是 Delphi 代码(编译后的 DLL 版本可以从这里下载): unit PasBallEntry; interface procedure EntryPoint( InInt: integer; InStr: PChar; var OutInt: integer; var OutStr: PChar); stdcall; procedure ReleaseString( OutStr: PChar); stdcall; procedure TimTamC( InInt: integer; InStr: PChar; var OutInt: integer; var OutStr: PChar); cdecl; procedure ReleaseStringC( OutStr: PChar); cdecl; procedure TimTamCS( InInt: integer
  • 通过回调从Inno Setup调用C#DLL(Call C# DLL from Inno Setup with callback)
    问题 我有一个正在运行的Inno Setup脚本,其中使用了Sherlock Software的innocallback.dll。 该DLL包装了我的过程,以便可以将其传递给C#DLL。 我不想使用此DLL,我想直接调用导出的C#方法并将其传递给回调过程。 我的问题是: 如何将我的Inno Setup过程( @mycallback )传递给C#DLL,以便可以将其用作我的delegate / UnmanagedFunctionPointer ? 正如我说的那样,该代码有效,但是我想使用尽可能少的外部DLL。 这是我的代码: Inno安装脚本 type TTimerProc=procedure(); TProgressCallback=procedure(progress:Integer); function WrapProgressProc(callback:TProgressCallback; paramcount:integer):longword; external 'wrapcallback@files:innocallback.dll stdcall'; function Test(callback:longword): String; external 'Test@files:ExposeTestLibrary.dll stdcall'; var endProgram