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

Tech Tip: Click here to run a free scan for Windows Errors and optimize PC performance



"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: am having a problem with pinvoke and StringBuilder[ ]
    ... DLL: Hello from TestLib.dll ... Since the String class is immutable, I have used StringBuilder in my code ... public static extern int EnumerateBoards(ref int numBoards, ...
    (microsoft.public.dotnet.framework.clr)
  • Problem calling C++ DLL from C# client
    ... A number of the routines in the DLL need to be passed string buffers through which that return results. ... The problem is that is I call FunctionA then FunctionB, passing both of them different StringBuilder buffers, I the buffer return by FunctionB is corrupted with content previously returned by FunctionA. ... Changing the capacity of the string buffers that I pass into the routines changes the behaviour, but does not solve the problem. ... int FAR PASCAL FunctionB; ...
    (microsoft.public.dotnet.languages.csharp)
  • Problem in correct performance of calling a dialog in a DLL(Window
    ... I use VC++ 2008 and have two part in my project(First part: my dll project ... “Select Reader” and then select one of these substrings and send it to the ... int nPtr=0; ... static buff* pad=new buff; ...
    (microsoft.public.dotnet.languages.vc)
  • Problem in correct performance of calling a dialog in a DLL(Window
    ... I use VC++ 2008 and have two part in my project(First part: my dll project ... “Select Reader” and then select one of these substrings and send it to the ... int nPtr=0; ... static buff* pad=new buff; ...
    (microsoft.public.vc.language)