vb6 dll In Delphi - delphi

I have written a VB6 dll with this code
Public Function RegGetStr(ByRef FullLocation_Name As String) As String
Dim oReg As Object
Set oReg = CreateObject("WScript.Shell")
RegGetStr = oReg.RegRead(FullLocation_Name, "REG_SZ")
Set oReg = Nothing
End Function
In Delphi I have library working
type
TRegGetStr = Function(Const FullLocation_Name: String): String; StdCall;
var
aRegGetStr: TRegGetStr;
and
#aRegGetStr := Windows.GetProcAddress(LibHandle, 'RegGetStr');
I have a crash
Is it because of the types of strings I'm using? or something else?

Your question asked about calling a VB DLL from Delphi.
VB6, out of the box, creates ActiveX dll's (created as an ActiveX DLL project)
How can I create a standard DLL in VB6? Look at the answer there describing ActiveX DLL.
While you can create standard DLL's in VB6 you have to go spelunking. It does not support that out of the box and is not recommended.
You would consume that VB ActiveX DLL just as you would any ActiveX dll in Delphi.
Deplhi Import Component - Type Library vs ActiveX
=====
IF, on the other hand, you are trying to call an external DLL (e.g. written in Delphi) FROM a VB application, you would create the Delphi function with pAnsiChar parameters for strings. Ex: in MyDelProcs.dll:
procedure MyDelProc(pStr1: pAnsiChar, MyInt: integer);stdcall;
.......................
exports
MyDelProc;
On the VB side you would then declare the procedure as
Declare Sub MyDelProc Lib "MyDelProcs.dll" (ByVal sStr1 as String, MyLong As Long)
Then call the procedure with
Call MyDelProc(sStr1, MyLong)
Some notes:
sStr1 is Unicode internal to VB, but on the call is converted to AnsiString. The ansistring has a chr(0) added to the end and moved to a buffer which is the length of the ansistring plus the chr(0).
Take care with other parameter types. Default Integer in VB is 2 bytes, default integer in Delphi is 4, which is equivalent to a Long type in VB.
If your Delphi function needs to know the length, pass it as another (long/integer) parameter.
The string buffer is fixed in size. If you are returning a string of longer length then either pad the original string with enough room, or pass a longer dummy string with enough length for the return.
Upon return the string is treated as ansistring. It will be converted back to Unicode to be placed into a VB internal string.

Related

how can i return pchar type from delphi dll function? [duplicate]

This question already has answers here:
How can I return a PChar from a DLL function to a VB6 application without risking crashes or memory leaks?
(7 answers)
Closed 8 years ago.
Vb6 code to run on the following error.
How can I fix the error?
How can I return a normal string?
vb6 code
Private Declare Function DllPchar Lib "C:\TEST\Project2.dll" (ByVal AStr As String) As String
Private Sub Command10_Click()
Dim tmp as String
tmp = DllPchar("123");
End Sub
Delphi7 code
function DllPchar( AStr: PChar) : PChar; stdcall;
Well, you haven't given much information about this problem. For instance, the error message. And the Delphi code for "DllPChar".
But never mind. The first thing I notice is that your Declare Function statement is returning a String. This will not work because VB is expecting a value of type BSTR to be returned. Delphi has a WideString type which is compatible with BSTR.
The reason why this is important is because VB strings are internally UTF-16, i.e. 2 byte per character Unicode Strings that are allocated by the COM memory manager. The Delphi PAnsiChar type is a pointer to an 8-bit ANSI character, and Delphi strings are allocated by Delphi's own memory manager. They are incompatible. However, there is a special case in VB6 where you can use Declare Function with a parameter ByVal ... As String, and VB handles and automatic conversion between a VB string and PAnsiChar before the call, and then between PAnsiChar and VB string after the call.
If you can't use BSTR in Delphi, your best bet is to rewrite DllPchar() so that it modifies the AStr parameter. Or alternatively, create a new parameter to return the value in.
If you can use BSTR, then you can modify AStr to pass it ByRef rather than ByVal. This will allow you to pass in a Unicode string from VB. You then return your result via the return value.

Send a String parameter from vfp 9 to a dll created on delphi 2007

