返回

C/C++ 混合编程中 fseek 导致 _invalid_parameter_noinfo 异常的解决方法

windows

C 和 C++ 混合编程中使用 fseek 时的 _invalid_parameter_noinfo 异常

问题

在 C 和 C++ 混合编程时,使用 fseek 函数可能会导致 _invalid_parameter_noinfo 异常。这是因为 C 和 C++ 使用不同的 FILE 结构。

问题分析

DLL 导出文件指针

假设我们有一个 DLL,其中包含一个导出函数 exportedFunction。该函数使用一个由应用程序初始化的文件指针 pFile 进行 fprintf 操作。

文件指针不匹配

问题在于应用程序和 DLL 使用不同的 _iob[] 数组,其中包含文件指针。这会导致 pFile 在应用程序和 DLL 中指向不同的文件位置。

解决方案

为了解决这个问题,我们需要在应用程序和 DLL 中使用相同的文件指针数组。

在 DLL 中显式加载 _iob[]

在 DLL 中,我们可以使用 __imp__iob 导入应用程序的 _iob[] 数组:

#ifdef BUILD_FOO
#    define FOOAPI __declspec(dllexport)
#else
#    define FOOAPI __declspec(dllimport)
#endif

FOOAPI  extern FILE* __imp__iob[];
FOOAPI  void exportedFunction();

在 DLL 中使用导入的 _iob[]

exportedFunction 中,我们可以使用 __imp__iob[] 而不是 pFile

void exportedFunction()
{
   fprintf(__imp__iob[0], "This will result in an exception\n");//<-This print will crash
}

在应用程序中显式导出 _iob[]

在应用程序中,我们可以使用 __declspec(dllexport) 导出 _iob[] 数组:

#undef BUILD_FOO
#include "API.H"

#pragma warning(disable : 4100) // disable warnings for using an unnamed extern
extern FILE* __declspec(dllexport) __iob[];

改进后的代码

DLLFile.c

#define BUILD_FOO
#include "API.H"

void exportedFunction()
{
   fprintf(__imp__iob[0], "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* __imp__iob[];
FOOAPI  void exportedFunction();

APPLICATION.C

#undef BUILD_FOO
#include "API.H"

void main()
{
#pragma warning(disable : 4100) // disable warnings for using an unnamed extern
extern FILE* __declspec(dllexport) __iob[];

pFile = fopen("path_to_folder","wt");
fprintf(pFile , "This print will work"); // <- This will be printed ok
exportedFunction(); 
}

结论

通过使用相同的文件指针数组,我们解决了在 C 和 C++ 混合编程时使用 fseek 时遇到的 _invalid_parameter_noinfo 异常。

常见问题解答

1. 为什么会出现 _invalid_parameter_noinfo 异常?

  • 因为 C 和 C++ 使用不同的 FILE 结构,导致文件指针不匹配。

2. 如何修复此异常?

  • 在应用程序和 DLL 中使用相同的文件指针数组。

3. 如何在 DLL 中导入 _iob[] 数组?

  • 使用 __imp__iob 导入应用程序的 _iob[] 数组。

4. 如何在应用程序中导出 _iob[] 数组?

  • 使用 __declspec(dllexport) 导出 _iob[] 数组。

5. 还有什么需要注意的吗?

  • 确保在应用程序和 DLL 中使用相同的编译器和库版本。