最近由于工作原因需要封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);
}
}
}
网友评论