我有一個簡單的本機類,它每9秒在目錄中創建一個小文件。C++ CLI自動刪除非託管對象
void SampleClass::DoWork(char *directoryPath, SegmentCreatedDelegate callback, bool *cancel)
{
if(*cancel) return;
char* segmentFileName = "test%d.ts";
// open the file to write
FILE *pFilempegTs = NULL;
int segmentIndex = 0;
clock_t beginingTime = clock();
char currentSegmentPath[256];
while(!*cancel)
{
// create the segment file to write if we haven't already.
if(pFilempegTs == NULL)
{
segmentIndex++;
strncpy(currentSegmentPath, directoryPath, sizeof(currentSegmentPath));
strncat(currentSegmentPath, segmentFileName, sizeof(currentSegmentPath));
sprintf(currentSegmentPath, currentSegmentPath, segmentIndex);
if((pFilempegTs = fopen(currentSegmentPath, "wb")) == NULL)
{
std::cout << "The file can not be opened for writing\n";
return;
}
}
if((double(clock() - beginingTime)/CLOCKS_PER_SEC) >= 9)
{
fclose(pFilempegTs);
pFilempegTs = NULL;
callback(currentSegmentPath); // the moment I invoke the delegate, the currentSegmentPath gets deleted.
beginingTime = clock();
}
}
if(pFilempegTs != NULL)
{
fclose(pFilempegTs);
callback(currentSegmentPath); // the moment I invoke the delegate, the currentSegmentPath gets deleted.
}
return;
}
當代碼在C++/cli項目中編譯本地類並通過.NET包裝調用時,此代碼完全按預期工作。
但是,如果本地類在本地dll(而不是C++ cli)中編譯並執行,則會在strncpy(currentSegmentPath, directoryPath, sizeof(currentSegmentPath))
處遇到錯誤。看來,當我調用SegmentCreatedDelegate
時,currentSegmentPath
在內存中被刪除。請記住,只有在SampleClass
位於本地dll中時纔會發生這種情況,並且使用__declspec(dllexport)
從C++/cli調用。
注意:SegmentCreatedDelegate
是一個託管到本機代理,使用以下代碼(.NET/C++/cli)創建。
void SampleClassNet::DoWork(System::String^ directoryPath, SegmentCreatedDelegateNet^ segmentCreatedCallback, bool% cancel)
{
SampleClass* nativeClass = new SampleClass();
System::IntPtr directoryPathPointer = System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(directoryPath);
char *directoryPathNative = static_cast<char*>(directoryPathPointer.ToPointer());
System::IntPtr callbackPointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(segmentCreatedCallback);
pin_ptr<bool> pinnedCancel = &cancel;
bool* pinnedCancelRef = pinnedCancel;
nativeClass->DoWork(directoryPathNative, (SegmentCreatedDelegate)(void*)callbackPointer, pinnedCancelRef);
System::GC::KeepAlive(segmentCreatedCallback);
System::Runtime::InteropServices::Marshal::FreeHGlobal(directoryPathPointer);
}
爲什麼調用SegmentCreatedDelegate
刪除currentSegmentPath
,只有在本地方法是C++/CLI項目之外編制?
這是我得到的確切錯誤信息。
試圖讀取或寫入受保護的內存。這通常是指示其他內存已損壞的 。
UPDATE
我創建了一個示例項目重現該問題。
https://bitbucket.org/theonlylawislove/so-c-cli-deleting-unmanaged-object-automatically
更新2
我添加了一個[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
屬性到我的託管委託,我的問題似乎是決心。這兩個項目都使用cdecl調用約定,所以我不知道爲什麼需要這樣做。
不要在'IntPtr'上做'(SegmentCreatedDelegate)(void *)callbackPointer'。相反,'(SegmentCreatedDelegate)callbackPointer.ToPointer()' –
請同時顯示'SegmentCreatedDelegate'的typedef –
您在[上一個問題]中得到了委託聲明錯誤(http://stackoverflow.com/questions/21054847/c- cli-marshaling-net-delegate-to-native-delegate),聽起來不像你有進步。你以前的代碼沒有崩潰是一個不幸的事故。 'currentSegmentPath'變量不能被「刪除」,它是一個局部變量。你一直堅持這個時間足夠長,爲了得到你需要的幫助,你必須發佈一個小的repro解決方案,將這個問題展示給文件共享服務,以便我們實際上可以重現問題。 –