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