60個BCB(C++Build)初學者應用實例(轉)

1.怎樣在C++Builder中建立使用DLL
2.用C++Bulider在WIN.INI中保存信息
3.如何在C++Builder中檢測硬件
4.C++Builder如何響應消息及自定義消息
5.利用C++ Builder開發動畫DLL
6.用C++ Builder 3製做屏幕保護程序
7.TCP/IP頭格式
8.UDP
9.判斷windows的Desktop及其它目錄
10用C++Builder建立數字簽名
11用Enter 鍵控制焦點切換的方法
12.攔 截 Windows 消 息
13.使用CommaText
14.程序開始時先顯示信息框
15.怎樣獲取程序的命令行參數?
16.如何監視剪貼板
17.如何使用OnIdle事件
18.用C++Builder編寫串行異步通訊程序
19.C++BUILDER非可視組件的消息處理技巧
20.用C++Builder 創建數據庫VCL使用經驗
21.用C++ Builder建立基於Internet的點對點Chat
22.用C++Builder獲取應用程序圖標
23.BIG5到GB的轉換技術
24.C++BUILDER讓你的任務欄圖標動起來
25.TFORM
26.用BCB在windows桌面建立快捷方式
27.讀磁片磁區
28.I/O 端口讀寫的實現
29.檢測鼠標位置
30.令Win32 應用程序跳入系統零層
31.如何取得Memo的行和列
32.使用Sockets
33.Windows95/98下怎樣隱藏應用程序不讓它出如今CTRL-ALT-DEL對話框中?
34.怎樣隱藏應用程序的任務條圖標
35.編寫本身的Ping.exe程序
36.用C++Builder在WINNT下編制一個Service
37.如何在C++ BUILDER中自動關閉WINDOWS屏保
38.顯示/隱藏任務欄圖標
39.信箱監視程序
40.C++Building製做鬧鐘
41.撥號上網IP地址的檢知
42.用C++ Builder編寫Tray程序
43.怎樣用代碼來最小化或恢復程序
44.製做主窗口顯示前的版權窗口
45.判斷是否已經聯到 internet
46.獲取登錄用戶名
47.隱藏桌面圖標
48.程序啓動時運行
49.控制面板的調用
50.模擬鍵盤按鍵
51.讓標題欄閃爍
52.啓動屏幕保護
53.年月日星期的取法
54.鍵盤事件
55.隱藏任務欄
56.禁止關機
57.怎樣以最小化方式啓動程序
58.在Memo中增長一行後,如何使最後一行能顯示
59.設置壁紙方法git

整的不容易啊支持下吧程序員


怎樣在C++Builder中建立使用DLL
  自從C++Builder從去年浪漫情人節上市以來,吸引了大量的Delphi、VC、Vb的程序員到它的懷抱,大量的C、C++程序員感嘆道:總算有了C的可視化開發工具,對我也是同樣,從BC、Delphi到C++Builder。
  動態連接庫(DLL)是Windows編程常遇到的編程方法,下面我就介紹一下在BCB (C++Builder下簡稱BCB)中如何建立使用DLL和一些技巧。
  1、建立:
  使用BCB File|NEW創建一個新的DLL工程,並保存好文件BCB,生成一個DLL的程序框架。
  1.DllEntryPoint函數爲一個入口方法,若是使用者在DLL被系統初始化或者註銷時被調用,用來寫入對DLL的初始化程序和卸載程序;參數:hinst用來指示DLL的基地址;reason用來指示DLL的調用方式,用於區別多線程單線程對DLL的調用、建立、卸載DLL;
  2.在程序中加入本身所要建立的DLL過程、函數;
  3.用dllimport描述出口;
  例程序以下:
#include
#pragma hdrstop
extern 揅?__declspec(dllexport) int test();
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason,void*)
{
return 1;
}
int test()
{
return 3;
}
  注意:動態連接庫中調用過程、函數時有不一樣的CALL方式 __cdecl、 __pascal,__fastcall、__stdcall,BCB中默認的方式爲__cdecl(可不寫),若是考慮兼容性可用時__stdcall聲明方法爲:
extern 揅?__declspec(dllexport) int __stdcall test();
  對於其中過程、函數也改成:
int __stdcall test()算法

整的不容易啊支持下吧
  2、使用DLL
  在BCB中使用DLL有兩種方法:
  1.用靜態調用法
  首先須要在BCB的項目中加入輸入接口庫(import library),打開工程項目,使用BCB View|ProjectManager打開項目列表,向項目中加入接口庫(*.lib)。
  其次在頭文件中加入接口聲明。
  例程序以下:
//define in include file
extern 揅?__declspec(dllimport) int __cdecl test();
//use function in main program
int I;
I=test();
注意:
(1)動態連接庫調用過程、函數時CALL方式 與建立時方式同樣不寫爲__cdecl,其它須要聲明。
(2)BCB建立的DLL有對應的輸入接口庫(importlibrary),如只有DLL而無庫時,可用BCB的implib工具產生:implib xxx.libxxx.dll;另外可用:tlib xxx.lib,xxx.lst產生DLL的內部函數列表,許多Windows的未公開技術就是用這種方法發現的。
  2.動態調用法
  動態調用法要用Windows API中的LoadLibrary()和GetProcAddress()來調入DLL庫,指出庫中函數位置,這種方法較常見。
  例程序以下:
HINSTANCE dd;
int _stdcall (*ddd)(void);
dd=LoadLibrary(搙xx.dll?;
ddd=GetProcAddress(dd,搕est?;
Caption=IntToStr(ddd());
FreeLibrary(dd);
  3、注意:
建立DLL時編譯連接時注意設置Project Options。
Packages標籤:去除Builder with runtime packages檢查框。
Linker標籤:去除Use dynamic RTL檢查框。
不然建立的DLL須要Runtime packages or Runtime library。shell


用C++Bulider在WIN.INI中保存信息數據庫

  如今許多軟件把程序中須要的數據保存在註冊表中,這樣當用戶裝的軟件愈來愈多時,導致註冊表愈來愈龐大,容易使系統出錯。固然,微軟也建議在註冊表中保存數據,但當咱們須要保存的數據很少時徹底能夠把數據保存在WIN.INI中,這樣能夠很方便地維護,實現方法相對來講比較簡單。下面我以BorlandC++ Builder爲例來講說如何實現。
  原理其實很簡單,只需調用API的WriteProfileString和GetProfileInt函數就能夠了。這兩個函數的原型是:BOOLWriteProfileString(LPCTSTR lpAppName,LPCTSTR lpKeyName,LPCTSTRlpString );
  UINT GetProfileInt(LPCTSTR lpAppName,LPCTSTR lpKeyName,INTnDefault);
  其中lpAppName指在WIN.INI中段的名字,即用[]括起來的字符串,lpKeyName指在這個段中每個項目的名字,lpString指這個項目的值,即「=」後的數,nDefault爲當GetProfileInt沒有找到lpAppName和lpKeyName時返回的值,即缺省值,前者返回爲布爾值(true或 false),後者返回爲無符號整形值。當在WriteProfileString函數中 lpKeyName爲空(NULL)時,則清除這個段的所有內容,lpString 爲空時,則清除這一項目的內容,即這一行將清除掉。
  下面舉一例子來講明這兩個函數的用法。新建一個應用程序,在Form1上放兩個Edit和三個Button,其中Edit的Text爲空,三個Button的Caption分別爲「添加」、「查看」、「清除」。雙擊「添加」按鈕加入下面代碼:
WriteProfileString(「例子程序」,「項目」,Edit1→Text.c_str());
  雙擊「查看」按鈕加入以下代碼:
unsigned int Temp;
Temp=GetProfileInt(「例子程序」,「項目」,100);
Edit2→Text=IntToStr(Temp);
  雙擊「清除」按鈕加入以下代碼:
WriteProfileString(「例子程序」,NULL,NULL);
  而後按F9鍵運行程序。
  下來能夠檢驗一下程序的正確性。在Edit1中輸入數字,如「3265」,按「添加」按鈕,這時運行「sysedit」來查看「WIN.INI」文件的最後面,能夠看到加入了以下內容:
  [例子程序]
  項目=3265
  其中「[]」和「=」是函數自動加上的。按下「查看」按鈕,在Edit2中出現「3265」,當按下「清除」按鈕可清除添加的部分。通過查看可知程序已達到預期的目的。
  喜好編程的朋友能夠把上述方法應用到本身的程序中去,來達到保存數據信息的做用。當確實要把信息保存到註冊表中,能夠在C++Builder中定義一個TRegistry類的對象來進行相關的操做,或者直接調用Windows的API函數,具體如何編程你們能夠參閱相關資料或者同我聯繫。編程

整的不容易啊支持下吧windows

如何在C++Builder中檢測硬件數組

  在咱們編寫的程序中經常要和硬件打交道,那麼如何在程序中肯定系統中是否有該設備,它的運行狀態又是怎樣的呢?對於初學者來講,這個問題經常很差解決,其實只需簡單地利用幾個API函數,硬件的問題並不神祕。下面就讓咱們一塊兒看看在C++Builder中是如何檢測硬件的。
  1. 檢測CPU的型號
  先讓咱們從最簡單的作起,看一看本身的CPU型號。首先,在C++Builder中畫出圖1所示的窗體,在下面的幾個例子中咱們將一直使用這個窗體做示範,它包括一個用來激活測試的Button和一個用來顯示結果的Memo。咱們能夠用GetSystemInfo這個API得到CPU的型號。將下列代碼添加到Button的Click事件裏就能夠了:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
//得到CPU型號
SYSTEM_INFO systeminfo;
GetSystemInfo (&systeminfo);
Memo1→Lines→Add(撃腃PU類型是:敓玈tring( systeminfo.dwProcessorType));
}
運行它,點擊Test試試,CPU型號出來了吧!
  2.檢測內存狀態
  得到內存狀態的方法和CPU型號差很少,只是他用到的是另一個API:GlobalMemoryStatus。
  其中,成員dwTotalPhys用來得到物理內存總量,而dwAvailPhys顧名思義是有效物理內存的意思。咱們只要把下面幾行代碼加到上面程序的後面就能夠了(不用重作,下同):
//得到內存狀態
MEMORYSTATUS memory;
memory.dwLength =sizeof(memory); //初始化
GlobalMemoryStatus(&memory);
Memo1→Lines→Add(撃奈錮砟詿媸?Mb):敓玈tring(int(memory.dwTotalPhys/1024/1024)));
Memo1→Lines→Add(撈渲鋅捎媚詿媸?Kb):敓玈tring(int( memory. /1024)));
  怎麼樣,看出點門道了麼?兩段程序的格式幾乎如出一轍,其實,GetSystemInfoGlobalMemoryStatus還能夠得到許多其餘有關CPU和內存的信息,就按照上面的格式去套就好了,更詳細的資料能夠去看C++Builder4的Help。
  3. 檢測可用硬盤空間
好了,通過前面兩個簡單問題的熱身,咱們來處理一個稍微複雜的問題:咱們知道安裝程序大都有一個檢測硬盤空間的過程,那麼這是怎麼實現的呢?他用到的是API函數GetDiskFreeSpace,這個函數輸入一個參數:目標盤的路徑;返回四個參數,依次是每簇的扇區數、每扇區的字節數、空閒的簇數、總簇數。假如咱們須要檢測C盤的總容量和可用容量,那麼能夠把如下代碼加到上面的程序中:
//得到C盤可用空間
DWORD sector,byte,cluster,free;
long int freespace,totalspace;
GetDiskFreeSpace(揅:?&sector,&byte,&free,&cluster); //得到返回參數
totalspace=int(cluster)*int(byte)*int(sector)/1024/1024;//計算總容量
freespace=int(free)*int(byte)*int(sector)/1024/1024; //計算可用空間
Memo1→Lines→Add(揅盤總空間(Mb):敓玈tring(totalspace));
Memo1→Lines→Add(揅盤可用空間(Mb):敓玈tring(freespace));
怎麼樣?如今能夠本身作安裝程序了吧!緩存


C++Builder如何響應消息及自定義消息安全

  Inprise(Borland)C++Builder中,能夠象在Delphi中同樣響應消息,只是看起來要稍複雜一點。
  對於系統已定義的消息,能夠直接響應:
#define WM_MY_OPEN_CMDLINE_FILE (WM_USER+1) //進程間通信的自定義消息
#define WM_MY_SEARCH_NODE (WM_USER+2) //查找命令的自定義消息
class TSomeForm : public TForm
{
//...類中的其它代碼
protected:
//消息的響應過程
void __fastcall OpenCmdLineFile(TMessage Message);
void __fastcall SearchDocumentNode(TMessage Message);
void __fastcall GetWindowMinMaxInfo(TWMGetMinMaxInfoMessage);
//如下經過宏定義實現消息的正確響應
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_MY_OPEN_CMDLINE_FILE, TMessage,OpenCmdLineFile)
MESSAGE_HANDLER(WM_MY_SEARCH_NODE, TMessage,SearchDocumentNode)
MESSAGE_HANDLER(WM_GETMINMAXINFO , TWMGetMinMaxInfo,GetWindowMinMaxIn fo)
END_MESSAGE_MAP(TForm)
};//end class
//如下爲實現代碼
void __fastcall TSomeForm::OpenCmdLineFile(TMessage Message)
{//直接經過消息結構傳遞參數
LPSTR lpCmdLine=(LPSTR)Message.LParam;//從Message中取得參數
this->HandleCmdLineFile(lpCmdLine);//處理命令行的參數
return;
}
void __fastcall TSomeForm::SearchDocumentNode(TMessageMessage)
{//響應查找消息
//Message中的參數在此處不須要。
this->SearchNode();
return;
}
void __fastcall TSomeForm::GetWindowMinMaxInfo(TWMGetMinMaxInfoMessag
e)
{//設置主窗口的最小尺寸
MINMAXINFO *MinMaxInfo=Message.MinMaxInfo;
MinMaxInfo->ptMinTrackSize.x=400;
MinMaxInfo->ptMinTrackSize.y=300;
return;
}
其中:TMessage和TWMGetMinMaxInfo類型的定義可參見:
C:/ProgramFiles/Borland/CBuilder/inlucde/vcl/Messages.hpp;其它的消息
響應方法與此相同。
另外,能夠爲自定義的消息也定義一個對應的消息結構(如:TSearchNode_Mes
sage),至於如何定義消息結構, 能夠參考:
C:/Program Files/Borland/CBuilder/inlucde/vcl/Messages.hpp

利用C++ Builder開發動畫DLL

  咱們在Windows98環境下執行拷貝文件、查找文件或計算機等耗時比較長的操做時,Windows會顯示一個小小的動畫,指示正在進行的操做,與死板的靜止圖像相比增色很多。那麼咱們本身開發軟件時,可否也顯示一個這樣的動畫提示呢?我在開發一個外貿應用軟件系統時,遇到的數據量很大,當經過複合條件查找時,由於不是數據庫表的每一個項目都有索引,因此很費時,系統也會表現出長時間停頓,用戶感受極爲不爽。我通過一段時間的探索,開發了一個可以在採用的開發環境PowerBuilder下調用的動畫DLL,因爲採用多線程編程,PB調用的DLL函數可以及時將控制權交還爲PB,不影響應用系統的運轉。用戶可以看到一個東西在動,也就不會想到系統是否是中止響應了,感受時間也彷佛沒那麼久了。
  代碼與編譯選項
  (1) 在C++Builder的File菜單下選擇New,在NewItem對話框的New屬性中選擇DLL,C++Builder就會建立一個空白的DLL項目。
  (2) 在File菜單下選擇New Form,C++Builder建立一個空白的Form,修改它的屬性爲
BorderStyle=bsDialog
BorderIcons的子屬性均爲False
FormStyle=fsStayOnTop
Position= poScreenCenter
Name=StatusForm
  (3) 在Form上添加一個Win32下的Animate控件Animate1,修改它的屬性爲
Align=alTop
  (4)在Form上添加一個Standard下的Button控件Button_Cancel,再添加System下的Timer控件Timer1,設置定時Interval時間位250,以較快的響應用戶的取消請求。
  由於PB應用系統與動畫窗體代碼分別屬於兩個線程,不能採用PB線程直接關閉動畫窗體線程的窗口,不然會引發系統運行不正常,所以採用PB線程設置關閉標誌,而動畫線程採用Timer控件定時檢查標誌,一旦檢測到關閉標誌,就關閉窗口,清除線程標誌,結束動畫線程。
  下面給出編碼及編碼原理:
  1.DLL DLL主體代碼:


TCommonAVI g_CommonAVI[]={
aviNone, aviFindFolder,
aviFindFile, aviFindComputer,
aviCopyFiles, aviCopyFile,
aviRecycleFile, aviEmptyRecycle,
aviDeleteFile
};
int gi_Canceled=0,gi_AVIType=0;
int gi_RequestClose=0,gi_WindowActive=0;
char lpsWinTitle[256];
HWND hWndParent=NULL;

extern "C" __declspec(dllexport)
int pascal DllEntryPoint(HINSTANCE hinst,
unsigned long reason, void*);
extern "C" __declspec(dllexport) int
pascal ShowStatusWindow(int AVIType,
LPSTR WinTitle,long hWnd);
extern "C" __declspec(dllexport) int
pascal GetStatus(int ai_CloseWin);
extern "C" __declspec(dllexport) int
pascal CloseStatusWindow();

class TFormThread : public TThread{
public:// User declarations
__fastcall TFormThread(bool CreateSuspended);
void __fastcall Execute(void);
};
__fastcall TFormThread::
TFormThread(bool CreateSuspended):
TThread(CreateSuspended){
}

void __fastcall TFormThread::Execute(void){
gi_WindowActive=1;
StatusForm=new TStatusForm(NULL);
StatusForm- >Caption=lpsWinTitle;
StatusForm- >ShowModal();
gi_WindowActive=0;
delete StatusForm;
gi_RequestClose=0;
}

TFormThread *FormThread;

__declspec(dllexport) int WINAPI DllEntryPoint
(HINSTANCE hinst, unsigned long reason, void*)
{
return 1;
}
__declspec(dllexport) int pascal
ShowStatusWindow(int AVIType,LPSTR
WinTitle,long hWnd){
hWndParent=(HWND)hWnd;
memset(lpsWinTitle,0,sizeof(lpsWinTitle));
strncpy(lpsWinTitle,WinTitle,sizeof(lpsWinTitle)-1);
if (AVIType >0 &&AVIType< =8)
gi_AVIType=AVIType;
FormThread=new TFormThread(true);
FormThread- >Priority = tpNormal;
FormThread- >Resume();
}
__declspec(dllexport) int pascal
GetStatus(int ai_CloseWin){
if (gi_Canceled)
if (gi_WindowActive){
gi_RequestClose=1;
while(gi_RequestClose);
}
return gi_Canceled;
}
__declspec(dllexport) int pascal
CloseStatusWindow(){
if (gi_WindowActive){
gi_RequestClose=1;
while(gi_RequestClose);
}
return gi_Canceled;
}
  2.窗體StatusForm的代碼:
TStatusForm *StatusForm;
//-----------------------------------
extern int gi_Canceled;
extern int gi_AVIType;
extern TCommonAVI g_CommonAVI[];
__fastcall TStatusForm::
TStatusForm(HWND ParentWindow)
: TForm(ParentWindow)
{
gi_Canceled=0;
}
//-----------------------------------
//取消按鈕並不直接關閉窗體,
而指示設置取消標誌,供調用者查看
void __fastcall TStatusForm::
Button_CancelClick(TObject *Sender)
{
gi_Canceled=1;
// ModalResult=mrCancel;
}
//-----------------------------------
// 激活動畫,在FORMCREATE事件中
void __fastcall TStatusForm::
FormCreate(TObject *Sender)
{
Animate1- >CommonAVI=g_CommonAVI[gi_AVIType];
Animate1- >Active = true;
}
//-----------------------------------
extern int gi_RequestClose;
// 定時器事件檢測到結束標誌關閉窗體
void __fastcall TStatusForm::
Timer1Timer(TObject *Sender)
{
if (gi_RequestClose){
ModalResult=mrOk;
}
}
//-----------------------------------
  (5) 設置編譯選項:Project->Options打開ProjectOptions對話框,清除Linker屬性頁中的Use Dynamic RTL標誌,清除Packages屬性頁中的Build withruntime packages。這樣只要單個DLL就能夠運行了,而沒必要安裝一些動態鏈接運行時間庫。使用動畫DLL
  上面編譯出DLL能夠由其它任何開發語言調用,下面給出在PB中的使用方法。
  (1) 定義:
//Declare - > Global External Functions
FUNCTION Long ShowStatusWindow(Long
AVIType,String WinTitle,long hWnd) &
LIBRARY "STATWIN.DLL" ALIAS FOR "ShowStatusWindow"
FUNCTION Long GetCancelStatus(Long CloseWindow)&
LIBRARY "STATWIN.DLL" ALIAS FOR "GetStatus"
FUNCTION Long CloseStatusWindow() &
LIBRARY "STATWIN.DLL" ALIAS FOR "CloseStatusWindow"
  (2) 調用:
long ll_EndTime
//顯示查找文件夾動畫
ShowStatusWindow(2)
setpointer(HourGlass!)
ll_EndTime = Cpu() + 10 * 1000
DO
if GetCancelStatus(0)=1 then
exit
end if
// 作想作的事情
LOOP UNTIL cpu() > ll_EndTime
CloseStatusWindow()

用C++ Builder 3製做屏幕保護程序

  屏幕保護程序是以scr爲擴展名的標準Windows可執行程序,在激活控制面板的顯示器屬性的"屏幕保護程序"頁時,該模塊會自動在Windows啓動目錄(Windows目錄和系統目錄)下查找擴展名是scr的基於Windows的可執行文件。使用屏幕保護程序,不只能夠延長顯示器的使用壽命,還能夠保護私人信息。
  編制屏幕保護程序不只要涉及消息的處理,還要涉及命令行參數的處理。在WIN32SDK文檔中描述了編制基於WIN32的標準的屏幕保護程序所必須遵照的嚴格標準。按照這些標準,屏幕保護程序必需要輸出兩個函數:ScreenSaverProc和ScreenSaverConfigureDialog,可是,在Windows系統中的不少屏幕保護程序並無遵循這些標準(使用impdef或者tdump實用工具查看便可)。而且使用該文檔中介紹的方法編寫屏幕保護程序,不只要使用資源編輯器,而且在連接時還要利用Scrsaver.lib文件(在C++Builder3環境下,不能成功鏈接)。不只要涉及消息的處理,還要涉及命令行參數的處理。
  C++Builder3是一種快速的應用程序開發工具,提供了許多類型的應用程序開發模板,但沒有提供開發屏幕保護程序的模板,而且在其在線幫助中也沒有說起如何開發這類應用程序。通過本人的研究,找到了用C++Builder3編制屏幕保護程序的方法。
  在控制面板的"顯示器屬性"項的"屏幕保護程序"頁中進行設置時,要遇到三種類型的命令行參數,而且,各類狀況下的屏幕保護程序的顯示結果也各不相同,通常來說,就須要三種類型的窗體(或兩種,在隨後的內容中討論)。下面將分四步來具體地說明如何編制屏幕保護程序。
  1、屏幕保護程序的選擇
  若是在標題爲"屏幕保護程序"的下拉列表框中選中了某個保護程序時,系統會自動啓動該程序,這個程序的顯示範圍是在這個頁面上的顯示器圖形的屏幕範圍,同時,會將兩個命令行參數:一個是"/p";另外一個是顯示窗口的句柄,傳遞給這個被選中的程序。所以,這類程序首先應該可以處理命令行參數。在C++Builder3中,與命令行參數處理有關的函數是:ParamCount()和ParamStr(),具體的申明方式以下:
  1.externPACKAGEint__fastcallParamCount(void);
  該函數返回命令行參數的個數,但不包含應用程序自己。
  2.externPACKAGEAnsiString__fastcallParamStr(intIndex);
  該函數返回指定索引值的命令行參數。ParamStr(0)返回的是應用程序自己。
  因此,在這以步驟中的參數判斷的語句以下:
if(UpperCase(ParamStr(1))==
"-p"||UpperCase(ParamStr(i))=="/p")
{
//addthecodeinhere
}
  在完成了參數判斷後,就應該對顯示窗口的處理,爲可以使程序在顯示器圖形的屏幕區域內顯示,就要從新設置程序的父窗口和顯示區域。這要涉及到父窗口句柄的得到及父窗口的設置,以及API函數的調用。這種環境下的父窗口句柄就是傳遞過來的第二個命令行參數;要設置父窗口,只需設置窗體的ParentWindow屬性便可。這段程序以下:
