使用vs2005创建智能设备的C#和C++混合项目

.NET Framework 一样,.NET Compact Framework 也提供了平台调用P/Invoke 功能以支持托管代码调用驻留于 DLL 中的非托管函数。关于.NET Compact Framework下p/Invoke的使用 详细讨论,请见 http://blog.csdn.net/YanChaoChao/archive/2007/07/17/1696325.aspx
 
通过P/Invoke 我们可以充分利用已有的非托管资源,使用非托管的系统API 函数,以弥补.NET Compact Framework 的不完备性。因此我们可以使用C++ 来编写非托管的DLL 函数,然后在借助通过P/Invoke C# 中进行调用。vs2005 提供了一个很好的集成环境,我们可以使用一个解决方案同时管理托管的C# 项目和非托管的C++ 项目。下面介绍使用vs2005 创建C++ C# 混合项目的方法。
 
1、  首先创建一个C# 智能设备项目。如智能设备-Pockent PC 2003 -设备应用程序,假定解决方案名为“MixedSolution ”,项目名为“DeviceApplication1 ”。
 
2、  添加C++ 智能设备项目。在解决方案“MixedSolution ”中添加一个新的项目,使用C++ 创建相同平台( Pockent PC 200) 的智能设备Win32 MFC 项目,假定项目名为“CppProject ”。注意CppProject 必须是Win32 MFC DLL 项目,因为我们需要使用P/Invoke 功能实现由C# 调用C++ 项目的DLL 。在C++ 项目中编写需要的函数处理后,对要导出的函数需要进行导出定义,该函数将被C# P/Invoke 调用,只有被正确导出的函数才能被P/Invoke 识别。这里值得注意的只有使用修饰符extern “C” _declspec(dllexport) 修饰的函数才能被P/Invoke 调用。在该修饰符中_declspec(DLLexport) 表示输出,即导出函数的定义;extern “C” 表示该函数使用C 编译方式,可以被C 调用,P/Invoke 只能调用使用这种方式编译的函数。
 
我们可以定义如下符号:
 
#define DLLAPI extern "C" __declspec(dllexport)
 
定义了该符号后,可以使用它来修饰要导出的函数,如声明函数MyFunction
 
DLLAPI int MyFunction(int, int);
 
声明了该函数后,在函数的定义部分使用或不使用DLLAPI 修饰都是被允许的。
int MyFunction(int, int) // 声明了函数后,在定义部分可以不加修饰符
{
              int ret = 0;
              //... 处理
 
              return ret;
}
 
也可以只给函数定义,而省略声明部分,这时当然就得加上修饰:
 
DLLAPI int MyFunction(int, int) // 只给出函数定义,必须加上修饰
 {
              int ret = 0;
              //... 处理
 
              return ret;
}
 
extern "C" __declspec(dllexport) 修饰符中
 
我们知道,DLL 本身不仅可以导出函数,还可以导出变量和类,但由于P/Invoke 只能导入DLL 中函数的定义,因此这里只关注 函数的导出。
 
3、  使用DllImport 导入函数定义。在C# 项目 DeviceApplication1 ”添加一个包装类,使用DllImport 导入“CppProject ”项目的导出函数。
 
internal class Wrapper
    {
        [DllImport("CppProject.dll")]
        internal static extern int MyFunction(int k1, int k2);
    }
 
4、  修改项目配置实现混合编译。前面的过程只是在一个解决方案下建立了C# 项目和C++ 项目,这两个项目物理上没有进行关联,因此我们必须先编译C++ 项目,生成"CppProject.dll" ,然后拷贝该文件到设备上,再运行C# 项目时才能通过P/Invoke 调用该文件中的导出函数。如果对C++ 项目进行了修改,必须重复以上过程,非常地麻烦。利用vs2005 的集成管理特点,对项目配置进行一下修改,我们就可以在两个项目建立关联。
 
首先修改C++ 项目的输出路径,在项目属性的[ 配置属性] [ 常规] [ 输出目录] 项下,将输出目录改为“$(SolutionDir)/ DeviceApplication1 ,即输出到C# 项目所在目录。然后生成一下C++ 项目,这时在C# 项目所在目录下会生成“CppProject.dll ”文件,将该文件添加到C# 项目中,并在属性中修改[ 复制到输出目录] 为“如果较新则复制”。最后在解决方案的项目依赖项中,设置项目“DeviceApplication1 ”依赖于项目“CppProject ”。
 
通过这样的配置,在启动项目的调试(F5) 时,会先生成C++ 项目,即输出“CppProject.dll ”文件到C# 项目所在目录,然后再生成C# 项目。在生成C# 项目的过程中,会检查CppProject.dll 是否被更新,如果被更新,则部署到设备上。这样修改了C++ 项目后同样可以执行启动调试来进行整体调试,不需要再手动去单独编译C++ 项目,以及复制DLL 文件了。
 
5、 C++DLL 项目的调试。vs2005 提供了多种调试模式,可以使用本机EXE 程序来对DLL 进行调试,也可以使用托管 EXE 中对DLL 进行调试。这里的DLL 项目最终是要被托管C# 调用的,因此我们使用由托管C# 项目创建的托管 EXE 来对C++ 项目DLL 进行调试。
 
  首先设置C++DLL 项目为启动项目,并将其项目属性的[ 配置属性] [ 调试] [ 远程可执行文件] 项改为C# 项目输出的EXE 程序名,如%CSIDL_PROGRAM_FILES%/MixedSolution/DeviceApplication1.exe ,注意该EXE 文件是在设备上的路径而不是在本机的路径。该EXE 程序名是由C# 项目的[ 输出文件夹] + [ 程序集名称] 确定。
 
 
按照以上创建智能设备的C++ C# 混合项目的方法,我创建了一个混合项目应用,为C# 应用程序增加等待光标(等待动画)的功能,以向用户表明程序正在处理,如下图:

 
设置等待光标可以使用Windows CE API 函数SetCursor(LoadCursor(NULL, IDC_WAIT)); 但实际上IDC_WAIT 是一个宏,在展开后等于(LPWSTR)((DWORD)((WORD)(32514))) ,因此IDC_WAIT 是无法直接在C# 下使用的,因而要在C# 下直接使用这个API 函数是非常困难的任务。而通过一个DLL 项目间接的使用这条API 则非常方便。DLL 项目向外导出函数SetWaitCursor ,这个函数不使用任何参数,可以方便被导入到C# 中。这个函数的定义如下:
void SetWaitCursor(void)
{
       hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
}
 
相应的C# 的导入定义如下:
 
internal class Wrapper
{
        [DllImport("W32DLL.dll")]
        internal static extern void SetWaitCursor();
}
 
当然,我们还需要一个恢复光标状态的函数,也使用这种方式进行定义。这里给出全部源码,有兴趣的朋友可以下载。代码在vs2005+ppc2003 模拟器下调试通过。

源码:http://dl2.csdn.net/down4/20070718/18001510326.rar
 

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值