C#调用DLL示例和注意事项

it2024-02-01  61

1. 生成dll文件

利用visual studio 2017新建一个windows控制台应用空项目。添加接口定义和实现相关的.h和.cpp文件,示例如下: # .h文件 #pragma once #include <stdio.h> #include <stdlib.h> #include <iostream> #ifdef ImageHandleDLL_EXPORTS #define ImageHandle_EXPORTS extern "C" __declspec(dllexport) #else #define ImageHandle_EXPORTS extern "C" __declspec(dllimport) #endif typedef enum { OPERATION_SUCCESS = (0), INPUT_CHANNELS_ERR = (1), INPUT_EMPTY_ERR = (2), PROCESS_FAILE = (3), } ErrCode; ImageHandle_EXPORTS ErrCode Read_Image(char * filepath, unsigned char **output_image_data, int &image_h, int &image_w, int &input_image_channels); ImageHandle_EXPORTS ErrCode Write_Image(unsigned char **intput_image_data, char * filepath, int image_h, int image_w, int input_image_channels); ImageHandle_EXPORTS ErrCode Image_Gray(unsigned char **input_image_data, unsigned char **output_image_data, int image_h, int image_w, int input_image_channels = 3); # .cpp文件 ErrCode Read_Image(char * filepath, unsigned char **output_image_data, int &image_h, int &image_w, int &input_image_channels) { try { cv::Mat src = cv::imread(filepath); image_h = src.rows; image_w = src.cols; input_image_channels = src.channels(); if (output_image_data[0] == nullptr) { output_image_data[0] = (unsigned char *)malloc(image_h*image_w *input_image_channels * sizeof(unsigned char)); } memcpy(output_image_data[0], src.data, image_h * image_w * input_image_channels * sizeof(unsigned char)); return OPERATION_SUCCESS; } catch (std::exception e) { if (output_image_data[0]) { free(output_image_data[0]); output_image_data = nullptr; } std::cout << e.what() << std::endl; return PROCESS_FAILE; } } ErrCode Write_Image(unsigned char **input_image_data, char * filepath, int image_h, int image_w, int input_image_channels) { try { if (input_image_channels == 4) { cv::Mat input_image(image_h, image_w, CV_8UC4, input_image_data[0]); cv::imwrite(filepath, input_image); } else if (input_image_channels == 3) { if (input_image_data) { cv::Mat input_image(image_h, image_w, CV_8UC3, input_image_data[0]); cv::imwrite(filepath, input_image); } } else if (input_image_channels == 1) { cv::Mat input_image(image_h, image_w, CV_8UC1, input_image_data[0]); cv::imwrite(filepath, input_image); } else { return INPUT_CHANNELS_ERR; } return OPERATION_SUCCESS; } catch (std::exception e) { std::cout << e.what() << std::endl; return PROCESS_FAILE; } } ErrCode Image_Gray(unsigned char **input_image_data, unsigned char **output_image_data, int image_h, int image_w, int input_image_channels) { try { if (input_image_data[0] == nullptr) { return INPUT_EMPTY_ERR; } if (output_image_data[0] == nullptr) { output_image_data[0] = (unsigned char *)malloc(image_h*image_w * 1 * sizeof(unsigned char)); } cv::Mat output_image; if (input_image_channels == 3) { cv::Mat input_image(image_h, image_w, CV_8UC3, input_image_data[0]); cv::cvtColor(input_image, output_image, cv::COLOR_BGR2GRAY); } else if (input_image_channels == 4) { cv::Mat input_image(image_h, image_w, CV_8UC4, input_image_data[0]); cv::cvtColor(input_image, output_image, cv::COLOR_BGRA2GRAY); } else if (input_image_channels == 1) { memcpy(output_image_data[0], output_image.data, image_h*image_w * 1 * sizeof(unsigned char)); return OPERATION_SUCCESS; } else { if (output_image_data[0]) { free(output_image_data[0]); output_image_data[0] = nullptr; } return INPUT_CHANNELS_ERR; } memcpy(output_image_data[0], output_image.data, image_h*image_w * 1 * sizeof(unsigned char)); return OPERATION_SUCCESS; } catch (std::exception e) { if (output_image_data[0]) { free(output_image_data[0]); output_image_data[0] = nullptr; } std::cout << e.what() << std::endl; return PROCESS_FAILE; } }

2. C#调用dll文件

利用visual studio 2017新建一个windows控制台应用空项目。

修改.cs文件如下:

#.cs文件 using System; using System.Runtime.InteropServices; namespace app_project { class Program { [DllImport("ImageHandle.dll")] public static extern int Read_Image(string filepath,ref UIntPtr output_image_data, ref int image_h, ref int image_w, ref int input_image_channels); [DllImport("ImageHandle.dll")] public static extern int Write_Image(ref UIntPtr intput_image_data, string filepath, int image_h, int image_w, int input_image_channels); [DllImport("ImageHandle.dll")] public static extern int Image_Gray(ref UIntPtr input_image_data,ref UIntPtr output_image_data, int image_h, int image_w, int input_image_channels = 3); static void Main(string[] args) { Console.WriteLine("测试"); string path = "test_align.jpg"; UIntPtr input_image_data = new UIntPtr(); int image_height = 0; int image_width = 0; int image_channels = 0; Read_Image(path,ref input_image_data,ref image_height,ref image_width,ref image_channels); UIntPtr output_image_data = new UIntPtr(); Image_Gray(ref input_image_data, ref output_image_data, image_height, image_width, image_channels); string path_1 = "test_align_gray.jpg"; Write_Image(ref output_image_data, path_1, image_height, image_width, 1); Console.WriteLine("OK"); Console.Read(); } } } 选择平台并生成exe,其中平台需要和生成dll文件时的平台一致,并将dll文件所以依赖的其他dll文件拷贝到exe所在的目录下。

3 说明

3.1 [DllImport("*.dll")]说明

每添加一个接口,均要有一条[DllImport("*.dll")] , 示例如下:

[DllImport("ImageHandle.dll")] public static extern IntPtr GetLibraryVersion(); [DllImport("ImageHandle.dll")] public static extern int Read_Image(string filepath, ref UIntPtr output_image_data, ref int image_h, ref int image_w, ref int input_image_channels);

3.2 形参类型转换

引用类型 c++接口中形参类型为int &, 而对应在c#中形参类型为ref int,其中ref参数表示变量作为参数传给方法时,同时希望在方法执行完成后,对参数所做的修改能够反映到变量上;示例如下: C++ 方式: Add( int &h, int &w, int &sum);

C# 方式:

Add(ref int h, ref int w, ref int sum); char * c++接口中形参类型为char *, 而在c#中形参类型为string,示例如下: Read_Image(char * filepath);

C# 方式:

Read_Image(string filepath); 数组 c++接口中形参类型为unsigned char **, 而在c#中形参类型为ref IntPtr,示例如下: Read_Image(unsigned char **intput_image_data);

C# 方式:

Read_Image(ref UIntPtr intput_image_data);

上述c++接口中,传递数组不能采用unsigned char *,其原因为:UIntPtr类型被称之为“平台特定的类型”,资源的大小取决于使用的硬件和操作系统,但其大小总是足以包含系统的指针,类似含有窗口句柄参数(HANDLE)。

最新回复(0)