第十三章 Win32 API及Registry 我們將利用Win32 API結合上一節所介紹的元件寫一個類似檔案總管的介面,也將介紹Registry的特性,進而利用Registry讓我們的程式更加有彈性。

Slides:



Advertisements
Similar presentations
软件开发技术基础 第 3 章 操作系统及程序设计 讲授教师:卫颜俊. 主 要 内 容 主 要 内 容 操作系统及其功能 进程管理应用程序设计 内存管理应用程序设计 设备与文件管理应用程序设计 人机接口管理应用程序设计.
Advertisements

C语言程序设计 主讲教师 :张群燕 电话:
第三章 以Borland C++ Builder開發 視窗介面為基之I/O控制技術
授课教师:江星玲 1.
Java Programming Hygiene - for DIDC
AI人工智慧報告 黑白棋 班級:資工四乙 學號:498G0009 姓名:盧冠妤.
计算机高级程序设计 第五章.
第 5 章 流程控制 (一): 條件分支.
基于VC++的数字图像特效处理系统的设计与实现
吉林大学远程教育课件 Windows A P I编 程 (第四十五讲) 主讲人 : 翟慧杰 学 时:48.
微博: weibo.com/zhnitj QQ:
第二十三章 InterNet網路程式設計 有沒有想過自己寫個Service呢?想不想自己也寫一套發信程式呢?在這一章節裡,我們將介紹socket的觀念以及BCB在Internet上開發應用程式的方法。
C# 程式設計 第一部分 第1-4章 C# 程式設計 - 南華大學資管系.
Tree(樹) 什麼是「樹」? 「樹」的範例 「樹」的定義 「樹」的表示法.
第二十八章 開發新的VCL元件 雖然BCB內提供了很多VCL元件,但是一定還有一些我們常常需要用的介面並沒有製作成VCL元件,或是一些個人化的介面,我們也有需要做成VCL元件。在第十三章,我們將介紹如何自行開發新的VCL元件。
進階輸出入元件(一) 本書第三章已介紹Form 、Label 、Edit 及Button 等最基本的輸出入元件, 本章將繼續介紹一些可以提昇輸出入視覺效果的元件, 例如CheckBox 、RadioButton 及RadioGroup 等17 個進階元件, 學習本章將可提昇使用介面的親和性。 核對框(CheckBox)
Lotus Domino R7 Designer
CH2 開發環境介紹 最簡單的互動設計 – Arduino一試就上手 孫駿榮、吳明展、盧聰勇.
第二十九章 DLL / LIB函式庫開發 當我們開發程式到一個階段之後,我們一定會希望各個Component的程式碼可以分開的越清楚越好。而這一章最主要就是要告訴各位讀者,我們常在Windows系統中看到的dll或是lib的檔案該怎麼實作?做出這樣的library我們又該如何運用?為什麼使用dll或是lib有利於我們開發程式?以上這些疑問都將會在這一章中得到解答。
第13章 WinForms基础知识.
CAA 第一章 安装 1 安装CATIA。在安装CATIA时,要把它装到根目录下,文件夹名称不能含有空格,(在此命名为CATIA)安装完后,用crack文件下JS0GROUP.dll拷贝到d:\CATIA\B14\intel_a\code\bin下的覆盖。 2 安装vc。装vc时选自定义,把里面的所有组件都选上。
基础综合 C++ Builder 显示与输入接口
Basis基本操作、使用者 管理與權限設定
第10章 App微信分享的实现 倚动实验室.
页眉 基础综合 C++ Builder 按钮组件
Windows 2000/XP网络组建与系统管理 李燕 中南分校.
第4讲 Windows编程基础 此为封面页,需列出课程编码、课程名称和课程开发室名称。
·线性表的定义及ADT ·线性表的顺序存储结构 ·线性表的链接存储结构 · 单向循环链表 · 双链表、双向循环链表 · 一元多项式的加法
第18章 B4J的跨平台應用程式開發 18-1 B4J的GUI設計工具與介面控制項 18-2 使用B4J的介面控制項
第1章 Delphi 6快速入门 1.1 Delphi 6概述 1.2 Delphi 6的安装 1.3 Delphi 6的界面描述.
C++ with Managed Extensions
实验一、注册表安全实验 实验开发教师:刘乃琦 谌黔燕.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Delphi程序设计与应用教程 宁正元 主编 刘雄恩 陈琼 副主编 中国水利水电出版社
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
第1章 Windows应用程序框架的 创建与消息处理
委派與執行緒 建國科技大學 資管系 饒瑞佶.
第十一讲 MFC常用控件的使用(3) 严宣辉 数学与计算机科学学院
MFC WinSock类的编程 为简化套接字网络编程,更方便地利用Windows的消息驱动机制,微软的基础类库(Microsoft Foundation Class Libary,简称MFC),提供了两个套接字类,在不同的层次上对Windows Socket API函数进行了封装,为编写Windows.
网络游戏开发语言基础 ——Windows程序设计
程式設計 Visual Basic簡介 週次:1 建國技術學院 資管系 饒瑞佶 2003年9月17日.
第十二章 Win32環境程式設計 這一章節可以說是本書精華之一,Win32程式設計算是比較複雜的部分,但是我們以最簡單的敘述帶領著大家進入Win32程式設計的殿堂,讓你寫出來的程式具有一定的水準以上。若能將本章與下一章的技巧靈活運用,更能讓大家寫出高階的視窗程式。
第九單元 Classes and data abstraction I
視窗程式設計 (Windows Programming)
Ch9 Communicating with Hardware
第六章 擷取輸入裝置的訊息和事件 鍵盤、滑鼠,是我們最常使用的輸入工具。我們是不是常常希望可以再按下某個按鈕後就可以有哪些功能出現呢?沒錯,這就是這一章節的重點,在第四章,我們提到了有關鍵盤、滑鼠、以及RS-232介面的事件及訊息偵測,讓我們更能掌控電腦週邊的硬體。
2019/1/17 Java语言程序设计-程序流程 教师:段鹏飞.
簡易 Visual Studio 2005 C++ 使用手冊
Visual Basic.NET 程序设计语言课程内容
第九章 各種對話方塊的建立 視窗介面可以說是最友善的人和電腦間的溝通介面,然而對話方塊就好像是電腦和使用者之間的對話通道。開檔案有開檔案的方式、存檔有存檔的介面、印表機設定、字型選擇、尋找字串、置換字串等等,在Win32的環境中,這類的對話方塊實在是太多了。在這一章我們將帶領大家進入設計對話方塊的世界。
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
实验一、注册表安全实验 2019/4/9.
第五章: 輸入與輸出.
JAVA 编 程 技 术 主编 贾振华 2010年1月.
第五章 递归与广义表 递归的概念 递归过程与递归工作栈 递归与回溯 广义表.
程式結構&語法.
第12章 使用注册表.
BEEP and Sound 授課:ANT 日期:2014/5/28.
程式的時間與空間 Time and Space in Programming
本节内容 Win32 API中的宽字符 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第二章 Java语法基础.
Inspiration From Above 1 Chinese Evangelical Free Church
C++程序设计 吉林大学计算机科学与技术(软件)学院.
目标 流程控制 字符串处理 C# 的类和对象 C# 访问修饰符 C# 构造函数和析构函数.
第 3 章 类的基础部分 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
PHP程式設計 五、程式流程控制結構 建國科技大學 資訊管理學系 饒瑞佶.
第1章 数据结构基础概论 本章主要介绍以下内容 数据结构研究的主要内容 数据结构中涉及的基本概念 算法的概念、描述方法以及评价标准.
第2章 Java语言基础.
Presentation transcript:

