1. 程式人生 > >動態連結庫匯出模板類以及一些問題

動態連結庫匯出模板類以及一些問題

這篇文章先說如何寫一個匯出模板類的動態連結庫,再說問題。

要編寫自己的動態連結庫首先需要建立一個dll工程,我用的是win10+vs2015


建立dll工程後vs會自動給你生成幾個檔案。在Dll2.h和Dll2.cpp中寫自己的類定義和類函式實現就好了。但是因為是要匯出類所以要有__declspec(dllexport)又因為是模板所以直接上程式碼看看怎麼做吧

.h

#pragma once
#include <string>
#include <fstream>
#include <iostream>



#ifdef _EXPORTS
#define _USE_DLL_ __declspec(dllexport)//用於匯出宣告
#else 
#define _USE_DLL_ __declspec(dllimport)//用於匯入宣告
#endif

template< class TYPE>//模板宣告
class _USE_DLL_ CTest
{
public:
	TYPE add(TYPE a, TYPE b);
	TYPE red(TYPE a ,TYPE b);
};
template <class TYPE> _USE_DLL_ CTest<TYPE>* Get();
.cpp
#include "pch.h"
#define _EXPORTS//這句要加在#include "pch.h"之前,用於匯出。
#include "Dll1.h"
template<class TYPE >
TYPE CTest::add(TYPE a,TYPE b)
{
	return a+b;
}
template<class TYPE >
TYPE CTest::red(TYPE a,TYPE b)
{
	return a-b;
}
template<class TYPE >
_USE_DLL_ CTest<TYPE>*  Get()
{
	CTest<TYPE> instance=new CTest<TYPE>();
	return instance;
}
void createcode()//生成程式碼
{
	CTest<float>* f_pTest= Get<float>();
	f_pTest->add(1.2,1.5);
	f_pTest->red(1.9,1.5);
}
從上面的程式碼看匯出模板類(一不小心贈送了一個模板函式)沒什麼貼別之處,除了加上了匯出生命和模板宣告之外最不同也是最關鍵的地方就是多了一個“沒用“的函式createcode()。這個函式之所以存在是和模板息息相關的。模板在不例項化(使用)的時候是不生成程式碼的,這樣的話我們寫的CTetst模板類和Get()模板函式都只是一個空。因為在dll內部他們並沒有被使用,所以不會產生相關程式碼。而有了createcode()這個“沒用”的函式,編譯器編譯Createcode的時候知道了createcode需要使用CTest<float>以及函式add和red,還有Get<float>(),所以編譯器生成了float版本的程式碼。也就是說目前這個dll只支援CTest模板類對float的例項化,如果要想支援int,則createcode函式裡要加上相應的int相關程式碼。是不是感覺很坑?沒辦法,能匯出就不錯了!返回來,也就說這個”沒用”的函式並不是沒有用處只是沒有使用,不僅有用而且還是匯出模板的關鍵所在。
下面就是要說封裝dll過程中遇到的問題了
問題1:應用程式無法正常啟動(0xc000a200).


最開始在網上查都說是dll位數不對 什麼32位機器用的64位dll吧啦吧啦。其實並不是,最終的解決的辦法是在dll專案屬性中聯結器的命令設定中增加了一條 /APPCONTAINER :NO 命令。然後重新生成dll。就不會包這個問題了。然而出現了新的問題




問題2:執行時提示自己缺少VCRUNTIME14D_APP.DLL這個問題好詭異,自己用depandency walker看了dll內部依賴,確實少這個dll。前面的名字是系統的dll,但是後面卻多了一個“_APP”。而且我找了確實找不到這個dll 但是在 C:\Windows\SysWOW64目錄下找到了VCRUNTIME14D.DLL,思考了良久有個群友說讓我把這個重新命名成VCRUNTIME14D_APP.DLL結果又提示VCRUNTIME14D.DLL找不到了。於是複製了一份VCRUNTIME14D.DLL,然後將副本重新命名為VCRUNTIME14D_APP.DLL再重新執行居然正常運行了,好吧我承認我很山寨,但是不管怎麼說可以運行了。至於為什麼出現這些問題以及為什麼這樣能解決。有時間在深究吧。

針對以上兩個問題有了正確的解決方案。問題1和問題2產生的原因根本原因是dll和客戶端程式“不匹配”。dll工程是 Universal Windows的而我的客戶端是win32的。win32工程 的意思是傳統的windows程式,而Universal Windows指的是UWP程式,這種程式是微軟跨平臺程式也就是PC,平板,手機,Xbox等其他win0系統裝置上的通用程式。這種程式預設是在沙盒中執行的,因此也就有了問題一的出現,也就解釋了為什麼/APPCONTAINER :NO命令可以“解決”問題一,

沙盒程式使用的dll,是存在於沙盒中名字為xxx_app.dll的動態連結庫,這又解釋了問題2。所以以上兩個問題的根本原因是客戶端和dll的專案型別“不匹配”造成的。