Interop(交互) Between C# and C++ 研究一

54 篇文章 0 订阅

         在进行这一个研究前,首先得有一个思想:语言只是一个工具,不同的语言在不同的平台与环境下发挥不同的作用,而你的权利是在选择.有一次我要开发一个关于视频点播系统(事实上这一个系统没什么用处)的时候,发现C#不是很合适进行对Directshow的开发.一个方面是directxC#环境下对Directshow的支持比较少,另一个方面是在存在Directshow.net(一个开源项目,是把directshow封装在.Net环境下调用)情况下,如果你想用它来写SourceFilter的话还是显得有点困难,因为你不是很容易调用系统较底层一点的API,都得用C#封装一下很麻烦.然后后面写这一个文章的动机可能是我自己个人的问题,我总是认为用C++做出来的界面难度大且不好看,但对C#来说就会很不一样,想开发成像vs2005界面那样左右都有可隐藏的窗口都要比用C++开发一个简单界面容易些.所以最后面这一个系统的开发方案是用C++实现directshowsource filter与网络通信,然后通过COM技术封装成一个Player.dllC#调用.而在此过程当中会遇到很多C++C#的通过COM实现相互调用的问题,我便在此总结了一下我的研究结果,有的也许也没有最终最好的答案,有的研究也许在这里只到一半便放弃了,总之这里是我在寻找思路与解决方案的过程.

         有了这一个方案后先开始写一个小小的test:


项目名:InteropWithCSharpAndCPP
    file1.h:
        
#pragma once
        
        #ifdef __WinTest_C_DLL
        
#else
        
#define __WinTest_C_DLL extern "C"  _declspec(dllimport)
        
#endif
        __WinTest_C_DLL 
int  add(int a,int b);
    file1.cpp:
        #include 
"file1.h"
        
        
int  add(int a,int b)
        
{
            
return a+b;
        }

然后再写了一个C
++ test 项目:cpptest1
    cpptest1.cpp:
        #include 
"stdafx.h"
        
        #include 
"file1.h"
        
        
using namespace std;
        
        
int _tmain(int argc, _TCHAR* argv[])
        
{
            cout
<<add(4,2)<<endl;
            getchar();
            
return 0;
        }

        
        
引用InteropWithCSarpAndCPP.lib与文件file1.h总后输出6测试成功.
然后又再写了一个C#的测试项目:charptest1
    Program.cs:
        
using System;
        
using System.Collections.Generic;
        
using System.Text;
        
        
using System.Runtime.InteropServices;
        
        
namespace charptest1
        
{
          
class Program
          
{
            [DllImport(
"InteropWithCSharpAndCPP.dll")]
            
public static extern int add(int a, int b);
            
static void Main(string[] args)
            
{
              Console.WriteLine(add(
24));
              Console.Read();
            }

          }

        }

同时把InteropWithCSharpAndCPP.dll放到charptest1 bin 目录下,也测试成功.
 

第一个测试成功,心想这事应该还比较好办.但接着一个问题,就是类的问题,最终Player.dll肯定不可能都用这一种方法的方式给C#调用吧?便开始了第二个简单测试,也就是上面的一个升级版本.突然一想在C#当中调用C++里面的类,还真不太好办,因为DllImport还真不能直接把一个类extern出来,不过后面想到这一种最简单的方法:


Project:WinTest3
    Files:
    Math.h
        
#pragma once
        
         
extern "C"  _declspec(dllimport) class  Math
        {
        
public:
            
static Math* instance();
            
int sub(int a,int b);
         
static     void deleteMath(void *);
         
void output(int a,int b);
        
private:
            Math(
void);
            
virtual ~Math(void);
        };
    Math.cpp
        #include 
"Math.h"
        #include 
<Windows.h>
        #include 
<iostream>
        #include 
<strstream>
        #include 
<sstream>
        
        
using namespace std;
        
        Math::Math(
void)
        {
        }
        Math
* Math::instance()
        {
            
return new Math();
        }
        
