locked
Interop: Importing WIN32 dll functions and void *data I/O parameters RRS feed

  • Question

  • I am not 100% sure what could be wrong here. I spent long hours and did all online research.

    Basically, I have this C# sharp class API DLL with over 100 DllImport functions from WIN32 APIENTRY DLL.   The following are two example functions I am having trouble with getting the proper I/O of passing of a byte array.

    namespace wcSDK
    {
            public static class wcServerAPI
    	{
    	////!----------------------------------------------------------------
    	////! Group: wcDoor32 API
    	////! BOOL APIENTRY DoorWrite(const void *data, DWORD size);
    	////! Write byte to output buffer
    	////! returns TRUE if data is written, otherwise see extended error
    	////!----------------------------------------------------------------
    	[DllImport("wcdoor32.dll", SetLastError=true)]
    	public extern static bool DoorWrite(ref byte[] data, uint size);
    
            ////!----------------------------------------------------------------
            ////! Group: wcsrv2.dll API
            ////! BOOL APIENTRY WcReadFile(WCHANDLE h, LPVOID buffer, DWORD requested, LPDWORD read);
            ////! Read bytes from input buffer
            ////! returns TRUE if successful, see read bytes
            ////!----------------------------------------------------------------
            [DllImport("wcsrv2.dll", SetLastError=true)]
            public extern static bool WcReadFile(int h, ref byte[] buffer, uint requested, ref uint read);
        }
    }

    There are other similar Read/Write byte I/O functions in the wcSDK. These are the example implementations:

    C/C++ working implementation for DoorWrite():
    
        char *buf = "hello world!";
        BOOL f = DoorWrite((BYTE *)buf, (DWORD)strlen(buf));
    
    C/C++ working implementation for WcReadRead():
    
        BYTE data[1024];
        DWORD n;
        BOOL rd = WcReadFile(hFile, data, sizeof(data), &n);
    
    C# failed implementation for DoorWrite:
    
        String buf = "Hello world!";
        //byte[] data = System.Text.Encoding.UTF8.GetBytes(buf); // tried this
        byte[] data = Encoding.ASCII.GetBytes(buf);
        bool b =  wcServerAPI.DoorWrite(ref data, buf.Length);
    
    
    C# failed implementation for WcReadFile
    
        byte[] data = new byte[1024];
        //System.Byte[] data = new System.Byte[1024];
        uint n;
        bool b = wcServerAPI.WcReadFile(hFile, ref data, data.Length, ref n);

    I am getting exceptions at these functions. I know I am missing something very simple. Any assistance or guidance in the right direction would be appreciated.

    Thanks


    Hector Santos, CTO Santronics Software, Inc. http://www.santronics.com

    Friday, April 17, 2020 4:18 PM

Answers

  • I'm not sure that I've correctly interpreted your functions, but take a look at  the following

    C DLL

    extern "C" BOOL __stdcall DoorWrite(const void* data, DWORD size)
    {
    	if (data == NULL || size == 0)
    	{
    		SetLastError(ERROR_INVALID_PARAMETER);
    		return FALSE;
    	}
    
    	//Assume that data is printable ASCII characters for example purposes
    	LPCBYTE pByte = static_cast<LPCBYTE>(data);
    
    	for (DWORD i = 0; i < size; i++)
    		printf_s("Character at index %d is %c\n", i, pByte[i]);
    
    	SetLastError(ERROR_SUCCESS);
    	return TRUE;
    }
    
    extern "C" BOOL __stdcall WcReadFile(HANDLE h, LPVOID buffer, DWORD requested, LPDWORD read)
    {
    	BYTE aBytes[] = { 'A', 'B', 'C', 'D', 'E' };  //Simulated data to return to C#
    	BOOL bRet = FALSE;
    
    	if (h == NULL || buffer == NULL || requested == 0 || read == NULL)
    	{
    		SetLastError(ERROR_INVALID_PARAMETER);
    		return FALSE;
    	}
    
    	if (requested > ARRAYSIZE(aBytes))
    	{
    		CopyMemory(buffer, aBytes, ARRAYSIZE(aBytes));
    		*read = ARRAYSIZE(aBytes);
    	}
    	else
    	{
    		CopyMemory(buffer, aBytes, requested);
    		*read = requested;
    	}
    
    	SetLastError(ERROR_SUCCESS);
    	return TRUE;
    }
    

    C# code

    [DllImport("ByteArray.dll", SetLastError = true)]
    public static extern bool DoorWrite(byte[] data, uint size);
    
    [DllImport("ByteArray.dll", SetLastError = true)]
    public static extern bool WcReadFile(IntPtr h, byte[] data, uint requested, ref uint read);
    
    ------------------------------------
    
    string buf = "Hello World!";
    byte[] data = Encoding.ASCII.GetBytes(buf);
    bool bret = DoorWrite(data, (uint) data.Length);
    
    byte[] data2 = new byte[1024];
    uint read = 0;
    IntPtr handle = (IntPtr)(1); // Pass non-zero handle for example purposes
    bret = WcReadFile(handle, data2, (uint) data2.Length, ref read);
    

    • Marked as answer by hector santos Saturday, April 18, 2020 1:24 AM
    Friday, April 17, 2020 5:33 PM