RECTrc;//Line1
HWNDhWnd=(HWND)
(atol(ParamStr(2).c_str()));//Line2
::GetClientRect(hWnd,&rc);//Line3
ParentWindow=hWnd;//Line4
Left=rc.left;//Line5
Top=rc.top;//Line6
Width=rc.right-rc.left;//Line7
Height=rc.bottom-rc.top;//Line8
  在上面的程序片斷中,第2行語句是將傳遞過來的第2個參數轉換成窗口句柄;而後,第3行語句利用這個窗口句柄,調用API函數以得到該窗口的客戶區域;第4行語句將選中的屏幕保護程序的父窗口設置爲指定的窗口;餘下的語句是將該程序的窗口大小設置成副窗口的客戶區大小。這一程序片斷的位置應該是在窗體的OnCreate事件處理中。
  須要說明的是,這種類型(包括第三步介紹的窗體)的窗體樣式應是:
FormStyle=fsStayOnTop;
  窗體邊界的樣式應爲:
BorderStyle=bsNone;
固然,這時也不須要鼠標圖形,所以,能夠將鼠標的形狀設爲crNone:
Cursor=crNone;
  2、初始化參數的設置
單擊"顯示器屬性"模塊的"屏幕保護程序"頁面中的"設置"按鈕時,系統會啓動指定的保護程序的初始值設置對話框,這時傳遞過來的命令行參數是:"/c"或"-c"(參數的處理與前面介紹的相同)。經過該對話框,能夠設置保護程序的一些初始參數,好比圖形的變化快慢等。在這段程序中,還要涉及到初始化文件或註冊表的讀寫,用以記錄初始化參數,便於保護程序啓動時使用。
  3、預覽及運行
  預覽的效果就是屏幕保護程序被激活後的顯示。單擊單擊"顯示器屬性"模塊的"屏幕保護程序"頁面中的"預覽"按鈕,就能夠觀察保護程序運行的實際效果。這時,系統啓動該程序時傳遞過來的命令行參數是:"/s"或"-s"。對於命令行參數的處理與前面的步驟相同,但在這一步中,還要對幾個消息進行處理,這些消息是:WM_MOUSEMOVE,WM_LBUTTONDOWN,WM_MBUTTONDOWN,WM_RBUTTONDOWN,WM_KEYDOWN,WM_ACTIVATE。對WM_MOUSEMOVE和WM_ACTIVATE消息的處理形式以下:
void__fastcallHandleSomeMessage(TMessage&Msg)
{
switch(Msg.Msg)
{//......
caseWM_ACTIVATE:if(Msg.WParamLo==WA_INACTIVE)
Close();
break;
caseWM_MOUSEMOVE:if(OldMouseX==-1&&OldMouseY==-1)
//Intheconstructor,OldMouseXand
OldMouseYmustbeinitializedby-1.
{OldMouseX=Msg.LParamLo;
OldMouseY=Msg.LParamHi;
}
elseif(OldMouseX!=Msg.LParamLo
||OldMouse!=Msg.LParamHi)
Close();
break;
......
}
}
  對於其餘的消息僅僅是調用Close()函數來關閉應用程序便可。應用這種消息處理方式時,必需要類定義時進行消息映射,否則的話,就要在相應的消息響應中進行處理(使用必定的布爾變量,就能夠與第一步合用一個窗體)。
  與第一步相似,在該步驟中,也不須要具體的鼠標指針的形狀,所以,將鼠標指針設爲crNone:
Cursor=crNone;
  4、修改項目源文件
  在C++Builder3中,一個窗體也就是一個類,換句話說,具備某些特性的類也就是一個窗體,所以,編制屏幕保護程序時,也不須要什麼主窗體,同時,也不用自動建立某些窗體了,這時就要修改項目源文件,下面所列出的程序就是筆者在編制某屏幕保護程序時使用的項目源文件,供讀者參考。
WINAPIWinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
CreateMutex(NULL,true,"ScreenSaver");
if(GetLastError()!=ERROR_ALREADY_EXISTS)
{
try
{
Application->Initialize();
Application->Title="屏幕保護程序測試";
if(UpperCase(ParamStr(1))==
"/C"||UpperCase(ParamStr(1))=="-C"
||ParamCount()==0)
{TScrSaverConfiguerF*ScrCfg=
newTScrSaverConfiguerF(NULL);
ScrCfg->ShowModal();
deleteScrCfg;
return0;
}//單擊"設置"按鈕
elseif(UpperCase(ParamStr(1))==
"/P"||UpperCase(ParamStr(1))=="-P")
{TScrForP*ScrFP=newTScrForP(NULL);
ScrFP->ShowModal();
deleteScrFP;
return0;
}//在"屏幕保護程序"下拉列表框中選擇一個程序
elseif(UpperCase(ParamStr(1))==
"/S"||UpperCase(ParamStr(1))=="-S")
{TScreenSaveF*ScreenSave=newTScreenSaveF(NULL);
ScreenSave->ShowModal();
deleteScreenSave;
return0;
}//單擊"預覽"按鈕,及運行屏幕保護程序
else
return1;
}
catch(Exception&exception)
{
Application->ShowException(&exception);
}
}
return0;
}//theWinMainFunctionend
  前面介紹了在C++Builder3下編制屏幕保護程序的方法.對於C++Builder3這種RAD工具來說,開發這類程序也是至關方便的,按照前述的方法,能夠在極短的時間開發出屏幕保護程序。對於屏幕保護程序,在本文中沒有說明的就是如何設置口令的問題,這部分就由讀者本身摸索吧。


TCP/IP頭格式


1、先是經常使用的IP頭格式。
IP頭格式:
版本號 (4位)
IP頭長度 (4位)
服務類型 (8位)
數據包長度 (16位)
標識段 (16位)
標誌段 (16位)
生存時間 (8位)
傳輸協議 (8位)
頭校驗和 (16位)
發送地址 (16位)
目標地址 (16位)
選項
填充

簡單說明
============
1. IP頭長度計算所用單位爲32位字, 經常使用來計算數據開始偏移量
2. 數據包長度用字節表示, 包括頭的長度, 所以最大長度爲65535字節
3. 生存時間表示數據被丟失前保存在網絡上的時間, 以秒計.
4. 頭校驗和的算法爲取全部16位字的16位和的補碼.
5. 選項長度是可變的, 填充區域隨選項長度變化, 用於確保長度爲整字節的倍數.

描述
============
struct iphdr {
BYTE versionihl;
BYTE tos;
WORD tot_len;
WORD id;
WORD frag_off;
BYTE ttl;
BYTE protocol;
WORD check;
DWORD saddr;
DWORD daddr;

};

2、TCP頭格式
TCP頭格式:
源端口 (16位)
目的端口 (16位)
序號 (32位)
確認號 (32位)
數據偏移 (4位)
保留 (6位)
標誌 (6位)
窗口 (16位)
校驗和 (16位)
緊急指針 (16位)
選項
填充

簡單說明
============
1. 數據偏移用於標識數據段的開始
2. 保留段6位必須爲0
3. 標誌包括緊急標誌、確認標誌、入棧標誌、重置標誌、同步標誌等。
4. 校驗和計算方式爲將頭與16位二進制反碼和中的16位二進制反碼加在一塊兒。
5. 選項長度是可變的, 填充區域隨選項長度變化, 用於確保長度爲整字節的倍數.
6. 更詳細的說明請參閱有關資料。

描述
============
struct tcphdr {
WORD SourPort;
WORD DestPort;
DWORD SeqNo;
DWORD AckNo;
BYTE HLen;
BYTE Flag;
WORD Window;
WORD ChkSum;
WORD UrgPtr;

};

UDP


1、說明
使用UDP時,直接使用API代替控件。

第一個程序(ReadBufferUdp)使用來接收到緩存中。

"Destino"變量很是重要,若是你從其餘地方接收數據到Buffer,你必須設置Destino = 0而且在之後執行的時候賦值你將要發送的包的地址給它(after the execution it will have theaddress which send you the packet.)。
若是你只想從一個指定的地址接收數據,你必須設置變量Destino =

.

"gvEncerrar" 用來停止處理過程。(gvEncerrar被設置爲全局變量。)

超時時間設置。"Inicio + 12" = 12 sec of timeout.

第三個程序是用來準備WinSock程序。

2、代碼

int ReadBufferUdp(unsigned long *Destino,void *T,int Size)
{
char Buffer[128];
SOCKADDR_IN SockAddr;
int LenSockAddr=sizeof(SOCKADDR_IN);
fd_set FdRead;
struct timeval t_val;
int Ret;
time_t Inicio = time(NULL);

Application->ProcessMessages();
if(gvEncerrar)
return false;

FD_ZERO(&FdRead);
FD_SET(gvSocket,&FdRead);
t_val.tv_sec=0;
t_val.tv_usec=0;

while((Ret=select(0,&FdRead,NULL,NULL,&t_val))!=1&& (Inicio + 12)>
time(NULL) && !gvEncerrar)
{
FD_ZERO(&FdRead);
FD_SET(gvSocket,&FdRead);
t_val.tv_sec=0;
t_val.tv_usec=0;
Application->ProcessMessages();
}
if(Ret != 1)
return false;

if(recvfrom(gvSocket,Buffer,Size,0,(LPSOCKADDR)&SockAddr,&LenSockAddr)!=Size)

return false;

if(*Destino == 0)
{
*Destino = SockAddr.sin_addr.s_addr;
}
else
if(*Destino != SockAddr.sin_addr.s_addr)
return false;

memcpy(T,Buffer,Size);
return true;
}

int WriteBufferUdp(unsigned long Destino,void *T,int Size)
{
SOCKADDR_IN SockAddr;
int Sent;

Application->ProcessMessages();
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = gvPortUdp;
SockAddr.sin_addr.s_addr = Destino;
Sent = sendto(gvSocket,(char
*)T,Size,0,(LPSOCKADDR)&SockAddr,sizeof(SockAddr));
if(Sent != Size)
return false;
else
return true;
}

void InicializaTCPIP()
{

WORD wVersionRequested;
WSADATA wsaData;
IN_ADDR In;
PSERVENT PServent;
SOCKADDR_IN SockAddrIn;
wVersionRequested = MAKEWORD( 1, 1 );

if(WSAStartup( wVersionRequested, &wsaData))
{
ShowMessage("Erro na inicializao do TCP/IP");
Application->Terminate();
return;
}

// Get the port on service file
if((PServent=getservbyname("your_service_name","udp"))==NULL)
{
ShowMessage("Erro obtendo port do servi transurb/udp");
Application->Terminate();
return;
}
gvPortUdp = PServent->s_port;
sprintf(StrAux,"Servi transurb/udpport:%d",ntohs(gvPortUdp));
Log(StrAux);

// Open de Socket
if((gvSocket = socket(AF_INET,SOCK_DGRAM,0))==INVALID_SOCKET)
{
ShowMessage("Erro na criao do socket");
Application->Terminate();
return;
}
Log("Socket criado com sucesso");

// Do the bind
SockAddrIn.sin_family = AF_INET;
SockAddrIn.sin_port = gvPortUdp;
SockAddrIn.sin_addr.s_addr = NULL;

if(bind(gvSocket,(LPSOCKADDR)&SockAddrIn,sizeof(SockAddrIn))==SOCKET_ERROR)

{
ShowMessage("Erro no bind do socket");
Application->Terminate();
return;
}
Log("Bind do socket com sucesso");

}


判斷windows的Desktop及其它目錄


使用API函數SHGetSpecialFolder。shlobj.h裏有SHGetSpecialFolder的原型聲明。這個函數能夠幫咱們找到windows的Desktop目錄、啓動目錄、個人文檔目錄等。

SHGetSpecialFolder須要三個參數。第一個參數是HWND,它指定了"全部者窗口":在調用這個函數時可能出現的對話框或消息框。第二個參數是一個整數id,決定哪一個目錄是待查找目錄,它的取值多是:

CSIDL_BITBUCKET 回收站
CSIDL_CONTROLS 控制面板
CSIDL_DESKTOP Windows 桌面desktop
CSIDL_DESKTOPDIRECTORY desktop的目錄
CSIDL_DRIVES 個人電腦
CSIDL_FONTS 字體目錄
CSIDL_NETHOOD 網上鄰居
CSIDL_NETWORK 網上鄰居virtual folder
CSIDL_PERSONAL 個人文檔
CSIDL_PRINTERS 打印機
CSIDL_PROGRAMS 程序組
CSIDL_RECENT 大多數最近打開的文檔列一
CSIDL_SENDTO 「發送到」菜單項
CSIDL_STARTMENU 任務條啓動菜單項
CSIDL_STARTUP 啓動目錄
CSIDL_TEMPLATES 臨時文檔
最後一個參數是pidl地址。SHGetSpecialFolderLocation把地址寫到pidl。

下面的代碼演示了怎樣使用SHGetSpecialFolderLocation:

//----------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
LPITEMIDLIST pidl;
LPMALLOC pShellMalloc;
char szDir[MAX_PATH];

if(SUCCEEDED(SHGetMalloc(&pShellMalloc)))
{
if(SUCCEEDED(SHGetSpecialFolderLocation(NULL,
CSIDL_DESKTOPDIRECTORY,
&pidl)))
{
// 若是成功返回true
if(SHGetPathFromIDList(pidl, szDir))
{
Label1->Caption = szDir;
}

pShellMalloc->Free(pidl);
}

pShellMalloc->Release();
}
}
//----------------------------------------------------------------------
注意: 有些目錄是空的。有些特定的目錄在這個文件系統上並無一個相應的目錄。


取得本地internet機器的名字及IP地址

1、下面的例子使用 Winsock API 取得本地主機的名字及地址
void __fastcall TForm1::Button1Click(TObject *Sender)
{
hostent *p;
char s[128];
char *p2;

//Get the computer name
gethostname(s, 128);
p = gethostbyname(s);
Memo1->Lines->Add(p->h_name);

//Get the IpAddress
p2 = inet_ntoa(*((in_addr *)p->h_addr));
Memo1->Lines->Add(p2);
}

void __fastcall TForm1::FormCreate(TObject *Sender)
{
WORD wVersionRequested;
WSADATA wsaData;

//Start up WinSock
wVersionRequested = MAKEWORD(1, 1);
WSAStartup(wVersionRequested, &wsaData);
}

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
WSACleanup();
}

