VC++ .NET 動態(tài)加載DLL,使用反射方式Invoke委托調(diào)用
因為我是做嵌入式開發(fā)的,每次設備程序更新后都需要修改上位機,并且多個上位機,修改起來特麻煩,又不想用C#主要是底層使用的是C語言,配置解析通信等在單片機里面寫好后可以直接復制到C++中使用,比較方便,我使用VC++開發(fā)比較方便,但是資料少,因此折騰了幾晚上.
每次新產(chǎn)品都需要配一個上位機,并且本地配置與遠程配置都需要重新開放配置程序,因此就想辦法把配置模塊變?yōu)橐粋€動態(tài)的控件,一次開發(fā)后續(xù)2個程序都可以同時使用,使用了很多種方法,最后還是使用反射方式.
一.首先新建一個窗體控件DLL
將需要的界面從源程序拷貝過來
//對外接口函數(shù),所有參數(shù)均為Object ^類型
//輸入的配置,用于設置輸入配置的緩沖區(qū)
public:void?Object_SetInConfig(Object?^Parameter)
{
if(Parameter?==?nullptr)
{
System::Windows::Forms::MessageBox::Show("內(nèi)存不足!","錯誤",
System::Windows::Forms::MessageBoxButtons::OK,System::Windows::Forms::MessageBoxIcon::Error);
return;
}
SetInConfig((void*)Convert::ToInt32(Parameter)); //調(diào)用函數(shù)設置輸入的配置參數(shù)
}
???//檢查參數(shù)是否合法
public:Object?^Object_XF_CheckParameter(void)
???{
???Object?^temp?=?gcnew?Object;
???temp?=?this->CheckParameter();
???return?temp;
???}
???//存儲配置
public:Object?^Object_SaveConfig(Object?^Parameter)
???{
???Object?^temp?=?gcnew?Object;
???if(Parameter?==?nullptr)
???{
???System::Windows::Forms::MessageBox::Show("內(nèi)存不足!","錯誤",
???System::Windows::Forms::MessageBoxButtons::OK,System::Windows::Forms::MessageBoxIcon::Error);
???temp?=?false;
???return?temp;
???}
???temp?=?this->SaveConfig((void*)Convert::ToInt32(Parameter));
???return?temp;
???}
???//獲取配置文件大小
public:Object?^Object_GetConfigSize(void)
???{
???Object?^temp?=?gcnew?Object;
???temp?=?this->GetConfigSize();
???return?temp;
???}二.動態(tài)加載調(diào)用
//通過方法名稱獲得方法 System::Reflection::Assembly?^assembly; System::Type^?type; Object?^obj; System::Reflection::MethodInfo?^XF_SetInConfig; //顯示讀取的配置 System::Reflection::MethodInfo?^XF_CheckParameter; //參數(shù)無誤 System::Reflection::MethodInfo?^XF_SaveConfig; //存儲配置 System::Reflection::MethodInfo?^XF_GetConfigSize; //獲取配置大小 System::Reflection::MethodInfo?^XF_DefaultConfig; //加載默認
//動態(tài)加載DLL文件
void?LoadDLL(String?^pDLL)
{
try
{
this->assembly?=?System::Reflection::Assembly::LoadFrom(USER_LIB.GetRunningDirectory()+"\device\"+this->pDevDLL); //加載DLL
}
catch?(System::IO::FileNotFoundException^?e)
{
System::Windows::Forms::MessageBox::Show("找不到依賴的設備配置文件:?"+this->pDevDLL+"?程序無法繼續(xù)運行!","程序發(fā)生錯誤",
System::Windows::Forms::MessageBoxButtons::OK,System::Windows::Forms::MessageBoxIcon::Error);
Application::Exit(); //程序退出
return;
}
this->type?=?this->assembly->GetType("XF_RTU_N_V1_0_CONFIG.XF_RTU_N_V1_0_CONFIGControl");
this->obj?=?this->assembly->CreateInstance("XF_RTU_N_V1_0_CONFIG.XF_RTU_N_V1_0_CONFIGControl");
this->panel1->Controls->Add((System::Windows::Forms::Control?^)this->obj); //將DLL的控件加載到panel1并顯示
this->PerformLayout();
//通過方法名稱獲得方法
this->XF_SetInConfig?=?this->type->GetMethod("Object_SetInConfig"); //顯示讀取的配置
this->XF_CheckParameter?=?this->type->GetMethod("Object_XF_CheckParameter"); //參數(shù)檢查
this->XF_SaveConfig?=?this->type->GetMethod("Object_SaveConfig"); //存儲配置
this->XF_GetConfigSize?=?this->type->GetMethod("Object_GetConfigSize"); //獲取配置大小
this->XF_DefaultConfig?=?this->type->GetMethod("DefaultConfig"); //加載默認
}//使用反射調(diào)用函數(shù)
1.無參數(shù),無返回函數(shù)調(diào)用最簡單
this->XF_DefaultConfig->Invoke(this->obj,?nullptr);
2.帶返回參數(shù)的函數(shù)調(diào)用,此處返回的是bool類型
if((bool)this->XF_CheckParameter->Invoke(this->obj,?nullptr)?==?true)//檢查參數(shù)
?{
?System::Windows::Forms::MessageBox::Show("配置參數(shù)無誤!","提示",
?System::Windows::Forms::MessageBoxButtons::OK,System::Windows::Forms::MessageBoxIcon::None);
?this->toolStripStatusLabel1->Text?=?"參數(shù)檢查無誤";
?}3.帶參數(shù)的函數(shù)調(diào)用需要使用cli::array< Object ^>^
將指針轉化為int類型傳入到參數(shù)表d中,此處只有1個形參,因此為
cli::array<?Object?^>(1),多個按照實際填寫.
cli::array<?Object?^>^??d?=?gcnew?cli::array<?Object?^>(1); ?d[0]?=?(int)&RTU_Config; //獲取指針并轉化為int ?this->XF_SaveConfig->Invoke(this->obj,?d); //存儲配置
三.本地配置上位機與其它程序實現(xiàn)統(tǒng)一,一次編寫,2個地方均可以使用
本地配置程序加載的配置控件
遠程后臺加載的同樣的控件
四.可實現(xiàn)同一個程序完成多個功能
同一個程序動態(tài)加載不同控件實現(xiàn)不同功能
五.通過與ini配置文件結合,可以在不修改程序代碼的情況下增加新設備支持,類似于插件
[設備數(shù)量] NUM=4 [設備類型] TYPE0=XF-RTU(老版) TYPE1=XF-RTU-N(標準版) TYPE2=XF-RTU-N(雙DTU版) TYPE3=XF-RTU-M(精簡版) [設備說明] INF0=第一代RTU INF1=第二代低功耗RTU INF2=第二代低功耗RTU INF3=低功耗簡版RTU口 [配置控件] DLL0=XF_RTU_老版本.dll DLL1=XF_RTU_N_V1_0_CONFIG.dll DLL2=XF_RTU_N_V1_0_CONFIG.dll DLL3=XF_RTU_N_V1_0_CONFIG.dll





