我把一个C++的可以独立运行的应用程序重新编译成了“带静态链接MFC的规则DLL”类型的DLL,然后在我的C#中调用,现在是可以调用DLL了,也能找到入口函数,但调用DLL中的这个函数时又出错了,唉。
DLL中的导出函数声明是:
extern "C" __declspec( dllexport ) void Dcm2Bmp(char *pFileName)
我的C#项目中这样声明:
[DllImport("wwstest2.dll")]
  public static extern void Dcm2Bmp(String pFileName);
然后引用:
Dcm2Bmp("My Documents\\ct1.dcm");
但当执行到DLL中的fopen()函数时,老是打不开,路径名称是正确的,文件也存在。有两个问题想请教:
(1)有个网友说,是因为我的项目中传的那个字符串是Unicode的,而DLL中的函数形参需要的是Ansi的字符串,所以出错,是这样吗?如果是这样我是不是要把我的项目中的那个字符串转成Ansi的?怎么转呢?
(2)另外,我昨天试着在我的项目里“添加引用”,竟然把我的那个DLL添加上了(以前那个MFC扩展DLL添加不上的),但添加上有什么用吗?是不是就不用DllImport就可以直接调用了?如果可以直接调用,会不会还会出现上面的那种情况呢?
  还望各位大哥不吝赐教呀,谢谢!!!!

