通过nsis和duilib实现自定义安装界面

来源:互联网 发布:程序员社招招聘条件 编辑:程序博客网 时间:2024/05/18 23:15
 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 __cdeclGetDialogSize(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 __cdeclGetDialogStyle(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 __cdeclGetSetupPath(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 __cdeclTrace(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 __cdeclGetCtrlPos(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, &lt);        ::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 $0FunctionEnd

参考wyrover的代码,感谢,获取源码请点击此链接

原创粉丝点击