用C++Builder建立數字簽名


  若是你在網絡上傳遞一份數據,但卻存在着種種不安全的因素,使你對數據可否原封不動地到達目的地而心存疑惑,這時,你就能夠給數據加上數字簽名,從而使對方能夠經過驗證簽名來檢查你所傳過去的數據是否已被他人修改。

  1、程序原理

  數字簽名的工做原理仍是比較簡單的,它是根據你所提供的原始數據,通過複雜的算法,產生特定的數據簽名,對方經過一樣的過程也產生簽名,若是數據已被修改,那麼就不可能獲得兩份如出一轍的簽名,從而就可判斷數據已被他人修改。編程人員利用Windows的CAPI接口,就能夠實現數據的加密、解密和數字簽名。  

  2、程序清單

  下面用C++ Builder的語句來看一下它的具體實現過程。
  先來建立數字簽名,假定其數據來自於一個文件。
  //變量聲明:
  HCRYPTPROV hProv;
  // CSP的句柄
  HCRYPTHASH hHash;
  // 散列的句柄
  const int BUFFER=4096;
  // 緩衝區大小常數
  BYTE pBuffer[BUFFER];
  // 存放讀文件內容的緩衝區
  BYTE pSignature[256];
  // 存放簽名的緩衝區
  DWORD dSignatureLen=256;
  // 簽名的長度
  TFileStream *sourceFile;
  // 一個文件流
  if(!CryptAcquireContext(&hProv,NULL,NULL,PROV-RSA-FULL,0))
  // 鏈接默認的CSP,接受它的句柄放入hProv
  {
    // 錯誤處理
  }
  if(!CryptCreateHash(hProv,CALG-MD5,0,0,&hHash))
  // 建立一個散列對象,獲得它的句柄放入hHash
  {
    // 錯誤處理
  }
  do
  {
   dReadLen=sourceFile->Read(pBuffer,BUFFER);
   if(!CryptHashData(hHash,pBuffer,dReadLen,0))
  // 根據文件的內容計算散列值
   {
    // 錯誤處理
   }
  }while(!(dReadLen
  if(!CryptSignHash(hHash,AT-SIGNATURE,NULL,0,pSignature,&dSignatureLen))
  //使用私人密鑰對散列值進行數字簽名
  //簽名數據放入pSignature,長度放入dSignatureLen
  // 錯誤處理
  }
  對基於文件的數據簽名進行檢驗。
  //變量聲明:
  HCRYPTPROV hProv;
  // CSP的句柄
  HCRYPTHASH hHash;
  // 散列的句柄
  HCRYPTKEY hPublicKey;    
  // 公共密鑰的句柄
  const int BUFFER=4096;  
  // 緩衝區大小常數
  BYTE pBuffer[BUFFER];    
  // 存放讀文件內容的緩衝區
  TFileStream *sourceFile; // 一個文件流
  BYTE pSignature[256];    
  // 上一段獲得的簽名的緩衝區
  DWORD dSignatureLen;    
  // 上一段獲得的簽名的長度
  if(!CryptAcquireContext(&hProv,NULL,NULL,PROV-RSA-FULL,0))
  // 鏈接默認的CSP,接受它的句柄放入hProv
  {
    // 錯誤處理
  }
  if(!CryptGetUserKey(hProv,AT_SIGNATURE,&hPublicKey); //獲得公共密鑰的句柄
  {
    // 錯誤處理
  }
  if(!CryptCreateHash(hProv,CALG-MD5,0,0,&hHash)) //建立一個散列對象,獲得它的句柄放入hHash
  {
    // 錯誤處理
  }
  do
  {
   dReadLen=sourceFile->Read(pBuffer,BUFFER);
   if(!CryptHashData(hHash,pBuffer,dReadLen,0))
  // 根據文件的內容計算散列值
   {
    // 錯誤處理
   }
  }while(!(dReadLen
  if(!CryptVerifySignature(hHash,pSignature,dSignatureLen,hPublicKey,NULL,0))
  {
    if(GetLastError()==NTE-BAD-SIGNATURE)ShowMessage(″文件已被修改″);
  }
  else
  {
   ShowMessage(″文件沒被修改″);
  }

  以上是一個數字簽名的簡單實現,獲得的簽名數據能夠單獨保存,也能夠分開保存。

用Enter 鍵 控 制 焦 點 切 換 的 方 法

在Windows 環 境 下, 要 使 一 個 控 件 取 得 焦 點, 可 在 該 控 件 上 用 鼠 標 單 擊 一 下,或按Tab 鍵 將 焦 點 移 至 該 控 件 上。 這 種 控 制 焦 點 切 換 的 方 法 有 時 不 符 合 用 戶 的 習慣。就 圖 一 而 言, 用 戶 就 希 望 用Enter 鍵, 控 制 焦 點 由Edit1 切 換 到 Edit2。 要 實 現這 樣的 功 能 需 借 助WinAPI 函 數SendMessage 來 完 成。 方 法 是: 先 設Form1 的KeyPreview屬 性 爲true, 然 後 在Form1 的OnKeyPress 事 件 中 加 入 如 下 的 代 碼。這 樣, 用 戶 就 能夠 通 過 按Enter, 鍵 控 制 焦 點 按 定 義 好 的Taborder 順 序 來 移 動 了!
void __fastcall TForm1::FormKeyPress(TObject *Sender, char&Key)
{
if(Key==VK_RETURN)

{
SendMessage(this- >Handle,WM_NEXTDLGCTL,0,0);
Key=0;
}
}


攔 截 Windows 消 息


- --Borland C++ Builder的API後門

---- 引子

---- C++Builder不愧爲Borland公司的優秀產品,用它來開發Windows程序很是快捷高效,但在編程過程當中你也會發現它的一些限制性,讓你沒法實現本身的想法。好比你沒法在修改表單的系統菜單;好比使用跟蹤欄時,你找不到StartTrack和EndTrack事件,而恰恰你的程序須要這兩個事件。WindowsAPI編程中,你就不會有這些麻煩,只需處理一下WM_SYSCOMMAND和WM_HSCROLL(或WM_VSCROLL)消息,就能實現上述功能。WindowsAPI的缺點是編程十分麻煩,太多的時間要耗在細節上面,但它的功能倒是最強大的。C++Builder的VCL在功能上只是它的一個子集,由於VCL是在API的基礎上封裝的,封裝時捨棄了一些不經常使用到的功能。可是程序員的想象力沒有被封裝,他們總懷着更大的熱情去實現別出心裁的想法,修改系統菜單和給跟蹤欄增長StartTrack和ndTrack事件只是其中的小把戲而已。但是VCL並無這些功能,怎麼辦?

----幸虧,Borland公司沒有把路堵死,而是留了個後門--容許程序員本身攔截並處理Windows消息,就象API編程同樣。因而,辦法有了...

---- 方法

---- 攔截Windows消息須要如下幾步:
---- 在表單頭文件內(如Unit1.h)
---- 1. 在類聲明中創建消息映射表,把某條消息的處理權交給自定義的消息處理函數。

BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(Windows消息名,TMessage,消息處理函數名)
MESSAGE_HANDLER(...)
END_MESSAGE_MAP(TForm)


---- 2. 在類聲明的private區內聲明消息處理函數。

private: // User declarations
void __fastcall 消息處理函數名(TMessage &Message);
在表單文件內(如Unit1.cpp)


---- 3. 寫出消息處理函數,在這裏實現你須要的功能。好比
void __fastcall MainForm::OnWMHScroll (TMessage&Message)
{
... // 在此加入你本身的代碼
TForm::Dispatch(&Message);
}


---- 解釋

---- 1. 關於TMessage

---- TMessage是VCL預約義的結構,定義以下:
struct TMessage
{
unsigned int Msg; //消息
int WParam; //字參數
int LParam; //長字參數
int Result; //消息結果
};


---- 2. 關於TForm::Dispatch(&Message)

----自定義的消息處理函數末尾最好加一句TForm::Dispatch(&Message),這一句的做用是讓消息繼續傳遞下去。若是沒有這一句,消息將被徹底攔截,VCL類可能因爲得不到消息而沒法實現正常功能。

---- 實例一:修改系統菜單

---- 有一些程序,主窗口很小,菜單也沒有,若是想加入關於或設置對話框,最好的辦法是拿系統菜單開刀。WindowsAPI編程中,修改系統菜單與實現其餘功能同樣,不太容易,也不會太難。但在C++Builder中,表單類(TForm)沒有提供有關係統菜單的任何屬性與方法,實現其餘功能易如反掌,而修改系統菜單彷佛難於上青天。

---- 還好,Borland公司容許程序員自已處理Window消息,因而機會來了!

1、用Window API函數修改系統菜單

假定表單名爲MainForm,設置MainForm::OnCreate()函數:

1.用GetSystemMenu(MainForm->Handle,false)取得系統菜單句柄;

2.用AppendMenu,DeleteMenu,ModifyMenu函數修改系統菜單,把新的ID號賦於自定義的菜單項。
這時運行程序,能夠看到系統菜單也被修改,但自定義的菜單項卻不能被響應。

2、攔截WM_SYSCOMMAND消息以響應自定義的菜單項
在表單頭文件內(如Unit1.h)

1. 在表單類定義末尾加入消息響應表,取得WM_SYSCOMMAND消息的處理權
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_SYSCOMMAND,TMessage,OnWMSysCommand)
END_MESSAGE_MAP(TForm)

2. 在表單類定義的private區內加入消息處理函數聲明
private: // User declarations
void __fastcall OnWMSysCommand(TMessage&Message);

在表單文件內(如Unit1.h)

3. 寫出消息響應函數
void __fastcall TForm1::OnWMSysCommand(TMessage&Message)
{
if(Message.WParam==ID_SysMenu_MyItem)
{
// Your Code Here, Do Something
}
TForm::Dispatch(&Message);
}


3、完整程序示例

實例二:給跟蹤欄增長OnStartTrack和OnEndTrack事件

當跟蹤欄用於進度控制時,OnStartTrack和OnEndTrack極可能是你須要的事件。好比在控制多媒體播放進度的場合,當用戶移動滑塊時,你須要OnStartTrack事件讓播放中止,須要OnEndTrack事件定位新的播放位置。但Borland公司沒有提供這兩個事件,我等編程愛好者只好自力更生,打攔截Windows消息的主意了。

1、攔截WM_HSCROLL消息,給跟蹤欄增長OnStartTrack和OnEndTrack事件

在表單頭文件內(如Unit.h)

1. 在表單類定義末尾加入消息響應表,把WM_HSCROLL消息處理權交給OnWMHScroll函數。
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_HSCROLL,TMessage,OnWMHScroll)
END_MESSAGE_MAP(TForm)

2. 在表單類定義的private區內加入OnWMHScroll函數聲明。
private: // User declarations
void __fastcall OnWMHScroll(TMessage &Message);


3. 在表單類定義的private區內加入StartTrack和EndTrack函數聲明。
private: // User declarations
void __fastcall TrackBar1StartTrack(TObject *Sender);
void __fastcall TrackBar1EndTrack(TObject *Sender);

在表單文件內(如Unit.cpp)

4.寫出OnWMHScroll函數,使它能根據消息參數調用StartTrack和EndTrack函數,在實際意義上產生OnStartTrack和OnEndTrack事件。

5. 寫出StartTrack和EndTrack函數。

若是是垂直跟蹤欄,把上面的WM_HSCROLL改成WM_VSCROLL便可。

2、完整程序示例

尾聲

Borland C++Builder編程中,攔截Windows消息是一項高級編程技術,能讓你儘可能挖掘Windows的潛力,尤爲讓曾用API編程的程序員感到心慰。攔截Windows消息是API盡情發揮的舞臺,當VCL不能爲你作什麼時,請想起底層的API。

使用CommaText

有時須要一個方便的方法存放一個StringList,它只有簡單的一行。例如,當你想使用一個INI文件,如何向一個INI文件中寫入一行呢,使用CommaText就能完成這個工做。

這裏有個例子,功能是建立一個blah.ini文件,並寫入一個以下形式的值:

[My Section]
Memo1=(你在Memo1中輸入的文字)

1.在Form1上有兩個按鈕btnLoad and btnSave和一個Memo1

2.還要加入:
#include

3.定義變量:
const String iniFile="blah.ini",iniSection="MySection",iniValue="Memo1";

4.保存按鈕代碼:
void __fastcall TForm1::btnSaveClick(TObject *Sender)
{
TIniFile *ini=newIniFile(ExtractFilePath(Application->ExeName)+iniFile);
ini->WriteString(iniSection,iniValue,Memo1->Lines->CommaText);
delete ini;
}

5.裝載按鈕代碼:
void __fastcall TForm1::btnLoadClick(TObject *Sender)
{
TIniFile *ini=newTIniFile(ExtractFilePath(Application->ExeName)+iniFile);
Memo1->Lines->CommaText=ini->ReadString(iniSection,iniValue,"");
delete ini;
}

6.如下代碼支持加載後對內容進行排序,到實際存儲不變:
void __fastcall TForm1::btnSortLoadClick(TObject *Sender)
{
TStringList *sl=new TStringList;
TIniFile *ini=newTIniFile(ExtractFilePath(Application->ExeName)+iniFile);
sl->CommaText=ini->ReadString(iniSection,iniValue,"");
sl->Sort();
Memo1->Lines=sl;
delete ini;
delete sl;
}

程序開始時先顯示信息框

1、軟件進入主窗口前,先顯示一個信息框,告訴用戶一些有關該軟件的信息,好比軟件名稱,版本號等。該信息框在顯示1~2秒後自動消失。
1.創建New Application,這時系統自動生成一個Form1,這做爲主Form.

2.File->New Form 創建一個新Form爲Form2,這個做爲信息框。

3.在Form2上添加組件TTimer(System控件條上),用於設定信息框的顯示時間。
4.TTimer的事件OnTimer中加入:Form2->Close();

5.在WinMain()函數中加入:
Application->CreateForm(__classid(TForm2),&Form2);
Form2->ShowModal( ); //這句要本身加入
Application->Run();
而且要把Form2的頭文件Unit2.h包括到WinMain()所在的Project1.cpp中。

6.運行程序,將先顯示Form2,顯示時間由TTimer的Interval屬性決定,1000是一秒。

2、軟 件 封 面 的 實 現
現 代 軟 件 設 計 的 流 行 作 法 是, 在 程 序 運 行 完 成 初 始 化 之 前, 先 調 用 一 幅 畫 面 作爲封 面, 通 常 是1/4 屏 幕 大 小, 顯 示 一 下 軟 件 的 名 稱、 做 者、 版 本 等 信 息。 要 用C++Builder 實 現 這 樣 的 功 能, 方 法 很 簡 單:

① 自 定 義 一 窗 體 類 TSplashForm, 將 其 設 置 成" 透 明 窗 口", 即 BorderIcons下 的 所 有 選 項 均 置 成false, BorderStyle=bsNone,FormStyle=fsStayOnTop,Position=poScreenCenter;

② 在TSplashForm 窗 體 上 放 置 一TPanel( 相 當 於 圖 形 的 鏡 框);

③ 在TPanel 上 放 置 一TImage 控 件, 調 入 所 需 要 的 圖 形;

④ 對WinMain 函 數 稍 加 修 改, 加 入 如 下 所 示 代 碼 即 可。 需 要 指 出 的 是, 這 段 代碼通 過 函 數 FindWindow, 搜 索 內 存 中 是 否 有 窗 口 標 題 爲 "Demo" 應 用 程 序 存 在,若存 在, 則 退 出 程 序 的 運 行。 該 功 能 可 防 止 程 序 的 再 次 運 行。 在 某 些 場 合 這 樣 設計 是必 須 的。

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
if(FindWindow(NULL,"Demo")!=0)
{
Application- >MessageBox (" 程 序 已 經 運 行!"," 警
告",MB_ICONSTOP);
return 0;
}

TSplashForm *splash=new TSplashForm(Application);

splash- >Show();

splash- >Update();

Application- >Initialize();

Application- >CreateForm(__classid(TForm1),&Form1);

splash- >Close();

delete splash;

Application- >Run();

}

catch (Exception &exception)

{

Application->ShowException(&exception);

}

return 0;

}

怎樣獲取程序的命令行參數?


你能夠用下面的兩種不一樣的技巧來解決這個問題。

技巧1:首先,也許是最簡單的方法是調用VCLParaStr()函數。你可以使用ParamCount()函數來肯定到底有多少個命令行參數傳遞給了應用程序。

ParamStr須要一個整數參數而且返回一個AnsiString對象。若參數爲0,ParamStr將返回可執行文件的全稱路徑。若參數爲1,將返回程序名及第一個命令行參數。若參數爲2,將返回第二個參數,等等。

做爲一個實踐,開啓一個新的項目,在主窗口上放置5個Label,將下面的代碼添加到窗口的構造函數中:

Label1->Caption = ParamStr(0);
Label2->Caption = ParamStr(1);
Label3->Caption = ParamStr(2);
Label4->Caption = ParamStr(3);
Label5->Caption = ParamStr(4);
再運行程序。通常應能看到相似字符串:

E:/CBUILDER/PROJECTS/PROJECT1.EXE
若是沒傳遞參數到程序,那麼Label2到Label5是空字符串。關閉程序,從C++Builder菜單中選擇 Run |Parameters。輸入幾個參數(-debug -testing -param)再次運行程序。你將看到:

E:/CBUILDER/PROJECTS/PROJECT1.EXE
-debug
-testing
-param
提示: ParamStr 對目錄中的空格能智能判斷。爲證明這點,把生成的EXE文件拷貝到ProgramFiles目錄下再運行它,你將會看到ParamStr(0)返回全路徑,幷包含空格。

技巧2:第二個方法就是調用GetCommandLineAPI函數。GetCommandLine不須要參數,而且返回一個C風格的char*,包含所有的命令行參數。你將不得不分解字符串以取得相關參數。

Label5->Caption =AnsiString(GetCommandLine());
運行後,Label5將爲:

"E:/CBuilder/Projects/Project1.exe" -debug -testing -param


如何監視剪貼板

在Form1的.h的private加上:
void __fastcall ClipboardChanged(TMessage&Msg);

在Form1的.h的public加上:
BEGIN_MESSAGE_MAP
 MESSAGE_HANDLER(WM_DRAWCLIPBOARD,TMessage,ClipboardChanged)
END_MESSAGE_MAP(TForm)

在Form1的.cpp內加上:
void __fastcall TForm1::ClipboardChanged(TMessage&Msg)
{
 POINT MousePos;
 GetCursorPos(&MousePos);
 PopupMenu4->PopupComponent=Form1;
 PopupMenu4->Popup(MousePos.x,MousePos.y);//一有變化,就彈出一個菜單,複製,剪切或清除都能引起此函數
}

在Form1的.cpp內有一個ToolButton
void __fastcall TForm1::ToolButton9Click(TObject *Sender)
{
 static HWND LastHandle;
 static bool clip=false;
 if(clip==true)
 {
  ToolButton9->Down=false;
  ChangeClipboardChain(Form1->Handle,LastHandle);//結束監視
 }
 else
 {
  ToolButton9->Down=true;
  Clipboard()->Clear();
  Application->Minimize();
  LastHandle=SetClipboardViewer(Form1->Handle);//啓動監視
 }
 clip=!clip;
}


如何使用OnIdle事件

使用OnIdle事件隨時監視剪貼板內容以改變彈出菜單的可執行項。

在Form1的.h的private加上:
void __fastcall OnIdle(TObject* Sender,bool&Done);

在Form1的.cpp內加上:
void __fastcall TForm1::OnIdle(TObject*Sender,bool& Done)
{
 boolTextSelected=DBRichEdit1->SelLength>0;
 N17->Enabled=TextSelected;//剪切,複製,清除
 N18->Enabled=TextSelected;
 N20->Enabled=TextSelected;
 bool CBHasText=Clipboard()->HasFormat(CF_TEXT);//需加入#include
 N19->Enabled=CBHasText;//粘貼
 boolHasText=RichEdit1->Lines->Count>0;
 N21->Enabled=HasText;//全選
 bool HasChanged=RichEdit1->Modified;
 ToolButton2->Enabled=HasChanged;
 ToolButton4->Enabled=HasChanged;
}

在Form1的OnCreate內加上:
Application->OnIdle=OnIdle;


 
用C++Builder4.0編寫Win 95下的串行異步通訊程序

  ·串口操縱的基本方法·


  在Win32下,對串口的操做就如同對文件同樣打開或關閉,對串行數據的讀寫可在用戶定義的讀寫緩衝區中進行。具體使用的函數爲:

  首先用CreateFile()打開通訊串口,其中參數lpFileName指向串口邏輯名,如「COM1」或「COM2」等,參數dwDesiredAccess定義文件的讀寫權限,通常設爲GENERIC-READ|GENERIC-WRITE;參數dwShareMode定義資源共享方式,此處必須設爲0,爲獨佔方式;lpSecurityAttributes定義安全屬性,Win95下爲NULL;dwCreationDistribution定義文件建立方式;dwFlagsAndAttributes定義文件屬性和標記,應設爲FILE-FLAG-OVERLAPPED,表示異步通訊方式;hTemplateFile指向一個模板文件的句柄,在 Windows 95下爲NULL。

  而後用BuildCommDCB( )和SetCommState( )函數經過通訊設備控制塊DCB(DeviceControl Block)設置串口通訊參數(如波特率、中止位、數據位、校驗位等),其中BuildCommDCB()中的字符串參數lpDef定義同DOS命令中MODE的參數格式,關於DCB更具體的設置須要根據用戶對數據流定義、握手信號及通訊控制要求具體定義,參見有關Windows技術資料。用GetCommState()能夠獲得當前的DCB參數值。若是須要還可經過SetCommTimeouts()和GetCommTomeouts()從新設置讀寫的超時參數;讀寫緩衝區的設置使用SetupComm(),參數dwInQueue和dwOutQueue分別定義爲輸入和輸出緩衝區的大小。

  在串口初始化完畢後,還要創建與通訊有關的事件對象。通常使用CreateEvent()函數,它返回一事件句柄,其中參數lpEventAttributes指向安全屬性結構地址,在Win95(無安全屬性)中爲NULL;布爾參數bManualReset 定義事件重置方式,true表示手工重置,false表示自動重置(相關函數爲SetEvent()和ResetEvent());參數bInitialState定義事件初始狀態,true表示發信號,不然爲不發信號;lpName是爲多進程設置的事件名,對於單進程定義爲NULL。而後用SetCommMask()定義用戶程序可監視的通訊事件類別。

  以上設置完成後,用戶程序就能夠等待通訊事件的產生,通常調用函數WaitCommEvent()監視通訊事件,其中參數lpEvtMask指向產生事件的掩碼地址,用於判斷事件產生的性質,lpOverlapped指向重疊結構地址,可簡單定義爲NULL。對於串口事件的響應通常有四種方式:查詢、同步I/O、異步I/O和事件驅動I/O,須要根據用戶不一樣控制要求而定。查詢方式佔用較長的計算機時間,同步I/O方式直到讀取完指定的字節數或超時時才返回,容易形成線程阻塞,異步I/O用於後臺處理,事件驅動是由系統通知用戶程序發生的事件並進行串口操做。比較而言事件驅動I/O方式較靈活。

  當有通訊事件產生時,就可用函數ReadFile()和WriteFile()直接對串口緩衝區進行讀寫操做了。其中lpBuffer指向讀寫緩衝區,nNumberOfBytes爲要讀寫的字節數,lpNumberOfBytes爲實際讀寫的字節數,lpOverlapped指定同步或異步操做。通訊結束後,調用函數CloseHandle()將串口關閉。

  ·應用實例說明·


  使用以上的API函數,筆者給出了簡化後的串口初始化的實例。圖1爲使用C++ Builder組件生成的串口通訊基本參數設置的界面實例。

  HANDLE hcom; //定義句柄

  DCB dcb;

  OVERLAPPED e; //定義重疊結構

  void -fastcall TForm1::OkBtnClick(TObjectSender)

  {hcom=CreateFile("COM2",GENERIC-READ|GENERIC-WRITE,0,NULL,OPEN-EXISTING,
FILE-ATTRIBUTE-NORMAL|FILE-FLAG-OVERLAPPED,NULL); //打開通信口

   BuildCommDCB("9600,O,8,1",&dcb);

//第一個字符串參數實際使用時由圖1選擇後組合,這裏僅簡單說明其格式

   SetCommState(hcom,&dcb);

   SetupComm(hcom,512,512);//設置讀寫緩衝區

   e.hEvent=CreateEvent(NULL,false,false,NULL); //設置事件

   SetCommMask(hcom,EV-RXCHAR| EV-TXEMPTY); //設置事件掩碼

   OkBtn-〉Enabled=false;}

C++BUILDER非可視組件的消息處理技巧

  一個非可視的組件必須對Windows操做系統或用戶定義的消息做出響應。然而,因爲一個非可視組件沒有窗口,所以它也沒有窗口句柄,天然它也不能接收到消息,爲了解決這一問題,咱們的思路是建立一個隱藏的窗口,使非可視組件可以接收到消息。

  爲了給你的非可視組件建立一個隱藏的窗口,須要有如下:

  1.一個私有變量型(Private Variable)的HWnd來取得窗口句柄。

  2.一個用來捕捉窗口發送給組件的函數(a WndProc)。

  3.對AllcolateHwnd的調用使之建立窗口句柄並設置WndProc。

  爲了清楚的解釋上述思路和展現建立過程,下面咱們將以一個具體的實例來講明。

  首先咱們先建立一個新的組件,在C++Builder中,選擇FILE|NEW...雙擊組件圖標顯示一個新的組件對話框改變AncestorType爲Tcomponent和Class name爲TTest並設置完畢。

  而後,切換到新組件的頭文件,在類的私有部分(private section)加入如下聲明:

  HWnd FHandle;

   void-fastcall WndProc

(TMessage& Msg);

  第一行聲明瞭一個調用Fhandle的HWnd變量,這個變量將用於窗口建立後捕獲窗口句柄。第二行聲明瞭一個用於接收消息的WndProc函數。這個函數的聲明必須加以標識,以便限定它是一個WndProc,而後在類聲明Public(公有)部分構造如下聲明:

  Viod DoIt( );

  這個公有函數將被咱們用來測試組件,類聲明應以下:

  class PACKAGE TTest : public

TComponent

  {

   private:

   HWnd FHandle;

   void-fastcall WndProc

(TMessage& Msg);

   protected:

   public:

   -fastcall TTest

(TComponent* Owner);

   void DoIt( );

   -published:

  };

  如今切換到組件的代碼單元,將下面一行加入到單元的頂部(在函數上也許是不錯的地方)

  #define MY-Message.WM_USER+1

  這一行聲明瞭一個在DoIt函數被調用時,組件將發送給它本身的用戶自定義消息。此時咱們必須爲組件分配一個窗口句柄。這個句柄將提供一個隱藏的窗口使咱們能夠捕捉組件中的消息。找到組件構造代碼,加入下面代碼:

  -fastcall Test::Test

(TComponent* Owner)

: TComponent(Owner)

  {

  FHandle=AllocateHWnd

(WndProc);

  }

  好,重要的一步已完成,AllocateHWnd函數建立了一個隱藏窗口而且返回它的句柄,注意這裏咱們爲了使Windows知道哪裏發來了消息,傳遞WndProc的地址;

  如今咱們來建立WndProc的函數部分。在源文件中加入:

  void-fastcall TTest::WndProc

(TMessage& Msg)

  {

   if (Msg.Msg == MY_MESSAGE)

  MessageBox(0, ″Got here!″, ″Message″, 0);

   try {

   Dispatch(&Msg);

   }

   catch (...) {

   Application-〉HandleException(this);

   }

  }

  不管什麼時候Windows發送消息給組件,Windows都會調用這個函數。這部分代碼完成了兩件事。首先,它檢查被接收的消息是不是咱們用戶自定義的消息。若是是,一個消息框將被顯示,你能夠看到實際上咱們接收到的消息。其次,這段代碼傳送了系統(或VCL)處理過程當中的消息,try/catch塊用來保證,若是異常出現,它將成爲缺省風格下的句柄。

  歸納地說,WndProc函數在爲缺省句柄傳遞全部其餘消息,監控了全部客戶消息。如今咱們建立DoIt函數,完成咱們的組件,加入咱們建立DoIt函數,完成咱們的組件,加入代碼:

  void TTest::DoIt()

  {

  PostMessage(FHandle,

MY-MESSAGE, 0, 0);

  }  這個函數發送一個消息組件的窗口句柄(記住,這個窗口句柄是之前存入到Fhandle數據成品中的)。如今咱們已經完成了建立組件選擇,用SelectFile|ColseAll來保存咱們的工做測試組件。

  下一步將測試組件。若是你使用BCB3,那麼你必須把組件加入到「包」(Packege)中,而後用Componet|install(能夠使用DCLSTD35Packege來快速測試)。再選擇你剛存的TestBCB.Cpp,一旦你安裝完成組件後,它將出如今組件板上。雙擊按鈕,爲按鈕的OnClick事件建立如下代碼:

   Test1-〉 DoIt( );

  如今運行程序,當你點擊按鈕時,將看到一個消息框顯示「Got here".

  ListingA和B包含了頭文件和源代碼如下列出。

  總結:一個能夠響應Windows消息的非可視組件有許多用途。最顯而易見的就是用來封裝某些方面的WindowsAPI。例如:TAPI和WinSock發送消息給事件的指定用戶。若是你寫的組件封裝了一個這樣的API。你將須要捕捉Windows發送的消息。而在你的組件中加入隱藏窗口將很好的幫你作到這一點。

  以上程序在C++ BUILDER 3.0中調試經過。

用C++Builder 創建數據庫VCL使用經驗

  隨着數據庫的普遍應用,數據庫編程已經成爲程序設計中發展迅猛的一支。C++Builder在數據庫開發方面具備的強大功能是無可比擬的,你甚至能夠不寫一行程序就生成漂亮的數據庫程序。

  下面對C++Builder中的幾個數據庫VCL的使用技巧作一下介紹:

  1、DBGrid控件

  1.設置DBGrid的字段顯示寬度屬性

  爲了在DBGrid中創建較小的列,你必須創建一個顯示標題,它等於或小於字段值。例如,你但願創建一個只有三個字符寬的列,你的列標題顯示必須只有三個字符或更少。

  2.改變DBGrid的顯示字段及日期顯示格式

  (1)雙擊DBGrid對應的Table1,進入字段編輯器。

  (2)點右鍵出現選單選「Add Fields…",出現添加字段對話框,選擇要添加的字段(該字段將在運行時由DBGrid顯示)而後點OK按鈕。

  (3)假設添加了「日期」字段,點該字段,在屬性表中的:DisplayLabel中填入你但願DBGrid顯示的字段名。若是原來字段名是英文的,這裏用中文名後DBGrid將顯示中文名。在DisplayFormat中填入:yyyy-mm-dd,之後日期將按1999-05-28格式顯示。

  2、Tquery控件

  Tquery控件是數據庫編程中很是重要的一個控件,它負責經過BDE與數據庫創建聯繫,經過SQL語句方便的創建查詢。Query必須創建相應的SQL才能生效。

  Tquery的參數設置以下:

  (1)在SQL屬性中:Select * from 表名 where 字段名=:變量名

  跟在「 : "後面的是變量。這樣寫後,在參數屬性中就能夠修改該變量的數據類型等。

  (2)對變量的賦值:

   Query1-〉Active=false;

   Query1-〉Params-〉Items[0]-〉AsString=Edit1-〉Text;

   Query1-〉Active=true;//查找符合變量的記錄

  (3)用DBGrid顯示結果

  DBGrid的DataSource與DataSource1鏈接,而DataSource1的DataSet與Tquery1鏈接。

  3、應用示例

  經過Query控件嵌入SQL語句創建的查詢比Table更簡單、更高效。

  用一個簡單的代碼來講明如何創建查詢程序:

  例如,要創建一個檢索表1中書名爲book1的程序則在表單上放置DBGrid,DataSource,Query三個控件加入如下代碼:

  DBGrid1-〉DataSource=DataSource1;

  DataSource1-〉DataSet=Tqery1;

  Query1-〉Close();

  Query1-〉SQL-〉Clear();

  Query1-〉SQL-〉Add(″Select * From 表 Where (書名=′book1′ ″);

  Query1-〉ExecSQL();

  Query-〉Active=true;

  你就能夠在生成的表格中看到全部名稱爲book1的記錄。

用C++ Builder建立基於Internet的點對點Chat

---- 建立基於Internet的應用程序,你也許會想到複雜的WinSock編程。不過,C++Builder3提供了新的WebBroker的Internet套件,其中的TClientSocket和TServerSocket組件封裝了Windows的有關API,大大簡化了WinSock編程。要經過Internet傳輸數據,至少須要一對Socket,一個Socket在客戶端,另外一個Socket在服務器端。其實TClientSocket、TServerSocket組件並非Socket對象,其屬性Socket將返回各自的Socket對象。TClientSocket用來處理客戶端到服務器端之間的socket鏈接,TServerSocket用來處理由客戶端發來的socket鏈接,一旦客戶端和服務器端都接通了socket,客戶端和服務器端就能夠相互通訊了。

---- 創建一新項目,建立應用程序的用戶界面:

----1.將組件頁切換到Internet頁,放一個TServerSocket組件和一個TClientSocket組件到窗體上,這樣應用程序既能夠是TCP/IP服務器,也能夠是TCP/IP客戶。將Port屬性都設爲同一個值(如1000),肯定Socket之間的鏈接類型爲NonBlocking(非阻塞方式)。

---- 2.放兩個TMemo組件到窗體上,用來分別顯示雙方的談話內容,將Memo2的ReadOnly屬性設爲True。

----3.在窗體的頂部放上一個Panel組件,在其上放三個按鈕:監聽(btnlisten)、鏈接(btnconnect)、斷開(btndisconnect),用來啓動相應的操做。

----4.在窗體底部放一個StatusBar組件,將其SimplePanel屬性設爲True,在相應的事件處理程序中改變狀態條信息,讓用戶隨時瞭解鏈接狀態。

---- 打開頭文件,在窗體類的Private段添加兩個私有成員: bool IsServer;StringServer。雙方通訊時需同時運行Chat程序,IsServer用來肯定哪一個Chat程序處於服務器端,Server用來存放服務器的主機名。創建窗體類的構造器以下:

__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
IsServer=false;
Server="localhost";
}


----這裏Server被缺省設爲localhost,這樣程序能夠在沒有連入Internet的單機上進行調試。在Windows子目錄下你能夠找到hosts.sam文件中,在該文件中已經將本機IP地址127.0.0.1定義了主機名:localhost。
void __fastcall TForm1::FormCreate(TObject *Sender)
{
btndisconnect- >Enabled=false;
}

----程序運行後,若是用戶按下"監聽"鈕,則將該程序設爲服務器端,這時應將TServerSocket的Active屬性設爲True,使服務器自動進入監聽狀態。
void __fastcall TForm1::btnlistenClick(TObject *Sender)
{
ClientSocket1- >Active=false;
ServerSocket1- >Active=true;
StatusBar1- >SimpleText="正在監聽...";
btnlisten- >Enabled=false;
btnconnect- >Enabled=false;
}

---- 當用戶按下"鏈接"鈕後,程序會彈出一個詢問框,要求用戶輸入要鏈接的服務器的主機名,而後創建鏈接。
void __fastcall TForm1::btnconnectClick(TObject *Sender)
{
if(InputQuery("鏈接到服務器","輸入服務器地址:",Server)){
if(Server.Length() >0){
ClientSocket1- >Host=Server;
ClientSocket1- >Active=true;
btnlisten- >Enabled=false;
btnconnect- >Enabled=false;
btndisconnect- >Enabled=true;
}
}
}


----當用戶提出鏈接請求後,客戶端會觸發OnCreate事件,程序先在狀態條中顯示鏈接信息,而後將顯示對方談話內容的Memo2清空,準備開始交談。
void __fastcall TForm1::ClientSocket1Connect(TObject *Sender,
TCustomWinSocket *Socket)
{
StatusBar1- >SimpleText="鏈接到:"+Server;
Memo2- >Lines- >Clear();
}


----在服務器接受了客戶的請求後會觸發OnAccept事件,在這個事件處理程序中將標誌服務器端的變量IsServer設爲True,並準備開始交談。
void __fastcall TForm1::ServerSocket1Accept(
TObject *Sender,
TCustomWinSocket *Socket)
{
Memo2- >Lines- >Clear();
IsServer=true;
StatusBar1- >SimpleText="鏈接到:"
+Socket- >RemoteAddress;
}


----在創建鏈接後,雙方就能夠在Memo1中輸入談話內容開始進行交談了,按下Enter鍵後,將所在行的文本發送出去。服務器端的Socket的Connections屬性返回一個數組,該數組由服務器當前活動的鏈接組成。
void __fastcall TForm1::Memo1KeyDown(
TObject *Sender, WORD &Key,
TShiftState Shift)
{
if(Key==VK_RETURN){
if(IsServer)
ServerSocket1- >Socket->Connections[0]- >SendText(
Memo1- >Lines- >Strings[Memo1->Lines- >Count-1]);
else
ClientSocket1- >Socket->SendText(
Memo1- >Lines- >Strings[Memo1->Lines- >Count-1]);
}
}


----在本例中咱們採用非阻塞傳輸方式,當其中的一方進行寫操做時,另外一方會觸發OnRead事件(客戶端)或OnClientRead事件(服務器端&
----在本例中咱們採用非阻塞傳輸方式,當其中的一方進行寫操做時,另外一方會觸發OnRead事件(客戶端)或OnClientRead事件(服務器端),這兩個事件的處理程序只是將接收到的內容添加到Memo2的後面。
Memo2- >Lines- >Add(Socket->ReceiveText());

----若是在用戶創建鏈接後單擊"斷開"鈕,將斷開客戶端與服務器的鏈接,服務器端將觸發OnClientDisconnect事件,而客戶端則會觸發OnDisconnect事件,這時服務器端應回到監聽狀態,等待用戶的鏈接;而客戶端將返回到鏈接前的狀態,等待用戶再次創建鏈接,若是有不止一個服務器的話,能夠選擇鏈接到其餘的服務器上。
void __fastcall TForm1::btndisconnectClick(
TObject *Sender)
{
ClientSocket1- >Close();
}
void __fastcall TForm1::ServerSocket1ClientDisconnect(
TObject *Sender,
TCustomWinSocket *Socket)
{
StatusBar1- >SimpleText="正在監聽...";
}
void __fastcall TForm1::ClientSocket1Disconnect(
TObject *Sender, TCustomWinSocket *Socket)
{
btnlisten- >Enabled=true;
btnconnect- >Enabled=true;
btndisconnect- >Enabled=false;
StatusBar1- >SimpleText="";
}


---- 此外在客戶端還應該增長錯誤捕獲機制,當用戶輸入無效的服務器名或服務器端沒有處於監聽狀態時可以及時給用戶反饋信息。
void __fastcall TForm1::ClientSocke
t1Error(TObject *Sender,
TCustomWinSocket *Socket,
TErrorEvent ErrorEvent, int &ErrorCode)
{
StatusBar1- >SimpleText="沒法鏈接到:
"+Socket- >RemoteHost;
ErrorCode=0;
}

用C++Builder獲取應用程序圖標

如今,網上有大量的有關圖標的共享軟件或免費軟件,並且不少也很好用,也方便。可是那畢竟是別人的,用起來總有些哪一個,何況本身又喜歡編程,何不本身動手呢!說幹就幹,並且手頭上有可視化編成的利器――C++Builder4.0,想來應該是很簡單的一件事。

首先啓動C++Builder,新建一工程,在窗體上放置一個Button控件,一個Image控件,和一個OpenDialog控件,它們的名稱均沒必要改動。雙擊Button控件,寫以下代碼:if(OpenDialog1->Execute())

{

FileName = OpenDialog1->FileName;

HICON hIcon;

// Total =(int) ExtractIcon( Form1->Handle,FileName.c_str(), -1);

 

Icon = new TIcon();

hIcon = ExtractIcon( Form1->Handle,FileName.c_str(), 0);

Icon->Handle=hIcon;

 

Icon->SaveToFile(TempFile);

Image1->Picture->LoadFromFile(TempFile);

}

其中:FileName,TempFile,Icon在其頭文件中定義:AnsiString  TempFile, FileName; Ticon *Icon;

這樣,你所選定的程序的第一個圖標就在Image控件中顯示了出來。本程序所用的是Windows APIExtractIcon來獲取圖表的,所以它只能獲取可執行文件的圖標,若是想獲取任意文件的圖標,那末你能夠調用Windows API的SHGetFileInfo函數來完成,SHGetFileInfo所能完成的任務有不少,具體用法可參見Win32的幫助文件。


BIG5到GB的轉換技術

中文由於數量太多,因此與英文用ASCII碼一個字節表示不一樣,它使用兩個字節來表示。經過計算這兩個字節,咱們能夠獲得其表示的漢字在中文字庫中的位置。讀取該位置的若干字節,以得到表示這個漢字的點陣信息。有了這些信息,就能夠分別在DOS或WINDOWS中顯示該漢字。事實上,在文本文件中保存的就是每一個漢字對應的兩個字節編碼,而顯示問題由中文操做系統自動解決。
漢字編碼並不統一,咱們使用的是GB碼,而臺灣地區使用的是BIG5碼。BIG5碼文件中保存的是漢字相應的BIG5編碼,GB碼文件中保存的是漢字相應的GB編碼(這也就是「亂碼現象」的來由)。因此轉換工做的關鍵是有一個記錄每一個BIG5編碼對應GB編碼的碼錶文件。
第一步 製做碼錶文件
BIG5碼編碼規則是這樣的:每一個漢字由兩個字節構成,第一個字節的範圍從0X81-0XFE,共126種。第二個字節的範圍分別爲0X40-0X7E,0XA1-0XFE,共157種。也就是說,利用這兩個字節共可定義出126 *157=19782種漢字。這些漢字的一部分是咱們經常使用到的,如1、丁,這些字咱們稱爲經常使用字,其BIG5碼的範圍爲0XA440-0XC671,共5401個。較不經常使用的字,如濫、調,咱們稱爲次經常使用字,範圍爲0XC940-0XF9FE,共7652個,剩下的即是一些特殊字符。
製做碼錶文件的原理是這樣的:首先將全部的BIG5編碼寫入一個文件,而後,使用具備BIG5碼到GB碼轉換功能的軟件,如地球村、東方快車、四通利方,將文件轉換爲GB碼文件,即獲得碼錶文件。
下面的源程序將全部可能的BIG5編碼(0XA100-0XFEFF)寫入文件「Table.TXT」。
//TURBO C++ 3.0
#include
#include
void main(){
FILE * codefile;
int i,j,k;
codefile=fopen("table.txt","w+b");
for (i=0xa1;i<=0xfe;I++){
for(j=0x00;j<=0xff;j++){
fwrite(& i,1,1,codefile);
fwrite(& j,1,1,codefile);}
}
fclose(codefile);
return;
}
運行地球村、東方快車或四通利方,將「Table.txt」從BIG5碼轉換爲GB碼,即得到碼錶文件。
第二步 轉換
下面的源程序,將BIG5碼文件轉換爲GB碼文件。
//TURBO C++3.0
#include
#include
void main(){
int que, wei;
FILE * sourcefile;
FILE * tabfile;
FILE * destfile;
sourcefile = fopen("big.txt', "r+b");
//BIG5 碼文件
tabfile = fopen("table.txt", 'r+b");
//碼錶文件
destfile = fopen("gb.txt","w+b");
//轉換生成的GB碼文件
while (!feof(sourcefile)){
fread(& que,1,1,sourcefile);
if (feof(sourcefile)){
break; }
if (que> =0xa1 &&que <=0xfe)
//叛斷是否漢字(BIG5編碼)
{fread(& wei,1,1,sourcefile);
if (wei<0xa1) wei = wei - 0x40;
if (wei>=0xa1) wei = wei - 0xa1 + 0x7e - 0x40 +1;
fseek(tabfile, 2 * ((que -0xa1) * (0xfe - 0xa1 + 1 + 0x7e - 0x40 +1 ) + wei), SEEK_SET);
fread(& que,1,1,tabfile);
fread(& wei,1,1,tabfile);
fwrite(& que,1,1,destfile);
fwrite(& wei,1,1,destfile);
}
else
fwrite(& que,1,1,destfile); //處理英文
}
fclose(sourcefile);
fclose(tabfile);
fclose(destfile);
return;
}
以上程序在Win95/97,TC3.0經過。稍加修改,也可用於VC或VB程序中。用一樣的方法,咱們也能夠將GB碼轉換爲BIG5碼。

C++BUILDER讓你的任務欄圖標動起來

----在windows環境下上網時,你有沒有注意到在屏幕的右下腳的任務欄上有一個動畫圖標呢?它一閃一閃的,形象的表示出網絡此時正在傳輸數據。關於任務欄圖標編程的文章有很多,但是如何才能編制出動態圖標呢?在C++Builder中能夠比較方便的實現。

----其基本編程思路是:經過設置Timer時鐘控件使應用程序在規定的時間間隔內發送特定的消息,使任務欄圖標不斷更改,從而造成動畫效果。實現方法爲在應用程序的表單中加載幾個Image控件,使他們裝載相應的圖畫,幾幅圖畫按順序連續的被顯示,就造成了動畫。

----在這裏,咱們用一個門的開關動畫來作例子,在表單上放置一個Timer控件,兩個Image,分別裝載「開門」和「關門」兩幅圖。開始加入代碼。

----應用程序必須用發送消息的辦法通知任務欄增長,刪除,和修改圖標。發送消息必須調用Shell_NotifyIcon。它的原形爲:

WINSHELLAPI BOLL WINAPI Shell_NotifyIcon(
DWORD dwMessage, POINTIFYCONDATA pnid);

第一個參數 dwMessage是發送消息的標誌,能夠選
NIM_ADD // 往任務欄通知區添加圖標
NIM_DELETE //往任務欄通知區刪除圖標
NIM_MODIFY //通知任務欄通知區修改圖標

編制消息發送函數TrayMessage
bool __fastcall TForm1::TrayMessage(DWORD dwMessage)
{
NOTIFYICONDATA tnd;
PSTR pszTip;
pszTip = TipText();
tnd.cbSize= sizeof(NOTIFYICONDATA);
//結構的大小
tnd.uCallbackMessage = MYWM_NOTIFY;
//自定義回調消息,在頭文件中聲明
tnd.hWnd= Handle;
//接受回調消息的窗口句柄
tnd.uID = IDC_MYICON;
//圖標標誌號
tnd.uFlags= NIF_MESSAGE | NIF_ICON | NIF_TIP;
//指定如下三個參數哪一個包含有效數據
if (dwMessage == NIM_MODIFY)
{
tnd.hIcon =
(HICON)IconHandle(); //取得圖標句柄
if (pszTip)
lstrcpyn(tnd.szTip, pszTip,
sizeof(tnd.szTip));
else
tnd.szTip[0] = '/0';
}
else
{
tnd.hIcon = NULL;
tnd.szTip[0] = '/0';
}
return (Shell_NotifyIcon(dwMessage, &tnd));
}
編制取得圖標句柄的函數
HICON __fastcall TForm1::IconHandle(void)
{
if (n==1)
{ return (Image1- >Picture->Icon->Handle);
//n是全局變量,1爲顯示Image1,0爲Image2
}
else
{ return (Image2- >Picture- >Icon->Handle);
}
}
編制圖標狀態轉換函數

void __fastcall TForm1::ToggleState(void)
{
if (n==1) //n爲圖標句柄鎖,是全局變量,
1爲顯示Image1,0爲Image2
{
n=n-1;
}
else
{
n=n+1;
}
TrayMessage(NIM_MODIFY);
//發送圖標變換消息
}


對Timer控件編制代碼,設它的Interval
屬性爲1000,即定時器每一秒響應一次。爲 Ontimer
事件鍵入代碼:

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{ ToggleState( );
}

----因爲篇幅有限,以上只列出了基本部分的代碼,其餘功能的實現,如關閉程序,打開窗口等,比較簡單,不在贅述。程序運行時,你將看到在屏幕的右下角任務欄有一扇門打開又關閉的動畫圖標。是否是頗有趣,快編一個你喜歡的吧。

TFORM


1、讓窗口老是在最前面
Form 的FormStyle屬性設置爲fsStayOnTop值。

2、 動 態 調 用 窗 體Form
在 缺 省 情 況 下, 由File/New Form 生 成 添 加 入 項 目 文 件 中 的 窗 體 都 具 有"AutoCreate"( 自動 創 建) 的 特 性。 即 只 要 程 序 運 行, 該 窗 體 就 存 在 於 內 存中 了, 不 管 當前它 是 否 被 調 用。 具 有 這 種 特 性 的 窗 體 一 般適 用 於 窗 體 屬 性 比 較 固 定、 經 常 被 調用 的情 況。 其 優勢 是 速 度 快, 缺 點 是 佔 用 內 存。 在 實 際 程 序 設 計 中, 會 碰見 大 量 類 似對 話框 功 能 的 窗 體, 它 們 用 於 顯 示 狀 態 或 輸入 信 息, 僅 須 在 程 序 中 調 用 一 下, 完 成其 功能 就 行 了, 無需 常 駐 內 存。 這 時 可 以 通 過 選擇Project/Options/Forms,將"Auto--Create forms " 欄 中 相 應 的 窗 體,如Form1, 用" >" 鍵 移 動 到 "Available forms" 欄 中, 並 在 程 序需 調 用 該 窗 體 處, 加 入 下 列 語 句:

TForm1 *myform=new TForm1(this);

myform- >ShowModal();

delete myform;

窗 體Form1 僅 是 在 須要 調 用 時 才 調 入 內 存,調 用 完 成 後, 即 用delete 清 除 出內存。這 樣 可 減 少 程 序 對 內 存 資 源 的 佔 用。

3、遍 歷 窗 體 控 件 的 方 法
要 訪 問 或 修 改 窗 體 上的 控 件, 方 法 很 簡 單, 以TEdit 爲 例 子:

Edit1- >Text="";

Edit2- >Text="";

但 如 果 窗 體 上 有 十 來個 像Edit1 這 樣 的 控 件, 需 要 進 行 相 同 的 初 始 化, 用 上面的方 法 一 個 一 個 地 進 行, 豈 不 麻 煩 ! 所 以 有 必 要 掌 握 遍 歷窗 體 控 件 的 方 法。 在 介紹該 方 法 之 前, 讓 我 們 先了 解 一 下 窗 體Form 的Components 和Controls 屬 性。 參 見表一。
表 一

屬性 類型 說明

ComponentCount Int 目前Form上各種
控件的總數

Components TCompont* 目前Form上指向
全部控件的數組

目前Form上指向
全部控件的數組
ControlCount
Int
目前Form上某一子
區域上各種控件的總數
Controls TControl*

目前Form上指向某一子
區域上全部控件的數組


以 圖 一 爲 例(圖 略) 說 明,Form1 的ComponentCount=6, 而Panel1的ControlCount=4.,

其 中: 數 組 對象

Components[0] Panel1

Components[1] Label1

Components[2] Edit1

Components[3] Label2

Components[4] Edit2

Components[5] Button1


數 組 對 象

Controls[0] Label1

Controls[1] Edit1

Controls[2] Label2

Controls[3] Edit2


下 面 這 段 代 碼 完 成 了 對Panel1 上 所 有TEdit 控 件 的 遍 歷 初 始 化。 讀 者 稍 加 修 改,便可 對 其它 控 件 進 行 遍 歷。 這 裏 有 一 個 小 技 巧, 我 們 把 需 要 進 行 初始 化 的 控 件 放 置在了 一Panel1 上, 與 不 需 要 初 始 化 的 控 件區 分 開 來, 這 樣 便 於 編 程。
AnsiString namestring="TEdit";
for(int i=1;i< Panel1- >ControlCount;i++)
{
if(Panel1- > Controls[i]- >ClassNameIs(namestring))

{

TEdit *p=dynamic_cast < TEdit* >(Panel1- >Controls[i]);

P- >Text="";

}
}

4、不規則窗口

1.在窗口定義中,加入HRGN hWndRgn;
2.在TForm::OnCreate()消息函數最後,加入下面的代碼:
hWndRgn=::CreateEllipticRgn(0,0,Width,Height);
::SetWindowRgn(hWndRgn,TRUE);
3.設置TForm的屬性爲無標題,無邊框。
4.編譯鏈接應用程序,就能夠看到一個橢圓形窗口。

5、MDI Form

1.Application->CreateForm(__classid(Tjjcginput),&jjcginput);

後不用在使用顯示Form的語句就能夠顯示出來了。

2.form 的onclose 事件必須用下面語句釋放空間:
void __fastcall TMDIChild::FormClose(TObject *Sender, TCloseAction&Action)
{
Action = caFree;
}

用BCB在windows桌面建立快捷方式

API提供了一個叫作IShellLink的COM接口容許咱們建立快捷方式。爲在桌面建立快捷方式,咱們建立一個IShellLink對象,設置它的屬性,而後把這個link保存到desktop目錄。

下面的例子代碼演示了怎樣建立一個快捷方式。在這個例子裏,這個快捷方式保存在C:/Drive目錄下。

//----------------------------------------------------------------------
include

void __fastcall TForm1::Button1Click(TObject *Sender)
{
if(OpenDialog1->Execute())
CreateShortCut(OpenDialog1->FileName);
}
//----------------------------------------------------------------------
void TForm1::CreateShortCut(const AnsiString&file)
{
IShellLink* pLink;
IPersistFile* pPersistFile;
if(SUCCEEDED(CoInitialize(NULL)))
{
if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink, (void **) &pLink)))
{
pLink->SetPath(file.c_str());
pLink->SetDescription("Woo hoo, look at Homer'sshortcut");
pLink->SetShowCmd(SW_SHOW);
if(SUCCEEDED(pLink->QueryInterface(IID_IPersistFile,
(void **)&pPersistFile)))
{
WideString strShortCutLocation("C://bcbshortcut.lnk");
pPersistFile->Save(strShortCutLocation.c_bstr(),TRUE);
pPersistFile->Release();
}
pLink->Release();
}

CoUninitialize();
}
}
//----------------------------------------------------------------------
上面的例子只是把快捷方式文件保存到了c:/drive目錄下,但沒保存到desktop目錄下。

要讓快捷方式出如今桌面上,只須把快捷方式文件保存到desktop目錄下。首先咱們要找到windows的desktop目錄,請參閱判斷windows的Desktop及相關目錄這一節。一旦咱們知道了desktop所在的目錄,咱們就能將快捷方式文件保存到desktop目錄下。而後windows就能將快捷方式圖標顯示到桌面上。下面是通過改進了的例子:

//----------------------------------------------------------------------
void TForm1::CreateShortCut(const AnsiString&file)
{
IShellLink* pLink;
IPersistFile* pPersistFile;
LPMALLOC ShellMalloc;
LPITEMIDLIST DesktopPidl;
char DesktopDir[MAX_PATH];

if(FAILED(SHGetMalloc(&ShellMalloc)))
return;

if(FAILED(SHGetSpecialFolderLocation(NULL,
CSIDL_DESKTOPDIRECTORY,
&DesktopPidl)))
return;

if(!SHGetPathFromIDList(DesktopPidl, DesktopDir))
{
ShellMalloc->Free(DesktopPidl);
ShellMalloc->Release();
return;
}

ShellMalloc->Free(DesktopPidl);
ShellMalloc->Release();

if(SUCCEEDED(CoInitialize(NULL)))
{
if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink, (void **) &pLink)))
{
pLink->SetPath(file.c_str());
pLink->SetDescription("Woo hoo, look at Homer'sshortcut");
pLink->SetShowCmd(SW_SHOW);

if(SUCCEEDED(pLink->QueryInterface(IID_IPersistFile,
(void **)&pPersistFile)))
{

WideString strShortCutLocation(DesktopDir);
strShortCutLocation += "//bcbshortcut.lnk";
pPersistFile->Save(strShortCutLocation.c_bstr(),TRUE);
pPersistFile->Release();
}
pLink->Release();
}
CoUninitialize();
}
}
//----------------------------------------------------------------------
不要陷於COM的泥沼之中
建立快捷方式包括一些對COM的使用。不要讓你陷入到COM的複雜之中。COM只是建立和使用對象的一種方法。在這個例子裏咱們能夠考慮不使用COM而是用等價的C++技術。

