2

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()はpFileに_iob [] からの要素を割り当てます。

DLLでは、fprintfが呼び出されると、pFileが_iob []の一部であることがチェックされますが、アプリケーションからの_iob []はDLL内のものと同じではないようです(アドレスが異なります)。

2同じユースケース(同じアプリケーション)ともう1つの似たようなDLLがあり、すべてが正常に機能します(_iob []はアプリケーションとDLLの同じ場所にあります)。

4

2 に答える 2

2

これは、アプリケーションとDLLが、使用しているCランタイムのバージョンに同意していないことが原因である可能性があります。両方がまったく同じバージョンのCランタイムに対してコンパイルされていない限り、すべての賭けは無効になり、別のデータを使用して1つのCRT関数を呼び出すことはできません。その逆も同様です。

この問題を回避する最も安全な方法は、FILE*DLLの境界を越えてポインタを渡さないことです。そうすれば、とのやり取りFILE*は常に同じバージョンのCRTを使用して行われ、不一致の危険はありません。したがって、DLLはFILE*変数を公開しないでください。代わりに、不透明(OPAQUE)型である必要があり、変数に対するすべての操作は同じモジュールで行われる必要があります。

例えば:

// 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 に答える