2

我有一个从 dll 导出的文件指针,它由应用程序初始化(fopen),然后在 dll 中使用(fprintf)。

问题是 fprintf 会抛出异常。

DLL文件.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();

应用程序.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()pFile分配 一个来自_iob[]的元素。

在调用fprintf的DLL中,检查pFile是否是_iob[]的一部分,但应用程序中的_iob[]似乎与 DLL 中的不一样(它们具有不同的地址)。

2 我有相同的用例(使用相同的应用程序)和另一个有点相似的 DLL,那里一切正常(_iob[] 在应用程序和 DLL 中的相同位置)。

4

2 回答 2

2

这可能是由于您的应用程序和您的 DLL不同意他们使用的 C 运行时版本。除非它们都是针对完全相同版本的 C 运行时编译的,否则所有的赌注都没有,并且您不能使用来自另一个的数据从一个调用 CRT 函数,反之亦然。

避免此问题的最安全方法是不要FILE*跨 DLL 边界传递指针。这样,与 a 的任何交互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;
}
于 2012-09-06T19:51:38.943 回答
0

让应用程序向 DLL 传递一个回调,并在该回调中让应用程序写入文件。

于 2012-09-06T19:40:20.403 回答