版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、<p> NSIS插件工作原理</p><p> 了解NSIS的童鞋都知道,在NSIS中調(diào)用插件有兩種方式,一種是通過Push將參數(shù)壓入棧中,然后使用CallInstDLL來調(diào)用插件中的函數(shù);另一種方式是使用插件命令,如plugin::function_name param1 param2 param 3...,本文的目的就是深入理解NSIS的插件命令是如何工作的,NSIS腳本是如何和插件dll進(jìn)行
2、交流的</p><p> 接下來我會(huì)以一個(gè)例子nsDialogs::Create 1018為例,具體講述NSIS究竟是怎樣解析這條語(yǔ)句,又是怎樣調(diào)用nsDialogs.dll中的Create函數(shù)的</p><p> NSIS腳本代碼是寫在一個(gè).nsi的文件中的,這種文件其實(shí)是一個(gè)文本文件,并不具備可執(zhí)行代碼的功能,它需要NSIS中的makensis.exe來編譯</p>
3、<p> 這種文件,編譯后會(huì)產(chǎn)生一個(gè).exe文件,就是生成的安裝包程序了,這個(gè)文件打開后就是一些安裝頁(yè)面,引導(dǎo)用戶進(jìn)行下一步操作,從而安裝</p><p> 文件到用戶的電腦上,也就是說NSIS中最厲害的其實(shí)是makensis.exe這個(gè)NSIS腳本編譯器了,NSIS是開源的,那么我們就來看看它的源碼是如何解析插件命令的調(diào)用的</p><p> 到目前為止,NSIS的最新版
4、本是2.46,它的源碼文件如下圖所示,NSIS是用C/C++寫的</p><p> 其中有幾個(gè)文件在解析插件命令時(shí)比較重要,build.cpp、Plugins.cpp、script.cpp、tokens.cpp、exehead\exec.c、exehead\plugin.c</p><p> NSIS中支持的命令、屬性、預(yù)處理指令等都在tokens.cpp中有定義,如下圖所示,只有少數(shù)
5、幾個(gè)沒有具體的命令關(guān)鍵字,如插件命令</p><p> 可以看到這里把NSIS支持的關(guān)鍵字和TOK_XXX關(guān)聯(lián)起來了,但是插件命令比較特殊,這里雖然沒有定義,但是在tokens.h中TOK__LAST的后面有一句TOK__PLUGINCOMMAND,也就是說這個(gè)其實(shí)就是解析插件命令時(shí)的token,makensis.exe源碼中的主函數(shù)是定義在makenssi.cpp中的,而解析這其中最關(guān)鍵是一個(gè)CEXEBuil
6、d類,NSIS大部分的解析工作都由此類和它的成員來完成的,在makenssi.cpp中的</p><p> main函數(shù)中構(gòu)造了CEXEBuild的實(shí)例build,經(jīng)過一些初始化和預(yù)處理后,開始解析nsi腳本,在使用時(shí)是用命令行的方式傳遞nsi腳本的文件名</p><p> 給makensis.exe,在makenssi.cpp的main函數(shù)中的470行開始讀取腳本文件的內(nèi)容:<
7、/p><p> 然后接下來的代碼開始解析腳本文件,主要是調(diào)用了CEXEBuild類的process_script函數(shù)來解析腳本代碼</p><p> 解析完成后,是生成一個(gè)exe文件,就是生成的安裝程序,根據(jù)前面解析的信息,最后調(diào)用CEXEBuild類的write_output函數(shù)生成exe程序</p><p> 本文要講的是插件的工作原理,因此我們重點(diǎn)來看看NS
8、IS是怎樣解析nsi腳本的,具體又是怎樣解析插件命令,調(diào)用插件的,來看CEXEBuild</p><p> 類的process_script函數(shù)是怎樣處理的,process_script函數(shù)是定義在script.cpp中的,如下圖所示:</p><p> 函數(shù)的一開始將filepointer文件指針傳遞給了CEXEBuild的成員變量fp,以便后續(xù)的文件讀取,然后解析的工作交給了222
9、行的</p><p> parseScript函數(shù),代碼如下:</p><p> 可以看到這里有一個(gè)for循環(huán),通過fgets函數(shù)讀取nsi腳本中的一行,然后調(diào)用doParse函數(shù)來解析這行腳本代碼,解析完一行for循環(huán)</p><p> 繼續(xù)進(jìn)行,繼續(xù)讀取一行,解析腳本,直到解析完最后一行腳本代碼為止??!那么就來看看doParse是怎樣解析一行腳本代碼的&l
10、t;/p><p> doParse函數(shù)中又使用了LineParser類來解析具體的一行腳本代碼,這里調(diào)用的是LineParser類的parse函數(shù),parse又調(diào)用了doline</p><p> 函數(shù)來解析一行代碼:</p><p> 這里用了while(*line)來遍歷這一行字符串,解析是否有NSIS指定的命令、屬性等關(guān)鍵字,具體的代碼在它的后面,如下圖所示
11、:</p><p> m_tokens是一個(gè)char**二級(jí)指針,它保存了所有掃描到的token關(guān)鍵字,至此,解析完了這一行代碼了,就是把掃描到的關(guān)鍵字保存起來</p><p> 以便后續(xù)使用,當(dāng)然這些處理之后會(huì)回到CEXEBuild::doParse函數(shù)中, 就是thisline.parse((char*)str)返回,然后繼續(xù)執(zhí)行后面的代碼,</p><p>
12、; 這里的代碼首先使用get_commandtoken函數(shù)獲取這一行解析到的關(guān)鍵字對(duì)應(yīng)的TOK_XXX,如關(guān)鍵字Abort對(duì)應(yīng)的token是TOK_ABORT</p><p> 然后來到365行調(diào)用m_plugins.IsPluginCommand來判斷關(guān)鍵字是不是插件命令,如果是,則設(shè)置tkid為TOK__PLUGINCOMMAND</p><p> 然后是處理一些tkid為TOK
13、_P_XXX的預(yù)處理指令,最后是調(diào)用doCommand函數(shù)來解析這條命令!!</p><p> doCommand這個(gè)函數(shù)非常大,代碼量超過5000行!一開始是調(diào)用build_plugin_table函數(shù)來建立插件表,就是掃描存放插件的目錄或</p><p> !addplugindir指定的目錄下的*.dll文件,內(nèi)部會(huì)調(diào)用Plugins類的GetExports函數(shù)讀取這些dll文件
14、,讀取其中的導(dǎo)出表,并建立幾個(gè)命令</p><p> 對(duì)應(yīng)插件路徑或函數(shù)的哈希表(std::map類型),然后是一個(gè)大大的switch..case,根據(jù)TOK_XXX來執(zhí)行對(duì)應(yīng)的命令,插件命令的case是</p><p> 在5862行開始,這里以nsDialogs::Create 1018這個(gè)插件命令為例,就是說line.gettoken_str(0)得到的是nsDialogs::C
15、reate,line.gettoken_str(1)得到的是1018,當(dāng)然它們都是字符串,這里首先調(diào)用m_plugins.NormalizedCommand函數(shù)規(guī)范化插件命令名字</p><p> 也就是說你寫的不規(guī)范的話,它會(huì)幫你規(guī)范化(就是說插件::函數(shù)名,如nsDialogs::Create不區(qū)分大小寫哇?。。笠痪涫堑玫搅诉@個(gè)</p><p> 插件dll的全路徑名稱。然后
16、是調(diào)用內(nèi)部函數(shù)Initialize_____Plugins來初始化插件,接著是把這個(gè)dll加入到要生成的exe安裝程序中,它會(huì)釋放</p><p> 到%temp%目錄下($PLUGINSDIR)</p><p> 然后執(zhí)行到這里就是調(diào)用這個(gè)插件了!這里先掃描nsDialogs::Create后面的token,掃描到就使用EW_PUSHPOP這個(gè)which調(diào)用add_entry<
17、/p><p> 函數(shù)完成參數(shù)入棧操作,在NSIS中,腳本代碼的參數(shù)堆棧和插件中的參數(shù)堆棧是同一個(gè),是共享的,因此在nsi腳本中將參數(shù)入棧,在插件中</p><p> 就能取出入棧的參數(shù)!最后是執(zhí)行which為EW_REGISTERDLL的add_entry函數(shù)來執(zhí)行插件命令!</p><p> add_entry函數(shù)是定義在exehead\exec.c文件中的,其
18、中EW_REGISTERDLL的case如下圖所示</p><p> 很明顯,這里是使用了GetProcAddress來獲取插件dll中的函數(shù)的地址,然后動(dòng)態(tài)調(diào)用這個(gè)函數(shù)?。?!注意的是插件dll中的導(dǎo)出函數(shù)的簽名</p><p> 必須是5個(gè)參數(shù),函數(shù)簽名是void (*func)(HWND,int,char*,void*,void*),NSIS給插件函數(shù)傳遞的參數(shù)分別是g_hwnd,
19、NSIS_MAX_STRLEN</p><p> g_usrvars,&g_st,&plugin_extra_parameters,其中最重要的一個(gè)參數(shù)是(void*)&g_st,這個(gè)參數(shù)是實(shí)現(xiàn)nsi腳本和插件dll傳遞函數(shù)參數(shù)</p><p> 關(guān)鍵,其中g(shù)_st是一個(gè)指向_stack_t結(jié)構(gòu)的指針,這個(gè)結(jié)構(gòu)的定義如下圖所示</p><p&
20、gt; nsDialogs::Create函數(shù)在插件dll中的定義是這樣的</p><p> 可以看到,它是符合void (*func)(HWND,int,char*,void*,void*)插件函數(shù)簽名的,g_st是指向_stack_t參數(shù)棧頂?shù)闹羔?,而NSIS將&g_st傳給</p><p> 了stacktop,然后賦值給了全局變量g_stacktop(通過EXDLL_
21、INIT宏),也就是說g_stacktop是指向g_st的指向,是指向參數(shù)堆棧頂?shù)亩?jí)指針,使用二級(jí)指針的好處是當(dāng)g_st的指向改變時(shí),g_stacktop不用改變指向,一旦g_stacktop指向了g_st,不管g_st的指向有沒有改變,它都能找到g_st,進(jìn)而找到參數(shù)堆棧頂,然后你想取出堆棧中的參數(shù)就很容易了??!</p><p> 另一個(gè)參數(shù)extra_parameters *extra也很重要,它是實(shí)現(xiàn)回
22、調(diào)函數(shù)的關(guān)鍵!就是在nsi腳本中使用插件命令注冊(cè)一個(gè)回調(diào)函數(shù),當(dāng)事件發(fā)生時(shí)</p><p> 會(huì)被自動(dòng)調(diào)用!當(dāng)然這個(gè)功能要在dll中使用extra這個(gè)參數(shù)來執(zhí)行注冊(cè)的回調(diào)函數(shù)才行</p><p> 為了方便取出參數(shù)堆棧中的參數(shù),NSIS的插件API還提供了幾個(gè)函數(shù)來操作g_stacktop,取出里面的參數(shù),如nsDialogs::Create 1018中就有</p>&l
23、t;p> 一個(gè)參數(shù),注意的是NSIS的插件命令中的參數(shù)全都是字符串,好在NSIS插件API還提供了popint()函數(shù)將參數(shù)字符串轉(zhuǎn)換成整型返回給你使用</p><p> 如本例的hwPlacementRect = GetDlgItem(hwndParent, popint())就是,這里是將字符串"1018"轉(zhuǎn)換成數(shù)字1018,原來它是一個(gè)控件ID號(hào)</p><
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 眾賞文庫(kù)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 基于動(dòng)力學(xué)原理的Maya粒子特效插件.pdf
- 基于Java的NSIS協(xié)議研究和設(shè)計(jì).pdf
- 插件機(jī)工作臺(tái)開題報(bào)告.doc
- 基于動(dòng)力學(xué)原理的MAYA混合動(dòng)力學(xué)角色插件.pdf
- 加密插件實(shí)現(xiàn)
- solidworks插件詳解
- 工業(yè)機(jī)器人pcb異形插件工作站
- edius字幕插件教程
- 接插件.DWG
- 接插件.DWG
- 接插件.DWG
- 接插件.DWG
- 防水接插件
- 接插件.DWG
- premiere插件大全介紹
- bho插件開發(fā)入門
- 接插件.DWG
- 汽車保險(xiǎn)盒自動(dòng)插件工作站設(shè)計(jì).pdf
- datax插件開發(fā)指南
- 【seg出品】grasshopper插件講解
評(píng)論
0/150
提交評(píng)論