我把一个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就可以直接调用了?如果可以直接调用,会不会还会出现上面的那种情况呢?
还望各位大哥不吝赐教呀,谢谢!!!!
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就可以直接调用了?如果可以直接调用,会不会还会出现上面的那种情况呢?
还望各位大哥不吝赐教呀,谢谢!!!!
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之后写托管代码。
(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中的函数?不懂,能不能说的详细点呢?
(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++的东西。
(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添加为引用是不是多余,没有用呢?
2、可能你的Framework有问题。
3、直接引用是多于的,不会起作用的。
[DllImport("youdllname.dll")]
public static extern void Dcm2Bmp([MarshalAs(UnmanagedType.LPStr)]string pFileName);
(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。
这句话是什么意思呢?是说参数转换行不通?我要重新改写DLL?使它可以接受Uncode字符串?这样工作量是不是挺大的呢? 这个工作量不会太大,只要替换其中和编码有关的函数和类型就可以了,比如所有的char替换为TCHAR这样的宏就可以。(2)忘了告诉您了,我的C#项目其实是Windows Mobile的移动开发项目,操作系统是WindowsCE,Compact Framework2.0,用VS2005做的,在PocketPC2003模拟器上调试。我晕,怎么不早说!
CE的话只支持Auto和Unicode,另外CE是支持MarshalAs(UnmanagedType.LPStr)的,我实验成功,我想你的问题可能处在Dll上。