dll引用小結(jié)
一哪审、dll與應(yīng)用程序
動(dòng)態(tài)鏈接庫(kù)(也稱為DLL蛾魄,即為“Dynamic Link Library”的縮寫(xiě))是Microsoft Windows最重要的組成要素之一,打開(kāi)Windows系統(tǒng)文件夾湿滓,你會(huì)發(fā)現(xiàn)文件夾中有很多DLL文件滴须,Windows就是將一些主要的系統(tǒng)功能以DLL模塊的形式實(shí)現(xiàn)。
動(dòng)態(tài)鏈接庫(kù)是不能直接執(zhí)行的叽奥,也不能接收消息扔水,它只是一個(gè)獨(dú)立的文件,其中包含能被程序或其它DLL調(diào)用來(lái)完成一定操作的函數(shù)(方法朝氓。注:C#中一般稱為“方法”)魔市,但這些函數(shù)不是執(zhí)行程序本身的一部分,而是根據(jù)進(jìn)程的需要按需載入赵哲,此時(shí)才能發(fā)揮作用待德。
DLL只有在應(yīng)用程序需要時(shí)才被系統(tǒng)加載到進(jìn)程的虛擬空間中,成為調(diào)用進(jìn)程的一部分枫夺,此時(shí)該DLL也只能被該進(jìn)程的線程訪問(wèn)将宪,它的句柄可以被調(diào)用進(jìn)程所使用,而調(diào)用進(jìn)程的句柄也可以被該DLL所使用橡庞。在內(nèi)存中较坛,一個(gè)DLL只有一個(gè)實(shí)例,且它的編制與具體的編程語(yǔ)言和編譯器都沒(méi)有關(guān)系扒最,所以可以通過(guò)DLL來(lái)實(shí)現(xiàn)混合語(yǔ)言編程丑勤。DLL函數(shù)中的代碼所創(chuàng)建的任何對(duì)象(包括變量)都?xì)w調(diào)用它的線程或進(jìn)程所有。
下面列出了當(dāng)程序使用 DLL 時(shí)提供的一些優(yōu)點(diǎn):[1]
- 使用較少的資源
當(dāng)多個(gè)程序使用同一個(gè)函數(shù)庫(kù)時(shí)吧趣,DLL 可以減少在磁盤(pán)和物理內(nèi)存中加載的代碼的重復(fù)量法竞。這不僅可以大大影響在前臺(tái)運(yùn)行的程序香缺,而且可以大大影響其他在 Windows 操作系統(tǒng)上運(yùn)行的程序廊宪。 - 推廣模塊式體系結(jié)構(gòu)
DLL 有助于促進(jìn)模塊式程序的開(kāi)發(fā)股耽。這可以幫助您開(kāi)發(fā)要求提供多個(gè)語(yǔ)言版本的大型程序或要求具有模塊式體系結(jié)構(gòu)的程序泽示。模塊式程序的一個(gè)示例是具有多個(gè)可以在運(yùn)行時(shí)動(dòng)態(tài)加載的模塊的計(jì)帳程序。 - 簡(jiǎn)化部署和安裝
當(dāng) DLL 中的函數(shù)需要更新或修復(fù)時(shí)秉剑,部署和安裝 DLL 不要求重新建立程序與該 DLL 的鏈接泛豪。此外,如果多個(gè)程序使用同一個(gè) DLL侦鹏,那么多個(gè)程序都將從該更新或修復(fù)中獲益诡曙。當(dāng)您使用定期更新或修復(fù)的第三方 DLL 時(shí),此問(wèn)題可能會(huì)更頻繁地出現(xiàn)略水。
二价卤、Dll的調(diào)用
每種編程語(yǔ)言調(diào)用DLL的方法都不盡相同,在此只對(duì)用C#調(diào)用DLL的方法進(jìn)行介紹渊涝。首先,您需要了解什么是托管,什么是非托管慎璧。一般可以認(rèn)為:非托管代碼主要是基于win 32平臺(tái)開(kāi)發(fā)的DLL,activeX的組件跨释,托管代碼是基于.net平臺(tái)開(kāi)發(fā)的胸私。如果您想深入了解托管與非托管的關(guān)系與區(qū)別,及它們的運(yùn)行機(jī)制鳖谈,請(qǐng)您自行查找資料岁疼,本文件在此不作討論。
調(diào)用DLL非托管函數(shù)的一般方法
首先缆娃,應(yīng)該在C#語(yǔ)言源程序中聲明外部方法捷绒,其基本形式是:
[DLLImport(“DLL文件”)]
修飾符 extern 返回變量類型 方法名稱 (參數(shù)列表)
其中:
DLL文件:包含定義外部方法的庫(kù)文件。
修飾符: 訪問(wèn)修飾符贯要,除了abstract以外在聲明方法時(shí)可以使用的修飾符暖侨。
返回變量類型:在DLL文件中你需調(diào)用方法的返回變量類型。
方法名稱:在DLL文件中你需調(diào)用方法的名稱郭毕。
參數(shù)列表:在DLL文件中你需調(diào)用方法的列表它碎。
注意:需要在程序聲明中使用System.Runtime.InteropServices命名空間。
DllImport只能放置在方法聲明上显押。
DLL文件必須位于程序當(dāng)前目錄或系統(tǒng)定義的查詢路徑中(即:系統(tǒng)環(huán)境變量中Path所設(shè)置的路徑)。
返回變量類型傻挂、方法名稱乘碑、參數(shù)列表一定要與DLL文件中的定義相一致。
若要使用其它函數(shù)名金拒,可以使用EntryPoint屬性設(shè)置兽肤,如:
[DllImport("user32.dll", EntryPoint="MessageBoxA")]
static extern int MsgBox(int hWnd, string msg, string caption, int type);
其它可選的 DllImportAttribute 屬性:
CharSet 指示用在入口點(diǎn)中的字符集套腹,如:CharSet=CharSet.Ansi;
SetLastError 指示方法是否保留 Win32"上一錯(cuò)誤"资铡,如:SetLastError=true电禀;
ExactSpelling 指示 EntryPoint 是否必須與指示的入口點(diǎn)的拼寫(xiě)完全匹配,如:ExactSpelling=false笤休;
PreserveSig指示方法的簽名應(yīng)當(dāng)被保留還是被轉(zhuǎn)換尖飞, 如:PreserveSig=true;
CallingConvention指示入口點(diǎn)的調(diào)用約定店雅, 如:CallingConvention=CallingConvention.Winapi政基;
C#例子:
1.啟動(dòng)VS.NET,新建一個(gè)項(xiàng)目闹啦,項(xiàng)目名稱為“import1”沮明,模板為“控制臺(tái)應(yīng)用程序”。
代碼如下
namespace import1
{
class Program
{
[DllImport("user32.dll", EntryPoint = "MessageBoxA")]
static extern int MsgBox(int hWnd, string msg, string caption, int type);
static void Main(string[] args)
{
MsgBox(0, " 這就是用 DllImport 調(diào)用 DLL 彈出的提示框哦窍奋! ", " 挑戰(zhàn)杯 ", 0x30);
}
}
}
然后運(yùn)行即可
生成一個(gè)自定義的C語(yǔ)言dll
所用平臺(tái)VisualStudio 2017
新建C++空項(xiàng)目
右鍵項(xiàng)目--->屬性--->選擇配置類型為動(dòng)態(tài)庫(kù)
在頭文件和源文件下分別建立test.h和test.c
test.h
__declspec(dllexport) int sum(int a, int b);
test.c
//test.c
#include "test.h"
#include <stdio.h>
int sum(int a, int b) {
return a + b;
}
生成項(xiàng)目荐健,在相應(yīng)的Debug文件夾下可以找到EasyHelloWorlddll.dll
找不到可以用listary搜索。
然后把該dll拷貝到C#項(xiàng)目文件的exe文件夾內(nèi)(點(diǎn)擊生成之后的Debug或者release文件夾)琳袄。
C# Vs中使用C的Dll
新建C#控制臺(tái)程序ConsoleAppTestDllImport
Program.cs代碼如下
using System;
namespace ConsoleAppTestDllImport
{
using System.Runtime.InteropServices;
class Program
{
[DllImport("EasyHelloWorlddll", EntryPoint = "sum", CallingConvention = CallingConvention.Cdecl)]
public static extern int Sum(int a, int b);
static void Main(string[] args)
{
Console.WriteLine(Sum(2,3));
Console.ReadKey();
}
}
其中 EntryPoint="sum"是定義入口函數(shù)名摧扇,使用這個(gè)可以自行在下面修改函數(shù)名稱,不使用則必須與C中的函數(shù)名相同挚歧。
這里注意[DllImport("EasyHelloWorlddll", EntryPoint = "sum", CallingConvention = CallingConvention.Cdecl)]
如果調(diào)用不加CallingConvertion扛稽,容易出現(xiàn)錯(cuò)誤
詳細(xì)見(jiàn):https://blog.csdn.net/wjeson/article/details/8263335
C++生成Dll
這里只是介紹最簡(jiǎn)單的生成方法,以后學(xué)多了考慮出個(gè)合集
同上C建立新工程滑负,只有代碼不同
C++ test.h
#pragma once //頭文件只編譯一次
extern "C" __declspec(dllexport) int __stdcall sum(int n1, int n2);
test.cpp
//test.cpp
#include "test.h"
#include <stdio.h>
int __stdcall sum(int a, int b)
{
return a + b;
}
C#上調(diào)用也是一樣的
{
using System;
using System.Runtime.InteropServices;
class Program
{
[DllImport("EasyHelloWorlddll", EntryPoint = "sum")]
public static extern int Sum(int a, int b);
static void Main(string[] args)
{
Console.WriteLine(Sum(2,3));
Console.ReadKey();
}
}
關(guān)于32位和64位DLL
因?yàn)樾掳娴腢nity不支持32位框架dll的導(dǎo)入在张,于是需要?jiǎng)?chuàng)建64位dll,
創(chuàng)建方式矮慕,把之前的改為64位帮匾,同時(shí)把屬性中的exe換為dll〕睁可行
C++ 調(diào)用 C++
生成 myfish.h
#pragma once
extern "C" __declspec(dllexport) double __stdcall sum(double delta, double freq, double phase);
生成 myfish.cpp
#include "psm.h"
#include <stdio.h>
#include <math.h>
double __stdcall sum(double delta,double freq ,double phase) {
double res = 100f * sin(delta+freq+ phase ) ;
return res;
}
生成看情況,正澄列保可以x64 Release
生成myfish.dll
新建項(xiàng)目aaa.sln
屬性->VC++ 目錄->包含目錄,包含.h的目錄
屬性->VC++ 目錄->庫(kù)目錄,包含.lib的目錄
鏈接器->輸入->附加依賴項(xiàng)->添加myfish.lib
#include <iostream>
#include "myfish.h"
int main()
{
std::cout << "Sum" << sum(7, 8, 0);
std::cout << "Hello World!\n";
system("pause");
}