DLL 封装动态链接库

最近由于工作原因需要封DLL给客户用同时还要提供C#调用demo,这两个好几年都没用过了有点手生,趁热打铁记录一下以供回头查看。
什么?你问我现在在干嘛?哦哦...我在玩儿iOS编程...半路出家自学的那种...好了废话不多说了开干吧(๑•̀ㅂ•́)و✧加油

1.生成"C"的DLL

vs编译器创建win32工程,并创建DLL工程(这里不展示创建,直白点好,直接上代码),然后code
>>> test_dll.h

#ifndef _TEST_DLL_HEADER_H_
#define _TEST_DLL_HEADER_H_

#if defined(TEST_DLL_EXPORT)
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif

#ifdef __cplusplus
extern "C" {
#endif

    typedef struct {
    
        void(*on_start)(int code, void *param);
        void(*on_stop)(void *param);
    }test_callbacks;

    DLL_API void* create_handle(test_callbacks cb, void *param);
    DLL_API void start_handle(void *handle);
    DLL_API void stop_handle(void *handle);
    DLL_API void destroy_handle(void *handle);

#ifdef __cplusplus
}
#endif

#endif

>>> test_dll.c

///define dll export macro
#define TEST_DLL_EXPORT

#include "test_dll.h"

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

typedef struct {

    test_callbacks  callbacks;
    void*           callback_param;
}test_handle;

void* create_handle(test_callbacks cb, void *param) {

    test_handle *h = (test_handle*)malloc(sizeof(test_handle));
    if (NULL != h) {

        h->callbacks = cb;
        h->callback_param = param;
    }
    return h;
}


void start_handle(void *handle) {

    test_handle *h = (test_handle*)handle;
    printf(">>> start handle...\n");
    if (NULL != h && NULL != h->callbacks.on_start) {

        h->callbacks.on_start(404, h->callback_param);
    }
}

void stop_handle(void *handle) {

    test_handle *h = (test_handle*)handle;
    printf(">>> stop handle...\n");
    if (NULL != h && NULL != h->callbacks.on_stop) {

        h->callbacks.on_stop(h->callback_param);
    }
}

void destroy_handle(void *handle) {

    test_handle *h = (test_handle*)handle;
    if(NULL != h){

        free(h);
        h = NULL;
    }
}

2.调用DLL演示,在C中调用DLL

>>> use_dll_in_c.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <strsafe.h>

#include "test_dll.h"

#define API_USE_DLL 1

/// this way need header file
#if !API_USE_DLL
#pragma comment(lib, "dll_for_cs_demo.lib")
#endif


void test_start(int code, void *param) {

    printf(">>> [cb_start] code: %d\nparam: %s\n", code, (char*)param);
}

void test_stop(void *param) {

    printf(">>> [cb_stop] param: %s\n", (char*)param);
}

void PeerLastErrorMessage(PTCHAR function) {

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError();
    DWORD len = 0;
    char *str = NULL;

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf,
        0, NULL);

    // Display the error message and exit the process

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
        (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)function) + 40) * sizeof(TCHAR));
    StringCchPrintf((LPTSTR)lpDisplayBuf,
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"),
        function, dw, lpMsgBuf);
#if defined(UNICODE)
    len = WideCharToMultiByte(CP_ACP, 0, (LPCTSTR)lpDisplayBuf, -1, NULL, 0, NULL, 0);
    str = (char*)malloc(sizeof(char) * (len + 1));
    WideCharToMultiByte(CP_ACP, 0, (LPCTSTR)lpDisplayBuf, -1, str, len, NULL, 0);
    str[len] = '\0';
#endif
    //MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
    printf("%s\n", str);

    free(str);
    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
    //ExitProcess(dw);

}

typedef void* (*_create_h)(test_callbacks cb, void* param);
typedef void(*_all_h)(void* param);

int main(int argc, const char *argv[]) {

    int b = 0;
    void* handle = NULL;
    HMODULE mh = NULL;
    _all_h _handles = NULL;
    _create_h _create = NULL;
    test_callbacks cb = {test_start, test_stop};

#if API_USE_DLL
    /// use dll
    mh = LoadLibrary(L"dll_for_cs_demo.dll");
    if (NULL == mh) {

        PeerLastErrorMessage(L">>> main");
        getchar();
        return EXIT_FAILURE;
    }

    _create_h _ch = (_create_h)GetProcAddress(mh, "create_handle");
    _all_h _sh = (_all_h)GetProcAddress(mh, "start_handle");
    _all_h _eh = (_all_h)GetProcAddress(mh, "stop_handle");
    _all_h _dh = (_all_h)GetProcAddress(mh, "destroy_handle");

    handle = _ch(cb, (void*)"haha");
    _sh(handle);
    _eh(handle);
    _dh(handle);
#else
    /// use lib
    handle = create_handle(cb, (void*)"hehe");
    start_handle(handle);
    stop_handle(handle);
    destroy_handle(handle);
#endif

    printf(">>> press anykey to exit...\n");
    getchar();

    return 0;
}

3.调用DLL演示,在C#中调用DLL

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

namespace use_dll_in_cs
{
    class Program
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate void on_start_d(int code, IntPtr param);

        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate void on_stop_d(IntPtr param);

        [StructLayout(LayoutKind.Sequential)]
        public struct callback
        {
            public on_start_d start_cb;
            public on_stop_d stop_cb;
        }

        [DllImport("dll_for_cs_demo.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "create_handle")]
        public extern static IntPtr create_handle(callback cb, IntPtr param);

        [DllImport("dll_for_cs_demo.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "start_handle")]
        public extern static IntPtr start_handle(IntPtr handle);

        [DllImport("dll_for_cs_demo.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stop_handle")]
        public extern static IntPtr stop_handle(IntPtr handle);

        [DllImport("dll_for_cs_demo.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "destroy_handle")]
        public extern static IntPtr destroy_handle(IntPtr handle);

        public static void test_start_cb(int code, IntPtr param)
        {
            Console.WriteLine(">>> [start_cb]: code: {0}, param: {1}", code, Marshal.PtrToStringAnsi(param));
        }

        public static void test_stop_cb(IntPtr param)
        {
            Console.WriteLine(">>> [stop_cb]: param: {0}", Marshal.PtrToStringAnsi(param));
        }

        static void Main(string[] args)
        {
            callback cb;
            cb.start_cb = test_start_cb;
            cb.stop_cb = test_stop_cb;
            IntPtr str_ptr = Marshal.StringToHGlobalAnsi("hello, c#");
            IntPtr handle = create_handle(cb, str_ptr);
            start_handle(handle);
            stop_handle(handle);
            Console.WriteLine("press any key to exit...");
            Console.ReadLine();

            destroy_handle(handle);
            Marshal.FreeHGlobal(str_ptr);
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容