C# DllImport with C++ boolean function not returning correctly

后端 未结 7 818
长发绾君心
长发绾君心 2020-11-29 04:20

I have the following function in a C++ DLL

extern \"C\" __declspec(dllexport) bool Exist(const char* name)
{
 //if (g_Queues.find(name) != g_Queues.end())
 /         


        
相关标签:
7条回答
  • 2020-11-29 04:54

    C'sbool is actually int, as there is no boolean type in the original C language. That means that if C#'s DLLImport is designed to interop with C code, then they will expect that C#'s bool to correspond to C's int. While this still doesn't explain why false would become true, fixing it should fix the problem.

    http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.unmanagedtype.aspx

    This says that UnmanagedType.Bool is the Win32 BOOL, which is an int.

    0 讨论(0)
  • 2020-11-29 05:08

    This is actually caused by EAX not being fully cleared out by typical C++ code that returns a bool. It's typical for EAX to contain some bogus value when entering a function, and to return false the compiler would typically emit xor al, al. This clears out only the LSB of EAX, and causes C# code to interpret the resulting non-zero value as true instead of false.

    0 讨论(0)
  • 2020-11-29 05:10

    I use signed int which can return true/false correctly.

    https://stackoverflow.com/a/42618042/1687981

    0 讨论(0)
  • 2020-11-29 05:13

    I found the solution for your problem. Your declaration should be preceded with this marshaling: [return:MarshalAs(UnmanagedType.I1)]

    so everything should look like this:

    [DllImport("Whisper.dll", EntryPoint="Exist", CallingConvention=CallingConvention.Cdecl)]  
    [return:MarshalAs(UnmanagedType.I1)]  
    public static extern bool Exist([MarshalAs(UnmanagedType.LPStr)] string name);
    

    I tested it in my very simple example and it worked!

    EDIT
    Why this happens? C defines bool as 4 bytes int (as some of you have said) and C++ defines it as 1 byte. C# team decided to use 4 byte bool as default during PInvoke because most of the system API function use 4 bytes values as bool. If you want to change this behavior you have to do it with marshaling specifying that you want to use 1 byte value.

    0 讨论(0)
  • 2020-11-29 05:15

    Perhaps marshaling the argument of the function might help:

    [MarshalAs(UnmanagedType.LPStr)]
    

    Here is how the declaration should look like:

    [DllImport("Whisper.dll", EntryPoint="Exist", CallingConvention=CallingConvention.Cdecl)]
            public static extern bool Exist([MarshalAs(UnmanagedType.LPStr)] string name);
    
    0 讨论(0)
  • 2020-11-29 05:16

    I send the boolean variable, using the following system

    __declspec(dllexport) const bool* Read(Reader* instance) {
        try {
            bool result = instance->Read();
            bool* value = (bool*)::CoTaskMemAlloc(sizeof(bool));
            *value = result;
            return value;
        } catch (std::exception exp) {
            RegistryException(exp);
            return nullptr;
        }
    }
    

    In C #, I do

    DllImport(WrapperConst.dllName)]
    public static extern IntPtr Read(IntPtr instance);
    
    public bool Read() {
        IntPtr intPtr = ReaderWrapper.Read(instance));
        if(intPtr != IntPtr.Zero) {
            byte b = Marshal.ReadByte(intPtr);
            Marshal.FreeHGlobal(intPtr);
            return b != 0;
        } else {
            throw new Exception(GetLastException());
        }
    }
    
    0 讨论(0)
提交回复
热议问题