COM code C++ psuedo-equivalent
IShellLink* pLink; TShellLink *Link;
IPersistFile* pPersistFile; TPersistFile *PersistFile;

CoInitialize();


CoCreateInstance(CLSID_ShellLink, Link = new TShellLink;
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink,
(void **) &pLink)


pLink->SetPath(file.c_str());Link->SetPath(file.c_str());
pLink->SetShowCmd(SW_SHOW);Link->SetShowCmd(SW_SHOW);


pLink->QueryInterface(IID_IPersistFile PersistFile=
(void **)&pPersistFile))) dynamic_cast(Link);

pPersistFile->Save("C://", TRUE);PersistFile->Save("C://");


pPersistFile->Release(); delete PersistFile
pLink->Release(); delete Link;

CoUninitialize();

讀磁片磁區


1、之前的DOS版要讀、寫、格式化第0軌的第1個磁區,程式大體以下:

char buffer[512];

reg.x.dx=0 ;
reg.x.bx=FP_OFF(buffer);
sreg.es=FP_SEG(buffer);
resg.x.ax=0x0201;
int86x(0x13,®,®,&sreg);

那麼在windows 下轉換爲呼叫 DeviceIoControl 以便格式化、讀取、寫入該磁軌,DIOC_REGISTERS這struct 在套上 DOS 下 Int21對HDD或FDD 的各項參數如要格式化是Int21也是有,但Windows下也另有提供。

l#pragma pack(push, 1)
struct DIOC_REGISTERS {
DWORD reg_EBX;
DWORD reg_EDX;
DWORD reg_ECX;
DWORD reg_EAX;
DWORD reg_EDI;
DWORD reg_ESI;
DWORD reg_Flags;
};
#pragma pack(pop)

sDiskImageInfo->hDevice =::CreateFile("////.//vwin32", 0, 0, NULL, 0,
FILE_FLAG_DELETE_ON_CLOSE, NULL);
if( sDiskImageInfo->hDevice ==INVALID_HANDLE_VALUE)
bRunNext = false;

// Reset Floppy Disk
reg.reg_EBX = 0;
reg.reg_EAX = 0x0000; // IOCTL for block devices
reg.reg_EDX = sDiskImageInfo->Driver;
reg.reg_EDI = 0; reg.reg_ESI= 0;
reg.reg_Flags = 0x0001; // assume error (carry flag is set)
dwResult = ::DeviceIoControl(sDiskImageInfo->hDevice,
VWIN32_DIOC_DOS_INT13,
®, sizeof(DIOC_REGISTERS), ®,
sizeof(DIOC_REGISTERS), &cb, 0);

// Seek Floppy
reg.reg_EBX = 0;
reg.reg_EAX = 0x0C00; // IOCTL for block devices
reg.reg_ECX = ( sDiskImageInfo->nC<< 8) |sDiskImageInfo->nS;
reg.reg_EDX = ( sDiskImageInfo->nH<< 8) |sDiskImageInfo->Driver;
reg.reg_EDI = 0;
reg.reg_ESI= 0;
reg.reg_Flags = 0x0001; // assume error (carry flag is set)
dwResult = ::DeviceIoControl(sDiskImageInfo->hDevice,
VWIN32_DIOC_DOS_INT13,
®, sizeof(DIOC_REGISTERS), ®,
sizeof(DIOC_REGISTERS), &cb, 0);

