我有一个简单的本机类,每9秒在目录中创建一个小文件。
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项目之外编译的?
这是我得到的确切错误消息。
尝试读取或写入受保护的内存。这通常是一个 表明其他内存已损坏。
更新
我创建了一个示例项目来重现该问题。
https://bitbucket.org/theonlylawislove/so-c-cli-deleting-unmanaged-object-automatically
更新2
我向我的托管代表添加了[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
属性,我的问题似乎已经解决了。这两个项目都使用了cdecl调用约定,所以我不知道为什么需要它。
答案 0 :(得分:0)
这可能与调用约定发生冲突。正如this MSDN page所述,非托管和混合程序集使用_cdecl调用转换,但对于纯托管程序集,构建器默认使用_clrcall。
尝试使用相同的调用约定编译这两个DLL。对于VS 2010,这可以在项目属性 - &gt;中完成。 C / C ++ - &gt;高级 - &gt;召集会议。