C++基礎語法梳理:Windows 的動態連結庫

2021-12-29 C語言編程學習基地

收錄於話題 #c++ 29個

Windows 應用程式入口函數

GUI(Graphical User Interface)應用,連結器選項:/SUBSYSTEM:WINDOWS

CUI(Console User Interface)應用,連結器選項:/SUBSYSTEM:CONSOLE

_tWinMain 與 _tmain 函數聲明

Int WINAPI _tWinMain(    HINSTANCE hInstanceExe,    HINSTANCE,    PTSTR pszCmdLine,    int nCmdShow);
int _tmain( int argc, TCHAR *argv[], TCHAR *envp[]);


Windows 的動態連結庫(Dynamic-Link Library)

部分知識點來自《Windows 核心編程(第五版)》

用處

(1)擴展了應用程式的特性

(2)簡化了項目管理

(3)有助於節省內存

(4)促進了資源的共享

(5)促進了本地化

(6)有助於解決平臺間的差異

(7)可以用於特殊目的

注意

(1)創建 DLL,事實上是在創建可供一個可執行模塊調用的函數

(2)當一個模塊提供一個內存分配函數(malloc、new)的時候,它必須同時提供另一個內存釋放函數(free、delete)

(3)在使用 C 和 C++ 混編的時候,要使用 extern "C" 修飾符

(4)一個 DLL 可以導出函數、變量(避免導出)、C++ 類(導出導入需要同編譯器,否則避免導出)

(5)DLL 模塊:cpp 文件中的 __declspec(dllexport) 寫在 include 頭文件之前

(6)調用 DLL 的可執行模塊:cpp 文件的 __declspec(dllimport) 之前不應該定義 MYLIBAPI

加載 Windows 程序的搜索順序

1、包含可執行文件的目錄

2、Windows 的系統目錄,可以通過 GetSystemDirectory 得到

3、16 位的系統目錄,即 Windows 目錄中的 System 子目錄

4、Windows 目錄,可以通過 GetWindowsDirectory 得到

5、進程的當前目錄

6、PATH 環境變量中所列出的目錄

DLL 入口函數

DllMain 函數

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){    switch(fdwReason)    {    case DLL_PROCESS_ATTACH:                        break;    case DLL_THREAD_ATTACH:                        break;    case DLL_THREAD_DETACH:                        break;    case DLL_PROCESS_DETACH:                        break;    }    return (TRUE); }

載入卸載庫

LoadLibrary、LoadLibraryExA、LoadPackagedLibrary、FreeLibrary、FreeLibraryAndExitThread 函數聲明

// 載入庫HMODULE WINAPI LoadLibrary(  _In_ LPCTSTR lpFileName);HMODULE LoadLibraryExA(  LPCSTR lpLibFileName,  HANDLE hFile,  DWORD  dwFlags);// 若要在通用 Windows 平臺(UWP)應用中加載 Win32 DLL,需要調用 LoadPackagedLibrary,而不是 LoadLibrary 或 LoadLibraryExHMODULE LoadPackagedLibrary(  LPCWSTR lpwLibFileName,  DWORD   Reserved);
// 卸載庫BOOL WINAPI FreeLibrary( _In_ HMODULE hModule);// 卸載庫和退出線程VOID WINAPI FreeLibraryAndExitThread( _In_ HMODULE hModule, _In_ DWORD dwExitCode);

顯示地連結到導出符號

GetProcAddress 函數聲明

