1

I have this method that I need to call and use in my application, but I don't know really know how to do it exactly.

This is the function that I need to call.

[DllImport(dll_Path)]
public static extern int DTS_GetDataToBuffer(int Position, int Length, char* Buffer, int* DataRead);

In my code, I have this function and I'm missing its implementation.

internal static void GetDataToBuffer(int position, int length, out byte[] data, out int dataRead)
    {
        unsafe
        {
             // the code I need
        }
    }

I think most of this is very selfexplanatory. I need to implement the latter function so I can be able to read the data into the buffer and the amount of data read (which should actually be the same as data.Length, but the manufacturer has this as separate option, so I need it). Can anyone help? Is this clear enough?

Thank you

Edit: Here is the unmanaged declaration from the .h file. Hope it helps.

 extern NAG_DLL_EXPIMP int DTS_GetDataToBuffer(int Position, 
                               int Length, 
                               unsigned char  *Buffer, 
                               int *DataRead );

Edit #2: Positon - the position from which to star reading the data. Length - The amount of data to read (this would be the buffer size). DataRead - the actual data size that was read.

2
  • Could you just call your DTS_ function inside GetDataToBuffer method? are there any issues with that? Commented Oct 15, 2010 at 11:26
  • I could. I should, but I don't know how to properly pass the managed types to unmanaged. That's the whole issue I'm having. Commented Oct 15, 2010 at 11:48

3 Answers 3

8

I don't think you really need to use unsafe pointers here. Declare function as

[DllImport(dll_Path)]
public static extern int DTS_GetDataToBuffer(
    int     position,
    int     length,
    byte[]  buffer,
    ref int dataRead);

Reasonable C# wrapper for this function:

internal static byte[] GetDataToBuffer()
{
    // set BufferSize to your most common data length
    const int BufferSize = 1024 * 8;
    // list of data blocks
    var chunks = new List<byte[]>();
    int dataRead = 1;
    int position = 0;
    int totalBytes = 0;
    while(true)
    {
        var chunk = new byte[BufferSize];
        // get new block of data
        DTS_GetDataToBuffer(position, BufferSize, chunk, ref dataRead);
        position += BufferSize;
        if(dataRead != 0)
        {
            totalBytes += dataRead;
            // append data block
            chunks.Add(chunk);
            if(dataRead < BufferSize)
            {
                break;
            }
        }
        else
        {
            break;
        }
    }
    switch(chunks.Count)
    {
        case 0: // no data blocks read - return empty array
            return new byte[0];
        case 1: // single data block
            if(totalBytes < BufferSize)
            {
                // truncate data block to actual data size
                var data = new byte[totalBytes];
                Array.Copy(chunks[0], data, totalBytes);
                return data;
            }
            else // single data block with size of Exactly BufferSize
            {
                return chunks[0];
            }
        default: // multiple data blocks
            {
                // construct new array and copy all data blocks to it
                var data = new byte[totalBytes];
                position = 0;
                for(int i = 0; i < chunks.Count; ++i)
                {
                    // copy data block
                    Array.Copy(chunks[i], 0, data, position, Math.Min(totalBytes, BufferSize));
                    position += BufferSize;
                    // we need to handle last data block correctly,
                    // it might be shorted than BufferSize
                    totalBytes -= BufferSize;
                }
                return data;
            }
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

I've edited and added the code from the header file. DataRead parameter is return value, it tells the actual data that is being read. A bit weird, but it is a return value.
It is still unclear how to determine the size of input array (amount of memory to allocate). If DataRead is only a return value, DTS_GetDataToBuffer can't determine buffer size and buffer overflow will occur if the buffer is too small.
Added the parameters for Position and Length. The Length is your byte array size. I was under impression the the unmanaged dll would initialize the byte array size. If declaration can be changed, I'm fine with that. As long as I can call managed GetDataToBuffer from my code and it calls the unmanaged dll without errors.
Thank you max. This looks like it would do the work. I will debug and see if all goes well. Until then, this is the accepted answer.
2

I can't test this but I think you should let the Marshaler do you conversion(s):

[DllImport(dll_Path)]
public static extern int DTS_GetDataToBuffer(out byte[] data, out int dataRead);

Comments

1

i agree you don't need to use unsafe block. you are using pinvoke, i hope below links might be useful : http://msdn.microsoft.com/en-us/magazine/cc164123.aspx http://www.pinvoke.net/

and there are post on stackoverflow too

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.