Tôi đang triển khai một chương trình và codebase là hỗn hợp của C++/CLI và C#. C++/CLI có tất cả các hương vị: bản địa, hỗn hợp (/clr
) và an toàn (/clr:safe
). Trong môi trường phát triển của tôi, tôi tạo một DLL của tất cả các mã C++/CLI và tham chiếu đến từ mã C# (EXE). Phương pháp này hoạt động hoàn hảo.Lỗi chế độ hỗn hợp C++/CLI: tham nhũng đống trong atexit (đăng ký hủy hoại tĩnh)
Đối với các bản phát hành của tôi mà tôi muốn phát hành một tệp thực thi duy nhất (chỉ cần nói rằng "tại sao không chỉ có một DLL và EXE riêng biệt?" Là không thể chấp nhận được).
Cho đến nay tôi đã thành công trong việc biên dịch EXE với tất cả các nguồn khác nhau. Tuy nhiên, khi tôi chạy nó, tôi nhận được hộp thoại "XXXX đã ngừng hoạt động" với các tùy chọn để Kiểm tra trực tuyến, Đóng và Gỡ lỗi. Các chi tiết vấn đề này như sau:
Problem Event Name: APPCRASH
Fault Module Name: StackHash_8d25
Fault Module Version: 6.1.7600.16559
Fault Module Timestamp: 4ba9b29c
Exception Code: c0000374
Exception Offset: 000cdc9b
OS Version: 6.1.7600.2.0.0.256.48
Locale ID: 1033
Additional Information 1: 8d25
Additional Information 2: 8d25552d834e8c143c43cf1d7f83abb8
Additional Information 3: 7450
Additional Information 4: 74509ce510cd821216ce477edd86119c
Nếu tôi gỡ lỗi và gửi cho Visual Studio, nó báo cáo:
Unhandled exception at 0x77d2dc9b in XXX.exe: A heap has been corrupted
Chọn kết quả đột phá trong nó dừng lại ở ntdll.dll 77d2dc9b() mà không thông tin thêm. Nếu tôi nói với Visual Studio để tiếp tục, chương trình khởi động tốt và dường như làm việc mà không có sự cố, có lẽ kể từ khi một trình gỡ lỗi được đính kèm.
Bạn làm gì cho điều này? Làm thế nào để tránh tham nhũng heap này? Chương trình này dường như hoạt động tốt ngoại trừ điều này.
kịch bản biên soạn tóm tắt của tôi là như sau (tôi đã bỏ qua lỗi của tôi kiểm tra cho ngắn gọn):
@set TARGET=x86
@set TARGETX=x86
@set OUT=%TARGETX%
@call "%VS90COMNTOOLS%\..\..\VC\vcvarsall.bat" %TARGET%
@set WIMGAPI=C:\Program Files\Windows AIK\SDKs\WIMGAPI\%TARGET%
set CL=/Zi /nologo /W4 /O2 /GS /EHa /MD /MP /D NDEBUG /D _UNICODE /D UNICODE /D INTEGRATED /Fd%OUT%\ /Fo%OUT%\
set INCLUDE=%WIMGAPI%;%INCLUDE%
set LINK=/nologo /LTCG /CLRIMAGETYPE:IJW /MANIFEST:NO /MACHINE:%TARGETX% /SUBSYSTEM:WINDOWS,6.0 /OPT:REF /OPT:ICF /DEFAULTLIB:msvcmrt.lib
set LIB=%WIMGAPI%;%LIB%
set CSC=/nologo /w:4 /d:INTEGRATED /o+ /target:module
:: Compiling resources omitted
@set CL_NATIVE=/c /FI"stdafx-native.h"
@set CL_MIXED=/c /clr /LN /FI"stdafx-mixed.h"
@set CL_PURE=/c /clr:safe /LN /GL /FI"stdafx-pure.h"
@set NATIVE=...
@set MIXED=...
@set PURE=...
cl %CL_NATIVE% %NATIVE%
cl %CL_MIXED% %MIXED%
cl %CL_PURE% %PURE%
link /LTCG /NOASSEMBLY /DLL /OUT:%OUT%\core.netmodule %OUT%\*.obj
csc %CSC% /addmodule:%OUT%\core.netmodule /out:%OUT%\GUI.netmodule /recurse:*.cs
link /FIXED /ENTRY:GUI.Program.Main /OUT:%OUT%\XXX.exe^
/ASSEMBLYRESOURCE:%OUT%\core.resources,XXX.resources,PRIVATE /ASSEMBLYRESOURCE:%OUT%\GUI.resources,GUI.resources,PRIVATE^
/ASSEMBLYMODULE:%OUT%\core.netmodule %OUT%\gui.res %OUT%\*.obj %OUT%\GUI.netmodule
Cập nhật 1
Sau khi biên dịch này với các biểu tượng gỡ lỗi và cố gắng một lần nữa, Tôi thực sự nhận được nhiều thông tin hơn. Các cuộc gọi stack là:
msvcr90d.dll!_msize_dbg(void * pUserData, int nBlockUse) Line 1511 + 0x30 bytes
msvcr90d.dll!_dllonexit_nolock(int (void)* func, void (void)* * * pbegin, void (void)* * * pend) Line 295 + 0xd bytes
msvcr90d.dll!__dllonexit(int (void)* func, void (void)* * * pbegin, void (void)* * * pend) Line 273 + 0x11 bytes
XXX.exe!_onexit(int (void)* func) Line 110 + 0x1b bytes
XXX.exe!atexit(void (void)* func) Line 127 + 0x9 bytes
XXX.exe!`dynamic initializer for 'Bytes::Null''() Line 7 + 0xa bytes
mscorwks.dll!6cbd1b5c()
[Frames below may be incorrect and/or missing, no symbols loaded for mscorwks.dll]
...
các dòng mã của tôi rằng 'gây' này (initializer động cho Bytes::Null
) là:
Bytes Bytes::Null;
Trong tiêu đề đó được khai báo là:
class Bytes { public: static Bytes Null; }
Tôi cũng đã thử làm một extern toàn cầu trong tiêu đề như vậy:
extern Bytes Null; // header
Bytes Null; // cpp file
Không thành công trong cùng một cách.
Dường như chức năng CRT atexit
có trách nhiệm, vô tình được yêu cầu do bộ khởi tạo tĩnh.
Fix
Như Ben Voigt chỉ ra việc sử dụng bất kỳ chức năng CRT (bao gồm initializers tĩnh bản địa) yêu cầu khởi tạo thích hợp của CRT (mà xảy ra trong mainCRTStartup
, WinMainCRTStartup
, hoặc _DllMainCRTStartup
).Tôi đã thêm một C tập tin ++/CLI hỗn hợp mà có một C++ main
hoặc WinMain
:
using namespace System;
[STAThread] // required if using an STA COM objects (such as drag-n-drop or file dialogs)
int main() { // or "int __stdcall WinMain(void*, void*, wchar_t**, int)" for GUI applications
array<String^> ^args_orig = Environment::GetCommandLineArgs();
int l = args_orig->Length - 1; // required to remove first argument (program name)
array<String^> ^args = gcnew array<String^>(l);
if (l > 0) Array::Copy(args_orig, 1, args, 0, l);
return XXX::CUI::Program::Main(args); // return XXX::GUI::Program::Main(args);
}
Sau khi làm điều này, chương trình bây giờ được xa hơn một chút, nhưng vẫn còn có vấn đề (mà sẽ được giải quyết ở nơi khác):
- Khi chương trình là hoàn toàn trong C# nó hoạt động tốt, cùng với bất cứ khi nào nó chỉ được gọi ++ phương pháp C/CLI, nhận C++/tài sản CLI, và tạo quản lý C++/CLI đối tượng
- sự kiện thêm bằng C# vào C++/Mã CLI không bao giờ kích hoạt (mặc dù chúng cần)
- Một lỗi lạ khác là một ngoại lệ xảy ra là một InvalidCastException nói không thể cast từ X để X (trong đó X là giống như X ...)
Tuy nhiên kể từ khi tham nhũng đống là cố định (bằng cách nhận được CRT khởi tạo) câu hỏi được thực hiện.
@Foole Cảm ơn bạn đã sửa tiêu đề. – coderforlife