C # DllImport con la función booleana de C ++ no está regresando correctamente

Tengo la siguiente función en una DLL C ++

extern "C" __declspec(dllexport) bool Exist(const char* name) { //if (g_Queues.find(name) != g_Queues.end()) // return true; //else // return false; return false; } 

Dentro de mi clase C # tengo lo siguiente:

 [DllImport("Whisper.dll", EntryPoint="Exist", CallingConvention=CallingConvention.Cdecl)] public static extern bool Exist(string name); 

Sin embargo, cada vez que llamo a mi función, SIEMPRE devuelve verdadero, incluso cuando comente mi pequeña función y la haga volver falsa. Tengo la sensación de que hay algo mal con mi convención de llamadas o cualquier otro problema con P / Invocar mi DLL, probablemente corresponde con la cadena y const char *, pero por ahora estoy completamente despistado. ¿Qué estoy haciendo mal? ¿Por qué se vuelve verdadero en lugar de falso?

EDITAR: he descubierto que esto no tiene nada que ver con el const char * o cadena, porque el problema persiste con una función vacía. Intenté cambiar la convención de llamadas entre Cdecl y StdCall y tampoco funcionó correctamente. También he logrado depurar mi DLL y se está llamando correctamente y, de hecho, devuelve falso, pero una vez que vuelva a C #, de alguna manera es cierto. Cambiar el CharSet tampoco tuvo ningún efecto. Me he asegurado de haber suministrado mi progtwig C # con la versión más reciente y correcta de mi archivo DLL cada vez, así que eso tampoco debería ser un problema. Una vez más, no tengo ni idea de por qué el resultado es cierto cuando de hecho estoy devolviendo el nombre falso.

EDIT2: SOReader me proporcionó una sugerencia que soluciona otro problema importante, vea mi comentario. Lamentablemente, no soluciona el problema de devolución.

EDIT3: he llegado a la conclusión de que cambiar el tipo de retorno de Exist (bool) a (int) de repente hace que devuelva el número correcto (verdadero = 1, falso = 0). Eso significaría que puede haber un problema entre C ++ bool y C # ‘s bool. Puedo continuar usando un int como bool, pero eso aún no explicaría el problema original. ¿Tal vez alguien más puede iluminarme en este caso? Quizás tiene que ver con el hecho de que estoy usando x64 (aunque ambos pojects están comstackdos como x86)

Encontré la solución para tu problema. Su statement debe ir precedida de esta clasificación: [return:MarshalAs(UnmanagedType.I1)]

entonces todo debería verse así:

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

¡Lo probé en mi ejemplo muy simple y funcionó!

EDITAR
¿Por qué sucede esto? C define bool como 4 bytes int (como algunos de ustedes han dicho) y C ++ lo define como 1 byte. El equipo de C # decidió usar 4 bytes bool como valor predeterminado durante PInvoke porque la mayoría de la función API del sistema utiliza valores de 4 bytes como bool. Si desea cambiar este comportamiento, debe hacerlo con cálculo de referencias que especifique que desea usar un valor de 1 byte.

El bool de C es en realidad int , ya que no hay un tipo booleano en el lenguaje C original. Eso significa que si el DLLImport de C # está diseñado para interoperar con el código C, entonces esperarán que el bool C # se corresponda con el int de C. Si bien esto aún no explica por qué lo falso se convertiría en realidad, corregirlo debería solucionar el problema.

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

Esto dice que UnmanagedType.Bool es el BOOL Win32, que es un int .

En realidad, esto se debe a que EAX no se ha eliminado por completo con el código típico de C ++ que devuelve un bool . Es típico que EAX contenga algún valor falso al ingresar una función, y para return false el comstackdor típicamente emitiría xor al, al . Esto borra solo el LSB de EAX y hace que el código C # interprete el valor resultante distinto de cero como true lugar de false .

Quizás ordenar el argumento de la función podría ayudar:

 [MarshalAs (UnmanagedType.LPStr)]

Así es como debería ser la statement:

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

Probé tu código y me devuelve falso. Así que debe haber algo más pasando.

¿Estás seguro de que estás recomstackndo la DLL correctamente? Intente eliminar el .DLL y hacer una reconstrucción.

Aparte de eso, todo parece estar bien asumiendo. De forma predeterminada, el marshalling manejará la cadena .NET para const char * sin tener que decorarla con atributos de Marshal, ya sea que la DLL esté comstackda como ANSI o Unicode.

Ver http://msdn.microsoft.com/en-us/library/s9ts558h.aspx#cpcondefaultmarshalingforstringsanchor5

Envío la variable booleana, usando el siguiente sistema

 __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; } } 

En C #, lo hago

 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()); } } 

Uso signed int que puede devolver verdadero / falso correctamente.

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