随笔混合,C#调用VC++编写的DLL

首先用DllImport导入动态库文件(DLL)。

  [System.Runtime.InteropServices.DllImport("ALComm.dll")]

我这里主要说的是,vc++中的各种变量类型,在C#中用什么样的类型代替。

数字参数

首先用vc++编写一个DLL,打开VS2010,选择新建WIN32工程,在下一步的时候,选择建立DLL。

项目命名"test".

接着进入test.cpp里编写一个函数,如下:

extern "C" __declspec(dllexport) ULONG Add(DWORD a,int b)
{
 return a+b;
}

然后C#里调用,如下:

    [System.Runtime.InteropServices.DllImport("test.dll")]
        public static extern int Add(int a, int b);
        private void button1_Click(object sender, EventArgs E)
        {
            int a = Add(5, 6);
            MessageBox.Show(a.ToString());
       }

结果如下:

可以看到,在VC++里,像DWORD,ULONG,USHORT之类的数字类型在C#中都可以用

int代替,一般情况下是不会出错的,只要在两种数据类型的公共范围就没问题。(变量所占字节数量是必须一致).

可以看到DWORD最终的定义是:unsigned long,ULONG也是一样。

但要传递的数据,如果超过了int类型,那就用uint类型吧。

字符和字符串参数

单个char类型,直接定义就可以了,C#和VC++中都有char类型。

关于字符串,首先来编写一个DLL,代码如下:

extern "C" __declspec(dllexport)void msg(WCHAR str1[],WCHAR *str2)
{
 MessageBox(NULL,str1,str2,MB_OK);
}

MessageBox里的第二个参数和第三个参数是LPCWSTR类型的,也就宽字符类型(VS里)

在VS里,你也可以指定单字符的(LPCSTR类型),如:

extern "C" __declspec(dllexport)void msg(char str1[],char *str2)
{
MessageBoxA(NULL,str1,str2,MB_OK); 
}

在C#调用就是这样:

      [System.Runtime.InteropServices.DllImport("test.dll",CharSet=System.Runtime.InteropServices.CharSet.Unicode)]
        public static extern void msg(string str1,string str2);
        private void button1_Click(object sender, EventArgs E)
        {
         msg("用window API来弹出提示框","这是标题");  
        }

如果DLL中的函数参数是宽字符,那么CharSet就要指定Unicode

事实上对于字符串类型,在C#中用string来代替,把字符传递过去是没问题的,但用string来获取,就

会有问题。

要用这种方式获取:DLL

extern "C" __declspec(dllexport)char * GetTitle(HWND wnd)
{
 char str2[100];
 ::GetWindowTextA(wnd,str2,10);
 return str2;
}

C#

   [System.Runtime.InteropServices.DllImport("test.dll")]
        public static extern string GetTitle(IntPtr wnd);
        private void button1_Click(object sender, EventArgs E)
        {
            string str2=GetTitle(this.Handle);
            MessageBox.Show(str2);
        }

但不能这样:

C#中传递一个string类型过去,然后DLL里,给它赋值,这边再取出。

如果要实现这种功能的话,在C#中一律用StringBuilder代替。看一个API示例函数,如下:
     [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "GetWindowText")]
        public static extern int GetTitle(
        IntPtr hwnd,
        StringBuilder lpString,
        int cch
        );

调用:

      private void button1_Click(object sender, EventArgs e)
        {
            StringBuilder lpString = new StringBuilder(255);
            GetTitle(this.Handle, lpString, 255);
            MessageBox.Show(lpString.ToString());

上面导入时,填了一个参数EntryPoint,指定入口函数,这样在下面可以给函数取一个别名GetTitle

句柄

句柄最终的定义是指针类型,所以在C#中,只要有句柄,一律用IntPtr代替

数字指针类型

可用ref引用参数代替,(LPDWORD等)如:

       [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int ProccessId);

调用:

 int pid = 0;
            GetWindowThreadProcessId(this.Handle, ref pid);
            if (System.Diagnostics.Process.GetCurrentProcess().Id == pid)
                MessageBox.Show("Yes,Success!");