Re: Using function with PChar data type

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



A followup Andrius <g>

The code below worked with .NET

dim s as string = "" ' <<--- MUST INITIALIZE
GetStatus("mike","xxxx", s)

without allocating space, because as I understand it, in this the
DELPHI DLL I was using was just copying to a null terminated string
pointer marshaled by .NET

But I was leery with the initializing and not allocating space for it.

So I went back to one my C/C++ dll functions where I have server
functions that outputting string and here I use DLLImportAttribute.

Seeing how I can use Declare ANSI I changed my .NET signature to use
Declare ANSI to see if that worked:

Declare Ansi Function GetConnectedServer Lib "wcsrv2.dll" _
(ByVal name As string, _
ByVal namesize As Integer) As Boolean

Here, I needed to allocate the string space in this wrapper function:

Function GetConnectedServer() As String
const namesize as integer = 255
dim name as string = space(namesize)
if GetConnectedServer(name,namesize) then
Dim wsp() As Char = {Chr(32), Chr(0)}
return name.tostring.trim(wsp)
end if
return ""
End Function

So I would not trust pchar string without allocating space.

Finally, I had seen many references to StringBuilder being useful for marshalling and that works very nicely:

Declare Ansi Function GetConnectedServer Lib "wcsrv2.dll" _
(ByVal name As StringBuilder, _
ByVal namesize As Integer) As Boolean

Function GetConnectedServer() As String
const namesize as integer = 255
Dim name As New StringBuilder(namesize)
if GetConnectedServer(name,namesize) then
return name.tostring
end if
return ""
End Function

Probably using StringBuilder for your GetStatus() makes sense/

--

Mike wrote:
Hi Andrius,

I was able to finally get the Delphi DLL to import and marshall correctly. Try this:

Declare Ansi Function GetStatus Lib "mydll.dll" _
(Byval user as string, _
byval pwd as string, _
ByRef status as String) as Boolean

The issue was the AUTO. Changing it to ANSI made it marshall correctly without requiring wrapping IntPtr.

Now, to use it you MUST initialize the status string:

dim s as string = "" ' <<--- MUST INITIALIZE
GetStatus("mike","xxxx", s)
writeline("- GetStatus() ==> [{0}] ",s)

Try it.

==


Andrius B. wrote:
Hi,

Thanks for your trying to help.
The problem is, that this DLL with that function was made not by me, but another programmer; I needed this function in order to improve my app written in VB.NET, bay adding some new function. So, the author of DLL just sent me the brief description of the function, and that's all.
After this weekend I'll try to connect with him and ask additional questions about specifications for using it in VB.

If I find out smth I will write here.

Thanks again.

Andrius





"Mike" <unknown@xxxxxxxxxx> wrote in message news:OMaDj902JHA.3544@xxxxxxxxxxxxxxxxxxxxxxx
Mike wrote:
Forgot to point out, maybe it will matter by the compiler directive

{$H-}

may make a big difference. Try {$H+} as well. If I recall, it makes a short STRING into a HUGE string. A short again, is the zero index byte length format but its limite to 255 characters. The {$H+} makes all those string type into C like pointer strings.

--
Andrius,

You might have figured it out by now, if you did, pass on the info :-)

I tried to figure out why I could not get basic delphi pascal DLL to marshal correctly. But what I did was to make sure it worked as a C dll.

---------------- cut/paste to mydll.c ------------
// file: mydll.c
// compiled like so: cl mydll.c /LD /DLL

#include <stdio.h>
#include <windows.h>

__declspec( dllexport ) int __stdcall GetStatus(char *status)
{
strcpy(status,"success from mydll.dll");
return 1;
}
------------------- cut here ------------------------

This worked calling it from C applet, VB.NET, even a delphi applet

For VB.NET, the import just like I gave you, worked fine:

' import mydll.c
Declare Auto Function cdll_GetStatus Lib "mydll.dll"
(ByVal status As IntPtr) As Integer

' wrapper
Function GetStatus(ByRef status As String) As Integer
Dim h As IntPtr = Marshal.AllocHGlobal(255)
Dim res As Integer = cdll_GetStatus(h)
status = Marshal.PtrToStringAnsi(h)
Marshal.FreeHGlobal(h)
Return res
End Function

Well, a Delphi DLL should work the same:

// File : testpasdll.pas
{$H-,O-,A-}
Library testpasdll;

uses
sysutils,windows;

function GetStatus(var status : pchar): integer; stdcall;
begin
StrPlCopy(status,'success from pascal dll',255);
result := 1;
end;
//////////////////////////////////// EXPORT LIST
Exports
GetStatus index 1;
end.

Its been so long that I have worked with the finer details of delphi, but I am sure it is related to getting to the mixed string stuff in delphi similar to how VB6 had BSTR string and fixed strings mixing.

Bu I just have not figured why the above does not marshal correctly. It is functionally the same as the c version. But I will say, that generally, it recommended when passing strings with have a size with it, similar to other WIN32 functions that has string by reference pointer with a size to copy to the pointer and the pointer is allocated in the caller side with the function simply filling in.

But if you don't have control of the DLL, then you have to prototype it the why it is with var status : pchar.

I'll be interested to see what you find out to get it right.

--




.



Relevant Pages

  • Re: Using function with PChar data type
    ... the author of DLL just ... short STRING into a HUGE string. ... those string type into C like pointer strings. ... I tried to figure out why I could not get basic delphi pascal DLL to ...
    (microsoft.public.dotnet.languages.vb)
  • Re: Explicit Linking of DLLs in VB.net
    ... yes this technique will only work on managed assemblys (exe or dll) ... "YourObject" is a form and is limited to the form methods. ... Wel implement propertys, methods, events in your interface and start ... Public Shared Function LoadMeByName(ByVal vstrAssemblyName As String, ...
    (microsoft.public.dotnet.languages.vb)
  • Re: Explicit Linking of DLLs in VB.net (attn Michel or any others)
    ... loads the dll and finds a form in the dll. ... Dim extForm As Form = extAssembly.CreateInstance("test.entry", ... Wel implement propertys, methods, events in your interface and start ... Public Shared Function LoadMeByName(ByVal vstrAssemblyName As String, ...
    (microsoft.public.dotnet.languages.vb)
  • Re: Access crashes when calling DLL function.
    ... I have started bypassing code in the form to find the problem. ... are local String variables. ... I then built a simple input form (in the same mdb) that calls the crashing ... functions from a DLL they provide. ...
    (microsoft.public.access.modulesdaovba)
  • Re: Populating CString in Win32 dll interface that accepts LPCTSTR
    ... ReleaseBuffer() if I actually modify the buffer after GetBuffer is called ... But the OP wanted the string to be "populated" by the DLL. ... Unicode or ANSI string, but the DLL might think it is a non-const pointer to an ANSI ...
    (microsoft.public.vc.mfc)