第十三章 Win32 API及Registry 我們將利用Win32 API結合上一節所介紹的元件寫一個類似檔案總管的介面,也將介紹Registry的特性,進而利用Registry讓我們的程式更加有彈性。

大綱 13-1. Win32 API初體驗 13-2. 如何設計檔案總管 13-3. Registry觀念介紹 本章習題

13-1. Win32 API初體驗 Win32 API是開發Windows程式非常重要的一環(API:Application Programming Interface)。雖然常有人都說要用Windows API就用Visual C++來開發比較方便,但是實際上在BCB上面使用Win32 API一樣非常方便,並不會因為開發環境的不同而使得Win32 API的功能打了折扣。 在BCB中也有提供與Windows API相關的On-Line Help可以閱讀,除了可以從BCB的IDE介面中呼叫出說明檔外,我們也可以直接從Windows中的程式集中的BCB內選取我們所需要的說明檔。除了BCB提供的輔助檔外,我們也可以在微軟的MSDN上面找到Windows SDK的資料。

13-1. Win32 API初體驗 範例程式 範例13-1:GetDriverType 主要用來抓取各個磁碟機的型態。從A到Z這二十六個不同的磁碟代碼所表示的是軟碟、硬碟、光碟、或是可移動式磁碟等不同的型態。 範例13-2:GetShellIcon 用來抓取某個檔案的Icon。Icon有Large Icon也有Small Icon,我們該如何抓到某個檔案的這些Icon呢?常常一個檔案內的Icon有好幾個,那代表這個檔案的Icon又是哪一個呢?在這一個範例中將告訴大家該怎麼抓取這些圖示。

13-1. Win32 API初體驗 範例程式 範例13-3:GetSpecialFolder 用來抓取一些系統資料夾的目錄。例如桌面的路徑、網路芳鄰的路徑、我的文件的目錄……etc,有非常多的系統路徑我們都可以透過這個範例來抓取。 範例13-4:MessageBox 訊息視窗的設計。雖然在Borland C++ Builder中已經有ApplicationMessageBox以及ShowMessage可以用,但是Win32 API提供的MessageBox則有著更多的功能。 範例13-5:螢幕解析度 取得目前螢幕的解析度。有人螢幕的解析度是800x600,有人是1024x768,當然也有不少人用更高或是更低的解析度。我們要如何偵測解析度的數值呢?這個範例將帶給大家答案。

13-1. Win32 API初體驗 重要細節 有些程式的最前面需要『#define NO_WIN32_LEAN_AND_MEAN』 記得要Include適當的header file。例如『ShellAPI.h』等。 有的Win32 API有限制一定要在Win95/98 or WinNT/2000的環境下使用,要注意相關訊息。不過絕大部分的Win32 API都是所有的Windows系統皆適用。

13-1. Win32 API初體驗 範例13-1:抓取磁碟機的類型 範例13-1運用很簡單的方式來偵測每一個磁碟機代碼所表示的磁碟種類。在這個範例程式中,我們使用『GetDriveType』這個函式來取得磁碟的種類。關於這個範例的詳細程式碼如下所示。 void __fastcall TForm1::BitBtn1Click(TObject *Sender) { int m; char i; char driver[3]; for (i = 'A' ; i <= 'Z' ; i++) for (m = 0 ; m < 3 ; m++) driver[m] = '\0'; driver[0] = i; driver[1] = ':'; if (GetDriveType(driver) == 0) { Edit1->Text = Edit1->Text + driver; Edit1->Text = Edit1->Text + " "; } if (GetDriveType(driver) == 1) Edit2->Text = Edit2->Text + driver; Edit2->Text = Edit2->Text + " ";

13-1. Win32 API初體驗 範例13-1:抓取磁碟機的類型 if (GetDriveType(driver) == DRIVE_REMOVABLE) { Edit3->Text = Edit3->Text + driver; Edit3->Text = Edit3->Text + " "; } if (GetDriveType(driver) == DRIVE_FIXED) Edit4->Text = Edit4->Text + driver; Edit4->Text = Edit4->Text + " "; if (GetDriveType(driver) == DRIVE_REMOTE) Edit5->Text = Edit5->Text + driver; Edit5->Text = Edit5->Text + " "; if (GetDriveType(driver) == DRIVE_CDROM) { Edit6->Text = Edit6->Text + driver; Edit6->Text = Edit6->Text + " "; } if (GetDriveType(driver) == DRIVE_RAMDISK) Edit7->Text = Edit7->Text + driver; Edit7->Text = Edit7->Text + " ";

13-1. Win32 API初體驗 範例13-1:抓取磁碟機的類型 執行結果

13-1. Win32 API初體驗 範例13-2:抓取檔案的圖示 範例13-2我們利用『SHGetFileInfo』來抓取Icon的ImageHandle,在這個程式範例中,我們放入了一個Image以及一個ImageList來當作顯示Icon的Interface。其中如果要抓取某個磁碟機的Icon的話,在Edit上要輸入『C:\』這樣的符號,如果是要抓取某個資料夾的Icon,則直接輸入資料夾的完整路徑,若是要抓取某個檔案的Icon,則輸入檔案的完整路徑及檔名。首先我們先將SHGetFileInfo的使用方法列在下方,由語法中我們也可以很輕易的看出,我們利用『SHGetFileInfo』來抓取Icon只不過是這個API的其中一個小功能的延伸,這個API可以做到的功能還很多,就等待各位使用者去發掘吧!

13-1. Win32 API初體驗 範例13-2:抓取檔案的圖示 SHGetFileInfo語法 WINSHELLAPI DWORD WINAPI SHGetFileInfo( LPCTSTR pszPath, DWORD dwFileAttributes, SHFILEINFO FAR *psfi, UINT cbFileInfo, UINT uFlag );

13-1. Win32 API初體驗 範例13-2:抓取檔案的圖示 (程式碼) void __fastcall TForm1::BitBtn1Click(TObject *Sender) { SHFILEINFO info; DWORD ImageHandle; if (ComboBox1->ItemIndex == 0) { ImageHandle = SHGetFileInfo(Edit1->Text.c_str(), 0, &info, \ sizeof(info), SHGFI_ICON | SHGFI_SYSICONINDEX); } else { ImageHandle = SHGetFileInfo(Edit1->Text.c_str(), 0, &info, sizeof(info), \ SHGFI_SMALLICON | SHGFI_OPENICON | SHGFI_SYSICONINDEX); if (ImageHandle != 0) { ImageList1->Handle = ImageHandle; ImageList1->ShareImages = true; ImageList1->GetIcon(info.iIcon,Image1->Picture->Icon);

13-1. Win32 API初體驗 範例13-2:抓取檔案的圖示 執行結果

13-1. Win32 API初體驗 範例13-3:抓取系統中的特殊目錄 範例13-3將讓大家知道一些比較特殊的資料夾的位置在哪裡。或許有人會說,我可以去Registry中慢慢找,我一樣可以找到這些特殊位置的路徑,不過這未免也太花時間了。在這個範例中,我們將要教大家一個Win32 API,這個API可以幫我們抓取系統的一些特殊資料夾的位置。 在程式13-3中我們所用的API就是『SHGetSpecialFolderLocation』這一個,但是除了『SHGetSpecialFolderLocation』外,我們也使用到其他的一些API,例如『SHGetMalloc』、以及『SHGetPathFromIDList』這兩個API,在這個範例中,我們在main.cpp檔案中的最前面一定要加入『#define NO_WIN32_LEAN_AND_MEAN』,否則將無法編譯成功。

13-1. Win32 API初體驗 範例13-3:抓取系統中的特殊目錄 SHGetSpecialFolderLocation的語法 hwndOwner -- Handle of the owner window that the client should specify if it displays a dialog box or message box. nFolder -- Value specifying the folder to retrieve the location of. This parameter can be one of the following values. ppidl -- Address that receives a pointer to an item identifier list specifying the folder's location relative to the root of the name space (the desktop). WINSHELLAPI HRESULT WINAPI SHGetSpecialFolderLocation(; HWND hwndOwner, int nFolder, LPITEMIDLIST *ppidl );

13-1. Win32 API初體驗 範例13-3:抓取系統中的特殊目錄 SHGetSpecialFolderLocation中nFolder的各種參數值 CSIDL_BITBUCKET -- 資源回收筒的路徑(Virtual Directory) CSIDL_CONTROLS -- 控制台(Virtual Directory) CSIDL_DESKTOP -- 桌面(Virtual Directory) CSIDL_DESKTOPDIRECTORY -- 桌面的路徑 CSIDL_DRIVES -- 我的電腦(Virtual Directory) CSIDL_FONTS -- 字型的目錄 CSIDL_NETHOOD -- 網路芳鄰的目錄 CSIDL_NETWORK -- 網路芳鄰的目錄(Virtual Directory) CSIDL_PERSONAL -- 我的文件夾目錄

13-1. Win32 API初體驗 範例13-3:抓取系統中的特殊目錄 SHGetSpecialFolderLocation中nFolder的各種參數值 CSIDL_PRINTERS -- 印表機目錄(Virtual Directory) CSIDL_PROGRAMS -- 程式集的目錄 CSIDL_RECENT -- 最近使用的文件的目錄 CSIDL_SENDTO -- 傳送到???的目錄 CSIDL_STARTMENU -- 開始功能表的目錄 CSIDL_STARTUP -- 啟動這個資料夾的目錄 CSIDL_TEMPLATES -- 暫存檔的目錄

13-1. Win32 API初體驗 範例13-3:抓取系統中的特殊目錄 case 8 : CSIDL_STR = CSIDL_PERSONAL ; break; case 9 : CSIDL_STR = CSIDL_PRINTERS ; break; case 10 : CSIDL_STR = CSIDL_PROGRAMS ; break; case 11 : CSIDL_STR = CSIDL_RECENT ; break; case 12 : CSIDL_STR = CSIDL_SENDTO ; break; case 13 : CSIDL_STR = CSIDL_STARTMENU ; break; case 14 : CSIDL_STR = CSIDL_STARTUP ; break; case 15 : CSIDL_STR = CSIDL_TEMPLATES ; break; } if(SUCCEEDED(SHGetMalloc(&pShellMalloc))) { if(SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_STR, &pidl))) if(SHGetPathFromIDList(pidl, szDir)) Edit1->Text = szDir; pShellMalloc->Free(pidl); pShellMalloc->Release(); //--------------------------------------------------------------------- //千萬不要忘記在這個範例要加入這個定義 #define NO_WIN32_LEAN_AND_MEAN void __fastcall TForm1::BitBtn1Click(TObject *Sender) { LPITEMIDLIST pidl; LPMALLOC pShellMalloc; char szDir[MAX_PATH]; int CSIDL_STR; switch (ComboBox1->ItemIndex) case 0 : CSIDL_STR = CSIDL_BITBUCKET ; break; case 1 : CSIDL_STR = CSIDL_CONTROLS ; break; case 2 : CSIDL_STR = CSIDL_DESKTOP ; break; case 3 : CSIDL_STR = CSIDL_DESKTOPDIRECTORY ; break; case 4 : CSIDL_STR = CSIDL_DRIVES ; break; case 5 : CSIDL_STR = CSIDL_FONTS ; break; case 6 : CSIDL_STR = CSIDL_NETHOOD ; break; case 7 : CSIDL_STR = CSIDL_NETWORK ; break;

13-1. Win32 API初體驗 範例13-3:抓取系統中的特殊目錄 執行結果

13-1. Win32 API初體驗 範例13-4: Win32 API所提供的MessageBox 雖然BCB有提供ApplicationMessageBox,也有ShowMessage等函式可以顯示訊息方塊,可是大家一定會覺得,好像總是缺個什麼似的,就是跟Windows出現的訊息方塊有點不一樣。基於以上的原因,我們在範例13-4中將告訴大家如何使用Win32 API來實做MessageBox。 在這個範例中,我們除了使用到MessageBox這個API外,我們也用到了『GetActiveWindow』這個API,這個API主要的功能是抓取目前Active的視窗的Handle,借此Handle程式才知道這個訊息窗是哪個視窗發出來的。 MessageBox的語法 int MessageBox( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType // style of message box );

13-1. Win32 API初體驗 範例13-4: Win32 API所提供的MessageBox MessageBox的傳回值 數值 說明 IDABORT 按下ABORT的按鈕 IDCANCEL 按下CANCEL的按鈕 IDIGNORE 按下IGNORE的按鈕 IDNO 按下NO的按鈕 IDOK 按下OK的按鈕 IDRETRY 按下RETRY的按鈕 IDYES 按下YES的按鈕

13-1. Win32 API初體驗 範例13-4: Win32 API所提供的MessageBox void __fastcall TForm1::BitBtn1Click(TObject *Sender) { unsigned int Flag; AnsiString TitleStr, BodyStr; switch (ComboBox1->ItemIndex) case 0: Flag = MB_ABORTRETRYIGNORE; break; case 1: Flag = MB_OK; break; case 2: Flag = MB_OKCANCEL; break; case 3: Flag = MB_RETRYCANCEL; break; case 4: Flag = MB_YESNO; break; case 5: Flag = MB_YESNOCANCEL; break; } switch (ComboBox2->ItemIndex) case 0: Flag = Flag | MB_ICONEXCLAMATION; break; case 1: Flag = Flag | MB_ICONWARNING; break; case 2: Flag = Flag | MB_ICONINFORMATION; break; case 3: Flag = Flag | MB_ICONASTERISK; break; case 4: Flag = Flag | MB_ICONQUESTION; break; case 5: Flag = Flag | MB_ICONSTOP; break; case 6: Flag = Flag | MB_ICONERROR; break; case 7: Flag = Flag | MB_ICONHAND; break; } switch (ComboBox3->ItemIndex) { case 0: Flag = Flag | MB_DEFBUTTON1; break; case 1: Flag = Flag | MB_DEFBUTTON2; break; case 2: Flag = Flag | MB_DEFBUTTON3; break; case 3: Flag = Flag | MB_DEFBUTTON4; break; TitleStr = Edit1->Text; BodyStr = Edit2->Text; MessageBox(GetActiveWindow(), BodyStr.c_str(), TitleStr.c_str(), Flag);

13-1. Win32 API初體驗 範例13-4: Win32 API所提供的MessageBox 執行結果

13-1. Win32 API初體驗 範例13-5:抓取目前螢幕解析度 在程式13-5中,我們將告訴各位我們怎麼抓取目前螢幕的解析度。因為這個範例比要簡單,所以我們直接列出程式碼讓各位看看,相信大家一定可以直接從程式碼中了解這個範例的意義。在這個範例中我們只使用『GetSystemMetrics』這個API。 程式碼 & 執行結果 void __fastcall TForm1::Button1Click(TObject *Sender) { int X, Y; AnsiString Content; X = GetSystemMetrics(SM_CXSCREEN); Y = GetSystemMetrics(SM_CYSCREEN); Content = "目前螢幕解析度為:" + IntToStr(X) + "x" + IntToStr(Y); MessageBox(GetActiveWindow(), Content.c_str(), "解析度", MB_OK); }

13-2. 如何設計檔案總管 談到檔案總管時,一定不能忘記介紹『Name Space』這個東西。Name Space簡單的說就是Windows的骨幹,整個Windows其實可以看成一棵樹,從桌面一直向下延伸,所以不管是『我的電腦』、『控制台』、『各個磁碟機』、『我的文件夾』、『網路芳鄰』、『印表機』……等等,都是在這個Name Space中。要弄懂Name Space的API並沒有想像中的難。而且在上一小節中,範例13-2以及13-3也是Name Space的範例之一,看起來是不是就簡單多了呢! 反過來說,要寫出檔案總管的介面,我們也不一定全部都要使用Name Space來寫,可以某部分採用Name Space,某部分採用我們一般的程式設計,雖然這樣看起來可能會跟真正的檔案總管有一點出入,不過至少我們也做到了『大部分』的相似,而且在設計上的難度也大大的降低。 在BCB的Example中,也有一個VirtualListView的範例,就是利用Name Space寫出的檔案瀏覽程式,該範例就很像檔案總管右邊的ListView。接著我們在範例13-6中,將利用簡單的檔案搜尋技巧將整個電腦的TreeView設計出來。

13-2. 如何設計檔案總管 範例13-6:檔案總管的TreeView實作 在這個範例中,我們為了不建立整個Name Space,所以用了許多『Dirty』的方法,當然這樣的程式並不能算是一個相當好的程式,不過在這邊為了讓大家提高對於這邊的學習興趣,所以只好採用這樣的方式建構出類似Name Space的整棵Tree。關於建構整個TreeView的程式碼如下所示,程式的說明將會直接在程式碼中以註解的方式出現!

13-2. 如何設計檔案總管 範例13-6:檔案總管的TreeView實作 程式碼 – main.h class TForm1 : public TForm { __published: // IDE-managed Components TTreeView *TreeView; void __fastcall FormCreate(TObject *Sender); void __fastcall TreeViewExpanding(TObject *Sender, TTreeNode *Node, bool &AllowExpansion); private: // User declarations void __fastcall TreeViewInitial(); void __fastcall CreateNewNode(char *str, int image1, int image2); void __fastcall CreateNewDisk(char *str, int image1, int image2); void __fastcall SearchDisk(); void __fastcall FindFirstLevelTree(char *prifix); void __fastcall FindSecondLevelTree(char *prifix); AnsiString __fastcall TreeViewGetPath(TTreeNode *Node); int __fastcall GetTreeViewShellImage(char *str, bool Open); AnsiString __fastcall GetSpecialFolder(int CSIDL_STR); int __stdcall CompareFunc(LPARAM LParam1, LPARAM LParam2, LPARAM LData); public: // User declarations __fastcall TForm1(TComponent* Owner); };

13-2. 如何設計檔案總管 範例13-6:檔案總管的TreeView實作 (程式碼 – main.cpp) //--------------------------------------------------------------------- //該程式需要定義"NO_WIN32_LEAN_AND_MEAN" #define NO_WIN32_LEAN_AND_MEAN #include <vcl.h> #pragma hdrstop #include "main.h" //將shellapi.h include進來 #include <shellapi.h> #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //宣告兩個TreeNode //*root用來紀錄Root //*node用在動態產生Node TTreeNode *root, *node; __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //----------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) //將Form建立的時候呼叫TreeViewInitial //TreeViewInitial就是整個Tree產生的起點 //在TreeView底下的這將進300行的Code中 //有使用到ShellAPI(NameSpace) //也有使用到最基本的檔案搜尋的API TreeViewInitial();

13-2. 如何設計檔案總管 範例13-6:檔案總管的TreeView實作 (程式碼 – main.cpp) 因為程式碼的部分相當的多,詳細的程式碼請直接參考書上的範例 執行結果

13-2. 如何設計檔案總管 範例13-7:檔案總管的ListView實作 接下來我們要談的就是範例程式13-7,也就是列出File的程式碼,在這部分我們也沒有使用Name Space的方式來抓取檔案,我們採用最簡單的方式,利用FindFirst和FindNext來找出所有的檔案,使用方式就是輸入路徑後讓程式幫我們搜尋出目錄中的所有檔案。在這個程式中,我們有一個Edit可以讓大家輸入路徑,輸入後按下『Find』,程式就會自動在所輸入的目錄內搜尋檔案。

13-2. 如何設計檔案總管 範例13-7:檔案總管的ListView實作 程式碼 void __fastcall TForm1::Button1Click(TObject *Sender) { AnsiString PathStr; TSearchRec sr; int iAttributes = faReadOnly | faDirectory; TListItem *p; if (Edit1->Text.c_str()[Edit1->Text.Length() - 1] == '\\') PathStr = Edit1->Text + "*"; else PathStr = Edit1->Text + "\\*"; ListView1->Items->Clear(); if (FindFirst(PathStr, iAttributes, sr) == 0) do { if ((sr.Attr & iAttributes) == sr.Attr) p = ListView1->Items->Add(); p->Caption = sr.Name; p->SubItems->Add(IntToStr(sr.Size)); p->SubItems->Add(FileDateToDateTime(sr.Time)); } } while (FindNext(sr) == 0); FindClose(sr);

13-2. 如何設計檔案總管 範例13-7:檔案總管的ListView實作 執行結果

13-2. 如何設計檔案總管 範例13-7:檔案總管的ListView實作 在這一節中我們大概只提到Tree的建法以及抓取檔案的方式,其實如果大家能將上面兩個範例的原理弄清楚,要寫一個簡單的檔案總管已經不是問題了,在這邊我們稍微提一下將Tree以及List整合起來有哪些需要注意的事項。 點下左方Tree上面的Node必須也要同時抓到TreeNode所表示的路徑,並且將這個路徑傳給List上搜尋檔案的程式碼。這樣才有辦法將ListView上的檔案資訊更新。 如果有一個ComboBox可以用來記錄目前路徑資料的話,當我們在ComboBox上輸入新的路徑時,並需要同時更新到TreeView以及ListView上。 在ListView上進入另一層目錄時,TreeView必須要同時更新。ComboBox也要更新。 若是按下『上一頁』或是『下一頁』之類的按鈕,TreeView以及ListView要同時更新。

13-3. Registry觀念介紹 Registry的觀念可以說從Win95 OSR2版本(俗稱Win97)之後就大行其道,一直到Win98/NT/2000/ME甚至是現在最新的Windows XP、Windows .NET,都持續的使用Registry,我們可以將Registry想成一個很大的資料庫,也可以想成一個很大的檔案,也可以想成是一堆資訊在裡面的容器,總之,關於這台電腦的所有事情幾乎都可以在Registry中找到。

13-3. Registry觀念介紹 在以前Win 3.1的時代,我們常常看到有許多『.ini』的檔案存在於電腦中,也常常看到一些config類型的檔案等等。其實在Windows 3.1的時候也有Registry的觀念,只是那時候儲存的資訊只有跟OLE相關的物件而已,而現在是不管什麼資料都全部放在Registry裡面了。Registry經過分析大概有以下這些特點: 集中化:不再像過去一樣散亂在各處。 結構化:樹狀目錄。 伸縮性:可用二進位、八進位、十進位、以及十六進位各式各樣的值。 安全性:有存取控制的限制。 隱密性:要了解或是知道放在哪邊並不容易。 不規則:一開始就很大,且很複雜,各項資料只有個大概的規則。 危險性:Registry是即時的、動態的,一改錯就有可能造成問題。

13-3. Registry觀念介紹 在Windows中要開啟Registry,我們可以在開始選單中的『執行』輸入『regedit』後按下『Enter』,這時候就會將Registry的編輯畫面呼叫出來。一般來說,除了有經驗的管理人員外,我們並不建議一般不熟悉Registry的管理者任意修改Registry中的值。除此之外,還要養成隨時備份Registry的習慣。

13-3. Registry觀念介紹 在Registry中主要分成五大部分: HKEY_CLASSES_ROOT HKEY_LOCAL_MACHINE\SOFT WARE\Classes的一個鏡對。也提供和Windows 3.X登陸資料庫的相容系。 HKEY_CURRENT_USER 目前使用者的相關事項及限制。當HKEY_USERS和HKEY_CURRENT_USER有一樣的值時,以HKEY_CURRENT_USER有較高的優先權。 HKEY_LOCAL_MACHINE 每一部份的資料都適合用在此電腦上,並不會因為使用者的不同而有不同的設定。 HKEY_USERS 包含帳戶內所定義的使用者。通常只會包含預設使用者跟目前正在使用的使用者,不然全部使用者都讀出來可能會造成浪費太多記憶體。 HKEY_CURRENT_CONFIG 系統目前的硬體資訊。

13-3. Registry觀念介紹 HKEY_LOCAL_MACHINE主要的子鍵 HARDWARE 在HKEY_LOCAL_MACHINE中最常變動的數值,每次開機都會自動偵測並且更新。在HARDWARE中也有三個子鍵,各是Description、DeviceMap、以及ResourceMap。Description主要的功能是開機時系統會執行自動偵測的程式,並將這程式傳回的資訊寫入Description。DeviceMap是裝置和驅動程式的設定值以及指標。ResourceMap則是記錄著硬體所使用的IRQ、DMA、I/O Port等資源。 SAM SAM就是Security Account Manager,SAM其實就是SECURITY中的一個子鍵。 SECURITY 要修改這個子鍵下的資料必須要呼叫Windows NT Security API才能更改,無法直接從編輯程式中修改。

13-3. Registry觀念介紹 HKEY_LOCAL_MACHINE主要的子鍵 (cont.) SOFTWARE 定義及維護所有32位元的軟體設定值,包括Windows本身也是。在這底下還包含著五個重要子鍵:Classes、Microsoft、Program Groups、Secure、以及Windows 3.1 Migration Status。其中Classes記錄著檔案和OLE之間的關係,這是由Windows 3.1那邊演變而來的。Microsoft內包含了系統上安裝的Microsoft相關軟體,當然也有一些協力廠商的軟體也會在這邊出現。Program Groups記錄著常用的應用程式或是軟體清單。Secure幾乎沒有用處。 SYSTEM 負責維護驅動程式和服務等資訊。在這底下也包含多個子鍵,大部分是ControlSet。其中ControlSet有四種狀態,現在值、預設值、失敗、以及LastKnowGood這四種狀態。而這四種檔案對應到哪個狀態則可以參閱SYSTEM\Select Key。

13-3. Registry觀念介紹 Registry中的五種資料型態 REG_BINARY 二進位資料。 REG_WORD REG_SZ 單純的字串。 REG_MULTI_SZ 多個字串,用空白隔開。 REG_EXPEND_SZ 可擴充的字串,一般都是變數。

13-4. 讀寫Registry 在寫程式之前,我們需要先知道在BCB中有一個物件叫做『TRegistry』,在這個類別中提供了許多屬性及方法可以讓我們使用。我們在程式13-8中的所有做法也都是照著TRegistry所提供的功能做出來的。下面我們先列出一些比較重要的方法讓大家知道: CloseKey, CreateKey, DeleteKey, DeleteValue, GetDateType, GetValueName, KeyExists, LoadKey, MoveKey, OpenKey, OpenKeyReadOnly, ReadBinaryData, ReadBool, ReadCurrency, ReadDate, ReadDateTime, ReadFloat, ReadIntegre, ReadString, ReadTime, RegistryConnect, RenameValue, ReplaceKey, RestoreKey, SaveKey, UnLoadKey, ValueExists, WriteBinaryData, WriteBool, WriteCurrency, WriteDate, WriteDateTime, WriteFloat, WriteIntegre, WriteString, WriteTime. 看到這麼多的Method都是由TRegistry實在是相當的恐怖,所以在這邊我們不在投影片上列出各個Method的說明,請大家自行參閱書上的說明。

13-4. 讀寫Registry 範例13-8:從Registry讀出資料 程式碼 (main.h) 記得要加入Registry的標頭檔 #include <Vcl\Registry.hpp> 也要宣告一個TRegistry的物件 TRegistry *Registry;

13-4. 讀寫Registry 範例13-8:從Registry讀出資料 (程式碼: main.cpp) void __fastcall TForm1::BitBtn1Click(TObject *Sender) { if ((ComboBox1->Text != "") && (Edit1->Text != "") && (Edit2->Text != "")) Registry = new TRegistry; switch (ComboBox1->ItemIndex) case 0 : Registry->RootKey = HKEY_CLASSES_ROOT; break; case 1 : Registry->RootKey = HKEY_CURRENT_USER; break; case 2 : Registry->RootKey = HKEY_LOCAL_MACHINE; break; case 3 : Registry->RootKey = HKEY_USERS; break; case 4 : Registry->RootKey = HKEY_CURRENT_CONFIG; break; } Registry->OpenKey(Edit1->Text.c_str(), false); Edit3->Text = Registry->ReadString(Edit2->Text.c_str()); Registry->Free(); } else MessageBox(GetActiveWindow(), "請輸入完整資訊", "錯誤", MB_OK|MB_ICONSTOP); //--------------------------------------------------------------------------- void __fastcall TForm1::BitBtn2Click(TObject *Sender) { ComboBox1->Text = ""; Edit1->Text = ""; Edit2->Text = ""; Edit3->Text = "";

13-4. 讀寫Registry 範例13-8:從Registry讀出資料 執行結果

13-4. 讀寫Registry 範例13-9:寫入資料到Registry中 程式碼 Main.h也要如上個範例一樣加入所需要的敘述,如標頭檔或是宣告等等 Main.cpp如下所示 case 3 : Registry->RootKey = HKEY_USERS; break; case 4 : Registry->RootKey = HKEY_CURRENT_CONFIG; break; } Edit1->Enabled = true; BitBtn2->Enabled = true; ComboBox1->Enabled = false; BitBtn1->Enabled = false; void __fastcall TForm1::BitBtn1Click(TObject *Sender) { if (ComboBox1->Text != "") Registry = new TRegistry; switch (ComboBox1->ItemIndex) case 0 : Registry->RootKey = HKEY_CLASSES_ROOT; break; case 1 : Registry->RootKey = HKEY_CURRENT_USER; break; case 2 : Registry->RootKey = HKEY_LOCAL_MACHINE; break;

13-4. 讀寫Registry 範例13-9:寫入資料到Registry中(程式碼) void __fastcall TForm1::BitBtn2Click(TObject *Sender) { if (Edit1->Text != "") Registry->OpenKey(Edit1->Text.c_str(), true); Edit2->Enabled = true; Edit3->Enabled = true; ComboBox2->Enabled = true; BitBtn3->Enabled = true; Edit1->Enabled = false; BitBtn2->Enabled = false; } void __fastcall TForm1::BitBtn3Click(TObject *Sender) { if ((Edit2->Text != "") && (Edit3->Text != "") && (ComboBox2->Text != "")) switch (ComboBox2->ItemIndex) case 0 : Registry->WriteString(Edit2->Text, Edit3->Text); break; case 1 : Registry->WriteString(Edit2->Text, Edit3->Text); break; case 2 : Registry->WriteString(Edit2->Text, Edit3->Text); break; case 3 : Registry->WriteInteger(Edit2->Text, Edit3->Text.ToInt()); break; } Edit2->Text = ""; Edit3->Text = ""; ComboBox2->Text = "";

13-4. 讀寫Registry 範例13-9:寫入資料到Registry中(程式碼) void __fastcall TForm1::BitBtn4Click(TObject *Sender) { ComboBox1->Text = ""; ComboBox2->Text = ""; Edit1->Text = ""; Edit2->Text = ""; Edit3->Text = ""; ComboBox1->Enabled = true; BitBtn1->Enabled = true; Edit1->Enabled = false; BitBtn2->Enabled = false; BitBtn3->Enabled = false; Edit2->Enabled = false; Edit3->Enabled = false; ComboBox2->Enabled = false; Registry->Free(); }

13-4. 讀寫Registry 範例13-9:寫入資料到Registry中 執行結果

本章習題 試著找書或是從網頁找到Windows中的Name Space這方面的資料。 試著看懂BCB中VirtualListView這個範例。 嘗試自己利用Name Space寫出完整的檔案總管,介面可以先以範例11-6朱的執行檔為基準。 利用Registry紀錄自己開發的軟體每次結束時的位置,以便於下次啟動同一套軟體時可以在同一個地方出現。 比較使用Visual C++和BCB開發Win32 API程式的差異性。