解决方案 »

  1.   

    1、首先要确认的是lZ的MFC Dll是ANSI还是Unicode,如果是ANSI那么对应的PINVOKE这样写:[DllImport("wwstest2.dll", CharSet=ChasSet.Ansi)] 
    public   static   extern   void   Dcm2Bmp(String   pFileName);如果是Unicode,最好写成:[DllImport("wwstest2.dll", CharSet=ChasSet.Unicode)] 
    public   static   extern   void   Dcm2Bmp(String   pFileName);
    2、对于DotNet引用,可以添加两类,其一是DotNet Assembly;其二是COM组件(由TlbImp导入)。如果想直接调用,可以使用MC++,混合编译,在#param unmanaged之后写unmanaged c/c++代码,使用#param managed之后写托管代码。
      

  2.   

    首先感谢lalac 大哥的热心帮助。
    (1)我也不知道我的那个DLL是Unicode还是Ansi,所以我就俺您的方法都试试(首先声明我的项目和DLL都是用的VS2005做的):
    [DllImport("wwstest2.dll", CharSet=CharSet.Ansi)] 
    public   static   extern   void   Dcm2Bmp(String   pFileName);
    这样编译都通不过,提示:“System.Runtime.InteropServices.CharSet”并不包含“Ansi”的定义。转到定义一查原来CharSet只有两个值:Auto(默认值)和Unicode。
    然后又试验:
    [DllImport("wwstest2.dll", CharSet=ChasSet.Unicode)] 
    public   static   extern   void   Dcm2Bmp(String   pFileName);
    这样依然不行,还是打不开文件。
    (2)看不大懂大哥说的,MC++是什么东西?是不是意思是说我现在把DLL添加到引用里来了,就可以在我的C#项目里加个#param   managed,在这个语句之后直接用C++的语句直接调用那个DLL中的函数?不懂,能不能说的详细点呢?
      

  3.   

    (1)你可以这样判断DLL是Unicode还是Ansi,打开菜单【项目】->【属性】对话框,找到【配置属性】->【通用】,在右边可以找到Character Set的配置,即可知道Dll是否Unicode;从lz的描述看来,应该是Ansi的。
    (2)VS2005肯定有CharSet.Ansi,下面是从MSDN摘选关于CharSet的说明: 
    CharSet 枚举规定封送字符串应使用何种字符集。 命名空间:System.Runtime.InteropServices
    程序集:mscorlib(在 mscorlib.dll 中)成员
    成员名称       说明 
     Ansi       以多字节字符串的形式封送字符串。  
     Auto       针对目标操作系统适当地自动封送字符串。在 Windows NT、Windows 2000、Windows XP 和 Windows Server 2003 系列上默认值为 Unicode;在 Windows 98 和 Windows Me 上默认值为 Ansi。尽管公共语言运行库默认值为 Auto,使用语言可重写此默认值。例如,默认情况下,C# 将所有方法和类型都标记为 Ansi。  
     None       此值已过时,它与 CharSet.Ansi 具有相同的行为。  
     Unicode    以 Unicode 2 字节字符形式封送字符串。 (3)MC++指Managed C++,建立在.NET平台的C++,从VS2002就有了,到VS2005才支持混合编译,即在Assembly内部可以有Unmanaged代码。
    (4)再次强调,.NET目前只支持PInvoke和COM,或者代理的方式调用unmanaged Dll,在C#里是没有#param managed,它是Managed C++的东西。
      

  4.   

    (1)我打开我的那个DLL后,找到配置属性,那个字符集配置,发现上面写着“使用Unicode字符集”,纳闷
    (2)我的VS2005怎么就没有呢?我在程序里,转到定义,就发现了以下定义:
    public enum CharSet
        {
            // 摘要:
            //     以 Unicode 2 字节字符形式封送字符串。
            Unicode = 3,
            //
            // 摘要:
            //     针对目标操作系统适当地自动封送字符串。在 Windows NT、Windows 2000、Windows XP 和 Windows Server
            //     2003 系列上默认值为 System.Runtime.InteropServices.CharSet.Unicode;在 Windows 98
            //     和 Windows Me 上默认值为 System.Runtime.InteropServices.CharSet.Ansi。尽管公共语言运行库默认值为
            //     System.Runtime.InteropServices.CharSet.Auto,使用语言可重写此默认值。例如,默认情况下,C# 将所有方法和类型都标记为
            //     System.Runtime.InteropServices.CharSet.Ansi。
            Auto = 4,
        }
    (3)我把DLL添加为引用是不是多余,没有用呢?
      

  5.   

    1、我想你的Dll实现可能有问题:在Unicode程序里,声明char*指的是传入Ansi,想传入Unicode,你需要使用wchar*,同时内部调用函数不能直接显示调用Ansi的,对于调用ANSI的,要对参数做转换(转换可能永远失败!)!extern   "C"   __declspec(   dllexport   )   void   Dcm2Bmp(wchar   *pFileName)
    2、可能你的Framework有问题。
    3、直接引用是多于的,不会起作用的。
      

  6.   

    lz试试这样声明PInvoke吧:
            [DllImport("youdllname.dll")]
            public static extern void Dcm2Bmp([MarshalAs(UnmanagedType.LPStr)]string pFileName);
      

  7.   

    谢谢大哥:
       (1)对于调用ANSI的,要对参数做转换(转换可能永远失败!)! 
    这句话是什么意思呢?是说参数转换行不通?我要重新改写DLL?使它可以接受Uncode字符串?这样工作量是不是挺大的呢?
       (2)忘了告诉您了,我的C#项目其实是Windows Mobile的移动开发项目,操作系统是WindowsCE,Compact Framework2.0,用VS2005做的,在PocketPC2003模拟器上调试。
        可能这就是我的CharSet只有两个值的原因,另外,我用您的PInvoke语句:
         [DllImport("wwstest2.dll")]
         public static extern void Dcm2Bmp([MarshalAs(UnmanagedType.LPStr)]String pFileName);
    也不行,会引发NotSupportedException,好像是不支持UnmanagedType.LPStr。
      

  8.   

    (1)对于调用ANSI的,要对参数做转换(转换可能永远失败!)!   
    这句话是什么意思呢?是说参数转换行不通?我要重新改写DLL?使它可以接受Uncode字符串?这样工作量是不是挺大的呢? 
    这个工作量不会太大,只要替换其中和编码有关的函数和类型就可以了,比如所有的char替换为TCHAR这样的宏就可以。(2)忘了告诉您了,我的C#项目其实是Windows   Mobile的移动开发项目,操作系统是WindowsCE,Compact   Framework2.0,用VS2005做的,在PocketPC2003模拟器上调试。我晕,怎么不早说!
    CE的话只支持Auto和Unicode,另外CE是支持MarshalAs(UnmanagedType.LPStr)的,我实验成功,我想你的问题可能处在Dll上。