FARPROC GetProcAddress(  HMODULE hInstDll,  PCSTR pszSymbolName  // 只能接受 ANSI 字符串,不能是 Unicode);

DumpBin.exe 查看 DLL 信息

在 VS 的開發人員命令提示符 使用 DumpBin.exe 可查看 DLL 庫的導出段(導出的變量、函數、類名的符號)、相對虛擬地址(RVA,relative virtual address)。如:

DUMPBIN -exports D:\mydll.dll

LoadLibrary 與 FreeLibrary 流程圖

LoadLibrary 與 FreeLibrary 流程圖

LoadLibrary


FreeLibrary


DLL 庫的編寫(導出一個 DLL 模塊)

DLL 庫的編寫(導出一個 DLL 模塊) DLL 頭文件


#ifdef MYLIBAPI

#else
#define MYLIBAPI extern "C" __declspec(dllimport)
#endif

MYLIBAPI int g_nResult;
MYLIBAPI int Add(int nLeft, int nRight);

DLL 源文件


#include <windows.h>
#define MYLIBAPI extern "C" __declspec(dllexport)
#include "MyLib.h"
int g_nResult;
int Add(int nLeft, int nRight){ g_nResult = nLeft + nRight; return g_nResult;}

DLL 庫的使用(運行時動態連結 DLL)

DLL 庫的使用(運行時動態連結 DLL)

 #include <windows.h> #include <stdio.h>  typedef int (__cdecl *MYPROC)(LPWSTR);  int main( void ) {     HINSTANCE hinstLib;     MYPROC ProcAdd;     BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;           hinstLib = LoadLibrary(TEXT("MyPuts.dll"));           if (hinstLib != NULL)     {         ProcAdd = (MYPROC) GetProcAddress(hinstLib, "myPuts");                   if (NULL != ProcAdd)         {            fRunTimeLinkSuccess = TRUE;            (ProcAdd) (L"Message sent to the DLL function\n");         }                 fFreeResult = FreeLibrary(hinstLib);     } 
if (! fRunTimeLinkSuccess) printf("Message printed from executable\n");
return 0;}

運行庫(Runtime Library)

典型程序運行步驟

(1)作業系統創建進程,把控制權交給程序的入口(往往是運行庫中的某個入口函數)

(2)入口函數對運行庫和程序運行環境進行初始化(包括堆、I/O、線程、全局變量構造等等)。

(3)入口函數初始化後,調用 main 函數,正式開始執行程序主體部分。

(4)main 函數執行完畢後,返回到入口函數進行清理工作(包括全局變量析構、堆銷毀、關閉I/O等),然後進行系統調用結束進程。

一個程序的 I/O 指代程序與外界的交互,包括文件、管程、網絡、命令行、信號等。更廣義地講,I/O 指代作業系統理解為 「文件」 的事物。

glibc 入口

_start -> __libc_start_main -> exit -> _exit

其中 main(argc, argv, __environ) 函數在 __libc_start_main 裡執行。

MSVC CRT 入口

int mainCRTStartup(void)

執行如下操作:

(1)初始化和 OS 版本有關的全局變量。

(2)初始化堆。

(3)初始化 I/O。

(4)獲取命令行參數和環境變量。

(5)初始化 C 庫的一些數據。

(6)調用 main 並記錄返回值。

(7)檢查錯誤並將 main 的返回值返回。

C 語言運行庫(CRT)

大致包含如下功能:

啟動與退出:包括入口函數及入口函數所依賴的其他函數等。

標準函數:有 C 語言標準規定的C語言標準庫所擁有的函數實現。

I/O:I/O 功能的封裝和實現。

堆:堆的封裝和實現。

語言實現:語言中一些特殊功能的實現。

調試:實現調試功能的代碼。

C語言標準庫(ANSI C)

包含:

標準輸入輸出(stdio.h)

文件操作(stdio.h)

字符操作(ctype.h)

字符串操作(string.h)

數學函數(math.h)

資源管理(stdlib.h)

格式轉換(stdlib.h)

時間/日期(time.h)

斷言(assert.h)

各種類型上的常數(limits.h & float.h)

變長參數(stdarg.h)

非局部跳轉(setjmp.h)

今天的分享就到這裡了,大家要好好學C++喲~

寫在最後:對於準備學習C/C++編程的小夥伴,如果你想更好的提升你的編程核心能力(內功)不妨從現在開始!

整理分享(多年學習的源碼、項目實戰視頻、項目筆記,基礎入門教程)

