Reputation: 307
I have a P/Invoke call in my application which communicates with an external piece of hardware via an API (a .dll file) written in C++
This method worked perfectly untill I installed the latest .Net 4.5.1, and without making any code changes it now throws an exception: "Cannot implicitly convert type 'void' to 'object'"
Is there anything I should check to make my app compatible with .Net 4.5.1? Rolling back to a previous framework is the only way I have found to make it work!
[DllImport("TestAPI", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
internal static extern bool OMBOpen(int VID, int PID, int CID,
StringBuilder description,
int bufferSize);
The native declaration of the method in C++
TESTAPI_API
bool OMBOpen(int VID,int PID,int IID,char* buffer,int bufferSize);
EDIT:
In the end the problem turned out not to be with the above method call itself at all, but with marshalling data from a pointer to a data structure (See accepted answer), which was elsewhere in the code as David Heffernan wiseley suspected.
Upvotes: 1
Views: 1835
Reputation: 388
The exception "Cannot implicitly convert type 'void' to 'object'" is thrown when attempting to assign the result of a void method to a variable. While this is normally a compiler error, if it's seen during execution then it usually occurred as a result of dynamic invocation of a method (e.g. using the dynamic keyword or using a dynamic language like IronPython).
.NET 4.5.1 introduced a overloads for Marshal.SizeOf
and Marshal.PtrToStructure
and dynamic method invocation may pick the new overload under certain circumstances. See Microsoft KB2909958. The above exception wouldn't be coming from the P/Invoke itself, but from the subsequent marshaling operations.
The easiest solution to these kinds of issues is to just introduce a cast within the call to ensure that the correct method is resolved.
#Code from 4.5
dynamic dynamicVar = ...
object boxedStruct = Marshal.PtrToStructure(myPtr, dynamicVar.GetType());
// Above resolves to 'object Marshal.PtrToStructure(IntPtr, Type)' in 4.5
// and resolves to 'void Marshal.PtrToStructure<T>(IntPtr, T)' in 4.5.1
int size = Marshal.SizeOf(dynamicVar.GetType());
// Above resolves to 'object Marshal.SizeOf(Type)' in 4.5
// and resolves to 'void Marshal.SizeOf<T>(T)' in 4.5.1
#Fixed for 4.5.1
dynamic dynamicVar = ...
object boxedStruct = Marshal.PtrToStructure(myPtr, (Type)dynamicVar.GetType());
// Adding the cast forces the code to resolve to
// 'object Marshal.PtrToStructure(IntPtr, Type)'
int size = Marshal.SizeOf((Type)dynamicVar.GetType());
// Adding the cast forces the code to resolve to
// 'int Marshal.SizeOf(Type)'
Upvotes: 2
Reputation: 612963
The only thing that I can find wrong with the code in the question is the return value. By default the marshaller will assume the native code is returning a 4 byte BOOL
. You should write the pinvoke like this:
[DllImport(...)]
[return: MarshalAs(UnmanagedType.I1)]
internal static extern bool OMBOpen(...);
However, I don't see how that could lead to the error that you report. I rather suspect that the actual problem lies in code that is not in the question.
References:
Upvotes: 2