通過nsis和duilib實現自定義安裝介面
阿新 • • 發佈:2019-01-07
nsis用於實現安裝邏輯,duilib用於實現UI介面
通過nsis呼叫duilib生成的dll庫來實現。現擷取部分duilib程式碼用於展示如何使用duilib編寫程式碼。
cpp檔案如下:
#include <windows.h>
#include <commctrl.h>
#include <Shlobj.h>
#include "plugin-common.h"
#include "DlgMain.h"
#pragma comment(lib,"Shell32.lib")
HINSTANCE g_hInstance;
HWND g_hwndParent;
extra_parameters *g_pluginParms = NULL;
CDlgMain *g_pMainDlg = NULL;
std ::map<HWND, WNDPROC> g_windowInfoMap;
CDuiString g_progressCtrlName = _T("");
CDuiString g_tabLayoutCtrlName = _T("");
bool g_bMSGLoopFlag = true;
#define NSMETHOD_INIT(parent) {\
g_pluginParms = extra; \
g_hwndParent = parent; \
EXDLL_INIT(); }
BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
g_hInstance = (HINSTANCE)hInst;
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
//do what you want at init time.
}
if (ul_reason_for_call == DLL_THREAD_DETACH || ul_reason_for_call == DLL_PROCESS_DETACH) {
//clean up code.
}
return TRUE;
}
// NSIS外掛匯出函式,NSIS規定函式宣告格式如下:
extern "C" __declspec(dllexport) void __cdecl
/*
* 在nsis指令碼中呼叫方法myPlugin::myFunction /NOUNLOAD $2
* /NOUNLOAD 表示呼叫完此方法後不解除安裝這個dll,用於儲存dll的資料
* hwndParent:安裝視窗的控制代碼
* stacktop:nsis傳入的引數堆疊, 通過popint/popstring 可以取出來
* extra:外掛裡面呼叫script的函式就需要用到這個
*/
add(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
// == 新增自己程式碼
int i = popint();
int j = popint();
int k = i + j;
pushint(k);
// ==
}
}
//視窗大小
extern "C" __declspec(dllexport) void __cdecl
GetDialogSize(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
HWND hwnd = (HWND)popint();
RECT rect;
::GetWindowRect(hwnd, &rect);
pushint(rect.bottom - rect.top);
pushint(rect.right - rect.left);
}
}
//視窗風格
extern "C" __declspec(dllexport) void __cdecl
GetDialogStyle(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
HWND hwnd = (HWND)popint();
int style = (int)::GetWindowLongA(hwnd, GWL_STYLE);
pushint(style);
}
}
extern "C" __declspec(dllexport) void __cdecl
GetSetupPath(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
char buf[512] = { 0 };
::GetModuleFileName(NULL, buf, 512);
pushstring(buf);
}
}
extern "C" __declspec(dllexport) void __cdecl
Trace(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
char buf[1024] = { 0 };
popstring(buf);
DUI__Trace(_T("NSISHelper Trace:%s"), buf);
}
}
extern "C" __declspec(dllexport) void __cdecl
GetCtrlPos(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
HWND hwnd = (HWND)popint();
RECT rect;
GetClientRect(hwnd, &rect);
DUI__Trace(_T("%d %d %d %d %d"), hwnd, rect.left, rect.top, rect.right, rect.bottom);
POINT lt = { rect.left, rect.top };
POINT rb = { rect.right, rect.bottom };
::ClientToScreen(hwndParent, <);
::ClientToScreen(hwndParent, &rb);
pushint(rb.y);
pushint(rb.x);
pushint(lt.y);
pushint(lt.x);
}
}
//=========================================== DUILIB =============================================
//許可協議介面
NSISAPI FindControl(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
char controlName[MAX_PATH];
ZeroMemory(controlName, MAX_PATH);
popstring(controlName);
CControlUI *pControl = static_cast<CControlUI *>(g_pMainDlg->GetPaintManagerUI()->FindControl(controlName));
if (pControl == NULL)
pushint(-1);
pushint(0);
}
//繫結控制元件
NSISAPI OnControlBindNSISScript(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
char controlName[MAX_PATH];
ZeroMemory(controlName, MAX_PATH);
popstring(controlName);
int callbackID = popint();
g_pMainDlg->SaveToControlCallbackMap(controlName, callbackID);//放入所有控制元件
}
NSISAPI ExitDUISetup(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
ExitProcess(0);
}
static UINT_PTR PluginCallback(enum NSPIM msg)
{
return 0;
}
//初始化介面--歡迎介面
NSISAPI InitDUISetup(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
extra->RegisterPluginCallback(g_hInstance, PluginCallback);
{
CPaintManagerUI::SetInstance(g_hInstance);
char buf[512] = { 0 };
::GetModuleFileName(NULL, buf, 512);
int len = strlen(buf);
--len;
while (len >= 0) {
if (buf[len] == '\\')
break;
buf[len] = '\0';
--len;
}
sprintf_s(buf, "%sskin", buf);
//CPaintManagerUI::SetResourcePath(buf);
g_pMainDlg = new CDlgMain();
g_pMainDlg->Create(NULL, _T("標題名字"), UI_WNDSTYLE_FRAME, WS_EX_STATICEDGE | WS_EX_APPWINDOW, 0, 0, 588, 384);
g_pMainDlg->CenterWindow();
g_pMainDlg->ShowWindow(FALSE);
pushint(int(g_pMainDlg->GetHWND()));
}
}
//顯示頁面
NSISAPI ShowPage(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
g_pMainDlg->ShowWindow(true);
//CPaintManagerUI::MessageLoop();
MSG msg = { 0 };
while (::GetMessage(&msg, NULL, 0, 0) && g_bMSGLoopFlag)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
}
//設定編輯框內容
NSISAPI SetEdit(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
char buf[512] = { 0 };
popstring(buf);
CEditUI *pEdit = static_cast<CEditUI *>(g_pMainDlg->GetPaintManagerUI()->FindControl("btEdit"));
if (pEdit)
pEdit->SetText(buf);
}
}
//checkBox選型
NSISAPI GetCheckboxStatus(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
char pszName[512] = { 0 };
popstring(pszName);//從nsis獲取控制元件
CCheckBoxUI *pChbAgree = static_cast<CCheckBoxUI *>(g_pMainDlg->GetPaintManagerUI()->FindControl(pszName));
if (!pChbAgree) {
pushint(-1);
return;
}
DUI__Trace("%s status:%d", pszName, pChbAgree->GetCheck() ? 1 : 0);
pushint(pChbAgree->GetCheck() ? 1 : 0);//輸出給nsis。
}
}
//設定進度
NSISAPI SetSliderRange(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
char buf[512] = { 0 };
//從nsis接收多個引數
popstring(buf);
int iMin = popint();
int iMax = popint();
CProgressUI *pProgress = static_cast<CProgressUI *>(g_pMainDlg->GetPaintManagerUI()->FindControl(buf));
if (pProgress == NULL)
return;
//設定進度
pProgress->SetMaxValue(iMax);
pProgress->SetMinValue(iMin);
}
}
//設定進度值
NSISAPI SetSliderValue(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
char buf[512] = { 0 };
popstring(buf);
int iValue = popint();
CProgressUI *pProgress = static_cast<CProgressUI *>(g_pMainDlg->GetPaintManagerUI()->FindControl(buf));
if (pProgress)
pProgress->SetValue(iValue);
}
}
//檔案路徑
NSISAPI SetDirValue(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
char buf[512] = { 0 };
popstring(buf);
CEditUI *pEdit = static_cast<CEditUI *>(g_pMainDlg->GetPaintManagerUI()->FindControl("editDir"));
if (pEdit)
pEdit->SetText(buf);
}
}
NSISAPI GetDirValue(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
CDuiString strFolderPath;
CEditUI *pEdit = static_cast<CEditUI *>(g_pMainDlg->GetPaintManagerUI()->FindControl("editDir"));
if (pEdit)
strFolderPath = pEdit->GetText();
pushstring((char*)strFolderPath.GetData());
}
}
//選擇安裝路徑--點選更改彈出檔案路徑選擇對話方塊
NSISAPI SelectInstallDir(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
//BROWSEINFO SHGetPathFromIDList 彈出資料夾選擇框
BROWSEINFO bi;
memset(&bi, 0, sizeof(BROWSEINFO));
bi.hwndOwner = g_pMainDlg->GetHWND();
bi.lpszTitle = "選擇安裝路徑";
bi.ulFlags = 0x0040;
char szFolderPath[MAX_PATH] = { 0 };
LPITEMIDLIST idl = SHBrowseForFolder(&bi);
if (idl == NULL)
{
pushstring(szFolderPath);
return;
}
SHGetPathFromIDList(idl, szFolderPath);
CEditUI *pEdit = static_cast<CEditUI *>(g_pMainDlg->GetPaintManagerUI()->FindControl("editDir"));
if (pEdit)
pEdit->SetText(szFolderPath);
pushstring(szFolderPath);
}
}
//更新
NSISAPI StartInstall ( HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
{
NSMETHOD_INIT(hwndParent);
{
g_bMSGLoopFlag = false;
}
}
BOOL CALLBACK PluginNewWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
BOOL res = 0;
std::map<HWND, WNDPROC>::iterator iter = g_windowInfoMap.find( hwnd );
if( iter != g_windowInfoMap.end() ) {
if (message == WM_NCCREATE || message == WM_CREATE || message == WM_PAINT || message== WM_NCPAINT) {
ShowWindow( hwnd, SW_HIDE );
} else if( message == LVM_SETITEMTEXT ) {
;
} else if( message == PBM_SETPOS ) {
CProgressUI *pProgress = static_cast<CProgressUI *>(g_pMainDlg->GetPaintManagerUI()->FindControl( g_progressCtrlName ));
if( pProgress == NULL )
return 0;
pProgress->SetMaxValue( 30000 );
pProgress->SetValue( (int)wParam);
if( pProgress->GetValue() == 30000 ) {
CTabLayoutUI *pTab = static_cast<CTabLayoutUI *>(g_pMainDlg->GetPaintManagerUI()->FindControl( g_tabLayoutCtrlName ));
if( pTab == NULL )
return -1;
int currentIndex = pTab->GetCurSel();
DUI__Trace("tabName:%s index:%d",g_tabLayoutCtrlName,currentIndex);
pTab->SelectItem(2);
}
} else {
res = CallWindowProc( iter->second, hwnd, message, wParam, lParam);
}
}
return res;
}
如下程式碼用於控制控制元件的響應檔案:
#include "DlgMain.h"
CDlgMain::CDlgMain()
{
}
CDlgMain::~CDlgMain()
{
}
void CDlgMain::Notify( TNotifyUI& msg )
{
std::map<CDuiString, int >::iterator iter = m_controlCallbackMap.find( msg.pSender->GetName() );
if( _tcsicmp( msg.sType, _T("click") ) == 0 ){
if( iter != m_controlCallbackMap.end() )
g_pluginParms->ExecuteCodeSegment( iter->second - 1, 0 );
}
else if( _tcsicmp( msg.sType, _T("textchanged") ) == 0 ){
if( iter != m_controlCallbackMap.end() )
g_pluginParms->ExecuteCodeSegment( iter->second - 1, 0 );
} else {
WindowImplBase::Notify(msg);
}
}
LRESULT CDlgMain::HandleCustomMessage( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
return 0;
}
void CDlgMain::InitWindow()
{
CRichEditUI * pRichEdit = static_cast<CRichEditUI*>(m_PaintManager.FindControl(_T("editLicense")));
if(pRichEdit) {
HRSRC hRsrc = FindResourceA(CPaintManagerUI::GetInstance(), MAKEINTRESOURCEA(IDR_TEXT_LICENSE), "TEXT");
if(!hRsrc)
return;
DWORD dwSize = SizeofResource(CPaintManagerUI::GetInstance(), hRsrc);
if(dwSize==0)
return;
HGLOBAL hGlobal = LoadResource(CPaintManagerUI::GetInstance(), hRsrc);
if(!hGlobal)
return;
LPVOID lpBuffer = LockResource(hGlobal);
if(!lpBuffer)
return;
pRichEdit->AppendText((char*)lpBuffer);
FreeResource(hGlobal);
}
}
可以看出,所有控制元件都通過繫結函式放到了集合中,在notify中找到控制元件來響應動作。
通過pop來接收nsis參進來的引數,push來給nsis傳遞引數。
在nsis中呼叫語法如下所示
這是繫結安裝介面控制元件事件格式
nsDui::FindControl "btnSelectDir"
Pop $0
${If} $0 == 0
GetFunctionAddress $0 OnBtnSelectDir
nsDui::OnControlBindNSISScript "btnSelectDir" $0
${EndIf}
在安裝邏輯中使用格式如下
Function OnBtnSelectDir
nsDui::SelectInstallDir
Pop $0
FunctionEnd