Re: am having a problem with pinvoke and StringBuilder[ ]

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



Hi Willy,

thanks a lot for your feedback.

1) I tried out your suggestions and that did not work either.
Although I dont get NullPointerExceptions, no data gets
passed between managed and unmanaged code. Here is
the output from my modified code.

c# b4: board0: 1111111111111111111
c# b4: board1: 2222222222222222222

DLL: Hello from TestLib.dll
DLL: board0: +4ù (prints junk instead of 1111111....)
DLL: board1: +4ù (prints junk instead of 2222222....)

c# Found 2 boards

c# after: board0: 1111111111111111111 (should actually print VGA )
c# after: board1: 2222222222222222222 (should actually print NIC)

2) Unfortunately, I dont have the source code for the thirdparty DLL and
it does take a char *** argument. Is there any way that I can pass a
char *** argument from C# to a DLL.

again, thanks for your help.
LK

"Willy Denoyette [MVP]" <willy.denoyette@xxxxxxxxxx> wrote in message
news:uulFLphqIHA.4928@xxxxxxxxxxxxxxxxxxxxxxx
"LK" <lkant2000@xxxxxxxxx> wrote in message
news:u0RgHEhqIHA.524@xxxxxxxxxxxxxxxxxxxxxxx
Hi,

From a C# program I need to access an existing DLL that enumerates the
boards detected via a hardware probe of the system. The function that
does the enumeration expects an int * where it stores the number of
boards
detected and a char *** where it stores the name of each board detected.

Since the String class is immutable, I have used StringBuilder in my code
but this results in a NullPointerException. Just for testing, I replaced
StriingBuilder[] with String[] and the code worked just fine (i.e, no
NullPointerExceptions occured and all messages populated in
the String[] in managed code was correctly printed by the DLL).

I am wondering what I am doing wrong in my code. For reference, I am
enclosing my C# code and my sample DLL code

thank you for your help.
Laxmikant Rashinkar (LK)

Here is the C# code
---------------------
using System;
using System.Text;
using System.Runtime.InteropServices;

class CallDll
{
[DllImport("TestLib.dll")]
public static extern void AccessCheck();

[DllImport("TestLib.dll")]
public static extern int EnumerateBoards(ref int numBoards, ref
StringBuilder[] boards);

public static void Main()
{
int numBoards = 0;
int maxBoards = 5;
int i;

StringBuilder[] boards = new StringBuilder[maxBoards];
for(i=0; i<maxBoards; i++)
boards[i] = new StringBuilder(100);

AccessCheck();
EnumerateBoards(ref numBoards, ref boards);
Console.WriteLine("Found " + numBoards + " boards\n");
for(i=0; i<numBoards; i++)
Console.WriteLine("" + boards[i] + "\n");
}
}

Here is the DLL code
----------------------
#include <stdio.h>
#include <string.h>

extern "C" __declspec(dllexport) void AccessCheck()
{
printf("Hello from TestLib.dll\n");
}

extern "C" __declspec(dllexport) int EnumerateBoards(int *numBoards, char
***boards)
{
char **cpp = *boards;

strcpy(cpp[0], "VGA");
strcpy(cpp[1], "NIC");
*numBoards = 2;
return 0;
}

Here is the output from my program:
------------------------------------
Hello from TestLib.dll

Unhandled Exception: System.NullReferenceException: Object reference not
set
to an instance of an object.
at CallDll.EnumerateBoards(Int32& numBoards, StringBuilder[]& boards)
at CallDll.Main()

And here is how I compile my test code
----------------------------------------
@echo off
cl TestLib.cpp -LD -FeTestLib.dll
csc CallDll.cs
CallDll




Why the triple (***) indirection, a stringBuilder is passed as a pointer
and a StringBuilder[] is passed as a pointer to a pointer?

..
extern "C" __declspec(dllexport) int EnumerateBoards(int *numBoards, char
**boards)
{
char **cpp = boards;
..

Remove the ref from the DllImport declaration and the function call in
your C# code and it should work.

...
public static extern int EnumerateBoards(ref int numBoards,
StringBuilder[] boards);

EnumerateBoards(ref numBoards, boards);


Willy.




.



Relevant Pages

  • Re: am having a problem with pinvoke and StringBuilder[ ]
    ... If you don't have the source of the DLL then you are in a world of pain, that means you wont be able to use the interop marshaler, you need to "custom" marshal. ... public static extern int EnumerateBoards(ref int numBoards, ... Since the String class is immutable, I have used StringBuilder in my code ...
    (microsoft.public.dotnet.framework.clr)
  • Re: pinvoke with StringBuilder[] not working for me
    ... The function that does the enumeration expects an int * ... Just for testing I replaced StriingBuilderwith String[] and the code ... the Stringin managed code was correctly printed by the DLL). ... public static extern int EnumerateBoards(ref int numBoards, ...
    (microsoft.public.dotnet.framework.interop)
  • Re: am having a problem with pinvoke and StringBuilder[ ]
    ... Since the String class is immutable, I have used StringBuilder in my code ... the Stringin managed code was correctly printed by the DLL). ... public static extern int EnumerateBoards(ref int numBoards, ...
    (microsoft.public.dotnet.framework.clr)
  • Re: am having a problem with pinvoke and StringBuilder[ ]
    ... From a C# program I need to access an existing DLL that enumerates the ... the Stringin managed code was correctly printed by the DLL). ... public static extern int EnumerateBoards(ref int numBoards, ...
    (microsoft.public.dotnet.framework.clr)
  • Re: pinvoke with StringBuilder[] not working for me
    ... public static extern int EnumerateBoards ... int numBoards, StringBuilder boards); ...
    (microsoft.public.dotnet.framework.interop)