惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
Google Online Security Blog
Google Online Security Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Simon Willison's Weblog
Simon Willison's Weblog
T
Threat Research - Cisco Blogs
C
CXSECURITY Database RSS Feed - CXSecurity.com
L
Lohrmann on Cybersecurity
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Forbes - Security
Forbes - Security
P
Palo Alto Networks Blog
Schneier on Security
Schneier on Security
S
Schneier on Security
T
Tor Project blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
WordPress大学
WordPress大学
The Hacker News
The Hacker News
Hacker News - Newest:
Hacker News - Newest: "LLM"
罗磊的独立博客
Application and Cybersecurity Blog
Application and Cybersecurity Blog
F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
C
Check Point Blog
Stack Overflow Blog
Stack Overflow Blog
Blog — PlanetScale
Blog — PlanetScale
雷峰网
雷峰网
S
Security @ Cisco Blogs
PCI Perspectives
PCI Perspectives
Spread Privacy
Spread Privacy
W
WeLiveSecurity
SecWiki News
SecWiki News
A
About on SuperTechFans
H
Help Net Security
博客园 - 司徒正美
Recent Commits to openclaw:main
Recent Commits to openclaw:main
爱范儿
爱范儿
S
Securelist
M
MIT News - Artificial intelligence
云风的 BLOG
云风的 BLOG
月光博客
月光博客
Jina AI
Jina AI
博客园 - 叶小钗
Vercel News
Vercel News
阮一峰的网络日志
阮一峰的网络日志
Recent Announcements
Recent Announcements
S
Secure Thoughts
The Cloudflare Blog
美团技术团队
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - MainTao

WebStorm 自定义字体+颜色+语法高亮+导入导出用户设置 WebStorm安装Vim以及快捷键设置 scroll clock–jQuery widget implement 基于iScroll 的开发(不断补充) C#操作Win7/Win8的库、收藏夹 WP7图片从独立存储绑定 编写jQueryUI插件(widget) 调试Javascript Windows Phone 7监测网络环境变化 Blend制作动画 用OpacityMask快速制作theme friendly UI 用gradient brush和OpacityMask实现fade edge效果 blend 画图 ControlTemplate & DataTemplate PhoneApplicationFrame以及设置Obscured/Unobscured的event handler Windows Phone 7 短信表情 WP7应用程序生命周期,以及各个event handler分别该做什么 第一个WP7程序 开发总结 XAML中的空格、换行、Tab
P/Invoke Interop 实例
MainTao · 2012-07-02 · via 博客园 - MainTao

新建一个项目,名为PInvoke:

image

image

建好项目后,添加一个cpp源文件,由于只是一个Demo,我们使用默认的名称Source.cpp:

image

Source.cpp代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>

typedef struct MyType{
    int i;
    char *s;
    double d;
    struct MyType *p;
} MyType;


int TestInt(int a, int b)
{
    return a + b;
}

void TestIntPtr(int *i)
{
    *i = *i * -1;
}

char* TestCharPtr(char *a, char *b)
{
    return strcat(a, b);
}

void TestStructPtr(MyType *p)
{
    p->i++;
    p->d++;
}

void TestPtrPtr(int **a, int length)
{
    *a = (int*)malloc(sizeof(int) * length);
    memset(*a, 0, sizeof(int) * length);
}

void TestArray(int *a, int length)
{
    for (int i = 0; i < length; i++)
    {
        a[i]++;
    }
}

void TestCallback(void (*pf) ( ))
{
    pf();
}

int TestCharWidth(char *s)
{
    return strlen(s);
}
添加一个新文件Source.def,用于导出Dll中的函数:
image

内容如下,其中LIBRARY "PInvoke"中的"PInvoke"是项目的名称:

LIBRARY "PInvoke"
    EXPORTS
        TestInt
        TestIntPtr
        TestCharPtr
        TestStructPtr
        TestPtrPtr
        TestArray
        TestCallback
        TestCharWidth

C的工程已经竣工了,下面来在解决方案中新加一个C#项目:

image

建好后,将ConsoleApplication1项目设置为启动项目,修改Program.cs代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct MyType
        {
            /// int
            public int i;

            /// char*
            [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
            public string s;

            /// double
            public double d;

            /// myType*
            public IntPtr p;
        }

        public delegate void Callback();

        [DllImport("PInvoke.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern int TestInt(int a, int b);

        [DllImport("PInvoke.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern void TestIntPtr(ref int i);

        [DllImport("PInvoke.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr TestCharPtr(System.IntPtr a, System.IntPtr b);

        [DllImport("PInvoke.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr TestStructPtr(ref MyType myType);

        [DllImport("PInvoke.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern void TestArray(int[] a, int length);

        [DllImport("PInvoke.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern void TestCallback(Callback callback);

        [DllImport("PInvoke.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern int TestCharWidth(IntPtr s);


        static void CallbackFunction() 
        { 
            Console.WriteLine("callback invoked"); 
        }

        static void Main(string[] args)
        {

            // TestInt
            Console.WriteLine(TestInt(1, 2));

            // TestIntPtr
            int i = 1;
            TestIntPtr(ref i);
            Console.WriteLine(i);

            // TestCharPtr
            IntPtr helloPtr = Marshal.StringToHGlobalAnsi("hello");
            IntPtr worldPtr = Marshal.StringToHGlobalAnsi("world");
            IntPtr helloWorldPtr = TestCharPtr(helloPtr, worldPtr);
            string helloWorld = Marshal.PtrToStringAnsi(helloWorldPtr);
            Console.WriteLine(helloWorld);
            Marshal.FreeHGlobal(helloPtr);
            Marshal.FreeHGlobal(worldPtr);
            // Marshal.FreeHGlobal(helloWorldPtr);  // 因为helloWorldPtr和helloPtr指向的是同一地址,所以再次释放会报错

            // TestCharWidth
            string a = "a的";
            IntPtr aPtr = Marshal.StringToHGlobalAnsi(a); // Ansi
            int len = TestCharWidth(aPtr);
            Console.WriteLine(len);
            a = Marshal.PtrToStringAnsi(aPtr);
            Marshal.FreeHGlobal(aPtr);

            aPtr = Marshal.StringToHGlobalUni(a); // Unicode
            len = TestCharWidth(aPtr); // 值是1,strlen没有正确处理unicode,所以不要使用strlen测量unicode字符串的长度
            Console.WriteLine(len);
            a = Marshal.PtrToStringUni(aPtr);
            Marshal.FreeHGlobal(aPtr);
            
            // TestStructPtr
            MyType myType = new MyType { i = 0, d = 1.1, s = "a的", p = IntPtr.Zero };
            TestStructPtr(ref myType);

            // TestArray
            int[] array = new int[] { 1, 2, 3 };
            TestArray(array, array.Length);

            // TestCallback
            TestCallback(CallbackFunction);

            Console.Read();
        }
    }
}

为了调试方便,我们在编译好C的dll后,自动把dll拷贝到C#项目的可执行文件目录下。在PInvoke项目上右键,属性,然后如下图:

image

按F5调试一下你的代码吧。

PInvoke Interop Assistant

PInvoke Interop Assistant是一个免费的把C/C++代码转成C#/VB.net的工具,非常好用。以下是使用截图:

image

在左边写native code,右边会自动转换成C#。所以如果有Native的类型不知转成C#该怎么写,它可以直接告诉你。

sample代码下载地址:https://files.cnblogs.com/dc10101/PInvoke.zip

PInvoke Interop Assistant下载地址:https://files.cnblogs.com/dc10101/PInvokeInteropAssistant.zip