void Math::deleteMath(void  * m)
        {
            Math 
* mIn=(Math*) m;
            delete mIn;
        }
        
int Math::sub(int a,int b)
        {
            
return a-b;
        }
        
void Math::output(int a,int b)//当时随兴突然想在GUI下测试一下
        {
            HWND hwnd
=GetForegroundWindow();
            HDC hdc
=GetDC(hwnd);
            wostringstream  myString;
          myString
<<"x="<<a<<","<<"y="<<b<<endl;myString.str();
            TextOut(hdc,
0,0,myString.str().c_str(),wcslen(myString.str().c_str()));
            ReleaseDC(hwnd,hdc);
        }
        Math::
~Math(void)
        {
        }
    WinTest_C.def
        LIBRARY    
"WinTest3"
        EXPORTS
        add   @
1
        
?sub@Math@@QAEHHH@Z @2
        
?instance@Math@@SAPAV1@XZ  @3
        
?deleteMath@Math@@SAXPAX@Z @4
        
?output@Math@@QAEXHH@Z @5
    千万别把上面的文件名,类名与方法名以某种联系,其实都是我当时突然想出来做一个测试用的.而文件WinTest_C.def中变形后的方法名是在文件WinTest3.map中找到的,你可以在项目中生成此文件的选项.
然后在C#项目中做一个测试:
Project:WinInterop
    Files:
    NMath.cs
        
using System;
        
using System.Collections.Generic;
        
using System.Text;
        
using System.Runtime.InteropServices;
        
        
namespace WinInterop
        {
          
class NMath
          {
            [DllImport(
"WinTest3.dll", EntryPoint = "?sub@Math@@QAEHHH@Z", CallingConvention = CallingConvention.ThisCall)]
            
public static extern int sub(IntPtr the, int a, int b);
        
            [DllImport(
"WinTest3.dll", EntryPoint = "?instance@Math@@SAPAV1@XZ", CallingConvention = CallingConvention.StdCall)]
            
public static extern IntPtr CreateMath();
        
            [DllImport(
"WinTest3.dll", EntryPoint = "?deleteMath@Math@@SAXPAX@Z", CallingConvention = CallingConvention.StdCall)]
            
public static extern void DeleteMath(IntPtr instance);
        
            [DllImport(
"WinTest3.dll", EntryPoint = "?output@Math@@QAEXHH@Z", CallingConvention = CallingConvention.ThisCall)]
            
public static extern void output(IntPtr instance, int a, int b);
          }
        }
    Form1部分:
            
private void button1_Click(object sender, EventArgs e)
            {
              IntPtr instance 
=NMath.CreateMath();
              NMath.output(instance, 
1010);
              NMath.DeleteMath(instance);
                  }
            这一个测试成功,界面上能看到输出的结果.

 看到上面这一段代码后,相信很多的朋友都会觉得很别扭,觉得真正实现当中怎么可能用这一种方法.首先说为什么我会用Math* Math::instance()这一种方法来生成类吧.因为在C#项目中,我不知道如何externMath的构造方法去生成类.对应的void Math::deleteMath(void * m) 也是一样的原因啦.然后说到WinTest_C.def的方法名,里面很多变异后的方法名是在.map文件当中找到的,并且你每添加一个方法都得重新生成并找出来,添加到.def文件当中,如果你想修改方法名的话更加烦麻.然后还有NMath里面那么多的static,entrypoint.这不是一个开发人员应该用的方法,代码写得多,没有结构,并且都还是做一些低级的开发工作,如查找无聊的方法名,当时就对这一种方法脑火了.

 

         上一个方法失败后开始想到IDispatch,IUnKnown等COM技术.但又不想自己全部去实现所有的这一些接口,然后想到用ATL项目开发.这样便开始走入正轨.关于COM的细节与ATL的一些知识我这里不能多说,水平也没达到,但我可以说一下我是如何使用ATL一步步实现我预期的方案的.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值