我通過在我捕獲的例外幀中包裝非托管呼叫來防止非托管 C 例外從我的 C /CLI 代碼中轉義const std::exception&。但是我有一個代碼路徑,其中非托管 C throw立即觸發警告SEHException,即使在 C /CLI 中的堆疊幀上方顯然有一個 catch 子句來攔截它。
我不明白SEHException可能發生在哪里。我想知道它是否是真的。
這是在呼叫堆疊中向下拋出例外的 C 代碼。
StringMap ParseTopLevelMap(std::istream& in)
{
StringMap yamlmap;
if (!TryParseTopLevelMap(in, yamlmap))
throw std::runtime_error("Unable to parse map"); // Causes SEHException warning.
return yamlmap;
}
在我進行上述操作的那一刻throw,我立即在輸出視窗中得到這個輸出:
Exception thrown: 'System.Runtime.InteropServices.SEHException' in MyCompany.Sdk_v143.dll
但我很清楚catch(const std::exception& ex)在 C /CLI 的呼叫框架中有一個更高的位置,它確實被呼叫了。這是(注意catch)
bool ScanContext::TryLoad(GsScan^ scan, String^ path, [SRI::Out]ScanContext^% ctx)
{
try
{
ctx = nullptr;
auto sPath= ToSdk(name);
ctx = gcnew ScanContext(scan, gs::LoadScanContext(scan->sdkScan(), sPath));
}
catch (const std::exception& ex)
{
std::cerr << ex.what() << std::endl; // This DOES execute
}
return ctx != nullptr; // If we did not throw, this is non-null and we succeeded.
}
So the catch clause above does get invoked, the error output message gets dumped, and control returns normally back to my managed C# code that called into the C /CLI.
So where did the SEHException go?
To double-check, I set the Exceptions dialog to actually break on SEHException. And it sure did.
This is the call stack at the point it breaks. My C code is in the process of throwing std::runtime_error
ntdll.dll!NtWaitForSingleObject() Unknown
KernelBase.dll!WaitForSingleObjectEx() Unknown
ntdll.dll!RtlpExecuteHandlerForException() Unknown
ntdll.dll!RtlDispatchException() Unknown
ntdll.dll!KiUserExceptionDispatch() Unknown
KernelBase.dll!RaiseException() Unknown
> vcruntime140d.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 75 C
gscored_v143.dll!gs::detail::YAML::ParseTopLevelMap(std::basic_istream<char,std::char_traits<char>> & in) Line 298 C
gscored_v143.dll!gs::ScanContext::loadContent(std::basic_istream<char,std::char_traits<char>> & is, const std::string & loadFolder) Line 172 C
gscored_v143.dll!gs::ScanContext::loadContent(std::basic_istream<char,std::char_traits<char>> & is) Line 63 C
gscored_v143.dll!gs::ScanContext::Load(const std::shared_ptr<gs::Scan> & scan, const std::string & name) Line 884 C
gscored_v143.dll!gs::LoadScanContext(const std::shared_ptr<gs::Scan> & scan, const std::string & name) Line 310 C
[Managed to Native Transition]
MyCompany.Sdk_v143.dll!MyCompany::Sdk::ScanContext::TryLoad(MyCompany::Sdk::Scan^ scan, System::String^ name, MyCompany::Sdk::ScanContext^% ctx) Line 660 C
MyCompany.Services.dll!MyCompany.Services.ScanService.GetScanContext(MyCompany.Sdk.Scan scan, string name) Line 1725 C#
Is this all just a false warning?
uj5u.com熱心網友回復:
有趣的。
從檔案中看不出這里到底發生了什么,但是Code Project上有一篇有趣的文章解釋了 Microsoft 編譯器如何處理(非托管)C 例外。基本上,當您呼叫throwSEH 例外時(通過RaiseException),運行時庫會捕獲并映射到 C 例外。
現在的問題是如何將其映射到托管 C 例外,以便您可以在托管代碼中捕獲它,而其背后的機制根本不清楚,但SEHException顯然以某種方式適合它。
也許 .NET 框架throw通過其自己的try...塊捕獲您的非托管,并使用不同的例外代碼(對應于 / 導致 的例外代碼)再次catch呼叫,這就是您在除錯器中捕獲的內容。然后它(通過...)捕獲它并使用某種魔法來生成托管代碼例外。反正就是這樣。RaiseExceptionSEHException__try__except
至于您是否需要關注這一點,檔案接著說:
請注意,SEHException 類不會導致呼叫非托管 C 例外解構式。要確保呼叫非托管 C 例外解構式,請在 catch 塊中使用以下語法。
C#
catch
{
// Handle catch here.
}
現在我真的不確定“C 例外解構式”是什么意思(我不知道有這樣的事情),但它可能yamlmap沒有被正確銷毀。如果這是真的,我會感到驚訝,但這可能值得檢查。處理托管代碼中的例外對我來說也沒有意義。也許這只是一個錯字。
回到那篇代碼專案文章,它參考了一個事實,即由非托管 C 引發的 SEH 例外的例外代碼throw是0xE06D7363. 如果你打破這一點,你可能會更多地了解這一切。再說一次,也許不是。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/426241.html
標籤:c .net visual-studio exception c -cli