I'm trying to use Delphi's DLL from Visual FoxPro 9 by passing string from VFP to Delphi's DLL. The Foxpro Crashes once I run the VFP code. My string values are under 254 characters.
Including ShareMem in delphi's code does not make any difference. It seems like the wrong string type is being used and I really don't know other types of string to code.
Please help me with an example on how to pass string.
The dll code works fine within Delphi.
in delphi's DLL...
library dll_examp_With_PARA;
uses
ShareMem,
SysUtils,
Classes,
Dialogs;
{$R *.res}
function showValues(var a:shortstring):shortstring; stdcall; export;
begin
Result:=('you passed ' + a);
end;
exports showValues;
end.
in VFP.....
CLEAR ALL
LOCAL vfpString as String
DECLARE STRING showValues IN dll_examp_With_PARA.dll STRING
vfpString = 'Hello World!'
? showValues(vfpString)
CLEAR ALL
That DLL cannot be called from Foxpro. You will have to modify the DLL or wrap it with an adapter. The problem is that you are using a private Delphi string type that is not suitable for interop. You have to understand that different languages have different ways to represent character data. For binary interop both sides must use the same representation.
Strings are passed from Foxpro as pointers to null-terminated arrays of 8 bit ANSI characters. In Delphi that is PAnsiChar. That will allow you to pass a string from Foxpro to Delphi. In the other direction you need the Foxpro code to allocate a sufficiently large enough string. And then the Delphi code can copy the text into the memory provided by Foxpro. You will therefore want to also pass the length of the out string buffer so that the Delphi code can avoid writing beyond the end of the buffer.
Adding Sharemem cannot help. That allows two Delphi modules to share the same native Delphi heap. Interop is difficult. You won't get anywhere with trial and error.

Delphi 7 calling DelphiXE2 dll getting corrupt widestrings

I have a Delphi 7 application that needs to call a SOAP API that is much too new for the available SOAP importers. I have satisfied myself that D7 can't call the SOAP API without too much effort to be worth while. But I also have Delphi XE2, and that can import the SOAP and call it quite happily. So I have written a simple dll wrapper in XE2 that exposes the necessary parts of the soap interface. I can call the dll from an XE program.
In Delphi7 I took the SOAP API import file from XE, stripped out the {$SCOPED_ENUMS ON} defines and the initialization section that calls unavailable SOAP wrappers, plus changed string to widestring throughout. That compiles. I'm using FastMM with ShareMM enabled to make string passing work and avoid making everything stdcall.
The reason I'm trying to do it this way is that if it works it will make the SOAP shim very easy to code and maintain, since 90% of the code is generated by the XE2 SOAP importer, and it will mean that when we move the D7 app to a modern Delphi the code will remain largely unchanged.
But when I run it, I get weird strings (and consequent access violations). I've got simple functions that don't use the SOAP code to make the problem more obvious.
Passing a widestring from Delphi7 exe into DelphiXE2 dll the string length is doubled (according to the Length() function), but there's no matching data conversion. So a widestring "123" in D7 becomes "1234...." in XE2, where the .... is whatever garbage happens to be on the stack. Viewed as byte arrays both have half zero bytes as expect.
Passing a widestring back from XE2 dll to D7 I get the mirror effect - the string length is halved and strings are simply truncated ("1234" becomes "12").
I'm pasting code in because I know you will ask for it.
In Delphi XE2 I'm exporting these functions:
// testing
function GetString(s:string):string; export;
function AddToString(s:string):string; export;
implementation
function GetString(s:string):string;
begin
Result := '0987654321';
end;
function AddToString(s:string):string;
begin
Result := s + '| ' + IntToStr(length(s)) + ' there is more';
end;
In Delphi 7:
function GetString(s:widestring):widestring; external 'SMSShim.dll';
function AddToString(s:widestring):widestring; external 'SMSShim.dll';
procedure TForm1.btnTestGetClick(Sender: TObject);
var
s: widestring;
begin
s := widestring('1234');
Memo1.Lines.Add(' GetString: ' + GetString(s));
end;
procedure TForm1.btnTestAddClick(Sender: TObject);
var
s: widestring;
begin
s := widestring('1234567890');
Memo1.Lines.Add(' AddToString: ' + AddToString('1234567890'));
end;
I can run from either side, using the D7 executable as the host app to debug the dll. Inspecting the parameters and return values in the debugger gives the results above.
Annoyingly, if I declare the imports in delphi7 as strings I get the correct length but invalid data. Declaring as shown I get valid data, wrong lengths, and access violations when I try to return.
Making it all stdcall doesn't change the behaviour.
The obvious solution is the just write simple wrapper functions that expose exactly the functionality I need right now. I can do that, but I'd prefer the above cunning way.
The DLL in question exports functions that expect to receive UnicodeString parameters. (As you know, the string type became an alias for UnicodeString in Delphi 2009.) A Delphi 7 application cannot consume that DLL; the run-time library doesn't not know how to operate on that type because it didn't exist back in 2002 when Delphi 7 was published.
Although the character size for UnicodeString is compatible with WideString, they are not the same types. UnicodeString is structured like the new AnsiString, so it has a length field, a reference count, a character size, and a code page. WideString has a length field, but any other metadata it carries is undocumented. WideString is simply Delphi's way of exposing the COM BSTR type.
A general rule to live by is to never export DLL functions that couldn't be consumed by C.1 In particular, this means using only C-compatible types for any function parameters and return types, so string is out, but WideString is safe because of its BSTR roots.
Change the DLL to use WideString for its parameters instead of string.
1 Maintaining C compatibility also means using calling conventions that C supports. Delphi's default register calling convention is not supported in Microsoft C, so use cdecl or stdcall instead, just like you've seen in every Windows DLL you've ever used.
There's not way to disable the UNICODE in Delphi XE2 (or any version greater than 2009) , however there are many resources that can help you to migrate your application.
White Paper: Delphi and Unicode (from Marco Cantù)
Delphi Conversion Unicode Issues
"Globalizing your Delphi applications" - Delphi Unicode Resources
Compilation of resources for migrate to Delphi 2009/2010 Unicode

