Pyromanci
Pyromanci

Reputation: 547

Issues import C DLL into C# program

I've been reading on this problem a lot before i decided to post it here. I have C dll that i need to access inside of a C# program. The DLL's code is pretty simple. As it's nothing more then a hook into biometrics driver (it's C because it's has to include lib and header files from driver for the code to work). Here is the code for the dll:

#include <stdio.h>
#include <windows.h>
#include <DPCN_TM.h>

__declspec(dllexport) unsigned char * ConvertPlatinumTemplateToDpTemplate(const unsigned char* inputData);

HRESULT Convert(
    const unsigned char* inputData,
    const size_t        size,
    DPCN_DATA_TYPE inputDataType,
    DPCN_DATA_TYPE outputDataType,
    DPCN_PURPOSE        purpose,
    unsigned char**     ppbOutputData,
    const void *        outputParameters,
    size_t *            pcbData)
{
    HRESULT hr = 0;
    size_t cbData = 0;
    if (FAILED(hr = DPCNConvertFingerprintData(inputData, size, inputDataType, purpose, NULL, outputDataType, outputParameters, NULL, &cbData))) {
        return hr;
    }

    if (!(*ppbOutputData = (unsigned char *)malloc(cbData))) {
        return DPCN_ERR_NO_MEMORY;
    }

    hr = DPCNConvertFingerprintData(inputData, size, inputDataType, purpose, NULL, outputDataType, outputParameters, *ppbOutputData, &cbData);

    *pcbData = cbData;
    return hr;
}


unsigned char * ConvertPlatinumTemplateToDpTemplate(const unsigned char* inputData) {
    HRESULT hr = 0;
    const size_t         inputSize = sizeof(inputData);
    DPCN_DATA_TYPE inputDataType  = DPCN_DT_DP_TEMPLATE;
    DPCN_DATA_TYPE outputDataType = DPCN_DT_DP_PLATINUM_TEMPLATE;
    unsigned char *pbOutputData = NULL;
    size_t cbData = 0;

    hr = Convert(inputData, inputSize, inputDataType, outputDataType, DPCN_PURPOSE_IDENTIFICATION, &pbOutputData, NULL, &cbData);

    return pbOutputData;
}

As you can see the contents of the DLL is pretty straight forward. From the code you can see I'm needing to access this function inside of the C# program.

unsigned char * ConvertPlatinumTemplateToDpTemplate(const unsigned char* inputData);

Now in my C# code I have done this:

[DllImport(@"path_to_dll\DPFPTemplateConvert.dll")]
public extern byte[] ConvertPlatinumTemplateToDpTemplate(byte[] inputData);

When I call the function I end up getting this error:

A first chance exception of type 'System.Runtime.InteropServices.MarshalDirectiveException' occurred in DLLImportTest.exe
Additional information: Cannot marshal 'return value': Invalid managed/unmanaged type combination.

What am I doing wrong?

Upvotes: 1

Views: 237

Answers (1)

Kris Vandermotten
Kris Vandermotten

Reputation: 10201

An unsigned char * cannot be converted to a .NET byte array, for one simple reason: what should be the length of that array?

And even then, it's a bad idea to pass a pointer out of your function, if that pointer is pointing to memory allocated by that function. Who will release this memory?

You should have the .NET side allocate the byte[] for the result, and pass it into the function.

If the .NET side does not know beforehand how big the allocated array needs to be, use a callback as explained here: http://blog.getpaint.net/2012/04/30/marshaling-native-arrays-back-as-managed-arrays-without-copying/

Upvotes: 1

Related Questions