All replies

  • I'm not sure that I've correctly interpreted your functions, but take a look at  the following

    C DLL

    extern "C" BOOL __stdcall DoorWrite(const void* data, DWORD size)
    {
    	if (data == NULL || size == 0)
    	{
    		SetLastError(ERROR_INVALID_PARAMETER);
    		return FALSE;
    	}
    
    	//Assume that data is printable ASCII characters for example purposes
    	LPCBYTE pByte = static_cast<LPCBYTE>(data);
    
    	for (DWORD i = 0; i < size; i++)
    		printf_s("Character at index %d is %c\n", i, pByte[i]);
    
    	SetLastError(ERROR_SUCCESS);
    	return TRUE;
    }
    
    extern "C" BOOL __stdcall WcReadFile(HANDLE h, LPVOID buffer, DWORD requested, LPDWORD read)
    {
    	BYTE aBytes[] = { 'A', 'B', 'C', 'D', 'E' };  //Simulated data to return to C#
    	BOOL bRet = FALSE;
    
    	if (h == NULL || buffer == NULL || requested == 0 || read == NULL)
    	{
    		SetLastError(ERROR_INVALID_PARAMETER);
    		return FALSE;
    	}
    
    	if (requested > ARRAYSIZE(aBytes))
    	{
    		CopyMemory(buffer, aBytes, ARRAYSIZE(aBytes));
    		*read = ARRAYSIZE(aBytes);
    	}
    	else
    	{
    		CopyMemory(buffer, aBytes, requested);
    		*read = requested;
    	}
    
    	SetLastError(ERROR_SUCCESS);
    	return TRUE;
    }
    

    C# code

    [DllImport("ByteArray.dll", SetLastError = true)]
    public static extern bool DoorWrite(byte[] data, uint size);
    
    [DllImport("ByteArray.dll", SetLastError = true)]
    public static extern bool WcReadFile(IntPtr h, byte[] data, uint requested, ref uint read);
    
    ------------------------------------
    
    string buf = "Hello World!";
    byte[] data = Encoding.ASCII.GetBytes(buf);
    bool bret = DoorWrite(data, (uint) data.Length);
    
    byte[] data2 = new byte[1024];
    uint read = 0;
    IntPtr handle = (IntPtr)(1); // Pass non-zero handle for example purposes
    bret = WcReadFile(handle, data2, (uint) data2.Length, ref read);
    

    • Marked as answer by hector santos Saturday, April 18, 2020 1:24 AM
    Friday, April 17, 2020 5:33 PM
  • Thanks for your input, the WIN32 API has long existed for my wcSDK platform.  It is part of a RPC (DCE) Client/Server platform with the client interface dll  wcsrv2.dll.   This can not change since it has been in use for many years.

    BOOL APIENTRY WcReadFile(WCHANDLE h, LPVOID buffer, DWORD requested, LPDWORD read)
    {
      InitContext(FALSE);
      DWORD status = WcsWcReadFile(wch, (unsigned long)h, (byte *)buffer, &requested);
      if (status) {
        SetLastError(status);
        return FALSE;
      }
      *read = requested;
      return TRUE;
    }
    

    WcsWcReadFile() is the RPC call to the server and it returns a (byte *) buffer.

    So I must prepare proper marshall for the .Net DLLImport and code the proper C# usage of the function.

    Similar, DoorWrite() has a "const void* data" parameter.   I can't change that.  I need the proper DLLImport and usage in C#.

    I now if I have these wrong, them the other functions will also be failing, like WcWriteFile() and DoorRead().  Once I see what needs to be done with the above functions, I can then apply it to any other byte array in or out.

    Thanks


    Hector Santos, CTO Santronics Software, Inc. http://www.santronics.com

    Friday, April 17, 2020 8:20 PM
  • Ok, I removed the "ref" in the DLLimport and in the call, and it all seem to work now.   

    Thanks for your guidance.



    Hector Santos, CTO Santronics Software, Inc. http://www.santronics.com

    Saturday, April 18, 2020 1:24 AM