// Read Floppy
R_CreateDiskImageFile:
reg.reg_EBX = 0;
reg.reg_EAX = 0x0200 | 0x01; // IOCTL for block devices
reg.reg_ECX = ( sDiskImageInfo->nC<< 8) |sDiskImageInfo->nS;
reg.reg_EDX = ( sDiskImageInfo->nH<< 8) |sDiskImageInfo->Driver;
reg.reg_EBX = (DWORD) &m_Buf;
reg.reg_EDI = 0;
reg.reg_ESI= 0;
reg.reg_Flags = 0x0001; // assume error (carry flag is set)
dwResult = ::DeviceIoControl( hDevice, VWIN32_DIOC_DOS_INT13,
®, sizeof(DIOC_REGISTERS), ®,
sizeof(DIOC_REGISTERS), &cb, 0);
if (!dwResult || (reg.reg_Flags & 0x0001))
{
}


I/O 端 口 讀 寫 的 實 現


細 心 的 讀 者 會 發現,C++ Builder 不 再 支 持 如inportb()、outportb() 一 類I/O 端口讀 寫指 令 了。 準 確 地 說, 在Windows 環 境 下,Borland C++ 僅 支 持16 位應 用 程 序 的端口 操 做, 對32 位 應 用 程 序 的 端 口 操 做 不 再 支持, 而C++ Builder 開 發 出 來 的 程序是32 位 的。 我 個 人 以 爲, 這是C++ Builder 設 計 者 的 敗 筆。 因 爲PC 機 中,I/O 地 址空間 與 內存 地 址 空 間 從 來 都 是 各 自 獨 立 的。 看 看Delphi, 不 就 通 過Port 數 組 實 現了對I/O 端 口 的 訪 問 了 嗎? 搞 不 清 楚 爲 什 麼C++ Builder 就 沒 有 提 供 類 似 的 機 制?下 面 這 幾 個 函 數 是 筆 者 從 網 上淘 下 來 的, 經 過 驗 證, 在Windows95 環 境 下, 的 確可實 現 對I/O 端 口 的 讀 寫。 讀 者 可 以 借 鑑 使 用。
void outportb(unsigned short int port, unsigned char value)

{

// mov edx, *(&port);

__emit__(0x8b, 0x95, &port);

// mov al, *(&value);

__emit__(0x8a, 0x85, &value);

// out dx, al;

__emit__(0x66, 0xee);

}

void outportw(unsigned short int port, unsigned short intvalue)

{

// mov edx, *(&port);

__emit__(0x8b, 0x95, &port);

// mov ax, *(&value);

__emit__(0x66, 0x8b, 0x85, &value);

// out dx, ax;

__emit__(0xef);

}

unsigned char inportb(unsigned short int port)

{

unsigned char value;

// mov edx, *(&port);

__emit__(0x8b, 0x95, &port);

// in al, dx;

__emit__(0x66, 0xec);

// mov *(&value), al;

__emit__(0x88, 0x85, &value);

return value;

}

unsigned short int inportw(unsigned short int port)

{

unsigned short int value;

// mov edx, *(&port);

__emit__(0x8b, 0x95, &port);

// in ax, dx

__emit__(0xed);

// mov *(&value), ax

__emit__(0x66, 0x89, 0x85, &value);

return value;

}


檢 測 鼠 標 位 置

例如,經過一個定時器Timer1的觸發事件源來檢測鼠標位置

void __fastcall TForm1::Timer1Timer(TObject *Sender)

{

TPoint pt;

GetCursorPos(&pt);

Label1->Caption = "(" +IntToStr(pt.x) +")("+IntToStr(pt.y) +")";

令Win32 應 用 程 序 跳 入 系 統 零 層


衆 所 周 知, 在Windows95/98 的Win32 on Intel x86 體 系 中 利 用 了 處 理 器 的 三 環保護 模 型 中 的 零 環(Ring0, 最 高 權 限 級 別) 和 三 環(Ring3, 最 低 權 限 級 別)。 一 般應 用程 序 都 運 行 在Ring3 下, 受 到 嚴 格 的" 保 護", 只 能 規 矩 地 使 用Win32API。 如 果我 們想 進 行 一 些 系 統 級 的 操 做, 例 如 在 嵌 入 匯 編 中 使 用 諸 如"Mov EAX,CR0", 或像在DOS 下 那 樣 調 用 一 些 必 不 可 少 的 系 統 服 務( 如BIOS,DPMI 服 務) 而 用"Int xx",都 會 導 致" 非 法 操 做"。 但 這 種 能 力 有 時 是 必 不 可 少 的, 一 到 這 種 時候Microsoft 就" 建 議 編 寫 一 個VxD"。VxD 大 家 早 有 所 聞 了, 在VxD 裏, 不 但 可 以 執行CPU 的 所 有 指令, 而 且 可 以 調 用VMM( 虛 擬 機 管 理 器) 和 其 他VxD 提 供 的 上 千 個 系統 級 服 務。 獲 得這 一 能 力 的 最 本 質 原 因 在 於 它 運 行 在Ring0, 與 系 統 內 核 同 一 級別。 但 是 它 體 系 的復 雜 性、 開 發 工 具 的 不 易 獲 得、 幫 助 文 檔 的 不 完 備,使Microsoft 排 除 了 一 大 批 程序 員 和 競 爭 對 手。 而 將 在Windows2000(Windows98 也 開 始 支 持) 中 取 代VxD 的WDM對Win95 程 序 員 也 是 個 噩 夢, 它 需 要 了 解Windows NT 核 心 驅 動 模 型。

----有 沒 有 簡 單 一 些 的 辦 法 呢 ? 我 們 可 以 令 一 個 普 通Win32 應 用 程 序 運行在Ring0 下, 從 而 獲 得VxD 的 能 力 嗎 ? 答 案 是 肯 定 的。 下 面 我 們 就 簡 述 一 下 這 一技巧, 有 關Intel x86 保 護 模 式 的 基 礎 知 識 請 大 家 看 有 關 書 籍。

----首 先 此 技 巧 基 於 以 下 理 論 根 據:

----1、SIDT 指 令( 將 中 斷 描 述 符 表 寄 存 器 IDTR - -64 位 寬,16 ~47Bit 存有中 斷 描 述 符 表IDT 基 地 址 - - 的 內 容 存 入 指 定 地 址 單 元) 不 是 特 權 指 令, 就 是說我 們 可 以 在Ring3 下 執 行 該 指 令, 獲 得IDT 的 基 地 址, 從 而 修 改IDT, 增 加 一 個 中斷門 安 置 我 們 的 中 斷 服 務, 一 旦Ring3 程 序 中 產 生 此 中 斷,VMM 就 會 調 用 此 中 斷 服務程 序, 而 此 中 斷 服 務 程 序 就 運 行 在Ring0 下 了。 這 一 點 與 在DOS 下 非 常 相 似。

----2、Windows95 Win32 應 用 程 序 運 行 一 個 映 射 到 全 部4G 內 存 的 段 中, 選擇子 爲0137h,Ring0 中 的VxD 運 行 在 另 一 個 映 射 到 全 部4G 內 存 的 段 中, 選 擇子028h,這 兩 個 段 除 了 選 擇 子 決 定 的 訪 問 權 限 不 同 外, 沒 什 麼 不 同, 各 自 段 中 相 同的 偏 移量 對 應 了 相 同 的 線 性 地 址。 所 以 我 們 放 在Win32 應 用 程 序 中 的 中 斷 服 務 程序 可 以以Ring3 的 段 偏 移 量 被Ring0 中 的VMM 尋 址。

----下 面 我 們 以 具 體 例 子 進 一 步 說 明, 程 序 中 有 詳 細 注 釋。

----這 是 一 個Win32 Console Program( 控 制 臺 應 用 程 序), 雖 然 運 行 中 看 起來很 像DOS 筐 中 運 行 的 實 模 式DOS 程 序, 但 它 是 貨 真 價 實 的 運 行 在Ring3 下的Win32 程序。 用Visual C + + 5.0 AppWizard 創 建 一 個Win32 Console Program 項 目, 添加 以 下.CPP 文 件, 編 譯 即 可。

#include
#include
#include
#include
// 若 無DDK 帶 下 劃 線 的 可 略 去,
這 些 語 句 演 示 了 調 用VMM/VXD 服 務
DWORDLONG IDTR,SavedGate;
WORD OurGate[4]={0,0x0028,0xee00,0x0000};
// 中 斷 門 描 述 符 格 式 如 下:


DWORD _eax,_ecx,_cr0;
WORD vmmver;
HVM sysvm;

void nothing()
{
//Used to test call in Ring0
sysvm=Get_Sys_VM_Handle();
}

void __declspec( naked ) Ring0Proc(void)
// 中 斷 例 程, 運 行 在Ring0
{
_asm{
mov _eax,eax //
mov _ecx,ecx //
mov eax, CR0
// 測 試Ring3 中 不 能 執 行 的 特 權 指 令
mov _cr0,eax //
}
VMMCall(Get_VMM_Version);
// 調 用VMM 服 務
_asm{
mov vmmver,ax
}
nothing();
// 測 試 在 運 行 於Ring0 的
中 斷 例 程 中 調 用 子
    _asm iretd
// 中 斷 返 回, 與 在 實 模 式
編 程 無 本 質 區 別
}
void main() // 主 程 序
{
_asm{
mov eax, offset Ring0Proc
mov [OurGate], ax // 將 中 斷 函 數 的 地 址
shr eax, 16 // 填 入 新 造 的 中 斷 門
mov [OurGate +6], ax // 描 述 符

sidt fword ptr IDTR
// 將 中 斷 描 述 符 表 寄 存 器(IDTR)
的 內 容 取 出
mov ebx, dword ptr [IDTR +2]
// 取 出 中 斷 描 述 符 表(IDT) 基 地 址
add ebx, 8 *9
// 計 算Int 9 的 描 述 符 應 放 置 的 地 址 選 用
Int9 是 因 爲 它 在Win32 保 護 模 式 下 未 佔 用

mov edi, offset SavedGate
mov esi, ebx
movsd // 保 存 原 來 的Int 9 描 述 符 到
movsd //SavedGate 以 便 恢 復

mov edi, ebx
mov esi, offset OurGate
movsd // 替 換 原 來 的 中 斷 門 描 述 符
movsd // 以 安 裝 中 斷 服 務 例 程

mov eax,0x6200
// 用 以 測 試 放 在EAX 中 的 數 據
能 否 正 確 傳 到Ring0 中 斷
mov ecx,0
// 用 以 測 試 放 在ECX 中 的 數 據
能 否 正 確 傳 到Ring0 中 斷
mov ecx,0
// 用 以 測 試 放 在ECX 中 的 數 據
能 否 正 確 傳 到Ring0 中 斷
// 因 爲 很 多VxD 服 務 都 用
此 二 寄 存 器 傳 遞 參 數
int 9h
// 人 爲 觸 發 中 斷, 平 時 會 出 現
保 護 錯 誤 藍 屏 或 非 法 操
// 做 對 話 框, 現 在 安 裝 了
// 中 斷 服 務 例 程 後, 就 會 通 過
//VMM 在Ring0 調 用 中 斷 服 務 例 程
- -Ring0Proc

mov edi, ebx
mov esi, offset SavedGate
movsd // 恢 復 原 來 的 中 斷 門 描 述 符
movsd
}
cout<<"CR0="<<_cr0<} _getch(); if(0="=_getch())" while(_kbhit()="=0);" do{}continue.?<


如何取得Memo的行和列


  新建一個應用,在窗體Form1上添加兩個TLabel組件名爲Label1,Label2;
添加兩個TButton組件名爲Button1,Button2;添加一個TMemo組件名爲Memo1。
而後在代碼編輯器中添加如下代碼。
  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
  Label1→Caption=SendMessage(Memo1→Handle,EM_LINEFROMCHAR,-1,0)+1;
  }
  
  void __fastcall TForm1::Button2Click(TObject *Sender)
  {
  Label2→Caption=Memo1→SelStart-SendMessage(Memo1→Handle,EM_LINEINDEX,-1,0)+1;
  }
  這種方法一樣適用於RichEdit。

使用Sockets


使用socketsSocket控件讓你創建一個利用TCP/IP和有關的協議與其餘系統進行通訊的應用。使用Sockets,你可以讀和寫經過它鏈接的其餘機器,而不用擔憂實際的網絡軟件的相關細節。Sockets提供基於TCP/IP協議的鏈接。除此之外還能很好的工做,在其餘相關的協議,例如XeroxNetwork System (XNS), Digital's DEC net, or Novell's IPX/SPX家族。
C++Builder提供你寫網絡服務器或客戶應用程序去讀和寫其餘的系統。一個服務或客戶程序一般專一於一個單一的服務如超文本傳送協議(HTTP)或文件傳輸協議(FTP)。使用serversockets,一個應用程序能夠提供這些服務中的一個去鏈接一個但願使用服務的客戶程序。Clientsockets容許一個應用使用這些服務中的一個去鏈接提供這個服務的服務應用。
使用sockets去寫應用程序,你必須理解下面這些知識:
1、服務工具
當你須要寫網絡服務或客戶應用時,Sockets提供一種接合。對於許多服務,象
HTTP 或FTP,第三方服務商提供這些服務已經至關有效。有些甚至隨着操做系統捆綁而來,以便不用你本身寫。然而,當你想更多的控制服務的實現,如想讓你的應用程序與網絡通訊更加緊密,或當沒有一個服務能提供你特殊須要的服務時,你可能想創建你本身的服務或客戶應用。例如,工做在分佈式datasets時,你可能想爲數據庫寫一層與其餘系統通訊的應用。想使用Sockets實現一個服務,你必須理解:

1.服務協議
在你寫一個網絡服務或客戶程序前,你必須明白你的應用將提供或使用什麼服務。你的網絡應用必須支持許多服務的標準協議。若是你爲標準的服務例如HTTP,FTP寫網絡應用,或evenfinger or time,你必須先理解與其餘系統通訊所使用的協議。特殊服務細節你必須看提供的或使用的文檔。
若是你的應用程序提供一個新的服務與其餘系統通訊,第一步是爲這個服務的
服務端和客戶端設計通訊協議。什麼信息將發送?如何整理這些信息?如何對這些信息進行編碼?

應用程序通訊
常常的,你的網絡服務端或客戶端應用程序要提供一層在網絡軟件和一個應用之間使用的服務。例如,一個HTTP服務站點在INternet與一個Web服務應用之間爲HTTP請求信息提供內容和應答。
在你的網絡應用(或客戶應用)和網絡軟件之間Sockets提供一個接口。你必須提供一個接口,在你的應用程序與應用間使用。你能夠拷貝第三方服務商提供的標準API(例如ISAPI),或你能夠設計和發佈你本身的API.

2.理解服務和端口
許多標準服務都有關聯的、指定的端口號。當 執行服務時,你能夠爲服務考慮一個端口號。若是你實現一個標準服務, Windowssocket objects 提供一些方法讓你爲服務尋找端口號。若是提供一個新的服務,在基於Windows 95 或NT機器上,你可以在文件Services中爲你的服務指定一個相關聯的端口號。設置Services文件的更多信息請看微軟的WindowsSockets文檔。

2、Socket鏈接的類型
Socket鏈接能夠分紅三個基本的類型,它們反映瞭如何開始鏈接和本地Socket 鏈接是什麼。這三個類型是:

1.客戶端鏈接
客戶端鏈接是一個本地系統的客戶端socket與一個遠程系統上的服務端Socket鏈接。客戶端鏈接由客戶端Socket開始。首先,客戶端Socket必須描述它想鏈接到的服務端Socket.接着客戶端socket查找服務端socket,當找到服務器時,就要求鏈接。服務端socket可能不能完成正確的鏈接。服務器sockets維持一個客戶端請求隊列,在他們有時間時完成鏈接。當服務端socket接受客戶端鏈接,服務端socket
將向它想鏈接的客戶socket發送一個完整的描述,客戶端的鏈接完成。

2.傾聽鏈接
服務器 socket不會去定位客戶端,代替的,他們造成被動的,"半鏈接"狀態,傾聽來自客戶端的請求。服務器sockets造成一個隊列,存放它們聽到的鏈接請求。這個隊列記錄着客戶端鏈接請求就象他們已鏈接進來同樣。當服務器sockets贊成客戶鏈接請求時,它造成一個新的socket去鏈接客戶端,所以這個傾聽鏈接能保持開放狀態容許其餘客戶端請求。

3.服務端鏈接
當傾聽socket贊成一個客戶端請求時,服務器端socket造成一個服務器鏈接。當服務器端贊成鏈接時,向客戶端發送一個服務端socket描述以完成鏈接,當客戶端socket收到這個描述時這個鏈接獲得確認,鏈接完成。一但鏈接到客戶端的Socket完成,服務端鏈接就不能識別從一個客戶端來的鏈接。末端雙方有一樣的能力去接收一樣的事件類型。只有傾聽(listening)鏈接是根本不一樣的,它只有一個單一的末端。

3、sockets描述
Sockets讓你的網絡應用軟件經過網絡與其餘系統進行通訊。在網絡鏈接中每一個socket能夠當作一個終端點。它有一個指定的地址。

*這個系統正在運行
*它理解的接口類型
*用來鏈接的端口
一個完整的socket鏈接描述,你必須提供sockets在鏈接兩端的地址。在你開始一個socket鏈接前,你必須完整的描述你想獲得的鏈接。有些信息能夠從你的應用
軟件運行的系統平臺上獲得。例如,你不須要描述一個客戶端socket的本地IP地址--這個信息能夠從操做系統上得到。你必須提供你工做所依靠的socket的類型的信息。客戶端socket必須描述他們想鏈接的服務器。偵聽服務器sockets必須描述他們提供反應的服務器的端口。一個socket鏈接終端的完整描述包括兩部分:

1.IP地址
主機是這樣一個系統,它運行着包含有socket的應用程序。你必須描述主機給socket,經過給出主機的IP地址來完成這個描述。IP地址是一個有四個數字(byte)值的,在標準internet點付內的字符串。
例如123.197.1.2
一個簡單的系統能夠支持多於一個的IP地址。IP地址一般難於記憶而且容易打錯。一個可供選擇的方法是使用主機名。主機名就是IP地址的別名,它就是你常看到的統一資源定位(URLs)。它是一個字符串,包括了域名和服務。
例如 http://www.wsite.com
許多內部網提供給主機的名字對應的系統IP地址是internetIP地址。在windows95和NT機器上,若是一個主機名不能用,你能夠在HOSTS文件中爲你的本地IP地址(這個本地IP地址應該是指你想鏈接的主機IP地址--zyqsj)創建一個進入的名字。
關於HOSTS文件的更多信息請看WINDOWS SOCKETS的文檔。
服務器sockets不須要指定主機。本地IP地址能夠從系統中讀到。若是本地系統支持多於一個的IP地址,服務器sockets將同時在全部的IP地址上偵聽客戶端請求。當一個服務器socket贊成一個鏈接,客戶端提供一個遠程IP地址。客戶sockets必須指定遠程主機經過提供主機名或者IP地址。

在主機名和IP地址間做一個選擇
許多應用軟件使用一個主機名去指定一個系統。主機名容易記住和容易檢查排版錯誤。進一步講,服務器能改變系統或與IP地址關聯的特殊的主機名。使用一個主機名,可以容許客戶端經過主機名描述找到抽象的站點,即便主機使用一個新的IP地址。
若是主機名是未知的,客戶socket必須指定服務器系統使用的IP地址。經過給一個IP地址來指定服務器將更快。當你提供主機名時,socket在定位服務器系統前,必須搜尋與這個主機名相關的IP地址。

2.端口號
雖然IP得地址提供了足夠的信息去找到socket鏈接中位於另外一端的系統,你一般還須要指定那個系統的端口號。沒有端口號,一個系統在同一時間只能進行一個單一的鏈接。端口號是惟一標識那容許一個獨立系統鏈接到支持同時多個鏈接的主機,每一個鏈接都必須指定一個端口號。
在網絡應用中,對於服務器工具來講端口號是一個數字代碼。有一個習慣就是偵聽服務鏈接到他們本身固定的端口號上,以便他們能找到客戶端sockets.服務器socket監聽爲他們提供服務的相關端口號。當他們容許給予一個客戶端socket鏈接時,他們建立一個獨立的socket鏈接,使用不一樣的專用的端口號。經過這個方法,能持續的監聽相關服務的端口號。
客戶端socket使用一個專用的本地端口號,就不用其餘的socket去尋找它們。他們指定他們想鏈接的服務器端socket的端口號,這樣他們就能找到服務器應用程序。經常的,這個端口號是經過命名想鏈接的服務來間接指定的。

4、使用socket控件
C++Builder提供兩個socket控件,客戶端sockets和服務器sockets.他們容許你的網絡應用構成鏈接其餘的機器和容許你經過這個鏈接來讀寫信息。與每一個socket控件相關聯的是windowssocket對象,它們在終端的的做用是一個實際的socket鏈接。socket控件使用windowssocket對象去封裝windows socket API調用,因此你的應用不用去關心鏈接創建的細節或管理socket信息。
若是你想利用windows socket API調用或自定義鏈接細節,socket控件提供了便利,你能夠使用windowssocket對象的properies,events和方法。

1.使用客戶端sockets
添加一個客戶端socket控件(TClientSocket)到你的form或data module使你的應用成爲一個TCP/IP客戶。客戶sockets容許你指定你想鏈接的服務器socket和你但願服務器提供的服務。一但你描述你想獲得的鏈接,你能夠使用客戶socket控件去完成鏈接服務。
每一個客戶socket控件使用獨立的客戶windowssocket對象(TClientWinSocket)去應答鏈接中的客戶終端。使用客戶sockets去:

A.指定想獲得的服務
客戶socket控件有一個數字properties,容許你指定想鏈接的服務器系統和端口。你能夠經過主機名來指定服務器系統,使用Hostproperty。
若是你不知道主機名,或者你關心找到服務器的速度,你能夠指定服務器系統的IP地址,經過使用 Addressproperty。你必須指定IP地址和主機名中的一個。
若是你兩個都指定,客戶socket控件將使用主機名。除服務器系統外,你必須指定你的客戶socket將鏈接的在服務器系統上的端口。你可以直接使用Portproperty來指定服務端口號。或者直接在Serviceproperty使用想獲得的服務的名字。若是你指定端口號和服務名,客戶socket控件將使用服務名。

B.創建鏈接
一旦你在客戶socket控件中完成了設置描述你想鏈接的服務器的屬性,你就能夠進行鏈接,經過調用Open方法。若是你想你的應用啓動時自動創建鏈接,在設計時設置Activeproperty爲true,經過使用Object Inspector來設置。

C.取得關於鏈接的信息
完成鏈接到服務器socket後,你能夠使用與你的客戶socket控件相關的客戶windows socketobject去取得關於鏈接的信息。使用Socket property去訪問client windows socketobject。windows socket object有一個properties,它能讓你肯定在鏈接的兩端客戶和服務器使用的地址和端口號。
當使用一個windows socket API調用時,你能夠使用SocketHandleproperty區得到socket鏈接使用的handle。你能夠使用Handleproperty去訪問windows,以便接收來自socket鏈接的信息。AsyncStylesproperty決定哪一種信息類型是windows handle要接收的。

D.關閉鏈接
當你完成通信想關閉socket鏈接時,你可以經過調用Close方法來關閉鏈接。鏈接可能要由服務器端來關閉。若是是這種狀況,你將收到一個OnDisconnect事件的通知。

2.使用服務器sockets
添加一個服務端socket控件(TServerSocket)到你的form或datamodule使你的應用成爲一個TCP/IP服務器。服務器sockets容許你指定你想提供的服務或你想用來監聽客戶請求時使用的端口。你能夠使用服務器socket控件去監聽和容許客戶鏈接請求。每一個服務器socket控件使用一個單一的服務器windowssocket Object(TServerWinSocket)去應答在服務器端監聽到的鏈接。它一般使用一個服務器客戶winodwssocketObject(TServerClientWinSocket)應答在服務器端每一個活動的,鏈接着獲得容許服務的客戶socket。使用服務器sockets去:

A.指定端口
在你的服務器socket可以監聽客戶請求以前,你必須指定一個端口給你的監聽服務。你能夠使用Portproperty來指定這個端口。若是你的服務器應用提供一個標準的服務,這個服務使用一個習慣使用的相關聯的端口。你可以使用Serviceproperty直接指定端口號。使用Service property是一個好的主意,可以減小設置端口號時的錯誤。若是你既指定了Portproperty,又指定了Service property,服務socket將使用服務名。

B.監聽客戶請求
一旦你在serversocket控件上設置好你的端口號,你就可以經過在運行時經過調用Open方法來監聽一個鏈接。若是你但願你的應用程序可以在啓動的時候自動監聽鏈接,在設計的時候經過使用ObjectInspector設置Active 屬性爲true。

C.鏈接到客戶端。
當監聽服務socket控件接收到一個客戶端鏈接請求時他們將自動接受這個請求。當你沒次收到通知時,OnClientConnetc事件將發生。

D.取得關於鏈接的信息
一但你的服務器socket打開了監聽鏈接,你可以使用與你服務器socket控件相關聯的服務器windows socketobject來取得關於鏈接的信息。使用Socket property去訪問server windows socketobject.windows socketobject有一個屬性可以讓你找到關於全部活動的客戶socket鏈接這些客戶socket是你經過服務器socket控件容許鏈接的。使用Handle屬性去存取windows經過socket鏈接收到的信息。
每一個活動的,鏈接到客戶應用是經過服務、客戶windows socket bject(TServerClientWinSocket)封裝的。你可以經過server windows socketobject的鏈接屬性來訪問全部的這些。這些server client windows socketobject有些屬性讓你可以決定哪些地址和端口號給鏈接的兩端--客戶和服務器socket使用。當你使用windows socketAPI調用時,能夠使用SocketHandle屬性去得到socket鏈接使用的handle。你可以使用Handle屬性去訪問windows從socket鏈接處得來的信息。AsyncStyles屬性決定windowshandle將接收哪一種類型的信息。

E.關閉鏈接
當你決定關閉監聽鏈接時,調用Close方法。這將關閉全部打開着的,鏈接到客戶應用的鏈接,取消任何還沒有贊成的鏈接,接着關閉監聽鏈接以便你的服務socket控件不在接受任何新的鏈接。當客戶端關閉他們本身獨立的鏈接到你的serversocket的鏈接時,你能夠在OnClientDisconnect事件中獲得訊息。

5、socket事件的應答
當使用sockets寫應用程序時,大多數工做發生在socket控件的handler事件中.當經過socket鏈接開始讀或寫時,OnRead和OnWrite事件在non-blockingclient sockets中發生從而通知sockets.一樣的,服務器sockets(blocking ornon-blocking)收到OnClientRead和OnClientWrite事件.
當服務器結束一個鏈接時,客戶scokets收到一個OnDisconnect事件.當客戶端結束一個鏈接時,服務器socket收到一個OnClientDisconnect事件.
另外,客戶端Sockets和服務器端socket從鏈接中收到一個錯誤信息時,都將產生有個錯誤事件.

錯誤事件:客戶sockets和服務器sockets一般會產生一個OnError事件,當他們從鏈接中收到一個錯誤信息的時候.你可以寫一個OnError事件處理去響應這些錯誤信息.這個OnError事件處理提供傳送關於socket試圖作什麼的時候這個錯誤發生的信息,以及錯誤信息提供的錯誤代碼.你能夠在OnError事件處理中對這個錯誤做出響應,而且把錯誤代碼改成0,以免socket產生一個例外.

當開始和完成發生時,socket控件一般會收到一個事件號(number ofevents).若是你的應用程序須要改變socket開始操做的處理過程或經過鏈接開始讀或寫操做時,你將寫事件handlers去應答這些clientevents和server events.

A.client events
當一個客戶socket打開一個鏈接時,如下事件發生:
1.一個OnLookup事件最早發生,它試圖去定位serversocket.在這裏你不能改變Host,Address,Port,Service屬性去改變你想定位的服務器.你可以使用Socket屬性去訪問clientwindows socket object,而且使用它的SocketHandle屬性去調用windowsAPI,以便改變socket的客戶屬性.例如,若是你想在客戶應用軟件中設置端口號,你必須在serverclient鏈接前作這件事.
2.windows socket設置和初始化事件通知.
3.當找到server socket時一個OnConnecting事件發生.在這事件中,windows Socketobject能夠利用的是經過socket屬性提供關於鏈接的另外一端的服務socket的一些信息.這是得到實際使用來鏈接的端口和IP地址的第一個機會,它可能不一樣於從監聽socket處贊成鏈接時獲得的端口或IP地址.
4.服務器贊成鏈接請求,客戶端socket完成鏈接.
5.當一個鏈接獲得肯定後,一個OnConnect事件發生.若是你的socket當即開始經過鏈接讀或寫,就應寫一個OnConnect事件Handler去做這件事.

B.服務器端事件(server events)
服務器socket控件經過兩中方式鏈接:監聽鏈接和鏈接到客戶應用.服務器socket收到這兩個鏈接的全部事件.

監聽時事件
當構成監聽鏈接前,OnListen事件發生.在這個時候你可以經過socket屬性得到server windows socketobject.你可以使用它的SocketHandle屬性去改變socket,在socket打開監聽以前.例如,若是你想限定監聽服務使用的IP地址,你能夠在這個OnListen事件Handler中作.

與客戶端鏈接的事件
當一個服務器socket贊成一個客戶鏈接請求時,接下來的事件發生:
1.服務器socket產生一個OnGetSocket事件,經過windows sockethandle傳送給鏈接的另外一端的socket.若是你想提供本身定義的TServerClientWinSocket ofdescendant,你能夠在OnGetSocket 事件handler中創建,將被用來替代TServerClientWinSocket.
2.一個OnAccept事件發生,傳送新的TServerClientWinSocket對象給事件句柄.這是第一個要點,當你使用TServerClientWinSocket的屬性去得到被鏈接中服務的那端的客戶的信息時.
3.若是服務類型是stThreadBlocking,一個OnGetThread事件發生.若是你想提供本身定義的TServerClientThread子類,你能夠在OnGetThread事件句柄中創建一個,它將替代TServerClientThread.
4.若是服務類型是stThreadBlocking,一個ONThreadStart事件發生當這個線程(thread)開始執行時.若是你想執行任何初始化這個線程,或調用一些windowssocket API在這線程開始經過鏈接讀和寫以前,應該使用OnThreadStart事件句柄.
5.當客戶端完成一個鏈接時,一個OnClientConnect事件發生.若是是non-blocking服務,你可能想開始經過socket鏈接在這端進行讀或寫操做.

6、經過socket鏈接進行讀和寫
經過socket鏈接到其餘機器的緣由是想經過這些鏈接來讀和寫信息.什麼信息是你要讀和寫的,或者當你想讀和寫時是依靠哪些socket鏈接的相關服務的.
經過sockets進行讀和寫能夠是異步的,因此在你的網絡應用中不須要阻塞其餘代碼的執行.這是調用non-blockingconnection.你也一樣能夠經過blocking connection,這時你的下一行代碼的執行必須等到讀或寫操做完成.

A.Non-blocking鏈接,讀和寫是異步的,因此在你的網絡應用中不須要阻塞其餘代碼的執行.創建一個Non-blocking鏈接:
1.在客戶socket中設置ClientType屬性爲ctNonBlocking.
2.在服務器socket中設置ServerType屬性爲stNonBlocking.
當鏈接是non-blocking時,鏈接的另外一端企圖讀或寫時讀和寫事件將把這個信息通知你的socket.

讀和寫操做事件
Non-blockingsockets想經過鏈接讀或寫時,它會產生一個讀和寫操做事件通知你的socket.在客戶端sockets,你能夠在OnRead或OnWrite事件句柄中對這些事件作出反應.在服務器端Scokets,能夠在OnClientRead或OnClientWrite事件句柄中對這些事件作出反應.與socket鏈接相關聯的windowssocket object在事件句柄的讀或寫中被看成一個參數.Windows socket object提供一個方法號(numberof methods)以容許你經過鏈接讀或寫.
經過socket鏈接讀,使用ReceiveBuf或ReceiveText方法.在使用ReceiveBuf方法前,使用Receivelength方法去肯定在鏈接的另外一端socket準備發送的字節數(numberof bytes).
經過socket鏈接寫,使用SendBuf,SendStream,或SendText方法.若是你經過socket發送信息後不在須要socket鏈接,你能夠使用SendStreamThenDrop方法.SendStreamThenDrop在寫完全部的信息後將關閉Socket鏈接,它可以從stream讀信息.若是你使用SendStream或SendStreamThenDrop方法,不要釋放Streamobject, socket在鏈接結束後會自動釋放這個Stream.
注意:SendStreamThenDrop將關閉一個獨立的客戶鏈接服務,而不是監聽鏈接.

B.Blocking connections
當你使用的鏈接是Blocking時,你的Socket必須經過鏈接發起讀或寫操做,賽過被動的等待從socket鏈接發來的通知.當你的鏈接末端的讀和寫操做發生改變時使用Blockingsocket.對於客戶端sockets,設置ClientType屬性爲ctBlocking 以便構成一個blocingconnection.根據你的客戶端應用想完成什麼,你可能想創建一個執行線程去完成讀或寫操做,以便你的應用可以繼續執行其餘的線程,當它在等待經過鏈接讀或寫操做的完成.
對於服務器sockets,設置ServerType屬性爲stThreadBlocking以便構成一個blockingconnection.由於blockingconnections在等待經過鏈接讀或寫信息完成時掛起了其餘代碼的執行,服務器socket控件一般產生一個新的執行線程給每個客戶鏈接,當ServerType設置爲stThreadBlocking時.許多使用Blocking鏈接的應用都寫使用線程(usingthreads.甚至若是你不使用線程,你可能也想使用(using) TWinSocketStream去讀和寫.
1)using threads
當使用一個blockingconnection進行讀或寫操做時,客戶sockets不會自動產生一個新線程.若是你的客戶應用程序沒有什麼事作,直到讀或寫信息完成,那麼這正是你想要的.若是你的應用包括了一個用戶界面,它還須要響應用戶的操做,那麼,你可能想產生一個獨立的線程去讀寫.當服務器sockets造成一個blocking鏈接時,他們經常產生獨立的線程給每個客戶鏈接,因此沒有客戶須要等待直到其餘客戶完成經過鏈接讀或寫操做.在默認狀況下,服務器sockets使用TServerClientThread對象去實現爲每一個鏈接執行不一樣的線程.
TServerClientThread對象模擬發生在non-blocking鏈接中的OnClientRead和OnClientWrite事件.但是,這些事件發生在監聽socket上時,不是本地線程(thread-local).若是客戶請求頻繁,你將想創建你本身的TServerClientThread子類去提供一個安全線程(Thread-Safe)去完成讀和寫操做.
當寫客戶線程或寫服務器線程時,你可以使用TwinSocketStream去作實際的讀寫操做.
A)寫客戶端線程
爲客戶端鏈接寫一個線程,定義一個新線程對象,使用新線程對象對話框.你的新線程對象Execute方法的句柄的經過線程鏈接進行讀寫操做的細節,能夠創建一個TWinSocketStream對象,而後使用它來讀或寫.
使用你本身的線程,在OnConnect事件句柄中創建它.關於創建和運行線程的更多信息,請看Executing threadobjects.
例子:這個例子顯示一個應用的客戶線程在鏈接肯定後向服務器發出寫請求.
void __fastcall TMyClientThread::Execute()
{
while (!Terminated &&ClientSocket1->Active)
// make sure connection is active
{
try
{
TWinSocketStream *pStream = newTWinSocketStream(ClientSocket1.Socket,60000);
try
{
char buffer[10];
GetNextRequest(buffer);
// GetNextRequest must be a thread-safe method
// write a request to the server
pStream->Write(buffer,strlen(buffer) + 1);
// continue the communication (eg read a response)

}
__finally

{
delete pStream;
}
}
catch (Exception &E)
{
if (!E.ClassNameIs("EAbort"))
Synchronize(HandleThreadException());
// you must write HandleThreadException
}
}
}

B)寫服務器線程
服務器鏈接線程由TServerClientThread派生.由於這個,不能使用新線程對象對話框.替代的,手動聲明你的線程以下:

class PACKAGE TMyServerThread :
public ScktComp::TServerClientThread
{
public
void __fastcall ClientExecute(void);
}

注意你將用重載ClientExcute方法替代Execute方法.執行ClientExecute方法必須爲客戶端鏈接寫一個一樣的Execute方法線程.然而,當你從控件欄上放一個客戶socket控件到你的應用上時來替代這個方法時.監聽服務socket贊成一個鏈接時,服務客戶線程必須使用TServerClientWinSocket對象來創建.這能夠利用共公共的CientSocket屬性.另外,你可以使用HandleException這個protected性的方法,賽過
你本身寫你的thread-safe例外操做.

警告:Serversockets會緩存他們使用到的線程.確信ClientExecute方法執行一些必要的初始化操做,以便它們在最後執行時不致於產生不利的結果.

當你使用你的線程時,在OnGetThread事件句柄中創建它.當創建線程,設置CreateSuspended參數爲false.
例子:這個例子顯示一個爲一個應用服務的線程,這個應用是在鏈接肯定後由客戶端來的讀請求.

void __fastcall TMyServerThread::ClientExecute()
{
while (!Terminated &&ClientSocket->Connected)
// make sure connection is active
{
try
{
TWinSocketStream *pStream = newTWinSocketStream(ClientSocket,
60000);
try
{
char buffer[10];
memset(buffer, 0, sizeof(buffer));
if (pStream->WaitForData(60000))
// give the client 60 seconds to start writing
{
if (pStream->Read(buffer, sizeof(buffer) == 0)

ClientSocket->Close();
// if can't read in 60 seconds, close the connection
// now process the request
}
else
ClientSocket->Close();
}
__finally

{
delete pStream;
}
}
catch (...)
{
HandleException();
}
}
}

C.使用TwinSocketStream
當爲一個blocking鏈接實現一個線程時,你必須肯定在鏈接的另外一端的socket是準備寫仍是讀.Blocking鏈接不會通知socket當它準備好寫或讀操做的時候.想看看鏈接是否準備好,使用TWinSocketStream對象.TWinSocketStream提供一個方法去幫助調整讀或寫操做時間的選擇.調用WaitForData方法去等待,直到socket另外一端的
準備好寫操做.當讀寫操做使用TWinSocketStream時,若是讀或寫操做在指定的時間期限內未能完成,Stream將發生超時.這個超時被看成一個結果,socket應用不會暫停,而是不斷的經過一個droppedconnection試圖讀或寫.

注意:你不能在non-blocking鏈接中使用TWinSocketStream

Windows95/98下怎樣隱藏應用程序不讓它出如今CTRL-ALT-DEL對話框中?


把你的應用程序從CTRL-ALT-DEL對話框中隱藏的一個簡單辦法是去應用程序的標題。若是一個程序的主窗口沒以標題,Windows95不把它放到CTRL-ALT-DEL對話框中。清除標題屬性的最好地方是在WinMain函數裏。

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Title = "";
Application->Initialize();
Application->CreateForm(__classid(TForm1),&Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}
另外一種方法是:調用RegisterServiceProcess API 函數將程序註冊成爲一個服務模式程序。RegisterServiceProcess是一個在Kernel32.dll裏相關但無正式文件的函數。在MSSDK頭文件裏沒有該函數的原型說明,但在Borland import libraries for C++Builder裏能找到。很顯然,這個函數的主要目的是建立一個服務模式程序。之因此說很顯然,是由於MSDN裏實質上對這個函數沒有說什麼。

下面的例子代碼演示了在Windows95/98下怎樣經過使用RegisterServiceProcess來把你的程序從CTRL-ALT-DEL對話框中隱藏起來。

//------------Header file------------------------------
typedef DWORD (__stdcall *pRegFunction)(DWORD, DWORD);

class TForm1 : public TForm
{
__published:
TButton *Button1;
private:
HINSTANCE hKernelLib;
pRegFunction RegisterServiceProcess;
public:
__fastcall TForm1(TComponent* Owner);
__fastcall ~TForm1();
};


//-----------CPP file------------------------------
#include "Unit1.h"

#define RSP_SIMPLE_SERVICE 1
#define RSP_UNREGISTER_SERVICE 0

__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
hKernelLib = LoadLibrary("kernel32.dll");
if(hKernelLib)
{
RegisterServiceProcess =
(pRegFunction)GetProcAddress(hKernelLib,
"RegisterServiceProcess");

if(RegisterServiceProcess)
RegisterServiceProcess(GetCurrentProcessId(),
RSP_SIMPLE_SERVICE);
}
}

__fastcall TForm1::~TForm1()
{
if(hKernelLib)
{
if(RegisterServiceProcess)
RegisterServiceProcess(GetCurrentProcessId(),
RSP_UNREGISTER_SERVICE);

FreeLibrary(hKernelLib);
}
}
//-------------------------------------------------
注: windows NT下沒有RegisterServiceProcess函數。

怎樣隱藏應用程序的任務條圖標


首先,請看看這些術語。系統托盤是一個在任務條右角的小方框,在托盤了應用程序能夠顯示小圖標。任務條是能夠在屏幕上伸展的工具欄。它就是程序圖標所在的位置。想隱藏程序的任務條圖標,你能夠應用ShowWindow函數並傳給它Application->Handle窗口句柄。

ShowWindow(Application->Handle, SW_HIDE);
若想讓任務條圖標再出現,只需將SW_HIDE改成SW_SHOW。

ShowWindow(Application->Handle, SW_SHOW);
注: 你能夠設置主窗口的Visible屬性爲false來隱藏它。

注:經過ShowWindow來隱藏窗口的任務條圖標是不持久的。某些動做會使任務條圖標重現。你能夠將隱藏的應用程序窗口設爲ToolWindow來移走程序的任務條圖標而避免它再次出現。Tool windows永遠不會有任務條圖標。 使應用程序窗口成爲一個ToolWindow有一個反作用:當用戶按下Alt-TAB時它將不在程序列表中出現。你能夠調用API函數GetWindowLong和SetWindowLong來使應用程序窗口成爲一個ToolWindow。

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{

DWORD dwExStyle =GetWindowLong(Application->Handle,GWL_EXSTYLE);
dwExStyle |= WS_EX_TOOLWINDOW;
SetWindowLong(Application->Handle, GWL_EXSTYLE,dwExStyle);

try
{
Application->Initialize();
Application->CreateForm(__classid(TForm1),&Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}


編寫本身的Ping.exe程序


在Windows系統中,咱們常常用Ping.exe來測試網絡的連通性。

  Ping的實現過程很簡單,該命令將引起IP層發送一個簡單的IP包,通常是32字節。而目的方收到這個包後,將源地址和目的地址變換一下,從新發送這個包便可,固然還要加一些超時機制。

  其實,咱們也可用C++ Builder NetMaster中的NMEcho控件來實現網絡鏈接檢測功能。

  首先定義如下控件:

  三個Edit控件:一個用於接收遠程主機的IP地址或域名,一個用於接收用戶設置的超時機制的時間,一個用於設置端口號。

  兩個RichEdit控件:一個用於給遠程主機發送信息,一個用於接收來自遠程主機的信息。

  兩個CheckBox控件:用於用戶是否本身設定端口號。

  一個Button控件:用於執行測試。

  一個StatusBar控件:用於顯示應用程序的狀態。

  程序實現代碼以下:

  void __fastcall TForm1::Button1Click(TObject Sender)

  { //設置NMEcho控件的標準TCP/IP屬性

   NMEcho1-〉Host=Edit1-〉Text ;

   NMEcho1-〉TimeOut=StrToInt(Edit2-〉Text) ;

   if(CheckBox1-〉Checked)

     NMEcho1-〉Port=StrToInt(Edit3-〉Text);

   else

     NMEcho1-〉Port=7;

  //TCP/IP中Echo的默認端口號

  NMEcho1-〉ReportLevel=Status_Basic;

   NMEcho1-〉Connect(); //創建鏈接

   RichEdit2-〉Clear ();

   for(int i=0;i
  //RichEdit1用於給遠程主機發送信息

  RichEdit2-〉Text=RichEdit2-〉Text+NMEcho1-〉Echo(RichEdit1-〉Lines-〉

  Strings[i]);

   NMEcho1-〉Disconnect ();

  }

  注意:在調用NMEcho控件的Connect()方法時,應該確保在接收數據以前鏈接已經創建。

  當調用Connect()方法後,若是用戶輸入的是域地址而不是IP地址,且域名服務器成功地解析了這個域名,將觸發控件的OnHostResoved事件,在此事件的處理中,咱們將解析成功的消息在狀態欄中顯示給用戶。具體實現代碼以下:  void__fastcall TForm1::NMEcho1HostResolved(TComponent Sender)

  {

   StatusBar1-〉Panels-〉Items[0]-〉Text="Host Resolved!";    

  }

  若是用戶輸入的遠程主機不正確,將觸發控件的OnInvalidHost事件,在此事件的處理中,彈出對話框要求用戶從新輸入遠程主機的IP地址或域名地址,而後試圖與服務器重建鏈接。具體代碼以下:

  void __fastcall TForm1::NMEcho1InvalidHost(bool&&Handled)

  {

   AnsiString s;

   if(InputQuery("Invailid host!","Specify a new host:",s))

   {

     NMEcho1-〉Host=s;

     Handled=true;

   }    

  }

  創建鏈接後,將觸發控件的OnConnect事件,在此事件的處理中,咱們將鏈接成功的消息在狀態欄中顯示給用戶。具體實現代碼以下:

  void __fastcall TForm1::NMEcho1Connect(TObject Sender)

  {

   StatusBar1-〉Panels-〉Items[0]-〉Text="Echo has connectedhost!";

    }

  若是在調用Connect()方法後,在超時時間仍然沒有與服務器鏈接,將觸發控件的OnConnectFailed事件,在此事件的處理中,咱們將鏈接失敗的消息顯示給用戶。具體實現代碼以下:

  void __fastcall TForm1::NMEcho1ConnectionFailed(TObjectSender)

  {

  ShowMessage("Connection failed!");    

  }

  除了NMEcho控件能夠實現以上功能外,NetMaster的NMDayTime、NMTime這兩個控件也能實現。方法與NMEcho控件同樣,區別是NMDayTime和NMTime這兩個控件不用首先調用Connect()方法,它們與服務器的鏈接是在使用DayTimeStr、TimeStr屬性時自動進行的。
用C++Builder在WINNT下編制一個Service


---- Windows NT與Windows 9x有一個很是重要的區別,即WindowsNT提供了不少功能強大的Service(服務)。這些Service能夠隨着NT的啓動而自啓動,也可讓用戶經過控制面板啓動,還能夠被Win32應用程序起停。甚至在沒有用戶登陸系統的狀況下,這些Service也能執行。許多FTP、WWW服務器和數據庫就是以Service的形式存在於NT上,從而實現了無人值守。就連最新版的「黑客」程序BackOrifice2000也是以Service形式在NT上藏身的。因爲Service的編程較複雜,許多開發者想開發本身的Service但每每都望而卻步。鑑於此,下面咱們就從頭至尾來構造一個全新的Service,讀者只要在程序中註明的地方加上本身的代碼,那麼就能夠輕鬆擁有一個本身的Service。在編寫Service以前,先介紹一下幾個重要的函數:

---- 1. SC_HANDLE OpenSCManager( LPCTSTR lpMachineName, LPCTSTRlpDatabaseName, DWORD dwDesiredAccess)

---- OpenSCManager 函數打開指定計算機上的service control managerdatabase。其中參數lpMachineName指定計算機名,若爲空則指定爲本機。LpDatabaseName爲指定要打開的servicecontrol manager database名, 默認爲空。dwDesiredAccess指定操做的權限,能夠爲下面取值之一:

---- SC_MANAGER_ALL_ACCESS //全部權限

---- SC_MANAGER_CONNECT //容許鏈接到service control managerdatabase

---- SC_MANAGER_CREATE_SERVICE //容許建立服務對象並把它加入database

---- SC_MANAGER_ENUMERATE_SERVICE //容許枚舉database 中的Service

---- SC_MANAGER_LOCK //容許鎖住database

---- SC_MANAGER_QUERY_LOCK_STATUS //容許查詢database的封鎖信息

---- 函數執行成功則返回一個指向service control managerdatabase的句柄,失敗則返回NULL。注意:WINNT經過一個名爲service control managerdatabase的數據庫來管理全部的Service,所以對Service的任何操做都應打開此數據庫。

---- 2. SC_HANDLE CreateService(SC_HANDLE hSCManager,

LPCTSTR lpServiceName,
LPCTSTR lpDisplayName,
DWORD dwDesiredAccess,
DWORD dwServiceType,
DWORD dwStartType,
DWORD dwErrorControl,
LPCTSTR lpBinaryPathName,
LPCTSTR lpLoadOrderGroup,
LPDWORD lpdwTagId,
LPCTSTR lpDependencies,
LPCTSTR lpServiceStartName,
LPCTSTR lpPassword)

---- CreatService函數產生一個新的SERVICE。其中參數hSCManager爲指向servicecontrol manager database的句柄,由OpenSCManager返回。LpServiceName爲SERVICE的名字,lpDisplayName爲Service顯示用名,dwDesiredAccess是訪問權限,本程序中用SERVICE_ALL_ACCESS。wServiceType,指明SERVICE類型,本程序中用SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS。dwStartType爲Service啓動方式,本程序採用自啓動,即dwStartType等於SERVICE_AUTO_START。dwErrorControl說明當Service在啓動中出錯時採起什麼動做,本程序採用SERVICE_ERROR_IGNORE即忽約錯誤,讀者能夠改成其餘的。LpBinaryPathName指明Service本體程序的路徑名。剩下的五個參數通常可設爲NULL。如函數調用成功則返回這個新Service的句柄,失敗則返回NULL。與此函數對應的是DeleteService(hService),它刪除指定的Service。
---- 3. SC_HANDLE OpenService(SC_HANDLE hSCManager,LPCTSTRlpServiceName, DWORD dwDesiredAccess )

---- OpenService函數打開指定的Service。其中參數hSCManager爲指向service controlmanager database的句柄,由OpenSCManager返回。LpServiceName爲Service的名字,dwDesiredAccess是訪問權限,其可選值比較多,讀者能夠參看SDKHelp. 函數調用成功則返回打開的Service句柄,失敗則返回NULL。

---- 4. BOOL StartService( SC_HANDLE hService, DWORDdwNumServiceArgs,LPCTSTR *lpServiceArgVectors )

---- StartService函數啓動指定的Service。其中參數hService爲指向Service的句柄,由OpenService返回。dwNumServiceAr爲啓動服務所需的參數的個數。lpszServiceArgs爲 啓 動 服務所需的參數。函數執行成功則返回True, 失敗則返回False。

---- 5. BOOL ControlService(SC_HANDLE hService DWORDdwControl,LPSERVICE_STATUS lpServiceStatus )

----Service程序沒有專門的中止函數,而是用ControlService函數來控制Service的暫停、繼續、中止等操做。參數dwControl指定發出的控制命令,能夠爲如下幾個值:

SERVICE_CONTROL_STOP //中止Service
SERVICE_CONTROL_PAUSE //暫停Service
SERVICE_CONTROL_CONTINUE //繼續Service
SERVICE_CONTROL_INTERROGATE //查詢Service的狀態
SERVICE_CONTROL_SHUTDOWN //讓ControlService調用失效

----參數lpServiceStatus是一個指向SERVICE_STATUS的指針。SERVICE_STATUS是一個比較重要的結構,它包含了Service的各類信息,如當前狀態、可接受何種控制命令等等。
---- 6. BOOL QueryServiceStatus( SC_HANDLEhService,LPSERVICE_STATUS lpServiceStatus )

---- QueryServiceStatus函數比較簡單,它查詢並返回當前Service的狀態。

----編制一個Service通常須要兩個程序,一個是Service本體,一個是用於對Service進行控制的控制程序。一般Service本體是一個console程序,而控制程序則是一個普通的Win32應用程序(固然,用戶不用控制程序而經過控制面板也可對Service進行啓、停,但不能進行添加、刪除操做。)

----首先,咱們來編寫Service本體。對於Service本體來講,它通常又由如下三部分組成:main()、ServiceMain()、Handler(),下面是main()的源代碼:(注:因爲篇幅的關係,大部分程序都沒進行錯誤處理,讀者能夠本身添上)

int main(int argc, char **argv)
{
SERVICE_TABLE_ENTRY ste[2];
//一個Service進程能夠有多個線程,這是每一個    
               //線程的入口表
ste[0].lpServiceName="W.Z.SERVICE"; //線程名字
ste[0].lpServiceProc=ServiceMain;
//線程入口地址
ste[1].lpServiceName=NULL;
//最後一個必須爲NULL
ste[1].lpServiceProc=NULL;
StartServiceCtrlDispatcher(ste);
return 0;
}


---- main()是Service的主線程。當servie controlmanager開始一個Service進程時,它老是等待這個Service去調用StartServiceCtrlDispatcher()函數。main()做爲這個進程的主線程應該在程序開始後儘快調用StartServiceCtrlDispatcher()。StartServiceCtrlDispatcher()在被調用後並不當即返回,它把本Service的主線程鏈接到servicecontrol manager,從而讓service controlmanager經過這個鏈接發送開始、中止等控制命令給主線程。主線程在這時就扮演了一個命令的轉發器的角色,它或者調用Handle()去處理中止、繼續等控制要求,或者產生一個新線程去執行ServiceMain。StartServiceCtrlDispatcher()在整個Service結束時才返回。
---- ServiceMain()是Service真正的入口點,必須在main()中進行了正確的定義。ServiceMain()的兩個參數是由StartService()傳遞過來的。下面是ServiceMain()的源代碼:

void WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)
{
ssh=RegisterServiceCtrlHandler
("W.Z.SERVICE",Handler);
ss.dwServiceType=SERVICE_WIN32_OWN
_PROCESS|SERVICE_INTERACTIVE_PROCESS;
ss.dwCurrentState=SERVICE_START_PENDING;
//如用戶程序的代碼比較多
(執行時間超過1秒),這兒要設成SERVICE_
START_PENDING,待用戶程序完成後再設爲SERVICE_RUNNING。
ss.dwControlsAccepted=SERVICE_ACCEPT_
STOP;//代表Service目前能接受的命令是中止命令。
ss.dwWin32ExitCode=NO_ERROR;
ss.dwCheckPoint=0;
ss.dwWaitHint=0;
SetServiceStatus(ssh, &ss);
//必須隨時更新數據庫中Service的狀態。

Mycode(); //這兒可放入用戶本身的代碼

ss.dwServiceType=SERVICE_WIN32_OWN_
PROCESS|SERVICE_INTERACTIVE_PROCESS;
ss.dwCurrentState=SERVICE_RUNNING;
ss.dwControlsAccepted=SERVICE_ACCEPT_STOP;
ss.dwWin32ExitCode=NO_ERROR;
ss.dwCheckPoint=0;
ss.dwWaitHint=0;
SetServiceStatus(ssh,&ss);

Mycode();// 這兒也可放入用戶本身的代碼
}


在ServiceMain()中應該當即調用
RegisterServiceCtrlHandler()註冊一個Handler
去處理控制程序或控制面板對Service的控制要求。


Handler()被轉發器調用去處理要求,
下面是Handler()的源代碼:
void WINAPI Handler(DWORD Opcode)
{
switch(Opcode)
{
case SERVICE_CONTROL_STOP: //中止Service
Mycode();//這兒可放入用戶本身的相關代碼
ss.dwWin32ExitCode = 0;
ss.dwCurrentState =SERVICE_STOPPED;
//把Service的當前狀態置爲STOP
ss.dwCheckPoint = 0;
ss.dwWaitHint = 0;
SetServiceStatus (ssh,&ss);
/必須隨時更新數據庫中Service的狀態
break;
case SERVICE_CONTROL_INTERROGATE:
SetServiceStatus (ssh,&ss);
/必須隨時更新數據庫中Service的狀態
break;
}
}


---- 好了,Service本體程序已基本完成,咱們接着來看一下Service的控制程序:
---- 控制程序是一個標準的window程序,上面主要有四個按紐:Create Service、DeleteService、start、stop,分別用來產生、刪除、開始和中止Service。下面是它們的部分源代碼:

1. 產生Service
void __fastcall TForm1::CreateBtnClick
(TObject *Sender)
{
scm=OpenSCManager(NULL,NULL,
SC_MANAGER_CREATE_SERVICE);
if (scm!=NULL){
svc=CreateService(scm,
"W.Z.SERVICE","W.Z.SERVICE",//Service名字
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS
|SERVICE_INTERACTIVE_PROCESS,
SERVICE_AUTO_START,
//以自動方式開始
SERVICE_ERROR_IGNORE,
"C://ntservice.exe", //Service本體程序路徑,
必須與具體位置相符
NULL,NULL,NULL,NULL,NULL);
if (svc!=NULL)
CloseServiceHandle(svc);
CloseServiceHandle(scm);
}
}

2. 刪除Service
void __fastcall TForm1::DeleteBtnClick
(TObject *Sender)
{
scm=OpenSCManager(NULL,NULL,
SC_MANAGER_CONNECT);
if (scm!=NULL){
svc=OpenService(scm,"W.Z.SERVICE",
SERVICE_ALL_ACCESS);
if (svc!=NULL){
QueryServiceStatus(svc,&ServiceStatus);
if (ServiceStatus.dwCurrentState==
SERVICE_RUNNING)//刪除前,先中止此Service.
ControlService(svc,
SERVICE_CONTROL_STOP,&ServiceStatus);
DeleteService(svc);
CloseServiceHandle(svc);
//刪除Service後,最好再調用CloseServiceHandle
}
//以便當即從數據庫中移走此條目。
CloseServiceHandle(scm);
}
}

3. 開始Service
void __fastcall TForm1::StartBtnClick(TObject *Sender)
{
scm=OpenSCManager(NULL,NULL,SC_MANAGER_CONNECT);
if (scm!=NULL){
svc=OpenService(scm,"W.Z.SERVICE",SERVICE_START);
if (svc!=NULL){
StartService(svc,0,NULL);//開始Service
CloseServiceHandle(svc);
}
CloseServiceHandle(scm);
}
}

4.中止Service
void __fastcall TForm1::StopBtnClick
(TObject *Sender)
{
scm=OpenSCManager(NULL,NULL,
SC_MANAGER_ALL_ACCESS);
if (scm!=NULL){
svc=OpenService(scm,"W.Z.SERVICE",
SERVICE_STOP|SERVICE_QUERY_STATUS);
if (svc!=NULL){
QueryServiceStatus(svc,&ServiceStatus);
if (ServiceStatus.dwCurrentState==
SERVICE_RUNNING)
ControlService(svc,
SERVICE_CONTROL_STOP,&ServiceStatus);
CloseServiceHandle(svc);
}
CloseServiceHandle(scm);
}
}

如何在C++ BUILDER中自動關閉WINDOWS屏幕保護


----在實際編程應用中,當程序須要用較長的時間來處理某些計算時,這段時間有可能使WINDOWS啓動屏幕保護,這樣程序的處理會相對變得更長。那麼如何在運行程序時自動關閉屏幕保護呢?
----WINDOWS在啓動屏幕保護前會向已激活的程序發送一個WM_SYSCOMMAND消息,並將該消息的WPARAM參數設置爲SC_SCREENSAVE。咱們可利用C++BUILDER中的TApplication類的OnMessage事件來處理WINDOWS發來的這條消息,若是在接收到的消息後將handled參數設爲true,這個響應的消息值就能夠阻止屏幕保護運行。

---- 在C++ BUILDER 4.0的過程以下:

---- 一、從主菜單中選擇File | New APPlication 來建立一個新的空工程文件。而後在Forn上加上一個Label對象,設置其Caption爲"此程序將關閉WINDOWS屏幕保護"。

---- 二、在程序頭文件unit1.h中對成員函數ProcessMessage的聲明加到TForm1的定義中。

class TForm1 : public TForm
{
__published: // IDE-managed Components
TLabel *Label1;
private: // User declarations
void __fastcall ProcessMessage
(TMsg &message,bool&handled);
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};

---- 三、在unit1.cpp中,在程序中增長ProcessMessage函數語句:
void __fastcall TForm1::ProcessMessage
(TMsg &message,bool &handled)
{
if(message.message==WM_SYSCOMMAND
&&message.wParam==SC_SCREENSAVE)
{
handled=true;
}
}
---- 四、在TForm1的構造函數增長如下代碼:
__fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner)
{
Application->OnMessage=ProcessMessage;
}


顯示/隱藏任務欄圖標


----標準的Windows應用程序運行時通常都會在任務欄上顯示任務圖標,用戶可直接用鼠標點擊任務欄圖標進行任務切換,但有些應用程序不使用任務欄圖標,如典型的Office工具條,也有些程序可由用戶定製顯示方式顯示或隱藏任務欄圖標,如Winamp。咱們的程序中也能夠作到,只要調用WindowsAPI函數SetWindowLong便可,以下:

// 隱藏任務欄圖標:
SetWindowLong(Application->Handle,
GWL_EXSTYLE, WS_EX_TOOLWINDOW);
// 顯示任務欄圖標:
SetWindowLong(Application->Handle,
GWL_EXSTYLE, WS_EX_APPWINDOW);


信箱監視程序


----本 文 將 向 大 家 介 紹 怎 樣 編 寫 自 己 的 信 箱 監 視 程 序, 程 序 將 直 接 調 用WinSock函 數 來 進 行 網 絡 通 信。 除 了 具 備WinSock 編 程 知 識 之 外, 還 必 須 了 解POP3 協 議。下面 是 對POP3 的 一 個 粗 略 的 介 紹, 讀 者 可 以 參 看RFC 1225 更 爲 詳 細 地 了 解 該協議。

1、 關 於POP3 協 議
----POP3 服 務 器 程 序 通 常 在TCP 端 口110 提 供 服 務。 當 客 戶 想 要 使 用 服 務 時, 它便與 服 務 器 建 立 一 個TCP 連 接。 一 旦 連 接 建 立,POP3 服 務 器 就 向 客 戶 發 送 一 條 歡迎 消息。 然 後 客 戶 開 始 給 服 務 器 發 送 命 令, 服 務 器 則 給 出 相 應 的 回 答。POP3 的 命令 由 一個 關 鍵 詞 或 者 關 鍵 詞 加 參 數 組 成。 每 個 命 令 以 回 車 換 行(0xD0xA) 做 爲 結束 標 志。對 於 所 有 的 命 令,POP3 服 務 器 都 會 提 供 一 個 回 答。 服 務 器 的 回 答 由 一 個狀 態 標 志加 一 些 附 加 信 息 組 成。 目 前 使 用 的 兩 個 標 志 是「 +OK」 和「 -ERR」, 分 別表 示 客 戶 的命 令 是 否 合 法。 所 有 的 回 答 也 是 以 回 車 換 行 結 束。
----與 本 文 討 論 的 話 題 相 關 的 四 個POP3 命 令 是USER、PASS、LIST 和QUIT。

USER 命 令
格 式USER name

----其 中name 是 用 戶 在 該POP3 服 務 器 上 的 用 戶 標 識。 客 戶 應 該 在 接 到 服 務器的 歡 迎 消 息 後 或 者 在 上 一 個 USER 或 者PASS 失 敗 之 後 可 以 發 送 此 命 令。

PASS 命 令
格 式PASS string

----其 中string 爲 該 用 戶 的 密 碼。 客 戶 在 發 送 了USER 命 令 並 且 收 到 了 +OK的回 答 之 後 方 可 發 送 此 命 令。 如 果 用 戶 名 和 密 碼 都 正 確, 服 務 器 回 答 +OK, 不然-ERR。

LIST 命 令
格 式LIST

----如 果 該 用 戶 有 郵 件, 則LIST 命 令 會 回 答 +OK, 並 列 出 所 有 郵 件 的 標 識 符和大 小( 每 個 郵 件 一 行), 最 後 一 個 僅 包 含 一 個 句 點 的 行(0xD0xA0x2E) 表 示 整 個回 答的 結 束。 如 果 該 用 戶 沒 有 郵 件, 有 些 服 務 器 會 返 回 -ERR, 有 些 在 可 能 返 回 一個+OK 和 一 個 僅 包 含 一 個 句 點 的 行。 當 然, 客 戶 必 須 在PASS 命 令 通 過 之 後 客 戶 程序才 能 給 服 務 器 發 送LIST 命 令。

QUIT 命 令

----從POP3 服 務 器 上 退 出 登 錄。

2、 實 現 相 關 函 數
----接 下 來 我 們 按 照POP3 協 議 所 定 義 的 通 信 規 則 來 實 現 一 個 名叫POP3CheckMail的 函 數, 只 要 調 用 此 函 數, 我 們 就 可 以 檢 測 信 箱 了。
----下 面 的 代 碼 是 用 與Delphi 4 兼 容 的Pascal 語 言 實 現 的, 我 們 必 須包含WinSock 單 元, 並 且 在 調 用 下 列 函 數 之 前 初 始 化 好WinSock 動 態 連 接 庫。 初始化WinSock 動 態 連 接 庫 的 代 碼 如 下:

----if WSAStartup( $002,wsadata)<>0 then Halt;

----POP3CheckMail 的 原 型 如 下:

----function POP3CheckMail(Email,Password:String;varMailList:TStringList;var ErrorMsg:String):Bool;

----參 數 說 明:

----Email 和Password 分 別 爲 用 戶 的email 信 箱 名 和 口 令。

----變 量 參 數MailList 用 於 返 回 郵 件 的 標 識 和 大 小,MailList.Count 表 示郵件 的 封 數。

----變 量 參 數ErrorMsg 返 回 出 錯 消 息。

----以 下 是POP3CheckMail 及 其 它 所 用 到 的 函 數 的 實 現 代 碼。

Connect_Server 函 數

----功 能: 與 指 定 的 主 機 建 立 一 個TCP 連 接, 返 回 一 個Socket 描 述 符。 參數host指 定 主 機 的 名 字,Port 指 定 端 口 號。

function Connect_Server(host:string;Port:integer):integer;
var i:integer;
p:^LongInt;
phe:pHostEnt;
sin:sockaddr_in;
begin
sin.sin_family:=AF_INET;
sin.sin_port:=htons(Port);
//Get the IP for host, allowing for dotted decimal
phe:=gethostbyname(pchar(host));
if phe<>nil
then begin
p:=Pointer(phe^.h_addr_list^);
sin.sin_addr.s_addr:=p^;
end
else begin
i:=inet_addr(PChar(Host));
if i<> -1 thensin.sin_addr.S_addr:=i
end;
//create a socket
Result:=socket(PF_INET,SOCK_STREAM,0);
if (Result=INVALID_SOCKET) then Exit;
//connect to server
if Connect(Result,sin,sizeof(sin))=SOCKET_ERROR
then begin {Error handling} end;
end;

Write_Socket 函 數

----功 能: 向Socket 寫 入 一 個 字 符 串。

function Write_Socket(sockfd:Integer; consts:string):Integer;
begin
result:=Winsock.Send(sockfd,pointer(s)^,Length(s),0)
end;

Socket_Readline 函 數

----功 能: 從Socket 上 讀 取 一 行。

function Socket_Readline(sockfd:Integer):String;
//Read until #10
var S:String; buf:array[0..1]of Char;
n:Cardinal;
begin
buf[0]:= #0;buf[1]:= #0; S:=‘';
n:=recv(sockfd,Buf,1,0);
while n>0 do begin
buf[1]:= #0;
S:=S +buf;
if (buf[0]= #10) then Break;
n:=recv(sockfd, buf, 1, 0);
end;
Result:=Trim(S);
end;

Pop3Response 函 數

----功 能: 讀 取POP3 服 務 器 的 一 行 返 回 信 息, 如 果 是「 +OK」 則 函 數 返回TURE,如 果 是「 -ERR」 則 返 回FALSE。

function Pop3Response(Sockfd:Integer):Bool;
var S: string;
begin
S:=socket_readline(sockfd);
if copy(s,1,3)=‘ +OK' then Result:=True
else {if copy(s,1,4)=‘ -ERR' then }Result:=False;
end;

POP3CheckMail 函 數

----功 能: 檢 測 名 字 爲email 的 信 箱, 如 果 有 新 郵 件, 則 通 過 變 量 參數MailList將 每 一 封 郵 件 的 大 小 返 回。

function POP3CheckMail
(Email,Password:String;var MailList:
TStringList;var ErrorMsg:String):Bool;
var sockfd,i:integer;
S, Host, User:String;
begin
Result:=False; ErrorMsg:=‘';
if MailList=nil then Exit;
S:=Trim(Email);
i:=Pos(‘@',Email);
User:=Trim(Copy(S,1,i -1));
Host:=Trim(Copy(S,i +1,Length(Email) -i));
MailList.Clear;
if (user=‘')or(host=‘') then begin
ErrorMsg:=‘Invalid email address.';exit; end;
if (Host[1]=‘[')and (Host[Length(host)]=‘]')
then begin Host[1]:=‘ ';Host[Length(host)]:= #0;end;
Host:=Trim(host);
sockfd:=Connect_Server(Host,110);
if not Pop3Response(sockfd)then begin ErrorMsg:=
‘Cannot connect to server';exit; end;
Write_Socket(sockfd,‘USER ' +User + #13 #10);
IF NOT POP3Response(sockfd) then begin ErrorMsg:=
‘USER failed'; Exit;end;
Write_Socket(sockfd,‘PASS ' +Password + #13 #10);
IF NOT POP3Response(sockfd) then begin ErrorMsg:=
‘PASS failed'; Exit;end;
Write_Socket(sockfd,‘LIST' #13 #10);
POP3Response(sockfd);
while true do begin
s:=Socket_readline(sockfd);
if s=‘.' then BREAK;
MailList.Add(S);
end;
Write_Socket(sockfd,‘QUIT' #13 #10);
Closesocket(sockfd);
Result:=True;
end;

3、 郵 件 的 檢 測
----下 面 我 們 來 看 一 個 使 用POP3CheckMail 函 數 的 簡 單 示 例。
var MailList:TstringList;
ErrorMsg:String;
...
MailList:=TstringList.Create;
POP3CheckMail(‘simon_liu@263.net',
‘mypassword', MailList, ErrorMsg);
If MailList.Count>0 then
MessageBox(0, Pchar(‘You have ' +IntToStr (MailList.Count) + ‘ newmessages!'),
‘New Message!', MB_ICONINFORMATION)
Else if ErrorMsg=‘' then MessageBox (0, ‘No message!', ‘',0)
Else MessageBox(0, Pchar(ErrorMsg), ‘Error', 0);
MailList.Free;

----如 果 你 仔 細 閱 讀 了POP3CheckMail 函 數 的 實 現 代 碼, 你 會 發 現 此 函 數 除了可 以 獲 取 郵 件 的 封 數 之 外, 還 可 以 獲 得 每 一 封 郵 件 的 大 小。 你 可 以經過POP3CheckMail 函 數 的 變 量 參 數MailList 的Strings 數 組 來 獲 取 郵 件 的大小。

----實 現 了POP3CheckMail 函 數, 再 在 此 基 礎 上 編 寫 一 個POP3 信 箱 的 監 視 程序就 變 得 很 簡 單 了。 你 可 以 通 過 一 個 定 時 器 來 定 期 地 調 用POP3CheckMail 函 數,這 樣你 就 可 以 監 視 某 個email 信 箱 了。 假 若 你 想 要 同 時 監 視 多 個email 信 箱, 只 要爲 每一 個 信 箱 創 建 一 個 線 程 並 且 在 線 程 中 定 期 調 用POP3CheckMail 函 數 即 可。 你的 程序 中 如 果 沒 有 使 用Delphi 的 控 件, 那 麼 一 個 完 整 的 信 箱 監 視 程 序 可 能 只有60K 左右。

C++Building製做鬧鐘


----大凡熱戀中的網蟲都曾經陷入下列的困境:約好女/男友晚七點半在老地方等,卻在計算機面前一直爬行到深夜,等反映過來,朋友早已拂塵而去,又得幾天的功夫去陪禮道歉。朋友何不按如下步驟作一簡單的鬧鐘,讓你安安心心上網,大大方方約會。你只要在上網的時候打開此應用程序,設置好約會時間(固然也能夠是默認好的)便可。時間一到,音樂響起,快去約會吧。

---- 本鬧鐘程序有如下組件組成:

序號 組件類型 組件名稱 功能
1 Tlabel l_Clock_1 顯示「輸入日期」
2 TdateTimePicker dtp_Clock_1 選擇日期
3 Tlabel l_Clock_2 顯示「輸入時間」
4 TdateTimePacker tdp_Clock_2 選擇時間
5 TmediaPlayer mp_Clock 演奏音樂
6 Tbutton b_Clock_Open 從新打開
7 Ttimer t_Clock 定時檢測
8 Tbutton b_Clock_Close 關閉應用程序

---- 屏幕組件一覽表

---- 屏幕組件一覽圖

---- 說明:dtp_Clock_1 的Kind屬性設置爲dtkDate , dtp_Clock_2的Kind屬性設置爲dtkTime,mp_Clock的FileName屬性設置爲你主機上存在的任何mid、wav、avi文件。t_Clock 的Interval屬性設置爲10。

---- 事件說明以下:

①、 t_Clock的OnTimer :
{
//按時觸發演示程序
struct date d;
struct time t;
AnsiString thour,tmin,tsec;
int dyear;
int dintyear;
int dmon,dday;
AnsiString tinthour,tintmin,tintsec;
AnsiString dintmon,dintday;
//取當天日期
getdate(&d);
dyear=d.da_year;
dday=d.da_day;
dmon=d.da_mon;
dintyear=StrToInt(dint.SubString(1,2));
dintmon=dint.SubString(4,2);
dintday=dint.SubString(7,2);
//取當時時間
gettime(&t);
thour=AnsiString(t.ti_hour);
tmin=AnsiString(t.ti_min);
//tsec=AnsiString(t.ti_sec);
//tint=AnsiString(DateTimePicker1- >Time);
tinthour=tint.SubString(10,2);
tintmin=tint.SubString(13,2);
//tintsec=tint.SubString(16,2);
//鬧鐘服務功能
if((StrToInt(thour)==StrToInt(tinthour))&&
(StrToInt(tmin)==StrToInt(tintmin))
&&(StrToInt(AnsiString(dyear).SubString(3,2))
==dintyear)&&(StrToInt(dmon)==StrToInt(dintmon))
&&(StrToInt(dday)==StrToInt(dintday)))
{
dTimer- >Enabled=false;
MediaPlayer1- >Open();
MediaPlayer1- >Play();
}
}
②、 b_Clock_Open 的OnClick:
{
t_Clock- >Enabled=true;
}
③、 b_Clock_Close的OnClick
{
Application- >Terminate();
}

---- 固然此程序還能夠拓展、細化,如我僅將觸發條件檢測到分,固然它徹底能夠檢測到秒,也能夠僅檢測到時。


撥號上網IP地址的檢知


隨着INTERNET在世界範圍內的迅速普及,上網的人數也愈來愈多。其中,絕大多數人是經過普通電話線撥號上網的。咱們知道,每一臺上網的計算機,不管是用何種方式上網,都被分配了一個或多個獨立無二的IP地址。對於撥號上網的用戶,通常是由其ISP在其每次撥號上網時動態分配一個IP地址,這個地址可能每次都不相同(其緣由主要是爲了充分利用有限資源)。那麼,咱們可否經過某種方法隨時方便地檢知本身上網時的IP地址呢?答案是確定的。下面咱們就用C++BUILDER編制一個小巧的程序來實現這種功能。(注:本程序在局域網中也一樣能運行)
---- 首先用BCB的FILE菜單下的New Application建立一個新項目,取名爲Ipcheck.bpr。

---- 而後,在窗體FORM1上添加五個標籤(LABEL)和兩個按鈕(BUTTON),如圖所示。

---- 接下來,雙擊窗體的OnCreate事件,在其中加上如下程序:

void __fastcall TForm1::FormCreate(Tobject *Sender)
{
WSAData wsaData;

if (WSAStartup(MAKEWORD(1,1),&wsaData)!=0)
{ //初始化WINSOCK調用

MessageBox(NULL,"Wrong WinSock
Version","Error",MB_OK);
return ;
}

Refresh1Click(Sender); //程序一開始,就調檢知IP地址
}

再雙擊Refresh按鈕,在其中加上如下程序

void __fastcall TForm1::Refresh1Click(Tobject *Sender)
//刷新IP地址
{
char HostName[80];

LPHOSTENT lpHostEnt;

struct in_addr addr[2];

//本程序假設主機不是多宿主機,即最多隻有

// 一塊網卡和一個動態IP
for (int I=0; I< 2; I++){
memset(&addr[I],0,sizeof(in_addr));
//對in_addr結構清0,以利後面填寫

}

if (gethostname(HostName,sizeof(HostName))==SOCKET_ERROR)

{ // 獲得本主機名

MessageBox(NULL,"Can't getting local hostname.","Error",MB_OK);
return ;
}

Label3- >Caption=HostName;

lpHostEnt=gethostbyname(HostName);//利用獲得的主機名去得到主機結構

if (!lpHostEnt){

MessageBox(NULL,"Yow! Bad host lookup.","Error",MB_OK);

return ;

}

for (int I=0; lpHostEnt- >h_addr_list[I]!=0;I++)

//從主機地址表中獲得IP地址

{

memcpy(&addr[I],lpHostEnt->h_addr_list[I],sizeof(in_addr));

}

Label4- >Caption=inet_ntoa(addr[0]);

Label5- >Caption=inet_ntoa(addr[1]);

}

再雙擊Refresh按鈕,在其中加上如下程序

void __fastcall TForm1::Button2Click(Tobject *Sender)

{

WSACleanup(); //釋放WINSOCK調用

Close();

}

---- 最後,不要忘了在程序頭部加上#include.....哦。

---- 好了,程序完成了,編譯後就可運行了。本程序在中文WIN95/NT4.0下編譯經過。


用C++ Builder編寫Tray程序


Tray(托盤)是Windows9x任務條上的一個特殊區域,它的技術名稱爲「任務欄佈告區」,一些軟件(如金山詞霸Ⅲ)運行時會在托盤上放置一個圖標,使用戶一眼就能知道這個程序正在後臺運行,要想激活它也很容易,一般只需單擊一下這個圖標便可,很是方便。
  Tray的編程比較特殊,但並不難,主要包括圖標、工具提示和消息等三個方面,它是Shell編程的一部分。ShellAPI提供了Shell-NotifyIcon函數,用它能夠增長、刪除或者修改托盤中的圖標,在托盤上放置圖標後,WindowsShell會負責把發生在圖標上的鼠標事件通知應用程序。Shell-NotifyIcon函數定義以下:

  WINSHELLAPI BOOL WINAPI Shell-NotifyIcon(DWORDdwMessage,PNOTIFYICONDATA pnid);

  dwMessage表示要完成的操做:NIM-ADD(增長圖標)、NIM-DELETE(刪除圖標)、NIM-MODIFY(修改圖標或提示文本),pnid是一個指向NOTIFYICONDATA結構的指針,結構的定義以下:

  typedef struct -NOTIFYICONDATA{

  DWORD cbSize;//結構所佔的字節數,必須用結構的大小來初始化。

  HWND hWnd;//接受Tray圖標消息的窗口句柄

  UINT uID;//由應用程序定義的圖標ID

  UINTuFlags;//用來鑑別那些須要改變其值的域,NIF_ICON表示hIcon有效,可用來修改圖標,NIF_MESSAGE表示uCallbackMessage有效,用來定義消息,NIF-TIP表示szTip參數有效,可修改工具提示。

  UINT uCallbackMessage;//應用程序定義的消息

  HICON hIcon;//Tray圖標的句柄

  char szTip[64];//工具提示的文本

  }NOTIFYICONDATA;

  下面咱們就經過一個具體例子來講明實現方法,程序運行時不會顯示主窗體,只在托盤上增長一個圖標,雙擊圖標可關閉程序。

  程序運行時托盤區顯示以下:

  新建一個工程,放置一個Timer控件到窗體上。打開unit1.h文件,增長頭文件說明#include,在TForm1定義的private段增長一些數據成員和方法的聲明:

  unsigned int iconmessage;//定義的消息

  void AddTrayIcon();//在托盤上增長圖標

  void RemoveTrayIcon();//從托盤中刪除圖標

  因爲要增長對自定義消息的處理,因此必須重載窗口過程函數WndProc,在TForm1的定義中增長protected段:virtualvoid --fastcall WndProc(Messages::Tmessage& Message);

  在unit1.cpp中定義相應的成員函數:

  void TForm1::AddTrayIcon()

  {

  NOTIFYICONDATA icondata;

  memset(&icondata,0,sizeof(icondata));

  //將結構icondata的各域初始化爲0

  icondata.cbSize=sizeof(icondata);

  icondata.hWnd=Handle;

  strncpy(icondata.szTip,″未知狀態″,sizeof(icondata.szTip));

  icondata.hIcon=Application->Icon->Handle;

  icondata.uCallbackMessage=iconmessage;

  icondata.uFlags=NIF-MESSAGE|NIF-ICON|NIF-TIP;

  Shell-NotifyIcon(NIM-ADD,&icondata);

  }

  void TForm1::RemoveTrayIcon()

  {

  NOTIFYICONDATA icondata;

  memset(&icondata,0,sizeof(icondata));

  icondata.cbSize=sizeof(icondata);

  icondata.hWnd=Handle;

  Shell-NotifyIcon(NIM-DELETE,&icondata);

  }

  重載TForm1的WndProc函數,加入對自定義消息的處理代碼,這其實至關於建立了TForm類的子類。

  void __fastcall TForm1::WndProc(Messages::TMessage&Message)

  {

  if(Message.Msg==iconmessage)

  {

   if(Message.LParam==WM-LBUTTONDBLCLK)

   {

   Application->Terminate();

  //若是雙擊圖標,則關閉應用程序

   }

   return;

  }

  TForm::WndProc(Message);//對於其餘的消息,調用基礎類的WndProc函數讓Windows進行缺省處理。

  }

  建立窗體的OnCreate事件句柄:

  void --fastcall TForm1::FormCreate(TObject *Sender)

  {

  iconmessage=RegisterWindowMessage(″IconNotify″);

  AddTrayIcon();

  }

  這裏經過調用RegisterWindowMessage函數來定義一個用戶消息,也能夠經過WM_USER+n來得到一個系統沒有使用的消息編號。

  void --fastcall TForm1::FormDestroy(TObject *Sender)

  {

  RemoveTrayIcon();

  //窗體在關閉時刪除托盤中的圖標

  }

  編寫Timer1的Timer事件代碼,當用戶將鼠標停留在圖標上時,顯示提示文本:

  void --fastcall TForm1::Timer1Timer(TObject *Sender)

  {

  NOTIFYICONDATA icondata;

  memset (&icondata, 0, sizeof (icondata));

  icondata.cbSize = sizeof (icondata);

  icondata.hWnd = Handle;

  String s=″個人圖標!″;//定義提示文本

  strncpy (icondata.szTip, s.c_str(), sizeof(icondata.szTip));

  icondata.uFlags = NIF-TIP ;

  Shell-NotifyIcon (NIM-MODIFY,&icondata);

  }

  程序運行時不顯示主窗體,只在托盤上放置相應的程序圖標,從C++ Builder主選單中選擇View|ProjectSource,在WinMain函數的Application→Initialize()語句後增長代碼:

  ShowWindow(Application→Handle,SW-HIDE);

  Application→ShowMainForm=false;

  按F9編譯並運行程序,托盤上就會出現相應的圖標。以上代碼在C++Builder三、Pwin98環境下編譯、運行經過。


怎樣用代碼來最小化或恢復程序


你可以用下面三種方法之一來實現它。
方法一:發送一條Windows消息到主窗口的Handle屬性或Application->Handle。這條消息就是 WM_SYSCOMMAND,將 wParam 設爲SC_MINIMIZE 或 SC_RESTORE。你能夠調用SendMessage API函數來發送消息。 //設置WPARAM爲SC_MINIMIZE來最小化窗口

SendMessage(Application->Handle, WM_SYSCOMMAND,SC_MINIMIZE, 0); 

// 設置WPARAM爲SC_RESTROE來恢復窗口

SendMessage(Application->Handle, WM_SYSCOMMAND,SC_RESTORE, 0);

方法二:調用 ShowWindow API 函數。

你必須傳送Application對象句柄到ShowWindow函數。若是你傳送給ShowWindow函數的句柄是主窗口,那麼主窗口將最小化到桌面(desktop)而不是任務條(taskbar)。// 最小化:傳送 SW_MINIMIZE 到 ShowWindow

ShowWindow(Application->Handle,SW_MINIMIZE); 

// 恢復:傳送SW_RESTORE 到 ShowWindow

ShowWindow(Application->Handle, SW_RESTORE);

方法三:調用Application對象的Minimize或Restore函數。 // 調用Minimize最小化應用程序

Application->Minimize(); 

// 調用Restore恢復應用程序

Application->Restore();

調用Application的方法較易用,但發送WM_SYSCOMMAND消息功能更強。

另外,WM_SYSCOMMAND消息容許你最大化程序,改變光標爲幫助光標,滾動程序,移動一個窗口,改變窗口大小,甚至模擬Alt-TAB切換到另外一窗口。緊記,實現這些功能用API函數更好。

儘管調用ShowWindow也能工做,你大概也不想用它來最小化或恢復程序。當隱藏的窗口被最小化時ShowWindow會引發最小化動畫出現。這看上去稍微有點傻,由於動畫是從程序主窗口的位置遠離中心。


製做主窗口顯示前的版權窗口

在工程文件中選File->New Form新建一個窗口,設計好窗口的外觀。
給窗口起名爲AboutBox,源文件命名爲AboutBox.Cpp

選Project->Options,將新建的窗口從自動創建中去掉。

選View->Project Source,打開工程文件的源文件,加入句子。

#include "AboutBox.h"

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

{

DWORD lTime;

try

{

Application->Initialize();

AboutBox=new TAboutBox(AboutBox);

AboutBox->Show();

AboutBox->Update();

lTime=GetTickCount();

Application->CreateForm(__classid(TMainForm),&MainForm);

while((GetTickCount()-lTime) / 1000 <3);

AboutBox->Hide();

AboutBox->Free();

Application->Run();

}

catch (Exception &exception)

{

Application->ShowException(&exception);

}

return 0;

}


判斷是否已經聯到 internet


使用 NetMasters Powersock 控件讀取本地IP 地址,若是是"0.0.0.0" 說明沒有鏈接。
例子:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if (Powersock1->LocalIP == "0.0.0.0")
ShowMessage("not connected");
else
ShowMessage(Powersock1->LocalIP);
}

獲取登錄用戶名


 void __fastcall TForm1::Button2Click(TObject *Sender)
{
DWORD dwSize = 0;
// 肯定字節所需內存
GetUserName(NULL, &dwSize);
// 定義緩衝區
char *szBuf = new char[dwSize];
szBuf[0] = '/0';
// 讀用戶名
GetUserName(szBuf, &dwSize);
Label2->Caption = szBuf;
delete [] szBuf;
}

隱藏桌面圖標


void __fastcall TForm1::Button1Click(TObject *Sender)
{
HWND hDesktop;

// 獲取桌面句柄
hDesktop = FindWindow("ProgMan", NULL);
// 隱藏桌面上的圖標
ShowWindow(hDesktop, SW_HIDE);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
HWND hDesktop;

hDesktop = FindWindow("ProgMan", NULL);
// 顯示桌面上的圖標
ShowWindow(hDesktop, SW_SHOW);
}

程序啓動時運行


void __fastcall TForm1::Button1Click(TObject *Sender)
{
TRegistry* Reg;
char AppFileName[256];

if( Edit1->Text=="" ) // 判斷文件名是否爲空
{
MessageBox(Handle,"應用程序名稱不能夠爲空。","錯誤",MB_OK+MB_ICONERROR);
exit(0);
}
Edit1->GetTextBuf(AppFileName, 256);
Reg = new TRegistry();
try
{
Reg->RootKey = HKEY_LOCAL_MACHINE;
if(Reg->OpenKey("Software//Microsoft//Windows//CurrentVersion//Run",FALSE) )
{
// 在註冊表中添加數值
Reg->WriteString("StartUp1",AppFileName);
}
else
MessageBox(Handle,"打開註冊表失敗。","錯誤",MB_OK|MB_ICONERROR);
}
catch(...)
{
Reg->CloseKey();
Reg->Free();
}
}

控制面板的調用


 
void __fastcall TForm1::Button1Click(TObject *Sender)
{
UINT Res; // WinExe的返回結果

// 顯示控制面板
Res = WinExec("rundll32.exe shell32.dll,Control_RunDLL",9);
if( Res==0 )
MessageBox(Handle, "程序超出內存。", "錯誤", MB_OK|MB_ICONERROR);
else if( Res==ERROR_BAD_FORMAT )
MessageBox(Handle,"命令錯誤。", "錯誤", MB_OK|MB_ICONERROR);
else if( Res==ERROR_FILE_NOT_FOUND )
MessageBox(Handle,"指定文件沒找到。", "錯誤", MB_OK|MB_ICONERROR);
else if( Res==ERROR_PATH_NOT_FOUND )
MessageBox(Handle,"指定路徑沒找到。", "錯誤", MB_OK|MB_ICONERROR);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
// 輔助選項 | 鍵盤
WinExec("rundll32.exe shell32.dll,Control_RunDLL access.cpl,,1",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
// 添加/刪除程序 屬性 | 安裝/卸載
WinExec("rundll32.exe shell32.dll,Control_RunDLL Appwiz.cpl,,1",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
// 顯示 屬性 | 背景
WinExec("rundll32.exe shell32.dll,Control_RunDLLdesk.cpl,,0",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button5Click(TObject *Sender)
{
// Internet 屬性 | 常規
WinExec("rundll32.exe shell32.dll,Control_RunDLLInetcpl.cpl,,0",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button6Click(TObject *Sender)
{
// 區域設置 屬性 | 區域設置
WinExec("rundll32.exe shell32.dll,Control_RunDLLIntl.cpl,,0",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button7Click(TObject *Sender)
{
// 遊戲控制器 | 通常
WinExec("rundll32.exe shell32.dll,Control_RunDLLJoy.cpl,,0",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button8Click(TObject *Sender)
{
// 鼠標 屬性 | 按鈕
WinExec("rundll32.exe shell32.dll,Control_RunDLLMain.cpl",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button9Click(TObject *Sender)
{
// 多媒體 屬性 | 音頻
WinExec("rundll32.exe shell32.dll,Control_RunDLLMmsys.cpl,,0",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button10Click(TObject *Sender)
{
// 調制解調器 屬性
WinExec("rundll32.exe shell32.dll,Control_RunDLLModem.cpl",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button11Click(TObject *Sender)
{
// 網絡 | 配置
WinExec("rundll32.exe shell32.dll,Control_RunDLLNetcpl.cpl",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button12Click(TObject *Sender)
{
// 密碼 屬性 | 更改密碼
WinExec("rundll32.exe shell32.dll,Control_RunDLLPassword.cpl",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button13Click(TObject *Sender)
{
// 掃描儀與數字相機 屬性 | 設備
WinExec("rundll32.exe shell32.dll,Control_RunDLLSticpl.cpl",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button14Click(TObject *Sender)
{
// 系統 屬性 | 常規
WinExec("rundll32.exe shell32.dll,Control_RunDLLSysdm.cpl,,0",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button15Click(TObject *Sender)
{
// 日期/時間 屬性 | 日期和時間
WinExec("rundll32.exe shell32.dll,Control_RunDLLtimedate.cpl",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button16Click(TObject *Sender)
{
// 電源管理 屬性 | 電源方案
WinExec("rundll32.exe shell32.dll,Control_RunDLLPowercfg.cpl",9);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button17Click(TObject *Sender)
{
// 撥號 屬性 | 個人位置
WinExec("rundll32.exe shell32.dll,Control_RunDLLTelephon.cpl",9);
}

模擬鍵盤按鍵

 
void __fastcall TForm1::Button1Click(TObject *Sender)
{
// 模擬在Edit1組件中按下了字母a鍵
PostMessage(Edit1->Handle, WM_KEYDOWN, 65, 0);
}
//---------------------------------------------------

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
// 模擬在窗體Form1中按下了Tab鍵
PostMessage(Form1->Handle, WM_KEYDOWN, VK_TAB,0);
}
//------------------------------------------


讓標題欄閃爍


 
void __fastcall TForm1::Button1Click(TObject *Sender)
{
// 激活定時器
Timer1->Enabled = true;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
// 禁止定時器
Timer1->Enabled = false;
// 使窗體恢復原狀
FlashWindow(Handle, false);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
// 使窗體標題欄閃爍
FlashWindow(Handle,True);
Beep(); // 聲音提示
}


啓動屏幕保護


 
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_SCREENSAVE, 0);


年月日星期的取法

 

AnsiString iYear,iMonth,iDay,iHour,iMinute,iSecond;
iYear=Now().FormatString("yyyy");//取年
iMonth=Now().FormatString("mm");//取月
iDay=Now().FormatString("dd");//取日
iHour=Now().FormatString("hh");//取小時
iMinute=Now().FormatString("nn");//取分鐘
iSecond=Now().FormatString("ss");//取秒
DayOfWeek(Now().CurrentDate())

鍵盤事件


 
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD&Key,
TShiftState Shift)
{
if( Shift.Contains(ssShift) ) // 若是按下了Shift鍵則在第一個面板上顯示Shift
StatusBar1->Panels->Items[0]->Text= "Shift";
if( Shift.Contains(ssAlt)) // 若是按下了Alt鍵則在第二個面板上顯示Alt
StatusBar1->Panels->Items[1]->Text= "Alt";
if( Shift.Contains(ssCtrl) ) // 若是按下了Ctrl鍵則在第三個面板上顯示Ctrl
StatusBar1->Panels->Items[2]->Text= "Ctrl";
if(Shift.Contains(ssAlt)&&(Shift.Contains(ssCtrl)))// 若是同時按下了Alt+Ctrl鍵則在第二個面板上顯示Alt+Ctrl
StatusBar1->Panels->Items[5]->Text= "Alt+Ctrl";
}
//---------------------------------------------------------------------------


void __fastcall TForm1::FormKeyUp(TObject *Sender, WORD&Key,
TShiftState Shift)
{
// 在Shift、Alt和Ctrl鍵彈起時清除狀態欄中相應面板上的內容
if( !(Shift.Contains(ssShift)) )
StatusBar1->Panels->Items[0]->Text= "";
if( !(Shift.Contains(ssAlt)) )
StatusBar1->Panels->Items[1]->Text= "";
if( !(Shift.Contains(ssCtrl)) )
StatusBar1->Panels->Items[2]->Text= "";
if(!Shift.Contains(ssAlt)&&(!Shift.Contains(ssCtrl)))
StatusBar1->Panels->Items[5]->Text= "";
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormMouseDown(TObject *Sender,TMouseButton Button,
TShiftState Shift, int X, int Y)
{
if( Shift.Contains(ssLeft) ) // 若是按下了左鍵則在第四個面板上顯示left
StatusBar1->Panels->Items[3]->Text= "Left";
if( Shift.Contains(ssMiddle) ) // 若是按下了中鍵則在第五個面板上顯示Middle
StatusBar1->Panels->Items[4]->Text= "Middle";
if( Shift.Contains(ssDouble) ) // 若是是雙擊則在第六個面板上顯示Double
StatusBar1->Panels->Items[5]->Text= "Double";
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormMouseUp(TObject *Sender,TMouseButton Button,
TShiftState Shift, int X, int Y)
{
// 在鼠標按鍵彈起時清除狀態欄中相應面板上的內容
if( !(Shift.Contains(ssLeft)) )
StatusBar1->Panels->Items[3]->Text= "";
if( !(Shift.Contains(ssMiddle)) )
StatusBar1->Panels->Items[4]->Text= "";
if( !(Shift.Contains(ssDouble)) )
StatusBar1->Panels->Items[5]->Text= "";
}

 

隱藏任務欄


 
void __fastcall TForm1::Button1Click(TObject *Sender)
{
HWND WndHandle;

// 獲取任務欄的窗口句柄
WndHandle = FindWindow("Shell_TrayWnd", NULL);
ShowWindow(WndHandle, SW_SHOW); // 顯示任務欄
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
HWND WndHandle;

WndHandle = FindWindow("Shell_TrayWnd", NULL);
ShowWindow(WndHandle, SW_HIDE); // 隱藏任務欄
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
SetWindowLong(Application->Handle, GWL_EXSTYLE,WS_EX_TOOLWINDOW);
}

禁止關機


1.先打開頭文件做以下修改:

class TForm1 : public TForm
{
__published: // IDE-managed Components
private: // User declarations
void __fastcall WMQueryEndSession(TWMQueryEndSession&msg);
public: // User declarations
__fastcall TForm1(TComponent* Owner);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_QUERYENDSESSION,TWMQueryEndSession,WMQueryEndSession)
END_MESSAGE_MAP(TForm)
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

2.而後對unit.cpp文件添加以下代碼:

void __fastcall TForm1::WMQueryEndSession(TWMQueryEndSession&msg)
{
msg.Result = 0;
ShowMessage("你不能關閉系統");
}

 


怎樣以最小化方式啓動程序


能夠調用Application->Minimize函數來最小化應用程序到任務條。如何你但願你的程序啓動時就最小化,只需在調用Run方法前調用Application->Minimize就好了。

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize();
Application->CreateForm(__classid(TForm1),&Form1);
Application->Minimize(); //以最小化方式啓動
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}

在Memo中增長一行後,如何使最後一行總能顯示


SendMessage(Memo1->Handle,EM_SCROLL,SB_LINEDOWN,0)


設置壁紙方法

經過IActiveDesktop接口來實現

好比設置壁紙,就能夠這樣

IActiveDesktop *a;

CoInitialize(NULL);

if(SUCCEEDED(CoCreateInstance(

Shlobj::CLSID_ActiveDesktop,NULL,CLSCTX_INPROC_SERVER,

IID_IActiveDesktop,(void **)&a)))

{

WideString c = "C://My Documents//yw2.jpg";

OleCheck(a->SetWallpaper(c.c_bstr(),0));

OleCheck(a->ApplyChanges(AD_APPLY_ALL));

a->Release();

}

CoUninitialize();

其它接口可查看msdn

注意在cpp的第一行加入#define NO_WIN32_LEAN_AND_MEAN

並要#include

相關文章
相關標籤/搜索