从 C# 模块调用 C++ 函数会引发随机崩溃
Posted
技术标签:
【中文标题】从 C# 模块调用 C++ 函数会引发随机崩溃【英文标题】:Invoke C++ function from C# module raises random crashes 【发布时间】:2019-09-30 09:49:21 【问题描述】:我的 C# 模块必须与暴露一组函数的 C++ dll 通信,并且需要根据被调用函数返回的数据进行处理。
这是我的 C# 代码,其中调用了 C++ 函数 (Npr),
[DllImport("CppModule.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "Npr"), System.Security.SuppressUnmanagedCodeSecurity]
public static extern IntPtr Npr([MarshalAs(UnmanagedType.LPWStr)]string moduleIDCur,
[MarshalAs(UnmanagedType.LPWStr)]string mName,
[MarshalAs(UnmanagedType.LPWStr)]string threadID,
[MarshalAs(UnmanagedType.LPWStr)]string sessionID,
[MarshalAs(UnmanagedType.LPWStr)]string reqID,
[MarshalAs(UnmanagedType.LPWStr)]string siteID,
[MarshalAs(UnmanagedType.LPWStr)]string siteName,
[MarshalAs(UnmanagedType.LPWStr)]string nodeOrder,
[MarshalAs(UnmanagedType.LPWStr)]string dateTime,
[MarshalAs(UnmanagedType.LPWStr)]string rType,
[MarshalAs(UnmanagedType.LPWStr)]string rCode,
[MarshalAs(UnmanagedType.LPWStr)]string headStr,
[MarshalAs(UnmanagedType.LPWStr)]string cookStr,
[MarshalAs(UnmanagedType.LPWStr)]string userAgent,
int flag);
...
IntPtr rets = Npr(reqHttp.Url.PathAndQuery,rAddr,Thread.CurrentThread.ManagedThreadId.ToString(),sessionID,reqGUID,
siteID,siteName,nodeStr,DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.GetCultureInfo("en-US")),reqHttp.RequestType,
HttpContext.Current.Response.StatusCode.ToString(), headers, cookieStr, uAgent,
flag); // Native Call from C#
...
在 CppModule.dll 中
EXTERN_C WCHAR* __cdecl Npr(WCHAR* testString,WCHAR* mname,WCHAR* threadID,WCHAR* sessionID,
WCHAR* rID,WCHAR* siteID,WCHAR* siteName,WCHAR* nodeOrder,
WCHAR* dateTime,WCHAR* rType,WCHAR* rCode,WCHAR* headStr,WCHAR* cookieStr,WCHAR* uAgent,int flag)
... ... return wcharPtr;
这个 Npr 函数调用随机给出异常。异常消息为Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
在 C# 中 Npr 函数调用的行号。我更改了这个函数 Npr 最近返回了一个 WCHAR*,从那里随机崩溃不断发生。我是否缺少任何与互操作相关的编组或类似内容?
【问题讨论】:
你的 C++ 函数返回一个指针,但它指向什么?该功能在做什么?如果崩溃是在 C++ 函数中,我们需要看到它才能提供帮助。 您将WCHAR*
返回值编组为IntPtr
的具体原因是什么?
只是猜测...停止返回 wchar* 并执行以下操作:
@Sel_va - 我在评论中向您展示了示例 :) 只需将其视为输出参数,而不是返回。返回指针时可能会出现一些问题。尤其是可能导致内存损坏问题的内存泄漏。
@AdamJachocki 请再次阅读您的评论,它不包含任何代码。
【参考方案1】:
通常在我的程序中,如果一个C++函数返回一个字符串,我更喜欢在参数中传递一个StringBuilder,然后修改它。
类似:
[DllImport("CppModule.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "Npr"), System.Security.SuppressUnmanagedCodeSecurity]
public static extern void Npr(StringBuilder returnValue, [MarshalAs(UnmanagedType.LPWStr)]string moduleIDCur,
[MarshalAs(UnmanagedType.LPWStr)]string mName,
[MarshalAs(UnmanagedType.LPWStr)]string threadID,
[MarshalAs(UnmanagedType.LPWStr)]string sessionID,
[MarshalAs(UnmanagedType.LPWStr)]string reqID,
[MarshalAs(UnmanagedType.LPWStr)]string siteID,
[MarshalAs(UnmanagedType.LPWStr)]string siteName,
[MarshalAs(UnmanagedType.LPWStr)]string nodeOrder,
[MarshalAs(UnmanagedType.LPWStr)]string dateTime,
[MarshalAs(UnmanagedType.LPWStr)]string rType,
[MarshalAs(UnmanagedType.LPWStr)]string rCode,
[MarshalAs(UnmanagedType.LPWStr)]string headStr,
[MarshalAs(UnmanagedType.LPWStr)]string cookStr,
[MarshalAs(UnmanagedType.LPWStr)]string userAgent,
int flag);
...
Npr(returnValue, reqHttp.Url.PathAndQuery,rAddr,Thread.CurrentThread.ManagedThreadId.ToString(),sessionID,reqGUID,
siteID,siteName,nodeStr,DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.GetCultureInfo("en-US")),reqHttp.RequestType,
HttpContext.Current.Response.StatusCode.ToString(), headers, cookieStr, uAgent,
flag);
...
在 c++ 代码中:
EXTERN_C void __cdecl Npr(WCHAR * wcharPtr, WCHAR* testString,WCHAR* mname,WCHAR* threadID,WCHAR* sessionID, WCHAR* rID,WCHAR* siteID,WCHAR* siteName,WCHAR* nodeOrder, WCHAR* dateTime,WCHAR* rType,WCHAR* rCode,WCHAR* headStr,WCHAR* cookieStr,WCHAR* uAgent,int flag)
... ...
【讨论】:
以上是关于从 C# 模块调用 C++ 函数会引发随机崩溃的主要内容,如果未能解决你的问题,请参考以下文章
当我从 C# 代码调用导入的 C++ 函数时,为啥会引发 AccessViolationException?