歡迎轉行和學習編程的夥伴,利用更多的資料學習成長比自己琢磨更快哦!

相關焦點

  • python3使用ctypes在windows中訪問C和C++動態連結庫函數示例
    python3使用ctypes在windows中訪問C和C++動態連結庫函數示例這是我們的第一個示例,我們儘量簡單,不傳參,不返回,不訪問其他的動態連結庫一 測試環境介紹和準備,與做python擴展庫不同,ctypes調用的c++庫其實與python沒有代碼關聯,只是提供了開放公共標準。
  • 解決JAVA調用C++ DLL文件Unable to load library的問題
    JAVA項目開發中,有時候會遇到調用C++編寫的動態連結庫的場景(比如調用第三方的動態連結庫、軟體中關鍵部分用C++編碼提供給外部調用)。我們知道JAVA調用動態連結庫(C/C++),可以通過以下二種方式:JNI、JNA。
  • 示例程序詳解MFC動態連結庫
    動態連結庫分為兩種win32和mfc動態連結庫,今天我們講解MFC動態連結庫 再閱讀本文之前,希望你看看《動態連結庫基礎詳解》
  • C++庫文件說明及使用方法
    每種類型的文件都有其存在的意義庫文件庫是一些函數和類的集合,其實現了某些特定的功能,是程序的開發免於從頭開始。庫有兩種:靜態連結庫和動態連結庫!在windows下靜態連結庫為.lib,動態連結庫為.dll;Linux下靜態連結庫為.a,動態連結庫為.so。這裡我們只介紹Windows下的庫。1.
  • C++機器學習庫介紹
    假設我們要實現線性回歸,那麼包含的額外頭文件是:#include <shark/ObjectiveFunctions/Loss/SquaredLoss.h>#include <shark/Algorithms/Trainers/LinearRegression.h>要編譯,我們需要連結到以下庫
  • python調用C++: ctypes庫教程
    一、準備C++代碼注意,使用ctypes庫調用C++代碼時,由於C++相比於C多了函數重載的特性,因此一個函數不能僅僅使用其名字來確定
  • 初學c++小白必備的工具附下載連結
    前不久,筆者在csdn的c++論壇發了一篇 貼文 ,以期能徵求大家的廣泛意見,得到了不錯的反響。本文在對該貼進行整理的基礎上,又做了一些補充。有以下幾點需要聲明:     - 本文主要是針對c++程式設計師的,但一些綜合類的通用型工具/軟體,作為c++程式設計師而言也是不可或缺的,因此也被列入其中。同樣,這些工具/軟體,對其他語言的程式設計師,也是適用的。
  • 關於Linux和Unix動態連結庫的安全
    實際上所有程序執行都依賴於庫。在包括Linux的大多數現代類Unix系統中,程序預設使用動態連接庫(DLL)進行編譯。這樣就可以更新某個庫,所有使用該庫的程序如果可能的話,都將使用新的(希望有所改進的)版本。  動態連接庫通常被放在若干特殊目錄下。
  • PSIM仿真軟體高級應用——C語言動態連結庫編寫和調用
    C語言知識C語言語法和常用編程流程;子函數的調用和申明;重點掌握C語言中數組、指針、結構體、共用體等應用;養成良好的編程習慣和變量命名習慣。3 PSIM仿真高級應用3.1靜態連結庫和動態連結庫(DLL)應用靜態連結庫就是常說的lib文件,用戶可以將常用的C語言子函數封裝成靜態庫文件,以便建立動態
  • 實現32位簡單版Windows和Linux雙平臺的C++運行庫
    因為要講清楚實現運行庫的細節是比較複雜的,同時也限於篇幅和避免複雜繁瑣,所以本文只會提及關鍵實現處並給出原始碼,同時給出相關知識點在《程式設計師的自我修養--連結、裝載與庫》中的相關章節和相關參考資料,如有不理解的地方請回帖或私信我,鑑於本人才疏學淺,如有錯誤,歡迎指正。1. 為了便於讀者理解,本文大量複製《程式設計師的自我修養--連結、裝載與庫》中的文字。2.
  • C++機器學習庫介紹 | 文末送書
    tutorials/tutorials.html使用Shark編譯程序#include <shark/ObjectiveFunctions/Loss/SquaredLoss.h>#include <shark/Algorithms/Trainers/LinearRegression.h>編譯需要連結到以下庫
  • xmake v2.3.8 發布, 新增 Intel C++/Fortran 編譯器支持
    xmake 是一個基於 Lua 的輕量級跨平臺構建工具,使用 xmake.lua 維護項目構建,相比 makefile/CMakeLists.txt,配置語法更加簡潔直觀$ xmake create -t qt.quickapp_static quickapp這裡,我們注意到,我們創建的是需要靜態link的Qt工程,因為 wasm 版本的 Qt 庫,我們需要強制靜態連結到程序才能正常使用。
  • 淺析動態連結庫側加載技術
    :隱式連結(load-time dynamic linking)也叫靜態調用和顯式連結(run-time dynamic linking)也叫動態調用。隱式連結方式一般用於開發和調試,而顯式連結方式就是我們常見的使用LoadLibary或者LoadLibraryEx函數(註:涉及到模塊加載的函數有很多)來加載DLL去調用相應的導出函數。調用LoadLibrary或者LoadLibraryEx函數時可以使用DLL的相對路徑也可以使用絕對路徑,但是很多情況下,開發人員都是使用了相對路徑來進行DLL的加載。
  • 第十七文:編譯基礎知識之cmake第一篇
    本文就是來講一些基礎編譯知識來解決這種尷尬的編譯回答。本文主要涉及到以下幾個話題:嵌入式開發編譯過程中用到哪些工具windows下MinGW是個什麼ghost在windows上交叉編譯liunx軟體cmake環境配置你的bat文件是個什麼角色一個hello_world兩種編法1.
  • Windows平臺安裝nim
    優雅宏無法更改Nim的語法,因為不需要它-語法足夠靈活。具有本地類型推斷,元組,泛型和和類型的現代類型系統。它的語法集python、lisp(主要是宏)、Ada之長於一身(可能對於習慣了C系語法的人來說有點不適應)。它其實更像是個「中間翻譯」語言:它把自身的語法翻譯成C/C++的,然後再藉助C編譯器(mingw)完成編譯連結。這個過程可以通過在nim命令行中添加「—nimcache」來查看。所以它編譯後的可執行文件的運行效率和體積都與直接用C/C++生成的文件不相上下。
  • scratch/python/c++,小孩學編程學哪個好?
    傳統編程建議學習c++或者python。如果目標就是奧賽,那建議學c++。c++是奧賽元老,而且會一直坐鎮下去,笑看其他語言上來又下去。關注本號也可以學習零基礎C++教程。c++效率高,資源佔用少,可以編寫底層的操作。比如windows系統等等。也有學習c++的同學自己鼓搗出一個作業系統。
  • Qt5.12.2+Opencv4.2配置動態連結庫以用Qt調用Opencv進行創作
    二、軟體安裝及環境變量配置1、Qt creator安裝(1)Qt安裝本教程針對之前下載的Qt 5.12.2進行安裝演示l 點擊下載好的qt-opensource-windows-x86l 選擇安裝路徑後點擊Nextl 點擊Install開始安裝3、Opencv的下載和安裝(1)Opencv庫的下載
  • C++卡牌小遊戲
    以前上學的時候業餘學了點c++ ,也僅僅用來做過一個控制臺版的「學生管理系統」,現在工作接觸最多的還是C語言,c++那各種屌炸天的語法和
  • python+C、C++混合編程的應用
    python與C/C++混合編程的本質是python調用C/C++編譯的動態連結庫,關鍵就是把python中的數據類型轉換成c/c++中的數據類型,給編譯函數處理,然後返回參數再轉換成python中的數據類型。