Question

I have a problem including a DLL (written in C) in my C# project and I hope you can help me. In my research I found the DLLImport, but I'm not sure which types the C variables convert to...

The C method from the DLL I want to import is the following:

int lou_translateString (
     const char * tableList,
     const widechar * inbuf,
     int *inlen,
     widechar *outbuf,
     int *outlen,
     char *typeform,
     char *spacing,
     int mode);

This is the DLLImport I tried:

[DllImport("liblouis-2.dll", EntryPoint = "lou_translateString", CharSet = CharSet.Ansi, ExactSpelling = true)]
    [return: MarshalAs(UnmanagedType.LPStr)]
    public static extern int translate([MarshalAs(UnmanagedType.LPStr)]
        String tableList,
        String inbuf,
        int inlen,
        String outbuf,
        int outlen,
        String typeform,
        String spacing,
        int mode);

But when I try to call the method I get:

MarshallDirectiveException Cannot marshal 'return value': Invalid managed/unmanaged type combination (Int32/UInt32 must be paired with I4 or U4)

Can anyone help with the exception? I'm pretty sure it has to do with the types of the parameters in the method, but I don't know how to declare them right. Any help would be appreciated!

Thanks in advance Alex

Added shorted Documentation for clarification

This function takes a string of 16-bit Unicode characters in inbuf and translates it into a string of 16-bit characters in outbuf.

The tableList parameter points to a list of translation tables separated by commas.

Note that both the *inlen and *outlen parameters are pointers to integers. When the function is called, these integers contain the maximum input and output lengths, respectively. When it returns, they are set to the actual lengths used.

The typeform parameter is used to indicate italic type, boldface type, computer braille, etc. It is a string of characters with the same length as the input buffer pointed to by *inbuf. However, it is used to pass back character-by-character results, so enough space must be provided to match the *outlen parameter. Each character indicates the typeform of the corresponding character in the input buffer. The values are as follows: 0 plain-text; 1 italic; 2 bold; 4 underline; 8 computer braille. These values can be added for multiple emphasis. If this parameter is NULL, no checking for type forms is done. In addition, if this parameter is not NULL, it is set on return to have an 8 at every position corresponding to a character in outbuf which was defined to have a dot representation containing dot 7, dot 8 or both, and to 0 otherwise.

The spacing parameter is used to indicate differences in spacing between the input string and the translated output string. It is also of the same length as the string pointed to by *inbuf. If this parameter is NULL, no spacing information is computed.

The mode parameter specifies how the translation should be done.

The function returns 1 if no errors were encountered and 0 if a complete translation could not be done.

This is what I wrote to test the function in Main:

        StringBuilder outbuf = new StringBuilder("Test", 30);
        int inlength = 100;
        int louint = 0;
        int outlength = 100;
        String inbuf = "test";


        louint = lou_translateString("de-de-g1.ctb", inbuf, inlen: ref inlength, outbuf: outbuf, outlen: ref outlength, typeform: null, spacing: null, mode: 8);

But at the end the original outbuf is not changed at all. Would you say the parameters are right? Do I have to modify the outbuf parameter somehow as it is a StringBuilder and not just a String ( outbuf.Replace() )?

Was it helpful?

Solution

The return value MarshalAs was just wrong. The return value is int and not a string. That explains the error, but there is more. The rest of your pinvoke declaration has errors. I would do it like this:

[DllImport("liblouis-2.dll", CharSet = CharSet.Unicode)]
public static extern int lou_translateString(
    [MarshalAs(UnmanagedType.LPStr)]
    string tableList,
    string inbuf,
    ref int inlen,
    StringBuilder outbuf,
    ref int outlen,
    [MarshalAs(UnmanagedType.LPStr)]
    StringBuilder typeform,
    [MarshalAs(UnmanagedType.LPStr)]
    StringBuilder spacing,
    int mode
);

The text buffers that are marshalled out of the function must be declared as StringBuilder. And you had some other errors. Translate int* as ref int.

In order to call the function you need to create a new instance of StringBuilder to pass as the outbuf parameter. You'll have to work out how large the buffer needs to be. I assume that the documentation for the function tells you how to do that. At least for initial testing you can pass null for typeform and spacing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top