在vs2013下手把手創建/調用dll


參考了大佬的文章

 

 

首先,體會一下靜態編譯:

創建Win32Project,選DLL,添加一個.h和.cpp文件

點擊生成解決方案,然后去debug目錄下拷貝.lib和.h文件。

新建一個控制台程序,添加一個main.cpp,效果如下:

(也可以在vs工具欄里添加,不過寫代碼更快更易懂方便)

靜態編譯部分到此結束。

 

 

 

 

 

 

 以下是動態編譯:

創建win32動態dll項目,添加.h和.cpp文件

 

在同一個工作環境下添加另一個win控制台應用程序,添加main文件如下

這樣以后就可以調用了,DLL內的函數分為兩種:

  (1)DLL導出函數,可供應用程序調用;

  (2) DLL內部函數,只能在DLL程序使用,應用程序無法調用它們。

以上就是動態鏈接庫內容,編寫dll時還可以添加一個.def文件,專門用於描述導出什么函數作為接口,如下:

在之前dll的.h和.cpp基礎上作改動:(頭文件里可以不用聲明deal函數)

以上全部內容,手把手跟着做就可以,優缺點設計原因自己解釋。

 

 

 

 DLL的靜態調用:
(與動態調用的不同點:編譯過程中就通過lib文件向exe文件中導入函數的信息,所以就不存在運行時再LoadLibrary)

(與普通函數的不同點:普通函數調用查函數表找地址運行就好,DLL函數查表得dll內存中位置及該函數序號,然后找dll調用該函數。ps:會有DllMain函數的調用,在該進程/線程開始及結束時)

總而言之,靜態調用相對方便,windows幫了不少忙,動態調用很麻煩,但靈活性高(運行效率高)

  (1)告訴編譯器與DLL相對應的.lib文件所在的路徑及文件名,#pragma comment(lib,"dllTest.lib")就是起這個作用。

  程序員在建立一個DLL文件時,連接器會自動為其生成一個對應的.lib文件,該文件包含了DLL 導出函數的符號名及序號(並不含有實際的代碼)。在應用程序里,.lib文件將作為DLL的替代文件參與編譯。

  (2)聲明導入函數,extern "C" __declspec(dllimport) add(int x,int y)語句中的__declspec(dllimport)發揮這個作用。

  靜態調用方式不再需要使用系統API來加載、卸載DLL以及獲取DLL中導出函數的地址。這是因為,當程序員通過靜態鏈接方式編譯生成應用程序時,應用程序中調用的與.lib文件中導出符號相匹配的函數符號將進入到生成的EXE 文件中,.lib文件中所包含的與之對應的DLL文件的文件名也被編譯器存儲在 EXE文件內部。當應用程序運行過程中需要加載DLL文件時,Windows將根據這些信息發現並加載DLL,然后通過符號名實現對DLL 函數的動態鏈接。這樣,EXE將能直接通過函數名調用DLL的輸出函數,就象調用程序內部的其他函數一樣。

 

 

 

關於DllMain函數我覺得百度百科的這一篇很詳盡

 

我在win32 dll項目.cpp文件里聲明DllMain函數,在vs項目屬性-->C/C++預編譯器去掉_USRDLL一項,再自己寫DllMain如下

DllMain的官方聲明如下:

BOOL WINAPI DllMain(
  _In_ HINSTANCE hinstDLL, // 指向自身的句柄
  _In_ DWORD fdwReason, // 調用原因
  _In_ LPVOID lpvReserved // 隱式加載和顯式加載
);
// 以上內容來自MSDN

 

 

 

 

 關於其他語言調用DLL

1 #ifndef LIB_H
2 #define LIB_H
3 int /*__stdcall*/ add(int x, int y);
4 
5 #endif    //    LIB

 

 

 

 

 

 

 

 

關於調用DLL中的全局變量

/*DLL項目部分*/

//DLL.h
#ifndef LIB_H
#define LIB_H
extern "C" int /*__stdcall*/ add(int x, int y);
extern "C" int dllGlobalVar;

#endif    //    LIB

//DLL.cpp
#include "WinDll.h"
#include <Windows.h>
#include <stdio.h>

int dllGlobalVar = 1997;

int deal(int x, int y){
    return 100 - x - y;
}

int /*__stdcall*/ add(int x, int y)
{
    return deal(x, y);
}

BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        printf("procss attach");
        dllGlobalVar = 1157;
        break;
    case DLL_PROCESS_DETACH:
        printf("procss detach, global var is%d\n", dllGlobalVar);
        dllGlobalVar = 0;
        break;
    case DLL_THREAD_ATTACH:
        printf("thread attach");
        break;
    case DLL_THREAD_DETACH:
        printf("thread detach");
        break;
    default:
        printf("can't default");
    }
    return TRUE;
}

/*  .def文件
LIBRARY WinDll

EXPORTS
add @ 1
dllGlobalVar DATA
*/



/*控制台程序部分*/

//main.cpp
#include <stdio.h>
#include <Windows.h>
#pragma comment(lib, "..\\Debug\\WinDll.lib")

extern "C" int __declspec(dllimport) dllGlobalVar;
extern "C" int __declspec(dllimport) add(int, int);

int main(int argc, char **argv)
{
    printf("\ndllGLobalVar:%d\n", dllGlobalVar);
    dllGlobalVar = 2018;

    return 0;
}

 

 

 

 

以上即C代碼導出dll的全部內容,下面進入到C++導出類:

懶得寫了,C++類的導出和C差不多,類的聲明如下

#ifndef POINT_H
#define POINT_H
#ifdef DLL_FILE
class __declspec(dllexport) point //導出類point
#else
class __declspec(dllimport) point //導入類point
#endif
{
public:
    float y;
    float x;
    point();
    point(float x_coordinate, float y_coordinate);
};

#endif

這樣的話生成lib和dll文件以后拷到需要的工程目錄下,

#pragma comment(lib, "path")

一句就可以了。

例如OpenCV庫,就需要在QT的pro文件里寫上

INCLUDEPATH += D:/opencv/build/include

CONFIG(debug, debug|release): {
LIBS += -LD:/opencv/build/x64/vc12/lib \
-lopencv_core2413d \
-lopencv_imgproc2413d \
-lopencv_highgui2413d \
-lopencv_ml2413d \
-lopencv_video2413d \
-lopencv_features2d2413d \
-lopencv_calib3d2413d \
-lopencv_objdetect2413d \
-lopencv_contrib2413d \
-lopencv_legacy2413d \
-lopencv_flann2413d
} else:CONFIG(release, debug|release): {
LIBS += -LD:/opencv/build/x64/vc12/lib \
-lopencv_core2413 \
-lopencv_imgproc2413 \
-lopencv_highgui2413 \
-lopencv_ml2413 \
-lopencv_video2413 \
-lopencv_features2d2413 \
-lopencv_calib3d2413 \
-lopencv_objdetect2413 \
-lopencv_contrib2413 \
-lopencv_legacy2413 \
-lopencv_flann2413
}

目的就是導入庫文件來進行靜態鏈接,可見我幾乎每天都在用但是今天才發現。

類的動態編譯也一樣,略。

 

 

關於DLL的方面告一小結,接下來要去整MFC了。

-------------2018.01.11----------------


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM