计算机崩溃并在新计算机上重新安装 C++Builder 12.2 后,某些代码无法再编译。例如:
void __fastcall TSynCustomExporter::CopyToClipboardFormat(UINT AFormat)
...
try // line 206
{
PtrData = ((Byte*) GlobalLock((HGLOBAL) hData));
if(ASSIGNED(PtrData))
{
try // line 211
{
fBuffer->Position = 0;
fBuffer->Read((void**)PtrData, (TNativeCount) (hDataSize - 1)); // trailing #0
}
__finally
{
GlobalUnlock((HGLOBAL) hData);
}
Clipboard()->SetAsHandle(AFormat, hData);
}
else
Abort();
}
catch(...)
{
GlobalFree((HGLOBAL) hData);
OutOfMemoryError();
}
错误信息是:
[bcc64x Error] SynEditExport.cpp(206): cannot use C++ 'try' in the same function as SEH '__try'
[bcc64x Hint] SynEditExport.cpp(211): conflicting '__try' here
其他编译器对此类错误消息有解释,但 C++Builder 有自己特殊的
__finally
扩展来重现 Delphi 行为。
我发现有一个补丁可能会导致新行为:
不幸的是我无法登录。
我想了解更多有关此错误消息的背景。如果补丁真的要对此负责,我想知道该补丁是否不会产生比修复错误更多的错误。
更新:
感谢您提出解决问题的建议。但是,为了简单起见,我没有充分解释其背景。
代码示例是使用 Delphi2CB 工具自动转换以下 Delphi 代码的结果:
procedure TSynCustomExporter.CopyToClipboardFormat(AFormat: UINT);
...
try
PtrData := GlobalLock(hData);
if Assigned(PtrData) then
begin
try
fBuffer.Position := 0;
fBuffer.Read(PtrData^, hDataSize - 1); // trailing #0
finally
GlobalUnlock(hData);
end;
Clipboard.SetAsHandle(AFormat, hData);
end
else
Abort;
except
GlobalFree(hData);
OutOfMemoryError;
end;
这种转换并不复杂,每个用户都可以立即理解。
示例代码取自 C++ 版本的 SynEdit 组件,该错误现在经常发生。针对这种情况构建特殊结构并不能解决其他情况。使用
scope_exit
将是一个通用解决方案,但不直观。
正如我一开始所说的,几周前这个问题还不存在。我不明白为什么代码突然停止工作。
我想将 Remy Lebeau 的最后一个答案标记为最佳答案,但找不到“答案左侧的绿色勾勒勾号”,所以我在这里重复一遍:
Clang 根本不支持在同一个函数中将 C++ try/catch 与 SEH __try/__ except/__finally 混合使用,而且从来不支持。 Borland 的 bcc32 编译器始终允许将其作为编译器扩展。这是有记录的: https://docwiki.embarcadero.com/RADStudio/en/Stricter_C%2B%2B_Compilers_(Clang-enhanced_C%2B%2B_Compilers)#Structural_Syntax
我补充一下:在C++Builder Athens补丁之前进行过这样的混合编译,但现在不再进行了。 Synedit 的现代 C++ 编译器版本的代码已通过使用代码防护进行更正,类似于 Pepijn Kramer 的建议。
void __fastcall TSynCustomExporter::CopyToClipboardFormat(UINT AFormat)
{
...
try
{
PtrData = ((Byte*) GlobalLock((HGLOBAL) hData));
if(ASSIGNED(PtrData))
{
{
auto olsLambda = onLeavingScope([&]
{
GlobalUnlock((HGLOBAL) hData);
});
fBuffer->Position = 0;
fBuffer->Read((void**)PtrData, (TNativeCount) (hDataSize - 1)); // trailing #0
}
Clipboard()->SetAsHandle(AFormat, hData);
}
else
Abort();
}
catch(...)
{
GlobalFree((HGLOBAL) hData);
OutOfMemoryError();
}
}
Delphi2CB 已更正,因此仅在不存在冲突时才使用 try...__finally