Question about IntPtr to managed object
See original GitHub issueHi, we have a “working” solution that allows native code to use managed logging with ILogger.
We are storing lots of function pointers and DNNE looks like a beautiful way to greatly simplify our code.
From the screenshots it looks like we pass the same IntPtr for the loggerHandle but when running the call with DNNE we get:
System.InvalidCastException: ‘Unable to cast object of type ‘Microsoft.Extensions.Logging.Logger’ to type ‘Microsoft.Extensions.Logging.ILogger’.’
Manually putting various casts into the watch window seem to work.
Examples: (ILogger?)handle.Target handle.Target as ILogger
Wondering if there are any ideas of what could be going on?
Here is the calling code with both the old and the new way with DNNE.
void LoggerProxy::Log( Level level, std::wstring logMessage )
{
// This call seems to work for casting purposes?
_loggerFunction( _logger->Handle(), (int) level, logMessage.c_str() );
// Call use DNNE - from InfrastructureNE.h
::Log( (intptr_t) _logger->Handle(), (int32_t) level, (intptr_t) logMessage.c_str() );
}
Here is the method we are calling into:
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
public static void Log(IntPtr loggerHandle, int loglevel, IntPtr message)
{
try
{
var handle = GCHandle.FromIntPtr(loggerHandle);
var logmessagetemp = Marshal.PtrToStringUni(message); // move a copy of this up here, to verify it works before exception
var logger = (ILogger?)handle.Target; // exception when using DNNE
if (logger == null)
{
throw new ArgumentException("Unable to convert loggerHandle to ILogger");
}
var logmessage = Marshal.PtrToStringUni(message);
logger.Log((LogLevel)loglevel, logmessage);
}
catch (Exception ex)
{
var logger = StaticLogging.CreateLogger(typeof(LoggerFactoryProxyService));
logger.LogError($"Unable to write log from native code. The log message will be lost. Reason: {ex.Message}");
}
}
Screenshot of the “working” call:
Screenshot of the call with DNNE
Issue Analytics
- State:
- Created a year ago
- Comments:13 (6 by maintainers)
Top GitHub Comments
My project isn’t open source but I can share the relevant parts for RPC. Code is in F# but it shouldn’t be too difficult to turn back into C# if required.
I had a similar issue where my assemblies are loaded twice: Once by the native exports and once by COM into the same process. My solution to communication between the two was to set it up as RPC using StreamJsonRpc. That way client and server use normal .NET interfaces to communicate no need to worry about
AssemblyLoadContext
.