建立安裝程式的兩種方法 (轉)

worldblog發表於2007-12-04
建立安裝程式的兩種方法 (轉)[@more@] 

建立的兩種方法


  ● 彭 進 趙 昕

   創 建 安 裝 程 序 是 程 序 員 經 常 遇 到 的 問 題 之 一。 本 文 僅 探 討 在 平 臺 上 創 建 安 裝(Setup) 程 序 的 兩 種 方 法。
   一、 使 用Visual C++ 編 程 生 成Setup 程 序
   生 成Setup 程 序 最 直 接 的 方 法 當 然 是 通 過 編 程 來 實 現。 對 於Windows 平 臺 來 說, 沒 有 比Visual C++ 更 好 的 開 發 工 具 了( 原 因 很 簡 單, 有 誰 能 比 更 了 解Windows 平 臺 呢 ?)。 下 面 的 例 程 就 是 使 用Visual C++ 5.0 編 譯 完 成 的。
  Setup 程 序 主 要 處 理 兩 個 方 面 的 問 題 :
  (1) 用 戶 界 面。 評 價 一 個Setup 程 序 的 優 劣 時, 用 戶 界 面 是 否 美 觀 是 其 中 的 一 個 重 要 因 素。 此 外, 通 過 交 互 式 界 面 還 應 能 夠 獲 得 用 戶 的 相 關 信 息( 比 如 目 標 目 錄)。
  (2) 文 件 拷 貝 與 程 序 組 的 生 成。 也 就 是 按 照 用 戶 輸 入 的 信 息, 生 成 相 應 的 目 錄 並 完 成 文 件 拷 貝 功 能( 這 要 涉 及 到 解 壓 縮 問 題)。 一 般 來 說, 還 應 包 括 將 可 執 行 文 件 的 圖 標 添 加 到 指 定 的 程 序 組 中。
  1、 為Setup 程 序 設 置 背 景
  Setup 程 序 的 用 戶 界 面 以 對 話 框 為 主, 不 過 若 有 美 麗 的 背 景 則 能 為 你 的 程 序 增 色 不 少。 你 可 以 選 擇 一 個 合 適 的BMP 文 件, 將 它 插 入 到 工 程 文 件(project) 中, 並 通 過 重 載 主 窗 口 類 的OnPaint() 函 數 顯 示 出 來。 值 得 注 意 的 是, 背 景 圖 片 不 應 過 於 眩 目, 否 則 會 有 喧 賓 奪 主 之 感。 例 如, 要 加 入 的BMP 文 件 的ID 號 是I_BIT。 下 面 給 出 應 加 在OnPaint() 中 的 函 數。

  void Background(CDC *pDC)

  {    CDC * pmem;
   CBitmap * pback;
   CBitmap * pold;
   BITMAP ff;
   pmem=new CDC;
   pbit=new CBitmap;
   pbit->LoadBitmap(IDB_BIT);
   pmem->CreateCompatibleDC(pDC);
   pold=(CBitmap *) pmem->(pbit);
   pbit->GetObject(sizeof(ff),&ff);

  pDC->BitBlt(0,0,bm.bmWidth,bm.bmHeight,pmem,0,0, MERGECOPY );

   delete pmem->SelectObject(pold);

   delete pmem;

   return;

  }

  2、 顯 示 全 屏 效 果

   一 般 的 主 窗 口 都 有 邊 界(border), 如 果 你 更 欣 賞D界 面 中 的 全 屏 效 果, 則 最 好 在 重 載CWnd:: PreCreateWindow(CREATESTRUCT&cs) 時 保 持cs.style 的 缺 省 值, 並 且 在 創 建 主 窗 口 時 使 用CreateEx(WS_EX_TO PMOST,AfxRegisterWndClass(CS_VREDRAW), NULL,WS_VISIBLE|WS_POPUP,0,0,(GetSystemMetrics (SM_CXSCREEN)),(GetSystemMetrics(SM_CYSCREEN)), HWND_DESKTOP,0);。

  3、 保 存 公 用 參 量

   通 過 對 話 框, 可 與 使 用 者 交 換 信 息。 那 麼, 如 何 將 程 序 運 行 時 必 需 的 參 量( 比 如 說 安 裝 目 錄) 保 存 起 來 呢 ? 當 然, 可 以 生 成 一 個 配 置 文 件, 不 過 更 為 專 業 的 作 法 是 將 相 關 信 息 存 入 到 系 統 的INI 文 件 中。 如 果 開 發 平 臺 是Windows 95, 則 一 切 都 將 變 得 很 簡 單, 因 為 你 面 對 的 就 是win.ini 文 件, 該 文 件 在Windows 目 錄 下。Visual C++ 提 供 了 如 下 的 一 組 函 數 來 操 作 該 文 件。

  (1)CWinApp::GetProfileString

  CString GetProfileString( LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault = NULL );

   用 來 讀 取lpszSection 區 域 內 的lpszEntry 參 數, 其 缺 省 值 為lpszDefault。

  (2)CWinApp::WriteProfileString

  BOOL WriteProfileString( LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue );

   用 來 寫 入lpszSection 區 域 內 的lpszEntry 參 數, 其 值 為lpszValue。

   如 果 你 的 開 發 平 臺 是Winnt, 則 要 麻 煩 一 點。 假 如 你 的 變 量 保 存 在e:winntsdi.ini 中, 則 在 使 用 以 上 函 數 之 前 必 須 調 用 :

  free((void*)m_pszProfileName);

  m_pszProfileName=_tcsdup(_T("e:winntsdi.ini"));

   如 果 要 存 取 的 變 量 並 不 多, 則 也 可 將 它 們 保 存 在 注 冊 關 鍵 字(registry key) 中。 假 如 你 的 變 量 保 存 在Moon 注 冊 關 鍵 字( 一 般 是 你 公 司 的 名 字) 下, 則 在 使 用 以 上 函 數 之 前 必 須 調 用 :

  free((void*)m_pszRegistryKey);

  m_pszRegistryKey=_tcsdup(_T("HKEY_CURRENT_ USERSoftwaremoon"));

  4、 文 件 的 拷 貝 與 解 壓 縮

   如 果 你 的 安 裝 程 序 是 針 對 軟 盤 的, 則 存 儲 空 間 就 成 了 必 須 考 慮 的 問 題。 原 封 不 動 地 把 應 用 程 序 拷 貝 上 去 未 免 太 傻 了, 較 為 合 適 的 方 法 是 將 應 用 程 序 壓 縮 在 軟 盤 中, 安 裝 時 再 解 壓 縮 到 相 應 的 目 標 目 錄 中。Visual C++ 提 供 了 一 套 以LZ 開 頭 的 函 數, 用 來 操 作 用Compress 命 令 壓 縮 的 文 件 : 你 可 以 用LzOpenFile() 打 開 原 文 件 和 目 標 文 件, 然 後 用LzCopy() 解 壓 縮 拷 貝。 該 組 函 數 調 用Windows 系 統 的lzexpand.dll 動 態 鏈 接 庫, 所 以 編 譯 鏈 接 時 一 定 要 注 意 加 入 頭 文 件lzexpand.h, 並 插 入 接 口 庫lz32.lib。

   還 有 個 更 為 簡 單 的 辦 法, 即 先 用 像arj.exe 這 類 的 共 享 壓 縮 程 序 壓 縮 原 程 序, 然 後 調 用system("arj ...") 來 完 成 解 壓 縮, 整 個 解 壓 縮 過 程 在 後 臺 進 行, 用 戶 不 會 知 道 你 到 底 用 的 是 什 麼 方 法。

  5、 顯 示 拷 貝 進 度

   很 多 專 業 安 裝 程 序 在 進 行 文 件 拷 貝 時 都 會 顯 示 進 度 欄, 甚 至 還 帶 有 動 畫。 如 何 實 現 這 種 效 果 呢 ? 辦 法 是 在 拷 貝 的 同 時 創 建 一 個modeless 對 話 框。 這 種 對 話 框 用create() 函 數 創 建, 類 似 於 創 建 了 一 個 與 主 線 程 獨 立 的 新 線 程。 這 樣 就 可 在 拷 貝 文 件 的 同 時 在 對 話 框 中 顯 示 出 拷 貝 進 度。Visual C++ 提 供 了 兩 個 很 有 用 的 控 件, 即CAnimateCtrl 和 CProgressCtrl。 可 在 對 話 框 中 畫 出 這 兩 個 控 件, 並 用ClassWizard 加 入 相 應 的 類。 其 中,CAnimateCtrl 是 用 來 顯 示.avi 文 件 的, 使 用 它 即 可 在 每 個 文 件 拷 貝 成 功 後 啟 動 一 個“ 小 紙 片 飛 過” 的 文 件 ;CProgressCtrl 用 來 顯 示 拷 貝 進 度, 當 各 個 拷 貝 成 功 後 使 表 示 進 度 的 藍 條 前 進 到 適 當 的 位 置。

  6、 程 序 組 和 程 序 項 的 生 成

   程 序 組 的 生 成 實 際 上 是 與 負 責 管 理 程 序 組 的Program Manager 進 行DDE 對 話, 你 可 以 通 過 該 對 話 來 添 加 相 應 的 程 序 組 和 應 用 程 序 的 圖 標。 同 時 由 於 該 對 話 是 單 向 的, 所 以 負 責 處 理 反 饋 消 息 的callback() 函 數 不 進 行 任 何 處 理。 下 面 給 出 其 源 程 序 及 其 用 法。

  HDDEDATA CALLBACK DDECallback( UINT uType, // transaction type

   UINT uFmt, // clipboard data format

   HCONV hconv, // handle to the conversation

   HSZ hsz1, // handle to a string

   HSZ hsz2,

   // handle to a string

   HDDEDATA hdata, // handle to a global memory object

   D dwData1,

   // transaction-specific data

   DWORD dwData2

   // transaction-specific data

  )

  {return NULL;}

  SendDdeCmd(LPSTR cmd)

  {

   LPDWORD dwDDEInst=0L;

   UINT ui;

   HSZ hszService,hszTopic,hszItem;

   HCONV hConv;

   HDDEDATA hexecData;

   ui=DdeInitialize((unsigned long *)&dwDDEInst, DDECallback,CBF_FAIL_ALLSVRXACTIONS,0L);

   if(ui!=DMLERR_NO_ERROR)

   {return FALSE;}

   hszService=DdeCreateStringHandle( (DWORD) dwDDEInst,"PROGMAN",CP_WINANSI);

   hszTopic=DdeCreateStringHandle((DWORD)dwDDEInst, "PROGMAN",CP_WINANSI);

   hszItem=DdeCreateStringHandle((DWORD)dwDDEInst,"GROUP", CP_WINANSI);

   hConv=DdeConnect((DWORD)dwDDEInst,hszService, hszTopic,NULL);

  DdeFreeStringHandle((unsigned long)dwDDEInst, hszService);

  DdeFreeStringHandle((unsigned long)dwDDEInst, hszTopic);

  DdeFreeStringHandle((unsigned long)dwDDEInst, hszItem);

  if(!hConv)

  return FALSE;

  hexecData=DdeCreateDataHandle((DWORD)dwDDEInst,(unsigned char *)cmd,lstrlen(cmd)+1,0,NULL,0,0);

  DdeClientTransaction((unsigned char *)hexecData, (DWORD)-1,hConv,NULL,0,XTYP_EXECUTE,1000,NULL);

  DdeDinnect(hConv);

  DdeUninitialize((unsigned long)dwDDEInst);

  return TRUE;

  }

   如 果 你 想 加 入 一 個 名 叫“demo” 的 程 序 組, 其 中 包 含 有 名 稱 為“test” 的 程 序 項, 並 執 行c:demotest.exe, 使 用 的 是“test.ico” 圖 標, 則 可 按 如 下 方 式 調 用 該 函 數 :

  SendDdeCmd("[CreateGroup (demo)] [AddItem (c:demotest.exe, test,c:demotest.ico)]")

   二、 利 用 工 具 軟 件 創 建 安 裝 程 序

   使 用Visual C++ 編 程 能 夠 生 成 功 能 強 大 的Setup 程 序。 不 過, 如 果 你 更 喜 歡 利 用 現 成 的 工 具, 則 不 妨 試 一 試 用 於 創 建 安 裝 程 序 的 工 具 軟 件InstallShield5 Free Edition。 該 軟 件 提 供 了 一 種 類 似 於Basic 的 編 程 語 言, 清 晰 易 懂。

   創 建 一 個 新 的 安 裝 程 序 時, 可 從Project Wizard 開 始, 首 先 啟 動 的 是 一 個Welcome 對 話 框, 它 包 括 以 下 幾 項 內 容 :

  (1)Application Name (edit box)

   在 這 個 對 話 框 中 輸 入 你 想 要 安 裝 的 應 用 程 序 的 名 字, InstallShield 將 用 該 名 字 注 冊 登 記 並 生 成 你 的 程 序 組。

  (2)Development Environment (list box)

   選 擇 開 發 該 應 用 程 序 的 環 境( 如Visual C++)。

  (3)Application Type (list box)

   選 擇 你 的 應 用 程 序 的 類 別。

  (4)Application Version (edit box)

   選 擇 你 的 應 用 程 序 的 版 本。

  (5)Application Executable (edit box)

   輸 入 應 用 程 序 的 主 運 行 文 件, 或 單 擊 ... 尋 找 該 文 件。

  (6) 單 擊“ 下 一 步”,select dialogs

   選 擇 你 的 安 裝 程 序 所 需 要 的 對 話 框, 如 果 你 暫 時 還 不 能 確 定 的 話, 則 可 按Preview 鍵 預 覽 一 下。

  (7) 單 擊“ 下 一 步”, 選 擇 適 合 於 該 應 用 程 序 的 操 作 系 統 平 臺。 你 可 以 選 擇Win 95、Winnt 3.x 或Winnt4.0。

  (8) 單 擊“ 下 一 步”, 選 擇 安 裝 程 序 使 用 的 語 言。 在 這 種free 版 本 中, 你 所 能 作 的 唯 一 選 擇 就 是“ 英 語”。

  (9) 如 果 你 想 在 你 的 安 裝 程 序 中 包 括 多 種 安 裝 類 型 選 擇, 則 單 擊“ 下 一 步”。 啟 動 的 對 話 框 中 提 供 了 上 述 功 能, 從 中 你 可 選 擇Compact、 Typical、 Customwork 等 多 種 安 裝 類 型。

  (10) 單 擊“ 下 一 步”, 選 擇 你 想 要 安 裝 的 組 件, 這 些 組 件 的 不 同 組 合 即 是 你 在 上 面 選 擇 的 不 同 安 裝 類 型。

  (11) 單 擊“ 下 一 步”, 選 擇 你 想 要 創 建 的 文 件 組, 該 文 件 組 是 你 的 應 用 程 序 所 包 括 文 件 的 邏 輯 分 組, 這 種 邏 輯 分 組 對 應 於 上 面 的 組 件。

  (12) 單 擊“ 下 一 步”, 概 括( 即“Summary” ) 你 所 輸 入 的 信 息。 如 果 不 滿 意, 則 還 可 以 修 改 ; 如 果 滿 意 的 話, 則 按“ 完 成” 鍵, 一 個 安 裝 程 序 的 框 架 就 大 功 告 成 了。

   下 面 介 紹 制 作 供 安 裝 程 序 使 用 的 工 程 文 件。

   實 際 上,Project Wizard 已 經 為 你 作 好 了 大 部 分 的 工 作。 為 了 創 建 一 個 完 整 的 安 裝 程 序, 首 先 要 弄 清 楚 工 程 文 件 中 各 個 項 目 間 的 關 系。 這 要 從File Group 說 起。File Group 是 應 用 程 序 文 件 的 邏 輯 分 組, 在 每 個 文 件 夾 下 都 有link 項, 用 右 鍵 單 擊 該 位 置, 選 擇 插 入 項, 則 可 將 你 的 應 用 文 件 進 行 適 當 分 組。 每 個File Group 中 含 有 若 幹 屬 性 值, 單 擊 該 屬 性 則 可 對 其 進 行 修 改。 比 如, 對 於Compress 項, 你 可 以 選 擇 是 否 對 該File Group 下 的 文 件 進 行 壓 縮。 幾 個File Group 可 以 同 屬 於 一 個Component, 通 過 劃 分Component 你 可 以 區 分 不 同 的 安 裝 方 式。 每 個Component 也 有 若 幹 屬 性 : 其 中,Destination 項 供 你 選 擇 該Component 將 要 安 裝 到 的 目 標 目 錄 ;Installation 項 供 你 選 擇 遇 到 相 同 文 件 名 時 的 處 理 方 式 ;SetupType 項 供 你 選 擇 不 同 的 安 裝 類 型 所 安 裝 的 組 件(Component)。 下 面, 你 將 進 入Script Files 項, 它 是 你 的 安 裝 程 序 的 腳 本 程 序, 如 果 你 只 想 創 建 一 個 標 準 的 安 裝 程 序, 則 只 需 對 其 作 很 小 的 改 動 即 可。 由 於 系 統 沒 有 為 你 生 成 創 建 程 序 組 的 部 分, 所 以 必 須 手 工 修 改function SetupFolders() 函 數, 在DialogShowSdSelectFolder() 中, 安 裝 腳 本 已 經 將 要 生 成 的 目 標 程 序 組 存 入 到 變 量svDefGroup 中, 所 以 你 只 需 在SetupFolders() 中 加 入 以 下 幾 行 內 容( 假 設 你 想 加 入 一 個 名 為“demo” 的 項, 執 行c:demo.exe 文 件, 使 用 的 圖 標 是“c:demo.ico”, 工 作 目 錄 為“c:test”, 用“Ctrl + Alt + 1” 作 為 熱 鍵, 並 且 該 程 序 項 將 作 為 該 程 序 組 的 第 一 項, 該 程 序 執 行 時 將 被 最 大 化)。

  STRING szProgram ="c:demo.exe"

  STRING szParam = " "

  LongPathToQuote (szProgram, TRUE);

  LongPathToShortPath (szParam);

  STRING szCommandLine = szProgram + " " + szParam;

  AddFolderIcon(svDefGroup, "demo",szCommandLine, "c:test","c:demo.ico",0, "Ctrl +Alt + 1", REPLACE |RUN_MAXIMIZED);

   現 在 修 改Re 項, 其 中String Table 存 儲 的 是 顯 示 在 對 話 框 裡 的 各 種 字 符 變 量。 例 如,FOLDER_NAME 是 你 的 程 序 組 的 缺 省 名 字,PRODUCT_KEY 是 你 的 程 序 項 的 運 行 文 件,PRODUCT_NAME 是 你 的 程 序 項 的 名 字,TITLE_CAPTIONBAR 將 顯 示 在 你 的 安 裝 程 序 背 景 窗 口 的 上 邊 框 內,TITLE_MAIN 將 顯 示 在 你 的 安 裝 程 序 背 景 窗 口 上。 對 於Win 95、Winnt 4.0 的 用 戶,UNINST_DISPLAY_NAME 將 顯 示 在 控 制 面 板 的“ 添 加/ 刪 除 程 序” 的 列 表 中。

   在Setup file 這 一 項 中, 你 可 以 修 改 安 裝 程 序 開 始 時 顯 示 的 圖 片, 只 需 將 編 輯 好 的 文 件 插 入 到Splash Screen 的Language Independent 下, 並 改 名 為Setup.bmp 即 可。

   如 果 你 已 經 正 確 地 添 如 了 上 述 各 項 內 容, 則 下 面 所 要 做 的 事 情 就 是 打 開Media 項 單 擊 右 鍵 選 擇 其 中 的Media Build Wizard 以 便 創 建 應 用 程 序 的 物 理 存 儲 結 構。 如 果 你 選 擇 的 是 軟 盤 方 式, 則 自 動 生 成 按 照Disk 劃 分 的 目 標 程 序。 至 此, 利 用 工 具 軟 件InstallShield 創 建 安 裝 程 序 的 過 程 宣 告 結 束。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988005/,如需轉載,請註明出處,否則將追究法律責任。

相關文章