Delphi - Problem using an existing dll

I have to use an existing dll, but got a problem with it.
Here's how I try to use it:
unit u_main;
...
implementation
procedure getUserData(var User, Pass: string); stdcall; external 'Common5.dll';
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
u, p: string;
begin
getUserData(u,p);
end;
...
end.
When I press the button the get the userData, I get an EInvalidPointer exception.
The dll is registerd and in some other projects it's in use and work. any ideas?
EDIT:
The DLL was created in Delphi7 and is now used in a Delphi 2009 project.
Maybe there's a problem with unicode strings or something like that?
You need to rebuild the Delphi 7 DLL, make it follow the WinApi standard of getting PChar and BufferLen parameters. You've got multiple problems with the current implementation:
string is platform-specific, it's implementation may change between delphi versions (and did change). You're not supposed to use string outside the platform!
You're passing the parameters as "var", suggesting the DLL might change the value of user and/or pass. String is an special, managed type, changing it requires allocating memory for the new string. This in turns requires you to share the memory manager between the DLL and the EXE (using sharemem.pas and BorlandMM.dll - or variants). The trouble is, sharing the memory manager between different versions of Delphi is an unsupported configuration! (gotton from embarcadero forums)
The Delphi 7 is hoping to receive an simple AnsiString (1 byte chars), while the Delphi 2009 exe is sending Unicode strings (2 bytes per char).
Along with using PChar, be sure to pre-allocate the space before you call GetUserData. i.e. if you assign 'foo' into a pchar that's empty, you'll blow up. So either use static length PChar/PAnsiChar arrays, or use this technique:
var
s : AnsiString;
begin
setlength(s,256);
MyDLLProc(PAnsiChar(s));
end;

How can I pass a Delphi string to a Prism DLL?

We try to pass a string from a native Delphi program to a Delphi Prism DLL.
We have no problem passing integers, but strings are mismatched in the DLL.
We saw Robert Love's code snippet in response to another question, but there is no code for the native Delphi program.
How can we pass strings from Delphi to a Delphi Prism DLL?
The best way would be to use WideString.
For several reasons.
It is Unicode and works before D2009
It's memory is managed in ole32.dll, so no dependency on either Delphi's memory manager or the CLR GC.
You do not have to directly deal with pointers
In Oxygene, you could write it like so:
type
Sample = static class
private
[UnmanagedExport]
method StringTest([MarshalAs(UnmanagedType.BStr)]input : String;
[MarshalAs(UnmanagedType.BStr)]out output : String);
end;
implementation
method Sample.StringTest(input : String; out output : String);
begin
output := input + "ä ~ î 暗";
end;
"MarshalAs" tells the CLR how to marshal strings back and forth. Without it, strings are passed as Ansi (PAnsiChar), which is probably NOT what you would want to do.
This is how to use it from Delphi:
procedure StringTest(const input : WideString; out output : WideString);
stdcall; external 'OxygeneLib';
var
input, output : WideString;
begin
input := 'A b c';
StringTest(input, output);
Writeln(output);
end.
Also, never ever use types, that are not clearly defined, for external interfaces.
You must not use PChar for DLL imports or exports. Because if you do, you will run into exceptions when you compile it with D7 or D2009 (depending on what the original dev system was)
Strings in Delphi Win32 are managed differently from strings in .Net, so you can not pass a .Net string to Delphi Win32 or vice versa.
To exchange strings values you'd better use PChar type which is supported by both compilers. That is the same way you send string values to Windows API functions.
Regards
P.S. I am NOT Robert ;-)

Resources