我用c写了一个dll,有个方法接受FILE*参数,然后在方法里分析file的内容,最后返回结果另外,用c写了一个主程序,该主程序通过fopen打开一个文件,调用DLL中的方法,出错(在主程序中可以对该FILE*正常使用)用/MTd参数时,跟踪进去发现是在_lock_str(stream)出访问冲突//////fread.c中的相关代码
#ifdef _MT
/* define locking/unlocking version */
size_t __cdecl fread (
        void *buffer,
        size_t size,
        size_t count,
        FILE *stream
        )
{
        size_t retval;        _lock_str(stream);              /* lock stream */
        __try {
                /* do the read */
                retval = _fread_lk(buffer, size, count, stream);
        }
        __finally {
                _unlock_str(stream);    /* unlock stream */
        }        return retval;
}
#endif  /* _MT */用/MLd参数时,跟踪进去发现是在校验文件句柄时出错
////read.c中的相关代码
/* now define normal version */
int __cdecl _read (
        int fh,
        void *buf,
        unsigned cnt
        )
{
        int bytes_read;                 /* number of bytes read */
        char *buffer;                   /* buffer to read to */
        int os_read;                    /* bytes read on OS call */
        char *p, *q;                    /* pointers into buffer */
        char peekchr;                   /* peek-ahead character */
        ULONG filepos;                  /* file position after seek */
        ULONG dosretval;                /* o.s. return value */        /* validate fh */
        if ( ((unsigned)fh >= (unsigned)_nhandle) ||
             !(_osfile(fh) & FOPEN) )
        {
            /* bad file handle */
            errno = EBADF;
            _doserrno = 0;              /* not o.s. error */
            return -1;
        }环境vs.net,win 2k server

解决方案 »

  1.   

    no one knows or it's too simple?
      

  2.   

    你得dll和exe不是用同一设置编译得
      

  3.   

    唉,csdn难道就没有高人???
      

  4.   

    传给dll的不能是指针。否则就会出错。至于原因自己想象。FILE*就是个指针吧。
      

  5.   

    默认的编译选项里面dll使用多线程crt库,而exe使用的是单线程crt
      

  6.   

    ◆hwndhwnd(何宗键):
        你说的我考虑过,DLL是用LoadLibrary()加载(只能用这种办法,因为可能使用的DLL是不确定的,但接口一样),我不清楚这样加载后DLL与exe是不是在同一地址空间(应该是吧?),如果不是,则如何解决,请教。◆maoxianwang(大大㊣BETAⅡ我想赶快结婚那样就可以)
        extern "C"加了,依然不对◆Kevin_qing():
        DLL与exe都是使用的相同的线程库,我手动改过,这一点我可以保证,但还是不对我还怀疑是不是系统环境的问题,因为环境是win 2k,安装了.Net,打了sp3,我怀疑是因为装了.Net的缘故,没有别的环境,没法试验,唉...
      

  7.   

    LoadLibrary()加载后,你的DLL就被映射到了进程所在的4G的虚拟地址空间里了。
    我上次头昏,连问题都没看清楚就胡说了一把。
    这次我要好好看看,争取将功补过。
      

  8.   

    还有奇怪的是,在DLL中用fread()失败;而用fprintf()则可以,但是当从DLL中返回后再调用fclose()则出错,怪哉
      

  9.   

    对不起,还是看不明白你说的。但是可不可以改成传递文件名给DLL,然后在DLL里面打开文件呢〉
      

  10.   

    你说的也是可以的,也曾经考虑过。但若有多个DLL需要顺序处理文件,则势必也要将文件位置指针信息(ftell())一起传递,感觉别扭,此其一;其二,我希望能知道究竟是什么原因造成的;其三,我用的是别人以前写好的东西,比较复杂,若都改,工作量大且繁琐关于问题,我在举例说明一下(实际程序相当复杂,此处简化,示意一下):
    exe程序:
    main(){
      char *dllFilePath = getDLL();
      HINSTANCE hDLL = LoadLibrary(dllFilePath);  //得到接口函数地址
      typedef SomeStruct* (*InfoGetter)();
      InfoGetter getInfo = getFunAddress(hDLL);  //根据字符串得到特定函数的地址
      typedef Result* (*FileReader)(FILE*);
      FileReader readFile = (FileReader)getFunAddr(getInfo(),"readFile");  typedef int (*FileWriter)(FILE*,char*);
      FileWriter writeFile = (FileWriter)getFunAddr(getInfo(),"writeFile");
      //准备文件
      char *filePath = getFilePath();
      FILE *pf = fopen(filePath,"r");  //调用
      Result r = readFile(pf); //<------此处调用的是DLL中的函数,执行时出现非法操作  //或者调用
      char *filePath2 = getFilePath();
      FILE *pf2 = fopen(filePath2,"w");
      if(writeFile(pf2,"some text")//<---调用DLL中函数,成功执行并返回
      {
          fclose(pf);//<----此时失败,出非法操作
      }
    }DLL文件:__declspec(dllexport) SomeStruct* info(){
     return void* []{readFile,writeFile};
    }__declspec(dllexport) Result* readFile(FILE* file){
      //...
      fread(buf,1,sizeof(buf),file);//<---读不出任何东西
      //...
      return result;
    }__declspec(dllexport) int writeFile(FILE* file,char* text){
      return fprintf(file,"%s",text);
    }希望能描述清楚
      

  11.   

    在DLL传递FILE *指针应该使用FILE **来传递一个指针值!!!!
      

  12.   

    DLL中作文件操作时有一些问题,我问微软的技术服务,最后也没有很好的解决方案。
    但我是在文件关闭删除文件句柄出问题,你能详细描述出错提示吗?
    可发到我的邮箱中[email protected]
      

  13.   

    输出信息
    ....
    HEAP[test.exe]: Invalid Address specified to RtlFreeHeap( 770000, 555620 )调用堆栈:
    NTDLL! 77f97704()
    NTDLL! 77fb6688()
    NTDLL! 77fb58fe()
    NTDLL! 77fa7111()
    NTDLL! 77fcbeda()
    TEST! free + 45 bytes
    TEST! _freebuf + 24 bytes
    TEST! fclose + 39 bytes
    ........
      

  14.   

    改一下源程序,传二级指针试试
    size_t __cdecl fread (
            void *buffer,
            size_t size,
            size_t count,
            FILE **stream
            )
      

  15.   

    原因没找出来,不过我想到了解决的方法使用回调机制调用exe连接的fread()来读取文件据我估计这个问题是VC crt库在被多个模块连接时没有共享FILE指针造成的
      

  16.   

    晕,是可以传递的啊。
    请再次检查你的dll和exe是否都使用的同一CRT库。
    最好都连接多线程的dll版本
      

  17.   

    Kevin_qing,非常感谢你一直以来的关注与努力!可以确定的是我用的是同一CRT库。
    另外,我想问的是,你的环境和我的相同吗,VS.Net + Win 2K + SP3
      

  18.   

    我的是vc6.0开始测试时dll使用多线程CRT dll
    exe使用单线程CRT dll,结果出现assert failed后来都使用多线程dll运行成功
      

  19.   

    最后建议自己把fread/fopen/fwrite/fclose包装一下,这样应该可以不会跟运行库的版本有关。例:
    class MyFile{
    virtual int open(...){
        m_fp=fopen(...);
    }
    virtual int read(...)
    {
     return fread(...);
    }
    ... FILE *fp;
    };
    exe传递MyFile*给dll以访问文件方法一定要是virtual的