C# ASP.NET中的P/Invoke(从dll读取/写入文本文件)

C# ASP.NET中的P/Invoke(从dll读取/写入文本文件),c#,c++,asp.net,pinvoke,C#,C++,Asp.net,Pinvoke,我有一个C++Win32程序,我在其中编写和读取一个文本文件。这个C++程序生成了一个DLL,我在ASP.NET Web应用程序中引用了这个DLL。 使用P/Invoke,我调用方法从这个dll读写文件 当我在WPF应用程序中使用p/invoke测试这个dll时,它运行良好。 引用dll位于此WPF应用程序的bin/Debug文件夹中,调用dll中的write方法时会在同一文件夹中生成文本文件。 此外,从同一文件夹,我可以使用dll的读取方法读取文本文件 但是,当我从ASP.NET web应用程

我有一个
C++Win32
程序,我在其中编写和读取一个文本文件。这个C++程序生成了一个DLL,我在ASP.NET Web应用程序中引用了这个DLL。 使用P/Invoke,我调用方法从这个dll读写文件

当我在WPF应用程序中使用p/invoke测试这个dll时,它运行良好。 引用dll位于此WPF应用程序的
bin/Debug
文件夹中,调用dll中的write方法时会在同一文件夹中生成文本文件。 此外,
从同一文件夹
,我可以使用dll的读取方法读取文本文件

但是,当我从ASP.NET web应用程序调用Dll方法时,genearted文件会转到其他目录(很可能是因为Dll加载到其他地方执行),我无法找到生成的文件的位置(没有任何错误)

与桌面应用程序类似,是否有某种方式将fie写入bin文件夹本身,以便我可以从bin文件夹本身读取

示例代码:
.cpp文件

extern "C" D_API int Write1()
{
    ofstream myfile;
    myfile.open ("example.txt");
    myfile << "Writing this to a file.\n";
    myfile.close();
    return 1;
}

extern "C" D_API char* Read1()
{
    ifstream myReadFile;
    myReadFile.open("test.txt");
    char output[100];
    if (myReadFile.is_open())
    {
        while (!myReadFile.eof()) 
        {
        myReadFile >> output;       
        }
    }
    return output;
}
extern "C" D_API int WriteTest(char *filename)
{
    ....
    myfile.open(filename);
    ....
}
[DllImport("Testing1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int WriteTest();

由于您使用的是相对路径,因此在调用本机代码时,文件将相对于进程的工作目录。正如你所发现的,这是一个相当脆弱的安排

我将通过向本机代码添加一个额外的字符串参数来解决这个问题,该参数指定要使用的文件的完整路径。我相信,您可以很容易地从托管代码生成它

本机代码

extern "C" D_API int Write1()
{
    ofstream myfile;
    myfile.open ("example.txt");
    myfile << "Writing this to a file.\n";
    myfile.close();
    return 1;
}

extern "C" D_API char* Read1()
{
    ifstream myReadFile;
    myReadFile.open("test.txt");
    char output[100];
    if (myReadFile.is_open())
    {
        while (!myReadFile.eof()) 
        {
        myReadFile >> output;       
        }
    }
    return output;
}
extern "C" D_API int WriteTest(char *filename)
{
    ....
    myfile.open(filename);
    ....
}
[DllImport("Testing1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int WriteTest();
托管代码

extern "C" D_API int Write1()
{
    ofstream myfile;
    myfile.open ("example.txt");
    myfile << "Writing this to a file.\n";
    myfile.close();
    return 1;
}

extern "C" D_API char* Read1()
{
    ifstream myReadFile;
    myReadFile.open("test.txt");
    char output[100];
    if (myReadFile.is_open())
    {
        while (!myReadFile.eof()) 
        {
        myReadFile >> output;       
        }
    }
    return output;
}
extern "C" D_API int WriteTest(char *filename)
{
    ....
    myfile.open(filename);
    ....
}
[DllImport("Testing1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int WriteTest();

另一点需要说明的是,您读取数据的函数不正确。它试图返回堆栈分配的缓冲区。您需要在托管代码中分配一个缓冲区,然后将其传递给本机代码。也许是这样的:

extern "C" D_API int ReadTest(char *filename, char* buffer, int len)
{
     //read no more than len characters from filename into buffer
}
在管理方面:

[DllImport("Testing1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int ReadTest(string filename, StringBuilder buffer, int len);
....
StringBuilder buffer = new StringBuilder(100);
int retval = ReadTest(FullySpecifiedFileName, buffer, buffer.Capacity);

..并且使用默认工作目录也可能会有权限问题-例如,您可能会得到一个IIS进程无法写入的目录。@MMo True,但事实上,它不是你想要的文件所在的地方,这才是真正的杀手。当然-我只是补充了一个原因,说明为什么最好不要随意使用当前的工作目录。@David Heffernan:所以,这意味着我应该传递文件的完整路径(在这种情况下是网站的默认
bin
文件夹),..WebSite1/bin/test.txt,然后使用相同的路径读取文件。Seams对我来说很好,但我想澄清一件事,如果在Dll中的每个方法调用上传递文件的路径是理想的,那么每次调用都将文件的完整路径传递给Dll就可以了。如果您担心这样做的开销,那么每次调用时都要打开和关闭一个文件这一事实应该会使参数传递开销相形见绌。