我有一个从dll导出的文件指针,由应用程序初始化(fopen),然后在dll中使用(fprintf)。
问题是fprintf会抛出异常。
DLLFile.c
#define BUILD_FOO
#include "API.H"
File *pFile;
void exportedFunction()
{
fprintf(pFile,"This will result in an exception\n");//<-This print will crash
}
API.H
#ifdef BUILD_FOO
# define FOOAPI __declspec(dllexport)
#else
# define FOOAPI __declspec(dllimport)
#endif
FOOAPI extern File *pFile;
FOOAPI void exportedFunction();
APLICATION.C
#undef BUILD_FOO
#include "API.H"
void main()
{
pFile = fopen("path_to_folder","wt");
fprintf(pFile , "This print will work"); // <- This will be printed ok
exportedFunction();
}
1从我完成的调试开始,这就是我所看到的:
在应用程序中,fopen()为 _iob [] 指定 pFile 元素。
在调用 fprintf 的 DLL 中,检查 pFile 是 _iob [] ,但应用程序中的 _iob [] 似乎与DLL中的 _iob [] 不同(它们具有不同的地址)。
2我有相同的用例(使用相同的应用程序)和另一个有点类似的DLL,一切正常(_iob []在应用程序和DLL中的相同位置)。
答案 0 :(得分:1)
这可能是由您的应用程序和DLL disagreeing on which version of the C runtime they're using引起的。除非它们都是针对完全相同版本的C运行时进行编译,否则所有投注都会关闭,并且您不能使用来自另一个的数据调用CRT函数,反之亦然。
避免此问题的最安全方法是不要在DLL边界之间传递FILE*
指针。这样,与FILE*
的任何交互都将始终使用相同版本的CRT进行,并且不存在任何不匹配的危险。所以你的DLL不应该公开FILE*
变量;相反,它应该是一些不透明的类型,并且变量上的所有操作都需要在同一个模块中进行。
例如:
// API.h
FOOAPI void set_file(void *file);
FOOAPI void set_fprintf_callback(int (*my_fprintf)(void *, const char *, ...));
FOOAPI void exportedFunction();
// DLLFile.c
void *pFile; // Not exported
int (*fprintf_callback)(void *, const char *, ...); // Not exported
FOOAPI set_file(void *file)
{
pFile = file;
}
FOOAPI set_fprintf_callback(int (*my_fprintf)(void *, const char *, ...))
{
fprintf_callback = my_fprintf;
}
FOOAPI exportedFunction()
{
// Call back into the application to do the actual fprintf
fprintf_callback(pFile, "This should not crash");
}
// Application.c
int mydll_fprintf(void *pFile, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int result = vfprintf((FILE *)pFile, fmt, ap);
va_end(ap);
return result;
}
int main()
{
FILE *pFile = fopen(...);
set_file(pFile);
set_fprintf_callback(&mydll_fprintf);
exportedFunction();
return 0;
}
答案 1 :(得分:0)
让应用程序向DLL传递一个回调,并在该回调中让应用程序写入该文件。