CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 15
  1. #1
    Join Date
    Jun 2007
    Posts
    5

    Question Return a BYTE Array

    I have an unmanaged C++ DLL and I want to return a BYTE Array to VB.NET. Can anyone help me with this?

  2. #2
    Join Date
    Jan 2002
    Location
    Scaro, UK
    Posts
    5,940

    Re: Return a BYTE Array

    The way I normally do it is to do something like this (which doesn't break any dll boundary rules e.g. no memory allocation takes place inside of the dll to be deallocated outside etc) :

    Code:
    void MyDllMethod( BYTE *pbByteArray, int *pnSize )
    {
        const BYTE abData[] = { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70 };
        const int nSizeOfData = sizeof(abData);
    
        if (pbByteArray == NULL)
        {
            // if NULL is passed in just return the length
            *pnSize = nSizeOfData;
        }
        else
        {
            *pnSize = min( nSizeOfData, *pnSize );
            ::memcpy(pbByteArray, abData, *pnSize);
        }
    }
    Basically you pass NULL in and recieve the size of the buffer. Then you allocate a buffer of this size and pass it back into the method where it's populated.

    You should have a .def file in your dll and specify your methods in there. This will prevent them from being 'decorated' i.e. having a load of gunk put around them.


    In C# you'd do this like this (sorry I don't know VB.NET enough to be able to do it in this language straight off : but it should give you an idea)

    Code:
    using System.Runtime.InteropServices;
    
    public class MyDllInterface
    {
        [DllImport("MyDll.dll")]
        static extern void MyDllMethod(IntPtr byteArray, ref int size);
    
        static public byte[] MyDllMethod()
        {
            int size = 0;
            MyDllMethod(IntPtr.Zero, ref size);
    
            byte [] data = new byte[size];
            GCHandle pData = GCHandle.Alloc(data, GCHandleType.Pinned);
            MyDllMethod(pData.AddrOfPinnedObject(), ref size);
            pData.Free();
            return data;
        }
    }
    OK ?

    Darwen.
    www.pinvoker.com - PInvoker - the .NET PInvoke Interface Exporter for C++ Dlls.

  3. #3
    Join Date
    Jun 2007
    Posts
    5

    Re: Return a BYTE Array

    I made a small change to the C++ code:

    Code:
    void MyDllMethod( BYTE *pbByteArray, int *pnSize )
    {
        const BYTE abData[] = { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70 };
        const int nSizeOfData = sizeof(abData);
    
        if (*pbByteArray == NULL)
        {
            // if NULL is passed in just return the length
            *pnSize = nSizeOfData;
        }
        else
        {
            *pnSize = min( nSizeOfData, *pnSize );
            ::memcpy(pbByteArray, abData, *pnSize);
        }
    }
    This is how the VB.NET code looks like after I translated from C#:

    Code:
    Imports System.Runtime.InteropServices
    
    Public Class MyDllInterface
    
    Public Declare Function MyDllMethod Lib "MyDLL.dll" (ByRef byteArray As IntPtr, ByRef size As Integer) As Integer
    
     Public Sub ByteArray(ByRef data() As Byte)
            Dim Size As Integer = 0
            MyDllMethod(Nothing, Size)
            ReDim data(Size)
    
            Dim pData As GCHandle = GCHandle.Alloc(data, GCHandleType.Pinned)
            MyDllMethod(pData.AddrOfPinnedObject(), Size)
             pData.Free()
        End Sub
    
    End Class
    The size is returned as 7 and that is correct, but the byte array is returned with only zeros?

    Any suggestions?

  4. #4
    Join Date
    Jan 2002
    Location
    Scaro, UK
    Posts
    5,940

    Re: Return a BYTE Array

    Code:
    if (*pbByteArray == NULL)
    Should be

    Code:
    if (pbByteArray == NULL)
    No '*'. You're testing for the pointer being null, not the first element being null.

    Darwen.
    www.pinvoker.com - PInvoker - the .NET PInvoke Interface Exporter for C++ Dlls.

  5. #5
    Join Date
    Jun 2007
    Posts
    5

    Re: Return a BYTE Array

    True, but even if I by-pass that part of the code and hard code the size of the array to 7, I still only get zeros as return value in the array?

  6. #6
    Join Date
    Jan 2002
    Location
    Scaro, UK
    Posts
    5,940

    Re: Return a BYTE Array

    The problem is in your interop dll method

    Code:
    Public Declare Function MyDllMethod Lib "MyDLL.dll" (ByVal byteArray As IntPtr, ByRef size)
    byteArray should be passed ByVal as it's a pointer to the start of the memory block, not a reference to the pointer to the start of the memory block.

    Here's a completed project for you :

    Darwen.
    Attached Files Attached Files
    www.pinvoker.com - PInvoker - the .NET PInvoke Interface Exporter for C++ Dlls.

  7. #7
    Join Date
    Jun 2007
    Posts
    5

    Smile Re: Return a BYTE Array

    It works fine. Thank you for all your help!

    /Sam

  8. #8
    Join Date
    Nov 2009
    Posts
    10

    Re: Return a BYTE Array

    hi every body,

    i try to use this code, but returning array of integer instead of bytes.
    so, i do the following changes:

    code c++:
    Code:
                                      void  MyDllMethod( int *pbByteArray, int *pnSize )
                                      {				
                                     const int abData[] = { 1, 2, 3, 4, 5, 6, 7 };
                                     const int nSizeOfData = sizeof(abData);
    
                                     if (*pbByteArray == NULL)
                                        {
                                           // if NULL is passed in just return the length
                                          *pnSize = nSizeOfData;
                                         }
                                      else
                                         {
                                           *pnSize = min( nSizeOfData, *pnSize );
                                           ::memcpy(pbByteArray, abData, *pnSize);
                                   }
    in the vb code,i replace the byte declarations by long declarations,

    when running with these changes, the array restitutes unexpected values,
    17179869171 25769803781 .........
    when 1 2 .... expected.

    so,what's wrong,or missing, in the changes?
    can anyone help?
    ps:returning array of double follows the same rules,or will there be others subtilities?

  9. #9
    Join Date
    Jul 2002
    Posts
    2,543

    Re: Return a BYTE Array

    ::memcpy(pbByteArray, abData, (*pnSize) * sizeof(int) );

  10. #10
    Join Date
    Nov 2009
    Posts
    10

    Re: Return a BYTE Array

    thanks for this quick reply,

    all is not fixed,i still get 17179869171 25769803781 .........
    when 1 2 .... expected.(but some values have been changed,however)

    i imagine some changes in the vba files may be innapropriate.
    here 's the code:

    MyDllInterface.vb
    Code:
    Imports System
    Imports System.Runtime.InteropServices
    
    Public Class MyDllInterface
    
        Public Declare Function MyDllMethod Lib "C:\Users\Frederic\Desktop\Documents\dll\maillage\meshdll\Debug\mesh.dll" _
        (ByVal byteArray As IntPtr, ByRef size As Integer) As Integer
    
        Public Function GetByteArray() As Long()
            Dim Size As Integer = 0
            MyDllMethod(Nothing, Size)
    
            Dim ResultByteArray As Long()
            ResultByteArray = Array.CreateInstance(GetType(Long), Size)
    
            Dim pData As GCHandle = GCHandle.Alloc(ResultByteArray, GCHandleType.Pinned)
            MyDllMethod(pData.AddrOfPinnedObject(), Size)
            pData.Free()
            Return ResultByteArray
        End Function
    End Class
    and main code in vba:
    Code:
            Dim myDllInterface As MyDllInterface = New MyDllInterface
            Dim tabByte As Long()
            tabByte = myDllInterface.GetByteArray()
    any suggestions?

  11. #11
    Join Date
    Jul 2002
    Posts
    2,543

    Re: Return a BYTE Array

    C++ code should look like this:

    [code]
    void MyDllMethod( int *pbByteArray, int *pnSize )
    {
    const int abData[] = { 1, 2, 3, 4, 5, 6, 7 };
    const int nSizeOfData = sizeof(abData) / sizeof(int);

    if (*pbByteArray == NULL)
    {
    // if NULL is passed in just return the length
    *pnSize = nSizeOfData;
    }
    else
    {
    *pnSize = min( nSizeOfData, *pnSize );
    ::memcpy(pbByteArray, abData, (*pnSize) * sizeof(int));
    }
    }
    [code]

    In .NET you should pass integer array, and not long.

  12. #12
    Join Date
    Nov 2009
    Posts
    10

    Re: Return a BYTE Array

    ok,i've got it.
    thanks.

  13. #13
    Join Date
    Nov 2009
    Posts
    10

    Re: Return a BYTE Array

    hi again,
    another problem,with the same kind of context:

    in vb,we have 2 arrays of integer:beginArray[100] and endArray[1500]
    the way to return endArray with the c++ dll is ok,the previous posts explain that.
    the problem comes from beginArray, how to initialize it,
    and avoid the clash when c++ dll receives it: (line int attempt = ....)


    vb.code:
    Code:
        sub usesCppDll()
    
            Dim inputArray(100) As Integer
    	'i tried also
    	'Dim inputArray As Integer()
    	'Dim Size As Integer = 0
            'initSmallArray(Nothing, Size)
            'inputArray = Array.CreateInstance(GetType(Integer), Size)
            'Dim pData As GCHandle = GCHandle.Alloc(outputArray, GCHandleType.Pinned)
            'initSmallArray(pData.AddrOfPinnedObject(), Size)
    
    
    
            For i = 0 To 99
                tabdep(i) = i
            Next
    
    
            Dim outputArray As Integer()
            Dim Size As Integer = 0
            initBigArray(Nothing, Size)
            outputArray = Array.CreateInstance(GetType(Integer), Size)
            Dim pData As GCHandle = GCHandle.Alloc(outputArray, GCHandleType.Pinned)
            returnArray(outputArray(0), pData.AddrOfPinnedObject(), Size)
            pData.Free()
    
        End sub

    c++ code

    Code:
    void __clrcall initSmallArray( int *anArray, int *pnSize )
    { 
    	int abData[100];
    	const int nSizeOfData = sizeof(abData) / sizeof(int);
    
    	if (*anArray == NULL)
    		*pnSize = nSizeOfData;
    	else
    		{
    		*pnSize = min( nSizeOfData, *pnSize );
    		::memcpy(anArray, abData, (*pnSize) * sizeof(int));
    		}
    };
    
    
    
    
    void __clrcall initBigArray( int *noArrayYet, int *pnSize )
    { 
    	int abData[1500];
    	*pnSize = nSizeOfData;
    };
    
    
    
    
    void __clrcall returnArray( int *initialArray, int *finalArray, int *pnSize )
    { 
    	int abData[1500];
    
    	int attempt = initialArray[1];//problem here to get the values from initialArray 
    
    	abData[i] = ...;//result of the dll treatment(no more problem at this stage,and after)
    	const int nSizeOfData = sizeof(abData) / sizeof(int);
    	*pnSize = min( nSizeOfData, *pnSize );
    	::memcpy(finalArray, abData, (*pnSize) * sizeof(int));
    };
    alex,may be?

  14. #14
    Join Date
    Jul 2002
    Posts
    2,543

    Re: Return a BYTE Array

    Please post only relevant code and explain exactly what doesn't work. I don't understand what is "problem here to get the values from initialArray": exception, junk values, something else?

  15. #15
    Join Date
    Nov 2009
    Posts
    10

    Re: Return a BYTE Array

    ok,i'll know for next time.

    i have found the solution.
    (it was contained in the previous posts,in fact)
    here's the modification in vb,if it can help someone.

    vb code:

    Code:
        sub usesCppDll()
    
            Dim inputArray As Integer()
            dim Size As Integer = 0
            initSmallArray(Nothing, Size)
            inputArray = Array.CreateInstance(GetType(Integer), Size)
            Dim pData As GCHandle = GCHandle.Alloc(outputArray, GCHandleType.Pinned)
            initSmallArray(pData.AddrOfPinnedObject(), Size)
    
            For i = 0 To 99
                tabdep(i) = i
            Next
    
            Dim outputArray As Integer()
            initBigArray(Nothing, Size)
            outputArray = Array.CreateInstance(GetType(Integer), Size)
            Dim pData As GCHandle = GCHandle.Alloc(outputArray, GCHandleType.Pinned)
            Dim pData2 As GCHandle = GCHandle.Alloc(inputArray, GCHandleType.Pinned)
            returnArray(pData2.AddrOfPinnedObject(), pData.AddrOfPinnedObject(), Size)
            pData.Free()
    
        End sub

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured