2

I'm quite lost and a newbie, so bear with me.

In C++ the function looks something like this:

int __stdcall helloworld(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause) {
    strcpy(data, "hello world");
    return 3;
}

I'm trying to replicate it in VB.NET, and I've hit a little wall with the char *data and char *parms part.

Public Shared Function helloworld(ByVal mWnd As IntPtr, ByVal aWnd As IntPtr, ByRef data As Char, ByRef parms As Char, ByVal show As Boolean, ByVal nopause As Boolean) As Integer
    data = "hello world"
    Return 3
End Function

This results in output of "h", so I tried data(), which results in gibberish. I then read somewhere that C/C++ char equivalent in VB.NET is byte, so I tried data() As Byte and data = System.Text.Encoding.Default.GetBytes("hello world"), which resulted in gibberish again.

What the DLL receives cannot be changed, so I need to find a way for VB.NET to deal with it. My question is; how do I do it in VB.NET? Can it even be done?

GSerg
  • 76,472
  • 17
  • 159
  • 346
Nipsu
  • 31
  • 4
  • What's the context of this replication? You say "what the DLL receives cannot be changed," does this mean you are trying to create a direct drop-in replacement? Or are you just trying to create a functional equivalent that will be published in a .NET assembly (or possibly through COM)? – Craig Nov 15 '19 at 14:18
  • So you don't want to marshal between the two right? `data` and `params` look like a C string to me so your parameter should probably be of type `String`. That doesn't explain what *"What the DLL receives cannot be changed"* means tho. – Timo Nov 15 '19 at 14:19
  • @Craig it's for mIRC, which is very specific about the functions it allows you to call. This is basically all you get: int __stdcall funcName(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause); The function name can be anything, but it has to be __stdcall and the parameters must be the same as in the example. COM would be one possibility, but preferably not. mIRC has its own $dll function which works with the above. – Nipsu Nov 15 '19 at 14:32
  • @Timo tried String, but it turns into a short string of gibberish. Could have worded it better, I meant the parameters must be what they are. "char *data" can't be changed into something more convenient. – Nipsu Nov 15 '19 at 14:32
  • If you have to be exact you probably have to go with `IntPtr` thats the closest thing to any pointer in .net (except for unsafe code). – Timo Nov 15 '19 at 14:35
  • You're going to need to get into some low-level tricks to export a naked function. See this article: http://darinhiggins.com/2009/11/12/creating-good-ol-standard-dlls-with-vb-net/ – Craig Nov 15 '19 at 15:32
  • I would imagine you can make it `String` on the .NET side, but it may require the correct banging on the IL to get marshaling right. Otherwise, make it an `IntPtr` and copy the data into a string to bring data in / copy data from a string (via `Encoding.GetBytes`) to push data out. – Craig Nov 15 '19 at 15:33
  • If you are using [`DLLExport`](https://stackoverflow.com/a/11756773/11683), then declare them as string and apply the marshaling attributes (e.g. `MarshalAs(UnmanagedType.LPStr)`). – GSerg Nov 15 '19 at 15:41
  • Yeah, I'm using DllExport, and it's working fine. It's just the in and out going char values. @GSerg will look into that. I'm a total newbie, but that at least opens a new door for me. – Nipsu Nov 15 '19 at 16:06
  • The possible mappings for `char*` are `StringBuilder`, `String`, `Char()`, `ByRef ... Char` and `IntPtr`. While I believe it is technically possible for it to be mapped to a `Byte()` as well, a better fit for that would rather be `unsigned char*`. Seeing what the C++ function does, I'd say a `StringBuilder` or a `String` seems to be the most likely mappings. – Visual Vincent Nov 15 '19 at 17:15

1 Answers1

1

After some intensive button smashing, I managed to do it thanks to Visual Vincent's StringBuilder suggestion:

Imports System.Runtime.InteropServices
Imports System.Text
Public Class MyClass
    <DllExport(CallingConvention.StdCall)>
    Public Shared Function helloworld(ByVal mWnd As IntPtr, ByVal aWnd As IntPtr, ByVal data As StringBuilder, ByVal parms As StringBuilder, ByVal show As Boolean, ByVal nopause As Boolean) As Integer
        data.Append("hello world")
        Return 3
    End Function
End Class

Changed ByRef to ByVal too.

Nipsu
  • 31
  • 4