生活随笔
收集整理的這篇文章主要介紹了
VC函数对象模板
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
2005-10-26 編程技巧 函數(shù)對象模板 - [ C++ ] 作者:rick1126 email: rickzhang@sina.com.cn 日期:2001-4-15 9:48:59 FUNCTION OBJECT BASES 要將書寫函數(shù)對象的進程簡單化, 標準庫提供兩個類模板作為這樣的對象的基類: std::unary_function 和 std::binary_function. 它們都在頭文件 < functional > 中聲明. 根據(jù)其命名, unary_function 提供接收一個參數(shù)的基函數(shù)而 binary_function 提供一個接收兩個參數(shù)的基函數(shù). template < class Arg, class Res > struct unary_function { typedef Arg argument_type; typedef Res result_type; }; template < class Arg, class Arg2, class Res > struct binary_function { typedef Arg first_argument_type; typedef Arg2 second_argument_type; typedef Res result_type; }; 這些模板不提供任何有用的函數(shù)體, 它們只是確保參數(shù)和返回類型具有統(tǒng)一的命名. 在下面的例子里面, 謂詞 is_vowel 表示一個參數(shù), 繼承自 unary_function: template < class T > class is_vowel: public unary_function< T, bool > { public: bool operator ()(T t) const { if ((t==’a’)||(t==’e’)||(t==’i’)||(t==’o’)||(t==’u’)) return true; return false; } }; ----------- Danny Kalev Tag: 編程博客 發(fā)表于 09:44:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 編程技巧 使用一個模板類實現(xiàn)對于類成員函數(shù)的回調(diào)執(zhí)行(編譯自Topica) - [ C++ ] 作者:rick1126 email: rickzhang@sina.com 日期:2001-4-13 9:23:39 A GENERIC CALLBACK DISPATCHER 可以創(chuàng)建一個通用的回調(diào)模板類進行成員函數(shù)的自動回調(diào). 這樣的一個模板將將類作為其成員函數(shù)的第一個參數(shù), 第二個參數(shù)是一個指向類成員函數(shù)的指針. 關(guān)鍵在于將第二個參數(shù)基于第一個參數(shù)如下: template < class T, void (T::*F)() > class callback {/**/}; 該模板的實現(xiàn)十分簡單: 它具備一個針對T的引用, 就是所需調(diào)用的成員函數(shù)的宿主類, 一個跟在其和一個稱之為execute()的成員函數(shù).: template < class T, void (T::*F)() > class callback { public: callback(T& t) : object(t) {}/*assign actual object to T*/ void execute() {(object.*F)();}/*launch callback function*/ private: T& object; }; 要通過一個成員指針調(diào)用成員函數(shù), 你必須具有一個針對確定的對象的引用. 這就是為什么模板需要一個 T& 作為成員變量. 現(xiàn)在你需要使用回調(diào)模板來執(zhí)行一個類 A 的成員函數(shù): class A { public: void f(); }; 你不能使用變量操作成員函數(shù)地址, 為此使用 & 操作來獲得函數(shù)地址. 最后, 傳遞該成員函數(shù)的數(shù)組對象給模板對象.: int main() { A a; /*first, create an object*/ callback < A, &A::f > c(a); /*instantiate template*/ c.execute(); /*invoke a.f()*/ } 你可以使用回調(diào)模板類結(jié)合任意類型的類, 只要其成員函數(shù)具有同樣的形式. ----------- Danny Kalev Tag: 編程博客 發(fā)表于 09:43:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 撥號上網(wǎng)程序(轉(zhuǎn)) - [ VC專欄 ] 作者:chache email: cyzhx@263.net 日期:2000-10-24 1:58:04 大家知道,在Netants、DownLoad Expert等軟件中都帶有定時撥號上網(wǎng)下載軟件的功能。而 一般用戶的撥號上網(wǎng),利用的是Windows的Remote Access Service(RAS,遠程訪問服務)。 下面介紹一下其在Visual C++下的實現(xiàn)。 Visual C++為我們提供了包含RAS API聲明的“ras.h″頭文件。要在程序中實現(xiàn)撥號 上網(wǎng)功能,其大致過程如下: 1. 利用Modem撥號進行連接,應使用RasDial函數(shù)。 其聲明如下: DWORD Ras Dial(LPRASDIALEXTENSIONS lpRas DialExtensions,LPCTSTR lpszPhoneboo k,LPRASDIALPARAMS lp Ras DialParams,DWORD dw Notifier Type,LPVOID lpv Notifier, LPHRASCONN lph Ras Conn ) 參數(shù)說明: lpRasDialExtensions和lpszPhonebook:僅在Windows NT下有效,在Windows 95下,這 兩個參數(shù)被忽略。 lpRasDialParams:這個參數(shù)很重要,它指向一個RASDIALPARAMS結(jié)構(gòu),該結(jié)構(gòu)包含以下 幾個成員: dwSize:應設定為sizeof(RASDIALPARAMS); szEntryName和szPhoneNumber:這兩個參數(shù)有聯(lián)系,szEntryName可以指定要建立的連接 ,比方說“我的連接”等等,這是處理用戶已經(jīng)在“撥號網(wǎng)絡”里建立的連接的。這時,Mo dem將撥打你在“我的連接”中設定的ISP號碼,此時szPhoneNumber成員設為空字符串“”即 可;如果你要在程序中自行指定要撥打的ISP號碼的話,szEntryName可以設定為空字符串“ ”,此時應設置szPhoneNumber為你的ISP號碼(169,663等),特別的,對于用201電話卡來 上網(wǎng)的情況,可以設為“201,,,賬號,密碼#,,ISP號碼#”(其中“,”表示停頓一段時 間(以等待確認賬號,密碼等),你可以根據(jù)自己所在位置的線路狀況自行調(diào)節(jié)。 SzCallBackNumber,szDomain:設為空串“”即可。 SzUserName,szPassword:登錄用戶名和密碼。如169公用賬號guest,guest。 其他成員不必設置。 DwNotifierType:指定是由窗口還是由回調(diào)函數(shù)來處理確認消息。通過確認消息我們可 以得到RasDial過程的當前狀態(tài)。如“正在打開段口”,“正在驗證用戶名和密碼”等。也可 設為NULL。 dwNotifier:指定處理確認消息的窗口或回調(diào)函數(shù)。也可設為NULL。 LphRasConn:指向一個類型為HRASCONN的變量。在調(diào)用RasDial前必須指定為NULL,Ras Dial若成功返回,則將RAS連接的句柄存放于它所指向的變量中。我們也可以通過此句柄來斷 開連接。 只要在程序中適當位置調(diào)用RasDial函數(shù)即可建立連接。 2. 理確認消息以得到撥號過程的當前狀態(tài)。 我們以指定窗口來處理確認消息為例說明如何得到撥號過程的當前狀態(tài)。 在處理確認消息的對話框類(或視圖類等)的實現(xiàn)代碼中加入: const UINT WM_RASEVENT = ::RegisterWindowMessageA(RASDIALEVENT); 在Message Map中手工加入消息映射:(****是你定義的對話框類名稱) BEGIN_MESSAGE_MAP(****, CDialog) //AFX_MSG_MAP(****) …… ON_REGISTERED_MESSAGE(WM_RASEVENT, OnRasDialEvent)(<-加入此句) //AFX_MSG_MAP END_MESSAGE_MAP() 加入成員函數(shù)處理消息: LRESULT CDialInfo::OnRasDialEvent(WPARAM wp, LPARAM lp) { RASCONNSTATE rasstate= (RASCONNSTATE)wp; CListBox *info =(CListBox *)GetDlgItem(IDC_INFOLIST); //用ListBox 控件(ID為IDC-INFOLIST)來顯示狀態(tài)) switch(rasstate) { case RASCS_OpenPort: info→AddString(_T(″打開端口……″)); break; case RASCS_PortOpened: info→AddString(_T(″端口已打開.″)); break; case RASCS_ConnectDevice: info→AddString(_T(″連接設備……″)); break; case RASCS_DeviceConnected: info→AddString(_T(″設備已連接.″)); break; case RASCS_Authenticate: info→AddString(_T(″驗證用戶及密碼″)); break; case RASCS_Authenticated: info→AddString(_T(″通過″)); break; case RASCS_Connected: info->AddString(_T(″已連接″)); reak; case RASCS_Disconnected: info->AddString(_T(″連接已斷開″)); m_hRasConn=NULL; //可定義類型為HRASCONN的成員變量m_hRasConn來保存RAS連接的句柄。 //在調(diào)用RasDial時用指向m_hRasConn的指針作為lphRasConn參數(shù)。 //既然用m_hRasConn來保存連接句柄,連接斷開后應重置為NULL. break; default: return (LRESULT)0; } return (LRESULT)0; } 3. 斷開連接: if (m_hRasConn != NULL) { RasHangUp(m_hRasConn); m_hRasConn = NULL; m_OnDial=TRUE; :Sleep(2000); } 注意 : Tag: 編程博客 發(fā)表于 09:42:02 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 詞法分析的C實現(xiàn)(做編譯器的時候很有用) - [ C語言 ] 作者:skyhorsebj email: XUEY@CIDC.COM.CN 日期:2001-7-3 12:41:52 這里以開始定義的PASCAL語言子集的源程序作為詞法分析程序的輸入數(shù)據(jù)。 在詞法分析中,自文件頭開始掃描源程序字符,一旦發(fā)現(xiàn)符合"單詞"定義的源程 序字符串時,將它翻譯成固定長度的單詞內(nèi)部表示,并查填適當?shù)男畔⒈怼=?jīng)過 詞法分析后,源程序字符串(源程序的外部表示)被翻譯成具有等長信息的單詞 串(源程序的內(nèi)部表示),并產(chǎn)生兩個表格:常數(shù)表和標識符表,它們分別包含 了源程序中的所有常數(shù)和所有標識符。 下面就詞法分析程序中的主要變量進行說明: FILE fp :文件指針,用于指向要分析的PASCAL源程序; char *key[8]:指針數(shù)組,用于指向關(guān)鍵字表; char *border[6]:指針數(shù)組,用于指向符號表; char *arithmetic[4]:指針數(shù)組,指向算術(shù)運算符表; char *relation[6]:指針數(shù)組,指向關(guān)系運算符表; char *consts[20]:指針數(shù)組,指向常數(shù)表; char *label[20]:指針數(shù)組,指向標識符表; int constnum,labelnum:整型變量,分別用于存放當前常數(shù)個數(shù)和標 識符個數(shù)。 程序中的主要子函數(shù): alphaprocess:關(guān)鍵字和標識符處理子函數(shù); digitprocess:數(shù)字處理函數(shù); otherprocess:其他字符處理函數(shù); search:查找子函數(shù); 下面簡要分析一下詞法分析程序的運行流程: 主函數(shù)main(): 打開要分析的PASCAL源程序,若不能正確打開,則報錯。 先從源程序中讀入一個字符ch,然后進行如下處理: 1、ch是字符:轉(zhuǎn)入關(guān)鍵字和標識符處理子函數(shù); 2、ch是數(shù)字:轉(zhuǎn)入數(shù)字處理函數(shù); 3、ch是其他字符:轉(zhuǎn)入其他字符處理子函數(shù); 結(jié)束。 關(guān)鍵字和標識符處理子函數(shù)alphaprocess(char buffer); 1、將buffer送入臨時數(shù)組alphatp[0],再讀入一個字符至buffer; 2、判斷buffer是否為字符或數(shù)字,若是,則alphatp[1]=buffer; 3、重復1,2,直到2判斷為假;在alphatp末尾添加’/0’; 4、調(diào)用search()子函數(shù),在關(guān)鍵字表中匹配alphatp,若匹配成功,則返回序號; 5、調(diào)用search,在標識符表中匹配alphatp,若匹配成功,則返回序號; 6、在標識符表中添加alphatp,并返回序號; 其余子函數(shù)的處理方式于alphaprocess類似,此處不再贅述。 [程序調(diào)試] 現(xiàn)有PASCAL程序清單如下: BEGIN IF I=1 THEN I:=I+1 # ELSE *&^ IF I=2 THEN I:=I+11; END. 運行詞法分析程序后,顯示如下結(jié)果: BEGIN (1,1) IF (1,4) I (6,0) = (4,2) 1 (5,0) THEN (1,5) I (6,0) := (2,2) I (6,0) + (3,0) 1 (5,0) # error,not a word ELSE (1,2) * (3,2) & error,not a word ^ error,not a word IF (1,4) I (6,0) = (4,2) 2 (5,1) THEN (1,5) I (6,0) := (2,2) I (6,0) + (3,0) 11 (5,2) ; (2,1) END (1,3) . (2,3) over 結(jié)果完全正確。 源程序: #include #include #include #include #include #define NULL 0 FILE *fp; char cbuffer; char *key[8]={"DO","BEGIN","ELSE","END","IF","THEN","VAR","WHILE"}; char *border[6]={",",";",":=",".","(",")"}; char *arithmetic[4]={"+","-","*","/"}; char *relation[6]={"<","<=","=",">",">=","<>"}; char *consts[20]; char *label[20]; int constnum=0,labelnum=0; int search(char searchchar[],int wordtype) { int i=0; switch (wordtype) { case 1:for (i=0;i<=7;i++) { if (strcmp(key[i],searchchar)==0) return(i+1); }; case 2:{for (i=0;i<=5;i++) { if (strcmp(border[i],searchchar)==0) return(i+1); }; return(0); } case 3:{for (i=0;i<=3;i++) { if (strcmp(arithmetic[i],searchchar)==0) { return(i+1); }; }; return(0); }; case 4:{for (i=0;i<=5;i++) { if (strcmp(relation[i],searchchar)==0) { return(i+1); }; }; return(0); }; case 5:{for (i=0;i<=constnum;i++) { if (strcmp(consts[i],searchchar)==0) { return(i+1); }; } consts[i-1]=(char *)malloc(sizeof(searchchar)); strcpy(consts[i-1],searchchar); constnum++; return(i); }; case 6:{for (i=0;i<=labelnum;i++) { if (strcmp(label[i],searchchar)==0) { return(i+1); }; } label[i-1]=(char *)malloc(sizeof(searchchar)); strcpy(label[i-1],searchchar); labelnum++; return( Tag: 編程博客 發(fā)表于 09:41:30 | 閱讀全文 | 評論 1 | 編輯 | 推薦 2005-10-26 從C到C++看對象的產(chǎn)生 - [ C++ ] 作者:rick1126 email: rickzhang@sina.com 日期:8/8/2001 4:20:33 PM 1. 對象解決了數(shù)據(jù)和方法的封裝以及變量的名字空間問題 1) 名字空間 以前的C里面, 所有變量包括DLL都共享同一個名字空間, 為此你不能保證每一個第三方提供的DLL都是互不沖突的. 2) 封裝, 抽象, 繼承, 多態(tài) [封裝] 封裝是針對對象而言的, 以前我們封裝數(shù)據(jù)和相應操作的方法是利用DLL, 現(xiàn)在我們可以使用對象將相關(guān)數(shù)據(jù)封裝起來. 對象比較DLL更加符合我們顯示世界的認知單位 [抽象] 抽象就是將現(xiàn)實世界中的對象進行一般化, 為此我們通常在進行系統(tǒng)分析和設計的時候, 將最最特殊的問題抽象成為類型 -- 注意, 特殊就是我們所關(guān)心的元素量最少, 最簡單, 由簡到繁的設計方式使得我們的系統(tǒng)更具擴展性. [繼承] 繼承使得對象之間有了聯(lián)系和層次. 通過向類型添加需要關(guān)心的元素, 新的類型派生出來. [多態(tài)] 多態(tài)是現(xiàn)實世界的一種對待問題的方式 2. 從結(jié)構(gòu)的角度看待對象 1) 類就是具有生命力的結(jié)構(gòu) 結(jié)構(gòu)是來自C的用戶自定義類型方式, 加上方法就使得結(jié)構(gòu)實例有了自己的"行為"能力, 成為"活生生"的對象. 這使得它具備了邏輯上的一種認識層次. 從計算機角度看, 結(jié)構(gòu)就是2進制數(shù)據(jù)的結(jié)構(gòu)化存儲, 是對于內(nèi)存空間的一種單元化使用, 添加了方法, 就是附加了相對應的函數(shù)指針, 有了這種認識, 對于我們以后學習COM涉及的虛函數(shù)和VTable都是很有幫助的. class和structure的區(qū)別僅僅在于出現(xiàn)的前后和默認存取類型的不同(class--private, structure--public), 所以我們以后接觸到的COM的interface就是structure的宏定義而已 上面就是目前我對于類和對象的粗淺認識, 希望各位網(wǎng)友指正. Tag: 編程博客 發(fā)表于 09:40:41 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 鼠標屏幕取詞原理 - [ VC專欄 ] 作者:獨孤九劍 email: mikaiyue@sina.com 日期:6/21/2001 10:21:49 AM 鼠標屏幕取詞 原理 “鼠標屏幕取詞”技術(shù)是在電子字典中得到廣泛地應用的,如四通利方和金山詞霸等軟件,這個技術(shù)看似簡單,其實在windows系統(tǒng)中實現(xiàn)卻是非常復雜的,總的來說有兩種實現(xiàn)方式: 第一種:采用截獲對部分gdi的api調(diào)用來實現(xiàn),如textout,textouta等。 第二種:對每個設備上下文(dc)做一分copy,并跟蹤所有修改上下文(dc)的操作。 第二種方法更強大,但兼容性不好,而第一種方法使用的截獲windowsapi的調(diào)用,這項技術(shù)的強大可能遠遠超出了您的想象,毫不夸張的說,利用windowsapi攔截技術(shù),你可以改造整個操作系統(tǒng),事實上很多外掛式windows中文平臺就是這么實現(xiàn)的!而這項技術(shù)也正是這篇文章的主題。 截windowsapi的調(diào)用,具體的說來也可以分為兩種方法: 第一種方法通過直接改寫winapi 在內(nèi)存中的映像,嵌入?yún)R編代碼,使之被調(diào)用時跳轉(zhuǎn)到指定的地址運行來截獲;第二種方法則改寫iat(import address table 輸入地址表),重定向winapi函數(shù)的調(diào)用來實現(xiàn)對winapi的截獲。 第一種方法的實現(xiàn)較為繁瑣,而且在win95、98下面更有難度,這是因為雖然微軟說win16的api只是為了兼容性才保留下來,程序員應該盡可能地調(diào)用32位的api,實際上根本就不是這樣!win 9x內(nèi)部的大部分32位api經(jīng)過變換調(diào)用了同名的16位api,也就是說我們需要在攔截的函數(shù)中嵌入16位匯編代碼! 我們將要介紹的是第二種攔截方法,這種方法在win95、98和nt下面運行都比較穩(wěn)定,兼容性較好。由于需要用到關(guān)于windows虛擬內(nèi)存的管理、打破進程邊界墻、向應用程序的進程空間中注入代碼、pe(portable executable)文件格式和iat(輸入地址表)等較底層的知識,所以我們先對涉及到的這些知識大概地做一個介紹,最后會給出攔截部分的關(guān)鍵代碼。 先說windows虛擬內(nèi)存的管理。windows9x給每一個進程分配了4gb的地址空間,對于nt來說,這個數(shù)字是2gb,系統(tǒng)保留了2gb到 4gb之間的地址空間禁止進程訪問,而在win9x中,2gb到4gb這部分虛擬地址空間實際上是由所有的win32進程所共享的,這部分地址空間加載了共享win32 dll、內(nèi)存映射文件和vxd、內(nèi)存管理器和文件系統(tǒng)碼,win9x中這部分對于每一個進程都是可見的,這也是win9x操作系統(tǒng)不夠健壯的原因。win9x中為16位操作系統(tǒng)保留了0到4mb的地址空間,而在4mb到2gb之間也就是win32進程私有的地址空間,由于 每個進程的地址空間都是相對獨立的,也就是說,如果程序想截獲其它進程中的api調(diào)用,就必須打破進程邊界墻,向其它的進程中注入截獲api調(diào)用的代碼,這項工作我們交給鉤子函數(shù)(setwindowshookex)來完成,關(guān)于如何創(chuàng)建一個包含系統(tǒng)鉤子的動態(tài)鏈接庫,《電腦高手雜志》在第?期已經(jīng)有過專題介紹了,這里就不贅述了。所有系統(tǒng)鉤子的函數(shù)必須要在動態(tài)庫里,這樣的話,當進程隱式或顯式調(diào)用一個動態(tài)庫里的函數(shù)時,系統(tǒng)會把這個動態(tài)庫映射到這個進程的虛擬地址空間里,這使得dll成為進程的一部分,以這個進程的身份執(zhí)行,使用這個進程的堆棧,也就是說動態(tài)鏈接庫中的代碼被鉤子函數(shù)注入了其它gui進程的地址空間(非gui進程,鉤子函數(shù)就無能為力了), 當包含鉤子的dll注入其它進程后,就可以取得映射到這個進程虛擬內(nèi)存里的各個模塊(exe和dll)的基地址,如: hmodule hmodule=getmodulehandle(“mypro.exe”); 在mfc程序中,我們可以用afxgetinstancehandle()函數(shù)來得到模塊的基地址。exe和dll被映射到虛擬內(nèi)存空間的什么地方是由它們的基地址決定的。它們的基地址是在鏈接時由鏈接器決定的。當你新建一個win32工程時,vc++鏈接器使用缺省的基地址0x00400000。可以通過鏈接器的base選項改變模塊的基地址。exe通常被映射到虛擬內(nèi)存的0x00400000處,dll也隨之有不同的基地址,通常被映射到不同進程 的相同的虛擬地址空間處。 系統(tǒng)將exe和dll原封不動映射到虛擬內(nèi)存空間中,它們在內(nèi)存中的結(jié)構(gòu)與磁盤上的靜態(tài)文件結(jié)構(gòu)是一樣的。即pe (portable executable) 文件格式。我們得到了進程模塊的基地址以后,就可以根據(jù)pe文件的格式窮舉這個模塊的image_import_descriptor數(shù)組,看看進程空間中是否引入了我們需要截獲的函數(shù)所在的動態(tài)鏈接庫,比如需要截獲“textouta”,就必須檢查“gdi32.dll”是否被引入了。說到這里,我們有必要介紹一下pe文件的格式,如右圖,這是pe文件格式的大致框圖,最前面是文件頭,我們不必理會,從pe file optional header后面開始,就是文件中各個段的說明,說明后面才是真正的段數(shù)據(jù),而實際上我們關(guān)心的只有一個段,那就是“.idata”段,這個段中包含了所有的引入函數(shù)信息,還有iat(import address table)的rva(relative virtual address)地址。 說到這里,截獲windowsapi的整個原理就要真相大白了。實際上所有進程對給定的api函數(shù)的調(diào)用總是通過pe文件的一個地方來轉(zhuǎn)移的,這就是一個該模塊(可以是exe或dll)的“.idata”段中的iat輸入地址表(import address table)。在那里有所有本模塊調(diào)用的其它dll的函數(shù)名及地址。對其它dll的函數(shù)調(diào)用實際上只是跳轉(zhuǎn)到輸入 Tag: 編程博客 發(fā)表于 09:39:48 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 VC++菜鳥學習手記 - [ VC專欄 ] 作者:pp.boy email: pp.boy@263.net 日期:2000-10-24 0:41:11 今天加入chinaasp的c/c++版,成立了c版菜鳥幫,也自己把自己選為了鳥幫幫主。嘻嘻...開始學習vc++了. 說自己有好菜,可能還沒有人相信,pp.boy只是稍稍懂點c語言,寫過一些dos程序,對于windows程序嘛,嘻嘻....了解的實在是太少了. 那為什么要選vc++呢?好象是在那本書上看到過這樣的話:業(yè)余的程序員用vb;聰明的程序員用delphi;真正的程序員用vc++. pp從很早前就想成為一名程序員,又怪pp天生愚笨,想了好久還是就看上vc++了! 雖然聽說vc難了點,可pp是不畏懼這些的!....嘻嘻...又說了好多廢話. pp可是做事情有三分的沖動的,剛剛加入C鳥幫,馬上就真的干了起來,瞧..從大堆光盤上找來了久違的Y版vc++光盤,迫不及待的就點了setup,...嘎吱...嘎吱..PP的3.2G的硬盤又在叫囂了,哎!找到工作就讓你下崗! VC到是裝好了,可要學習什么了?聽說VC可以有很多用處的啊!見上連上qq向各位大哥大嫂問了問,得知其中的MFC可算是VC的最大特點,也能輕車熟路...哈哈...看中你了! 目標鎖定!開始找資料!PP告訴大家一個的消息,自從前周被"程序員大本營2000"騙去了半月生活費后PP的鍋都不能揭了,哪里有錢買書啊!....只好連上網(wǎng)到什么yesky,vckbase也下了寫東東...一個字...看! 看了良久,PP也是個丈二和尚,干脆就聽chache的教導來個實際的.實踐實踐. 打開VC編輯器,呵呵還算是不陌生,和以前的tc的菜單都差不多,和interdev也很相試,ok沒有問題!打開FILE,在new選項卡上選projects毫不憂郁的用MFC APPWIZARD(EXE)就新建了一個工程.看見屏幕的左邊,出現(xiàn)了三個標簽。InfoView / ClassView / FileView 。ClassView 標簽列出了好多看不懂的類來,FileView 標簽給出了項目中文件的列表。看文件列表把PP下了一跳,有到幾個文件,一個一個打開文件看看...O...我的天啦!...大哥你在哪里?...怎么像main()或是winmain()的都看不到!怎么一回事.這個時候就只有看當下來的電子圖書了!書上說: "用VC++的MFC庫編程與傳統(tǒng)上使用 C 語言直接訪問 Windows API不同是 MFC 已經(jīng)包含和壓縮了所有標準的"樣板文件"代碼,這些代碼是所有用 C 編寫的 Windows 程序所必需的." 嘻嘻...難道說MFC里面的"樣板文件"里就包含了winmain(),我們不需要在寫這樣的程序了?現(xiàn)在就姑且認為是吧. 在看代碼,發(fā)現(xiàn)好多從來都沒有見過的標注,用msdn一個一個的查它是做什么的,搞了半天,msdn和英文詞典都被PP翻攔了也看不懂一二.哎!放棄這條路. 再次連上QQ好容易找才了個好友給了段最簡單的代碼: 1 //hello.cpp 2 #include <afxwin.h> 3 // Declare the application class 4 class CHelloApp : public CWinApp 5 { 6 public: 7 virtual BOOL InitInstance(); 8 }; 9 // Create an instance of the application class 10 CHelloApp HelloApp; 11 // Declare the main window class 12 class CHelloWindow : public CFrameWnd 13 { 14 CStatic* cs; 15 public: 16 CHelloWindow(); 17 }; 18 // The InitInstance function is called each 19 // time the application first executes. 20 BOOL CHelloApp::InitInstance() 21 { 22 m_pMainWnd = new CHelloWindow(); 23 m_pMainWnd->ShowWindow(m_nCmdShow); 24 m_pMainWnd->UpdateWindow(); 25 return TRUE; 26 } 27 // The constructor for the window class 28 CHelloWindow::CHelloWindow() 29 { 30 // Create the window itself 31 Create(NULL, 32 "Hello World!", 33 WS_OVERLAPPEDWINDOW, 34 CRect(0,0,200,200)); 35 // Create a static label 36 cs = new CStatic(); 37 cs->Create("hello world", 38 WS_CHILD|WS_VISIBLE|SS_CENTER, 39 CRect(50,80,150,150), 40 this); 41 } 嘻嘻....怎么像gwbasic一樣有行好啊!..哦..原來是為了好看. 怎么又是一個hello world!這樣的程序? 官它3721啊!先把它編譯連接運行后在說!再次打開VC編輯器,用new -> projects -> win32 application 鍵一個空的工程(an emply project).ok! 存盤后有四個文件(HELLO.OPT、HELLO.NCB、HELLO.DSP 和 HELLO.DSW)這下好了文件比上次少了很多,連*.CPP和*.HPP都沒有! 分別打開這四個文件得知HELLO.DSW是這個工程的工程文件,其它文件有什么用嘛?PP還不知道! 不管了!PP又打開"File"菜單中選擇"New"建了一個文件名為hello.cpp的"Text File".然后將上面的這代碼除開行號后粘貼了進去,然后就開始編譯了!PP的硬盤又好好的響了一陣,哎,看來PP的32M內(nèi)存也該下課了!..開始連接了...哦..我的天啦..怎么有好多錯誤,說是什么標識沒有定義..怎么搞的????又只好問問在線的大哥了..原來還沒有告訴項目要使用MFC庫。按照joker2000說的選擇"Project"菜單的"Settings"。在出現(xiàn)的對話框中選擇"General"標簽。在"Microsoft Foundation Classes"組合框中,選擇"Use MFC in a Shared DLL"后! 重新連接..good !..能夠運行了...好有成就感啊!PP還在沾沾自喜....旁邊一個室友來了一句:這樣的東西用VB就需要 Tag: 編程博客 發(fā)表于 09:38:01 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 vc開發(fā)的域名查詢組件 - [ VC專欄 ] 作者:小牧 email: amumy@sina.com 日期:7/31/2001 12:57:55 AM [#FF0000]轉(zhuǎn)[/#] 一個用vc開發(fā)的域名查詢組件(源代碼及說明) 關(guān)鍵詞:Visual C++ 最近經(jīng)常見到有人問如何在asp中查詢域名是否被注冊,所以寫了這個組件,主要原理就是向gopher站點的whois服務器發(fā)送whois請求,由于沒有太多時間,所以很簡陋,目前只能實現(xiàn)向cnnic查詢,并且返回的信息沒有進行處理,如果你要用的話,清在asp里自己處理一下吧。以后如果有時間將加上過及域名的查詢功能。其實最主要的目的還是給大家做組件提供一點參考,畢竟組件的寫法有些特殊。 下載地址: 組件:http://homepage.qdcatv.com.cn/bigeagle/whois.zip 源代碼:http://homepage.qdcatv.com.cn/bigeagle/whoiscode.zip 組件介紹 域名查詢組件0.01版 組件名稱:WhoIS 描述: 查詢域名是否已注冊,如果注冊,則顯示該域名的信息,包括注冊者的詳細信息。 版本:0.01 (之所以稱為0.01版是因為是在是太簡陋了,目前只能查詢國內(nèi)注冊的站點,也就是以cn結(jié)尾的站點。另外輸出未做處理,需要在外部進行再包裝。實在沒有時間。) 日期:2000/9/15日 作者:bigeagle 使用方法(以asp調(diào)用為例) <% dim m_objDomainInfo ’創(chuàng)建whois對象 set m_objDomainInfo = server.CreateObject ("WhoIs.DomainInfo") ’查詢新浪,你可以改變,但不能加前面的www m_objDomainInfo.GetDomainInfoCn ("cctv.com.CN") if m_objDomainInfo.IfSuccess <> 0 then ’如果成功 Response.Write replace( m_objDomainInfo.DomainInfo , vbcrlf , "<br>") else ’如果失敗 Response.Write "失敗原因:" & m_objDomainInfo.DomainInfo end if set m_objDomain = nothing %> Tag: 編程博客 發(fā)表于 09:37:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 Visual C++實現(xiàn)文件間批量轉(zhuǎn)換功能 - [ VC專欄 ] 作者:skyhorsebj email: XUEY@CIDC.COM.CN 日期:2001-7-3 18:07:19 全部代碼用Visual C++6.0在Windows95/98/2000下編譯通過。 首先用MFC AppWizard生成一個SDI風格的應用程序test,生成過程中全部使用缺省設置。 其次,利用資源編輯器,在主菜單“文件”下增加一個菜單項“轉(zhuǎn)換”,屬性為: ID:ID_CONVERT Caption: 轉(zhuǎn)換 Prompt: 在不同格式文件之間進行轉(zhuǎn)換/n轉(zhuǎn)換文件 然后用“CTRL-W”熱鍵激活MFC ClassWizard,為CmainFrame類增加響應ID_CONVERT消息的命令函數(shù)OnConvert()。加入轉(zhuǎn)換功能的代碼如下所示: void CMainFrame::OnConvert() { LPMALLOC pMalloc;//利用shell擴展功能 BROWSEINFO bi; if (SUCCEEDED(SHGetMalloc(&pMalloc)))//為生成目錄選擇對話框分配自由內(nèi)存 { ZeroMemory(&bi,sizeof(bi));//清零分配的空間 char pszDirName[MAX_PATH];//存放選擇的目錄名 LPITEMIDLIST pidl; bi.hwndOwner = GetSafeHwnd(); bi.pidlRoot = NULL; bi.pszDisplayName = pszDirName; bi.lpszTitle = _T("選擇要批量轉(zhuǎn)換文件所在的目錄"); bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS; bi.lpfn = NULL; bi.lParam = 0; if ((pidl = ::SHBrowseForFolder(&bi)) != NULL)//調(diào)用選擇目錄對話框 { if (::SHGetPathFromIDList(pidl, pszDirName))//獲得所選擇的目錄 { file://設置選擇的目錄為當前目錄,以便查找 SetCurrentDirectory(pszDirName); file://定義一個查找 CFileFind findch1; CString strconv; CString strsour; if(findch1.FindFile("*.CH1"))//在當前目錄進行查找 { CFile SourceFile; CStdioFile TargetFile; BOOL bfindresult; do { file://查找下一個符合條件的文件 bfindresult= findch1.FindNextFile(); file://獲得查找到的文件名 strsour=findch1.GetFilePath(); strconv=strsour; file://把文件名轉(zhuǎn)換為小寫 strconv.MakeLower(); file://把*.ch1類型的文件轉(zhuǎn)換為*.txt strconv.Replace(".ch1",".txt"); file://打開*.ch1類型的文件作為源文件 SourceFile.Open(strsour,CFile::modeRead); file://打開*.txt類型的文件作為目標文件 TargetFile.Open(strconv,CFile::modeCreate|CFile::modeWrite); file://此處調(diào)用*.ch1類型的文件的解碼函數(shù) file://此處調(diào)用轉(zhuǎn)換成文本文件的函數(shù) file://文件使用完畢,要關(guān)閉 SourceFile.Close(); TargetFile.Close(); }while(bfindresult); MessageBox("轉(zhuǎn)換完畢!","轉(zhuǎn)換完畢!",MB_OK); } else { MessageBox("沒找到CH1文件","沒找到",MB_OK); } findch1.Close();//關(guān)閉這個搜索 } pMalloc->Free(pidl);//釋放使用完的資源 } pMalloc->Release();//釋放使用完的資源 } } 編譯并運行程序,選擇“文件”菜單下的“轉(zhuǎn)換”命令, 選擇一個目錄就完成了對此目錄下所有具有.ch1擴展名的文件的轉(zhuǎn)換工作。 Tag: 編程博客 發(fā)表于 09:36:01 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 Visual C++的程序設計技巧(轉(zhuǎn)) - [ VC專欄 ] 作者:skyhorsebj email: XUEY@CIDC.COM.CN 日期:2001-7-3 18:12:19 Microsoft Visual C++是一種可視化編程語言,因功能強大而受到廣大程序設計人員的青睞。但是,由于VC++的應用程序框架結(jié)構(gòu)非常復雜,使得許多初學者望而卻步。本文通過對設置視圖背景顏色和改變對話框標題的幾種實現(xiàn)方法的分析研究,揭示了VC++程序代碼執(zhí)行時的一些本質(zhì)特征和有關(guān)的程序設計技巧,對理解MFC庫的結(jié)構(gòu)和Windows操作系統(tǒng)的內(nèi)部工作方式提供了一定的幫助。 設置視圖背景顏色 對于VC++文檔、視結(jié)構(gòu)中的視圖,從用戶的角度來看,只是可以改變大小、位置的普通窗口,同其他基于Windows應用程序的窗口是一樣的;從程序員的角度來看,視圖并不是普通的窗口,而是從MFC庫中CView類派生的類對象。像任何VC++對象一樣,視圖對象的行為由類的成員函數(shù)(數(shù)據(jù)成員)決定,包括派生類中應用程序定義的函數(shù)和從基類繼承來的函數(shù)。 提出問題 視圖的背景一般來說是白色的,在缺省情況下,它和系統(tǒng)定義的顏色COLOR_WINDOW是一致的。設計者一般會希望自己的程序可以讓用戶輕松地改變窗口背景顏色,或是用漂亮的圖片來充填背景。我們可以用Windows函數(shù)SetSysColors來重新指定COLOR_WINDOW所對應的實際顏色,來達到改變視圖背景顏色的目的。但這樣會同時改變其他應用程序的視圖窗口背景,使得整個Windows系統(tǒng)的顏色設置產(chǎn)生混亂。另外,我們可能會用以下方法來設置視圖的背景顏色,即在CView的OnDraw函數(shù)中添寫如下一段程序代碼: void CTestView::OnDraw(CDC* pDC) { CTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); CRect rectClient; CBrush brushBkColor; GetClientRect(rectClient); brushBkColor.CreateSolidBrush(RGB(255,0,0)); pDC->DPtoLP(rectClient); pDC->FillRect(rectClient,&brushBkColor); … } 這樣可以達到改變當前應用程序的視圖背景的目的,但同時也產(chǎn)生了一些不良影響,使得程序運行效果不盡如人意。 分析問題 我們知道,在VC++的文檔、視結(jié)構(gòu)中,CView的OnDraw函數(shù)用于實現(xiàn)絕大部分圖形繪制的工作。如果用戶改變窗口尺寸,或者顯示隱藏的區(qū)域,OnDraw函數(shù)都將被調(diào)用來重畫窗口。并且,當程序文檔中的數(shù)據(jù)發(fā)生改變時,一般必須通過調(diào)用視圖的Invalidate(或InvalidateRect)成員函數(shù)來通知Windows所發(fā)生的改變,對Invalidate的調(diào)用也會觸發(fā)對OnDraw函數(shù)的調(diào)用。正因為OnDraw函數(shù)被頻繁調(diào)用,所以在其執(zhí)行時,每次都刷新填充一次視圖客戶區(qū)域,便會使屏幕不穩(wěn)定,產(chǎn)生閃爍現(xiàn)象。 筆者通過對VC++應用程序框架結(jié)構(gòu)和Windows消息映射系統(tǒng)的仔細研究,找到另外一種改變視圖背景的方法,其執(zhí)行效果比上述兩種方法都好。其實在程序調(diào)用OnDraw函數(shù)之前,會觸發(fā)一個Windows消息:WM_ERASEBKGND,以擦除視圖刷新區(qū)域。在缺省情況下,Windows系統(tǒng)使用視圖窗口注冊時窗口類中的成員hbrBackground所描述的畫刷來擦除屏幕,這一般會將屏幕刷新成COLOR_WINDOW所對應的顏色。因此,在OnDraw函數(shù)中設置背景顏色的執(zhí)行過程是這樣的:先將屏幕刷新成COLOR_WINDOW所對應的顏色,接著又在OnDraw函數(shù)中填充其他顏色,這正是產(chǎn)生屏幕閃爍的根本原因。 解決問題 通過上述分析,我們應將視圖背景顏色填充移到Windows消息:WM_ERASEBKGND所對應的消息映射函數(shù)中,而不是在OnDraw函數(shù)中。我們可以通過下列步驟實現(xiàn)這一過程:在文檔類中增加一成員變量m_viewBkColor保存當前背景顏色,同時增加兩個成員函數(shù)GetViewBkColor和SetViewBkColor對其進行讀寫操作。這樣做的好處是可以對m_viewBkColor成員進行序列化,將其和文檔聯(lián)系在一起,打開某一文檔時,其背景將和上一次程序操作該文檔時的背景保持一致。在視圖類中為視圖的Windows消息WM_ERASEBKGND增加消息映射函數(shù)OnEraseBkgnd,代碼如下: BOOL CTestView::OnEraseBkgnd(CDC* pDC) { CRect rect; CBrush brush; brush.CreateSolidBrush(GetDocument()->GetViewBkColor()); pDC->GetClipBox(rect); pDC->FillRect(rect,&brush); return true; } 在該函數(shù)中不需要對客戶區(qū)域矩形進行設備坐標到邏輯坐標的轉(zhuǎn)換,并且Windows在調(diào)用該函數(shù)時會自動進行裁剪區(qū)域的計算,使得需要刷新的屏幕面積達到最小。這樣我們可以在程序中通過設計下列菜單函數(shù)輕松地改變視圖背景的顏色,而且運行效果相當令人滿意。 void CTestView::OnChangeViewBkcolor() { CColorDialog cdlg; if(cdlg.DoModal()==IDOK) { GetDocument()->SetViewBkColor (cdlg.GetColor()); InvalidateRect(NULL); } } 改變對話框標題 提出問題 在VC++程序設計過程中經(jīng)常會遇到這樣的情況:執(zhí)行程序的多個地方需要調(diào)用同一個對話框,但在不同的情況下希望給對話框加上不同的標題。開始我們可能會用下面的一段程序以達到這一目的: CTestDialog dlg; dlg.SetWindowText(“標題-1"); dlg.DoModal(); 利用上述辦法,我們本希望在程序不同的地方,通過設置函數(shù)SetWindowText不同的參數(shù),以達到使同一對 Tag: 編程博客 發(fā)表于 09:35:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 Winsocket網(wǎng)絡編程談 - [ VC專欄 ] 作者:五一 日期:00-7-7 下午 02:01:48 (作者:李其 2000年07月07日 13:34) Winsocket編程是非常復雜的,這令一般人望而生畏。但如果你想編寫這樣的程序,又不懂得相關(guān)知識,怎么辦呢?Delphi的網(wǎng)絡組件庫中為我們提供了關(guān)于實現(xiàn)網(wǎng)絡通信的組件,其中ClientSocket和ServerSocket組件使我們能夠很方便地編寫出自己的網(wǎng)絡通信和資源共享程序。 一、設置Winsocket屬性 在Delphi 4.0中,將Winsocket細分為兩種組件:ClientSocket和ServerSocket,它們分別作為客戶端和服務器端的組件。通過這兩種組件之間的通信,再加上輔助的應用程序代碼,就可以實現(xiàn)一個簡單的通信程序。當然,如果你想在客戶端程序中再引入ServerSocket的話,那么客戶端程序就可以充當服務器了,可以對其他的客戶端程序的請求進行響應。 如果正在編寫服務器端程序,就必須設置ServerSocket組件的Port屬性。設置此參數(shù)主要是因為在同一臺計算機上可能運行著多個服務器程序,而它們可能總在不停地接受來自于遠程客戶端程序的連接請求。也可以設置Service屬性,它指示了ServerSocket所提供的服務類型,比如:FTP、HTTP等,然后設置Active屬性為True。 如果正在編寫客戶端程序,則設置ClientServer組件的屬性就多一些。Port屬性應設置成和服務器端的Port屬性值一致,另外Host的屬性必須正確設置,它是一個只讀屬性,在設計時不可用。Host指示了客戶程序所要連接的遠程服務器的主機名。也可以設置Address屬性,也就是遠程主機的IP地址。 二、建立與遠程計算機的連接 要在遠程計算機系統(tǒng)之間進行數(shù)據(jù)傳輸,首先必須在通信的兩臺主機之間建立連接。 服務器端的ServerSocket組件調(diào)用Open方法初始化Socket連接,同時也就設置了Active屬性為True,將ServerSocket組件設置成偵聽模式,隨時偵測是否有連接請求。 如果服務器接受了客戶程序的連接請求,則觸發(fā)OnAccept事件,如下代碼就是處理接受連接后服務器程序所要做的工作。 procedure Myform..ServerSocketAccept(Sender: TObject,Socket: TCustomWinSocket); begin IsServer := True; end; 在客戶端程序中,ClientSocket組件則設置Port、Host等必須的屬性,然后設置Active屬性為True,提出連接請求。 三、計算機之間的數(shù)據(jù)傳輸 一旦服務器端接受了客戶機方面的連接請求,客戶機就可以發(fā)送數(shù)據(jù)。這時,在客戶機和服務器之間就擁有了一個Socket,通過此Socket雙方實現(xiàn)通信。所以Socket屬性很重要,它又擁有很多的方法,用其中的幾個簡單的方法,就可以實現(xiàn)數(shù)據(jù)的發(fā)送和接收。 客戶機端用如下形式:ClientSocket1.socket.sendtext(’string you want to send’); 在服務器端采用如下形式:ServerSocket1.socket.recievetext( str: string); 此函數(shù)返回接收到的字符串的長度,將字符串存儲在變量str中。 上述是數(shù)據(jù)傳輸?shù)淖詈唵蔚睦?#xff0c;你還可以采用Socket屬性所提供的其他方法來實現(xiàn)復雜的數(shù)據(jù)傳輸。 Tag: 編程博客 發(fā)表于 09:34:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 WINDOWS高級窗口的客戶區(qū)域拖動技術(shù)及其應用(轉(zhuǎn)載) - [ VC專欄 ] 作者:chache email: cyzhx@263.net 日期:2000-10-23 17:30:50 作者:宋立波 WINDOWS應用程序窗口一般包括兩種:普通窗口和常居頂層的無標題條高級窗口。前者是 由WINDOWS內(nèi)部功能定制的,它具有WINDOWS應用程序窗口的所有普通特性:具有標題條、窗 口邊框、最大化按鈕、最小化按鈕和系統(tǒng)默認的快捷鍵及鼠標支持功能等,利用鼠標左鍵拖 動該種窗口的標題條可以在屏幕上任意移動窗口,當鼠標光標停在窗口邊框上時可以改變窗 口大小;后者是一種定制的高級窗口,它不具有普通窗口的任何屬性,整個窗口的控制必須 由編程者來一一確定,使用這種窗口的典型實例有WINDOWS中的IME輸入法應用程序、UCWIN4 .0平臺、各種浮動工具箱、OFFICE中的桌面工具欄和第三方開發(fā)的漢字輸入平臺等。 WINDOWS 這種無標題條常居頂層高級窗口的一個顯著特點是,不需改變窗口大小但必須 具有窗口的客戶區(qū)域拖動功能。由于普通窗口的拖動功能是由系統(tǒng)來完成的,編制普通的應 用程序根據(jù)無須考慮客戶區(qū)域拖動問題,因此一般編程人員很難遇到這個問題,更談不上如 何實現(xiàn)這一功能了。開發(fā)者往往希望自己開發(fā)出來的軟件具有經(jīng)典軟件中的窗口客戶區(qū)域拖 動功能,筆者曾經(jīng)利用模仿系統(tǒng)鼠標點擊標題條拖動窗口和WINDOWS系統(tǒng)內(nèi)部提供的API發(fā)送 函數(shù)發(fā)送內(nèi)部拖動命令來實現(xiàn)無標題常居頂層高級窗口的客戶拖動功能,結(jié)果都不理想。后 來只好在窗口函數(shù)中通過直接處理WM_LBUTTONDOWN、WM_MOUSEMOVE和WM_LBUTTONUP消息,自 行控制窗口拖動的客戶命令區(qū)、拖動開始、窗口移動、拖動虛框繪制、虛框移動和拖動結(jié)束 等過程,來實現(xiàn)高級頂層窗口的客戶區(qū)域拖動方案。下面就自己實踐經(jīng)驗詳細介紹實現(xiàn)該方 案的具體方法和主要技巧。 一、WINDOWS檢測客戶拖動命令及鼠標光標動態(tài)提示的實現(xiàn)方法 WINDOWS 無標題條常居頂層高級窗口的客戶區(qū)域一般分為兩種:特定客戶命令區(qū)域和非 特定客戶命令區(qū)域。特定客戶命令區(qū)域是指利用"RECT"定義的特定子矩形區(qū)域,窗口函數(shù)對 發(fā)生在該區(qū)域內(nèi)的鼠標命令進行檢測并處理;非特定客戶命令區(qū)域是指沒有明確定義的窗口 客戶區(qū)域部分,即所有特定客戶命令區(qū)域之外的部分,窗口函數(shù)根據(jù)實際需要來確定是否對 該區(qū)域內(nèi)發(fā)生的鼠標命令進行處理。實現(xiàn)常居頂層高級窗口拖動功能的首要問題,是如何檢 測和處理特定客戶命令區(qū)域和非特定客戶命令區(qū)域內(nèi)的鼠標命令,以及如何利用鼠標光標來 動態(tài)提示用戶此時可以進行窗口的拖動操作。 1、在特定客戶區(qū)域檢測鼠標命令的方法 當窗口中設置了實現(xiàn)拖動功能的圖標命令按鈕時,就必須在資源文件中定義命令按鈕的 特定客戶區(qū)域,該區(qū)域一般也就是顯示命令按鈕中圖標的矩形區(qū)域,這個區(qū)域的定義方法為 "RECT DragRT",其中DragRT為定義的檢測鼠標命令矩形區(qū)域,它用DragRT.LEFT、DragRT.T OP、DragRT.RIGHT和DragRT.BOTTOM四個參數(shù)來描述矩形區(qū)域相對于窗口客戶區(qū)域左上角的相 對坐標值,這四個參數(shù)必須事先定義具體的數(shù)值,也可以利用"SETRECT"函數(shù)直接填充。 窗口函數(shù)在處理鼠標消息WM_LBUTTONDOWN時,在接收系統(tǒng)傳遞的鼠標位置參數(shù)lParam后 ,通過MAKEPOINT( )函數(shù)將其轉(zhuǎn)換為窗口坐標值,利用判斷某坐標點是否位于特定矩形區(qū)域 內(nèi)的函數(shù)PtInRect(),就可以判斷鼠標指針是否點擊在拖動命令按鈕之內(nèi),從而完成窗口拖 動功能的啟動任務。其描述性功能代碼示例如下: case WM_LBUTTONDOWN://鼠標光標點擊處理 POINT pt;//鼠標在屏幕上位置指針,包括pt.X和pt.Y兩個參數(shù), //該指針值利用MAKEPOINT通過lParam參數(shù)轉(zhuǎn)換而來 pt=MAKEPOINT(lParam); //獲取鼠標當前屏幕位置指針 if(PtInRect(&DragRT,pt)){//判斷鼠標是否點擊在拖動按鈕內(nèi) //實現(xiàn)鼠標拖動窗口方案的啟動功能 } else { //進行其它特定或非特定命令客戶區(qū)域判斷處理 } break; 2、在非特定客戶區(qū)域檢測鼠標命令的方法 當窗口應用程序中采取了非特定客戶區(qū)域拖動方法時,必須在資源文件中事先確定各個 特定客戶區(qū)域的矩形坐標,這時非特定客戶區(qū)域是不規(guī)則的區(qū)域,它需要根據(jù)實際的應用程 序窗口及各個命令按鈕矩形區(qū)域來確定,也就是各個命令按鈕相對于窗口矩形區(qū)域的“非” 子集。窗口函數(shù)在處理鼠標消息WM_LBUTTONDOWN時,首先利用函數(shù)PtInRect()判斷當前鼠標 指針是否點擊在各個命令按鈕矩形區(qū)域內(nèi),如果未點擊在任何命令按鈕區(qū)域內(nèi),則可確定鼠 標點擊在非特定客戶區(qū)域內(nèi),從而實現(xiàn)窗口拖動功能的啟動。其描述性功能代碼示例如下: case WM_LBUTTONDOWN: //鼠標光標點擊處理 POINT pt; //定義鼠標在屏幕上的位置指針 pt=MAKEPOINT(lParam); //取得鼠標光標當前位置指針 for(i=0;i if(PtInRect(&DragRT[i],pt)){//DragRT[i]為按鈕矩形數(shù)組 break; //鼠標點擊在其它按鈕上中斷 } } if(i //鼠標點擊在其它特定客戶區(qū)域內(nèi)則處理其它按 Tag: 編程博客 發(fā)表于 09:33:25 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 常量const的使用(編譯自Topica) - [ C語言 ] 作者:rick1126 email: rickzhang@sina.com.cn 日期:2001-4-13 6:27:23 CONST AND PASS-BY-VALUE 使用一個常量前綴(const)可以避免傳址變量的修改: void f(const string & s); 一些開發(fā)者即使針對傳值變量也用 const : void f(const int n); /*n is passed by value, why const?*/ const 是否真的必要? 不, 不需要. 記住, 在你使用傳值變量的時候, 調(diào)用函數(shù)不會修改變量值而僅僅復制它. 進一步講, 根據(jù) C++ 標準, Top-level cv-qualification 前綴是被忽略的. 讓我們解釋這個術(shù)語: "cv-qualification" 指常量和非穩(wěn)定. "Top-level" 意味著參數(shù)不是一個組合或者非完整的類型, 比如: 不是指針, 引用或者數(shù)組. 這樣: void f(int const param1); 還是作為下列方式對待: void f(int param1); 為此, 傳遞一個類型為 ’const int’ 類型的參數(shù)給 void f(int param1); 是允許的: void f(int n); /*non-const parameter*/ int main() { f(1); /*const int; fine*/ } 相反, 下列對于常量的使用則有影響: void f(int *p1); void f(const int *p2); 這里, 常量被用于一個組合類型, 稱之為 int *. 這樣, 不能傳遞類型為"一個指向常量整數(shù)的指針" 給第一個函數(shù) f(). void f(int *p1); /*non const version*/ int n=0; const int *p=&n; f(p); /*error, cannot convert ’const int *’ to ’int *’*/ 作為一個規(guī)則, 如果變量以傳值方式傳遞或者返回不能聲明為常量, 只有針對組合類型使用常量類型. ----------- Danny Kalev Tag: 編程博客 發(fā)表于 09:32:26 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 非法探取密碼的原理及其防范(轉(zhuǎn)) - [ VC專欄 ] 作者:九流 email: molimin@163.net 日期:8/8/2001 11:59:25 AM 一、非法獲取Password的原理: Edit控件是Windows的一個標準控件,當把其Password屬性設為True時,就會將輸入的內(nèi)容屏蔽為星號,從而達到保護的目的。雖然我們看來都是星號,但程序中的Edit控件實際仍是用戶輸入的密碼,應用程序可以獲取該控件中的密碼,其他應用程序也可以通過向其發(fā)送WM_GETTEXT或EM_GETLINE消息來獲取Edit控件中的內(nèi)容。黑客程序正是利用Edit控件的這個特性,當發(fā)現(xiàn)當前探測的窗口是Edit控件并且具有ES_PASSWORD屬性時,則通過SendMessage向此窗口發(fā)送WM_GETTEXT或EM_GETLINE消息,這樣Edit框中的內(nèi)容就一目了然了。 二、黑客軟件工作方法: 首先要取得當前的窗口,并判斷是否是Edit控件,一般多通過鼠標來指定要探測的窗口,例如在WM_MOUSEMOVE消息的響應函數(shù)中進行判斷,現(xiàn)列舉代碼片段如下: //將客戶坐標轉(zhuǎn)換成屏幕坐標 ClientToScreen(&point); //返回一個包含指定屏幕坐標點的窗口 CWnd* pWnd = CWnd::WindowFromPoint(point); if (pWnd) { //獲取窗口句柄 HWND hwndCurr = pWnd->GetSafeHwnd(); if ((::GetWindowThreadProcessId (GetSafeHwnd(), NULL)) != (::GetWindowThreadProcessId (hwndCurr, NULL))) { char lpClassName[255]; //獲取類名 if (::GetClassName(hwndCurr, lpClassName, 255)) { //判斷是否是Edit控件 if (0 == m_strWndClass.CompareNoCase("EDIT")) { //獲取窗口風格 LONG lStyle = ::GetWindowLong(hwndCurr, GWL_STYLE); //如果設置了ES_PASSWORD屬性 if (lStyle & ES_PASSWORD) { char szText[255]; //通過掌握的句柄hwndCurr向此控件發(fā)送WM_GETTEXT消息 ::SendMessage(hwndCurr, WM_GETTEXT, 255, (LPARAM)szText); //密碼已保存在szText中 m_strPassword = szText; } } } } } 上述代碼中值得注意的有以下幾個關(guān)鍵地方: ClientToScreen(&point); CWnd* pWnd = CWnd::WindowFromPoint(point); HWND hwndCurr = pWnd->GetSafeHwnd(); 這三句代碼可以獲取當前鼠標位置所在窗口的窗口句柄,在SendMessage中要用到的。 ::SendMessage(hwndCurr, WM_GETTEXT, 255, (LPARAM)szText); 這便是真正起作用的SendMessage了,其第一個參數(shù)指定了要接收消息的窗口句柄,我們已經(jīng)通過上面的代碼獲取到了,第二個參數(shù)就是讓Edit控件返回字符的WM_GETTEXT消息了,并將得到的內(nèi)容保存在szText中。 三、防范措施 既然我們搞清除了黑客軟件普遍采取的手法,那我們自然能制訂出一套防范其攻擊的措施來。下面我們就要對Password進行保護。 從以上分析我們可以看出:Edit控件的漏洞主要在于沒有對發(fā)送WM_GETTEXT或EM_GETLINE消息者的身份進行檢查,只要能找到Edit窗口句柄,任何進程都可獲取其內(nèi)容。所以必須要對發(fā)送消息者的身份進行驗證,這里給出一種方法來驗證發(fā)送消息者的身份是否合法: 1.創(chuàng)建新CEdit類 從CEdit繼承一個子類CPasswordEdit,申明全局變量g_bSenderIdentity表明消息發(fā)送者的身份: BOOL g_bSenderIdentity; 然后響應CWnd的虛函數(shù)DefWindowProc,在這個回調(diào)函數(shù)中進行身份驗證: LRESULTCPasswordEdit::DefWindowProc (UINTmessage,WPARAMwParam,LPARAMlParam) { //對Edit的內(nèi)容獲取必須通過以下兩個消息之一 if((message==WM_GETTEXT) ||(message==EM_GETLINE)) { //檢查是否為合法 if(!g_bSenderIdentity) { //非法獲取,顯示信息 AfxMessageBox(_T ("報告:正在試圖竊取密碼!")); return 0; } //合法獲取 g_bSenderIdentity=FALSE; } return CEdit::DefWindowProc (message,wParam,lParam); } 2.在數(shù)據(jù)輸入對話框中做些處理 在對話框中申明一個類成員m_edtPassword: CpasswordEdit m_edtPassword; 然后在對話框的OnInitDialog()中加入下列代碼: m_edtPassword.SubclassDlgItem(IDC_EDIT_PASSWORD,this); 將控制與新類做關(guān)聯(lián)。 之后要在對話框的數(shù)據(jù)交換函數(shù)中將身份設為合法: void CDlgInput::DoDataExchange (CDataExchange*pDX) { //如果獲取數(shù)據(jù) //注意:對于CPropertyPage類這里不需要 if (pDX->m_bSaveAndValidate)條件 if(pDX->m_bSaveAndValidate) { g_bSenderIdentity=TRUE; } CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CDlgInput) DDX_Text (pDX,IDC_EDIT_PASSWORD,m_sPassword); //}}AFX_DATA_MAP } 這樣,Password輸入框就擁有了合法身份,會受到保護。 結(jié)論: 以上的方法僅針對VC程序,對于其他語言如VB、Delphi等語言,需要借助VC做一個Password的ActiveX控件,實現(xiàn)方法與上述方法基本類似。以上程序均用VisualC++6.0編制調(diào)試通過。 Tag: 編程博客 發(fā)表于 09:31:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 構(gòu)建穩(wěn)定的服務器端組件的七個步驟(轉(zhuǎn)) - [ VC專欄 ] 作者:poolnet email: poolnet@sina.com 日期:2001-6-19 8:36:36 實現(xiàn)健壯性能的規(guī)則 Hank Marquis 來自于Enterprise Solutions for Microsoft BackOffice and Windows NT Magazine 在你的服務器上安裝了微軟IIS(Internet Information Server),你就可以發(fā)揮ASP(Active Server Pages)的優(yōu)勢了,ASP利用ActiveX組件來為你的網(wǎng)絡應用完成所有種類的工作。盡管你可以在HTML和有ASP頁面的IIS里面使用許多ActiveX組件,服務器端組件也不是運行在一臺服務器上的普通組件。它在運行時不會告訴你同需要特別關(guān)照的產(chǎn)品服務器有關(guān)的任何信息。你將無法做任何事情去改變其對服務器性能、安全和穩(wěn)定性的影響。對服務器端的組件的不恰當選擇可能會導致一些問題,包括速度的明顯下降,安全漏洞或者其它更惡劣的問題。 客戶端的組件在用戶計算機上執(zhí)行。客戶端組件包括絕大多數(shù)我們現(xiàn)在已經(jīng)了解的一些流行組件:標簽控件,文本框,命令按鈕,格子等。這些組件可以通過<OBJECT>標簽和(或)HTML對象語法來包含在客戶端HTML代碼中。 多數(shù)的有用的客戶端組件會提供特定種類的用戶界面。記住,使用客戶端組件就意味著真實組件已經(jīng)被傳到客戶計算機上。尋常的做法就是把組件下載到客戶計算機上。當然,用戶不得不等待下載過程,而且客戶計算機必須被配置為允許下載。 與此形成對比的是,服務器端的組件在服務器計算機上執(zhí)行。服務器端組件也為用戶做一些工作,但卻是在服務器上運行的。你必須認識到這個差異并且相應地編制代碼。服務器端組件為你的整個應用程序封裝了一些邏輯或功能。 當一個用戶使用應用程序時,他將不會真正看到服務器端的組件。這些組件大多數(shù)都可以通過需要使用組件的ASP腳本中的<OBJECT>標識來被包含。你同樣可以通過服務器的CreateObject語法來包含服務器端的組件。 建造健壯的組件 用于創(chuàng)建健壯組件的好材料并不多。但是,我在這里向大家推薦七個關(guān)鍵步驟,它可以幫助你創(chuàng)建穩(wěn)定和安全的服務器端組件,可以很優(yōu)雅地縮放并且維持性能。在創(chuàng)建一個服務器端網(wǎng)絡應用時,你需要把穩(wěn)定,安全和性能放在你心目中的首要位置。 服務器端組件不應該具有GUI(圖形用戶界面)。因為服務器端組件是在服務器上運行,網(wǎng)絡應用的用戶是看不到可能彈出的任何對話的。你的組件需要能夠同腳本和其它組件進行交流,卻無需同用戶交流。避免所有的消息框和其它任何圖形的用戶界面單元。你必須開發(fā)利用返回結(jié)果來同狀態(tài)和其它模塊信息進行交流的代碼。如果什么東西出問題,不要拋出一個錯誤消息或者使用一個消息框,可以返回一個狀態(tài)變量。你需要做的最后一件事是鎖定忙碌服務器等待OK按鈕被按下。 服務器端組件不得被傳遞引用或者傳遞引用給對象。普遍的做法是把控制作為一個參數(shù)傳遞給其它過程或組件。這包括其它對象的引用,比如RecordSets。盡管如此,向網(wǎng)絡中的組件傳遞引用可能導致速度明顯下降,使一個繁忙的服務器更加緩慢,網(wǎng)絡應用程序在響應用戶需求時也表現(xiàn)得更慢。 服務器端組件應該盡可能地少含方法和屬性。每一個方法或?qū)傩缘恼{(diào)用都需要大量處理。因此,一個編寫的好的服務器端組件應該幾乎不含明顯的方法和屬性。組件含有的那些方法和屬性會帶來更多的參數(shù)。具有很多參數(shù)的調(diào)用越少,性能就越好,尤其是你的網(wǎng)絡應用程序需要支持許多用戶時。這個技巧和許多開發(fā)人員的經(jīng)驗是相反的。盡量少的使用帶有許多參數(shù)的調(diào)用也會帶來另外一些問題,這使得編碼和調(diào)試更加困難,但是速度上的改進是與付出的努力相當?shù)摹? 服務器端組件必須實現(xiàn)恰當?shù)木€程模型。利用單線程組件可能導致服務器限制一個線程的會話,這將帶來速度的明顯下降。應該選擇VB的房間模型線程選項并且努力避免單線程組件。但是,VB不能創(chuàng)建你可以在Visual C++里發(fā)現(xiàn)的具有線程選擇范圍的組件,。這一點也表明VB不是一種很合適這項工作的開發(fā)語言。 服務器端組件應該使用早期綁定。如果你的服務器應用程序要擴容,這顯得特別重要。早期綁定的對象在編譯時就擁有引用解析,可以節(jié)省不少執(zhí)行時間。 服務器端組件不能使用在應用程序或會話作用域的聲明中。請注意你的控件是如何被限定作用域的。作用域描述了如何創(chuàng)建一個組件的實例,這對你的服務端組件的成功起著關(guān)鍵作用。正如上月所討論的那樣,存在三種級別的作用域:頁面級,會話級和應用程序級。頁面級作用域?qū)ο罂梢杂庙撁姹旧淼腍TML和ASP腳本代碼來創(chuàng)建。頁面級作用域組件的最佳性能可以通過使用房間線程來得到。而對應用程序級和會話級作用域組件來說,可以通過使用ATL組件的雙線程模型來得到。同作用域結(jié)合的線程模型也影響服務器的安全性能。例如,一個利用應用程序級作用域的房間線程組件在系統(tǒng)安全環(huán)境里運行,但并不是當前用戶的安全環(huán)境。這對那些具有安全意識的人來說可能是一個問題。 為了速度,服務器端組件應該是進程中組件;為了穩(wěn)定,則應該是進程外組件。有兩種方式去創(chuàng)建COM(OLE)服務器--進程中和進程外。在VB里,你用EXE或DLL擴展名去編譯服務器。具有DLL擴展名的OLE服務器就被稱為進程中服務器;而具有EXE擴展名 Tag: 編程博客 發(fā)表于 09:30:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 關(guān)于PostMessage函數(shù)的中文幫助文件 - [ VC專欄 ] 作者:hxfwsk email: hxfwsk@hotmail.com 日期:6/18/2001 2:54:50 PM 關(guān)于PostMessage函數(shù)的中文幫助文件 PostMessage函數(shù)放置(發(fā)送)一個消息到一個隨著創(chuàng)建窗體而創(chuàng)建的消息隊列,而且不會等待線程處理這個消息就返回。消息隊列中的消息會通過調(diào)用GetMessage或PeekMessage函數(shù)取得。 BOOL PostMessage( HWND hWnd, // 目標窗口句柄 UINT Msg, // 要發(fā)送的消息 WPARAM wParam, // 第一個消息參數(shù) LPARAM lParam // 第二個消息參數(shù) ); 參數(shù) hWnd Identifies the window whose window procedure is to receive the message. Two values have special meanings: 接收消息的窗口標識。兩個值有特定的意義。 值 意義 HWND_BROADCAST 消息被發(fā)送到所有系統(tǒng)頂級窗口,包含不可用的和不可視的獨立的窗口,重疊窗口,彈出 窗口。不會被傳遞到子窗口。 NULL 設置為此參數(shù)時,函數(shù)作用類似于PostThreadMessage函數(shù)使用dwThreadId參數(shù),代表當前 線程 Msg 要發(fā)送的消息 wParam 附屬的消息信息 lParam 附屬的消息信息 返回值 成功返回非零值 失敗返回0,可通過GetLastError函數(shù)取得出借信息 Tag: 編程博客 發(fā)表于 09:29:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 關(guān)于ShellExecute函數(shù)的中文說明 - [ VC專欄 ] 作者:hxfwsk email: hxfwsk@hotmail.com 日期:6/18/2001 2:49:35 PM 關(guān)于ShellExecute函數(shù)的中文說明 ShellExecute 函數(shù) 打開或打印一個指定的文件。文件可以是可執(zhí)行文件也可以是一個文檔。請查看關(guān)于ShellExecuteEx的幫助。 HINSTANCE ShellExecute( HWND hwnd, // 主窗口句柄 LPCTSTR lpOperation, // 字符串指針,指定要執(zhí)行的操作 LPCTSTR lpFile, // 字符串指針,指定文件名或目錄名 LPCTSTR lpParameters, // 字符串指針,指定傳給可執(zhí)行文件的參數(shù) LPCTSTR lpDirectory, // 字符串指針,指定缺省目錄 INT nShowCmd // 文件顯示模式 ); 參數(shù) hwnd 指定一個主窗體。這個窗體與應用程序產(chǎn)生的message boxes。例如, lpOperation 一個非空的字符串指針,指定操作方式。有以下操作方式可用 字符串意義 "open" 該函數(shù)打開由lpFile指定的文件,文件可以是一個可執(zhí)行文件,也可以是文檔文件,也可以是一個要打開的目錄。 "print" 該函數(shù)打印由lpFile指定的文件。文件應該是一個文檔文件。如果是一個可執(zhí)行文件則運行這個文件就象指定用"opne"操作方式一樣。 "explore" 函數(shù)打開瀏覽由lpFile指定的目錄窗口。 如果該參數(shù)為NULL,則相當于使用"open"操作方式。 lpFile 一個非空字符串指定要打開或打印的文件,或者是要打開瀏覽的目錄名。該函數(shù)可以打開一個可執(zhí)行文件或一個文檔文件,也可以打印一個文件。 lpParameters 如果lpFile指定一個可執(zhí)行文件,則lpParameters 是一個指向非空字符串的指針,代表要傳給這個應用程序的參數(shù)。 如果lpFile指定一個文檔文件,則其應該為空。 lpDirectory 非空字符串指定缺省目錄 Tag: 編程博客 發(fā)表于 09:28:26 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 回調(diào)方式的事件實現(xiàn) - [ VC專欄 ] 作者:rick1126 email: rickzhang@sina.com 日期:7/7/2001 6:37:45 PM 服務端 -- IDL: // Chapter7_Server.idl : IDL source for Chapter7_Server.dll // // This file will be processed by the MIDL tool to // produce the type library (Chapter7_Server.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; [ object, uuid( 6E8087CE-C144-4eea-B48A-2D9FD376E8FA ), helpstring( "ICallBack Interface" ), pointer_default(unique) ] interface ICallBack: IUnknown //回調(diào)接口 { //事件對應的方法 [helpstring("method ComputationComplete")] HRESULT ComputationComplete( long lResult ); }; [ object, uuid(CE4BD5E1-B808-4617-91F0-2B4728290D4F), helpstring("IMath Interface"), pointer_default(unique) ] interface IMath : IUnknown { //組件自身方法, 如果需要觸發(fā)事件, 需要在適當?shù)牡胤教砑? /* if ( m_pCallBack ) m_pCallBack->ComputationComplete( lResult ); */ [helpstring("method Add")] HRESULT Add([in]long lOp1, [in]long lOp2 ); [helpstring("method Subtract")] HRESULT Subtract([in]long lOp1, [in]long lOp2 ); [helpstring("method Multiply")] HRESULT Multiply([in]long lOp1, [in]long lOp2 ); [helpstring("method Divide")] HRESULT Divide([in]long lOp1, [in]long lOp2 ); //回調(diào)接口維護方法 // 其實其中的ICallBack只是一個ATL的公開的回調(diào)接口, 需要組件提供一個成員變量保存這個ICallBack實例 // 下列函數(shù)的相應實現(xiàn): /* //ICallBack STDMETHODIMP CMath::Advise( ICallBack *pCallBack ) { m_pCallBack = pCallBack; m_pCallBack->AddRef(); return S_OK; } STDMETHODIMP CMath::Unadvise() { m_pCallBack->Release(); m_pCallBack = 0; return S_OK; } */ [helpstring("method Advise")] HRESULT Advise([in]ICallBack* pCallBack); [helpstring("method Unadvise")] HRESULT Unadvise(); }; [ uuid(E208EDBD-30BF-4868-9D46-133E66C60C87), version(1.0), helpstring("Chapter7_Server 1.0 Type Library") ] library CHAPTER7_SERVERLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); [ uuid(F257585E-5190-4E7C-B5B2-990B5FD3DA5C), helpstring("Math Class") ] coclass Math { [default]interface IMath; interface ICallBack; }; }; 事件的好處就是異步... Tag: 編程博客 發(fā)表于 09:27:39 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 基于MFC的大型數(shù)據(jù)文件處理方法 - [ VC專欄 ] 作者:SKYHORSEBJ email: XUEY@CIDC.COM.CN 日期:2001-7-4 17:30:36 在Visual C++中,MFC(微軟基礎類庫)提供了CFile和CStdio File兩個類來進行程序中的文件輸入輸出操作。Cfile類提供了基于二 進制流的文件操作,功能類似于C語言中的fread()和fwrite()函 數(shù)。CStdioFile提供了基于字符串流的文件操作,功能類似于C語言中 的fgets()和fputs()函數(shù)。但是,使用這兩個類進行文件操作時 ,對于一次文件讀寫的數(shù)據(jù)量的大小必須限制在65535字節(jié)以內(nèi)。其原 因是在VC中訪問大于65535字節(jié)的緩沖區(qū)需要Huge型指針,而在CFile 和CStdioFile類中,使用的是Far型的指針。由于Far型指針不具有跨 段尋址的能力,因此限制了一次文件讀寫的長度小于65535字節(jié)。如果 傳遞給CFile和CStdioFile兩個類的成員函數(shù)的數(shù)據(jù)緩沖區(qū)的大小大于 65535字節(jié)的時候,VC就會產(chǎn)生ASSERT錯誤。 筆者在使用Visual C++進行多媒體程序設計的時候,由于程序 處理的數(shù)據(jù)量非常大,所以需要頻繁地讀寫大于65535字節(jié)的數(shù)據(jù)。在 使用CFile和CStdioFile類處理巨型數(shù)據(jù)的時候一般是分段讀寫,筆者 感到這樣的處理方法非常地繁瑣,同時容易導致程序編制錯誤。筆者 在查閱了相關(guān)的文獻以后,找到了使用Visual C++直接讀寫巨型數(shù) 據(jù)的方法。 在MFC的CFile類中提供了兩個未載入文檔的函數(shù),其原型聲明在 AFX.H中。函數(shù)原型如下: DWORD CFile::ReadHuge(void FAR *lpBuffer,DWORD dwCo unt); void CFile::WriteHuge(const void FAR*lpBuffer,DWORD dwCount); 在這兩個函數(shù)內(nèi)部使用的都是Huge型指針來對傳遞的緩沖區(qū)進行 尋址,因此可以讀寫大于65535字節(jié)的巨型數(shù)據(jù)。 對于ReadHuge()和WriteHuge()函數(shù)需要的巨型緩沖區(qū)可以使 用Windows的API函數(shù)GobalAlloc()來創(chuàng)建。 作為一個例子,下面的程序段演示了通過使用Read Tag: 編程博客 發(fā)表于 09:26:27 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 利用鍵盤鉤子在Windows平臺下捕獲鍵盤動作 - [ VC專欄 ] 作者:skyhorsebj email: XUEY@CIDC.COM.CN 日期:2001-7-3 18:10:43 一。我們可以在應用程序中毫不費力的捕獲在本程序窗口上所進行的鍵盤操作,但如果我們想要將此程序作成一個監(jiān)控程序,捕獲在Windows平臺下任意窗口上的鍵盤操作,就需要借助于全局鉤子來實現(xiàn)了。 二、系統(tǒng)鉤子和DLL 鉤子的本質(zhì)是一段用以處理系統(tǒng)消息的程序,通過系統(tǒng)調(diào)用,將其掛入系統(tǒng)。鉤子的種類有很多,每種鉤子可以截獲并處理相應的消息,每當特定的消息發(fā)出,在到達目的窗口之前,鉤子程序先行截獲該消息、得到對此消息的控制權(quán)。此時在鉤子函數(shù)中就可以對截獲的消息進行加工處理,甚至可以強制結(jié)束消息的傳遞。 在本程序中我們需要捕獲在任意窗口上的鍵盤輸入,這就需要采用全局鉤子以便攔截整個系統(tǒng)的消息,而全局鉤子函數(shù)必須以DLL(動態(tài)連接庫)為載體進行封裝,VC6中有三種形式的MFC DLL可供選擇,即Regular statically linked to MFC DLL(標準靜態(tài)鏈接MFC DLL)、Regular using the shared MFC DLL(標準動態(tài)鏈接MFC DLL)以及Extension MFC DLL(擴展MFC DLL)。 在本程序中為方便起見采用了標準靜態(tài)連接MFC DLL。 三、鍵盤鉤子程序示例 本示例程序用到全局鉤子函數(shù),程序分兩部分:可執(zhí)行程序KeyHook和動態(tài)連接庫LaunchDLL。 1、首先編制MFC擴展動態(tài)連接庫LaunchDLL.dll: (1)選擇MFC AppWizard(DLL)創(chuàng)建項目LaunchDLL;在接下來的選項中選擇Regular statically linked to MFC DLL(標準靜態(tài)鏈接MFC DLL)。 (2)在LaunchDLL.h中添加宏定義和待導出函數(shù)的聲明: #define DllExport __declspec(dllexport) …… DllExport void WINAPI InstallLaunchEv(); …… class CLaunchDLLApp : public CWinApp { public: CLaunchDLLApp(); Tag: 編程博客 發(fā)表于 09:25:26 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 連接點的事件實現(xiàn) - [ VC專欄 ] 作者:rick1126 email: rickzhang@sina.com 日期:7/7/2001 6:41:45 PM 服務端 1. 首先保證你創(chuàng)建ATL對象的時候選中了IConnectionPoint的支持 // Chapter7_CPServer.idl : IDL source for Chapter7_CPServer.dll // // This file will be processed by the MIDL tool to // produce the type library (Chapter7_CPServer.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(76E00670-8C03-458D-8A36-AB7E179346CF), dual, helpstring("IMath Interface"), pointer_default(unique) ] interface IMath : IDispatch { [helpstring("method Add")] HRESULT Add([in]long lOp1, [in]long lOp2, [out] long* plResult ); [helpstring("method Subtract")] HRESULT Subtract([in]long lOp1, [in]long lOp2, [out] long* plResult ); [helpstring("method Multiply")] HRESULT Multiply([in]long lOp1, [in]long lOp2, [out] long* plResult ); [helpstring("method Divide")] HRESULT Divide([in]long lOp1, [in]long lOp2, [out] long* plResult ); }; [ uuid(503AB931-AF9A-4CE0-8D34-D106C6341A58), version(1.0), helpstring("Chapter7_CPServer 1.0 Type Library") ] library CHAPTER7_CPSERVERLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); [ uuid(FC5CB2DB-6011-4431-80AA-01E7B60461EC), helpstring("_IMathEvents Interface"), ] dispinterface _IMathEvents//事件接口, 看到了吧_前綴需要注意, 而且它是一個純Dispatch接口 { properties: methods: [id(1),helpstring("method ComputationComplete")] HRESULT ComputationComplete([in]long lResult); }; [ uuid(7A11D9AD-52ED-4A3C-92E4-7AA579713C11), helpstring("Math Class") ] coclass Math { [default] interface IMath; [default,source] dispinterface _IMathEvents; }; }; 客戶端: class CMathEvents: public CComObjectRoot, public _IMathEvents { public: CMathEvents(){} BEGIN_COM_MAP( CMathEvents ) COM_INTERFACE_ENTRY(_IMathEvents) END_COM_MAP() //IMathEvents public: STDMETHODIMP GetTypeInfoCount( UINT* ) { return E_NOTIMPL; } STDMETHODIMP GetTypeInfo( UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo ) { return E_NOTIMPL; } STDMETHODIMP GetIDsOfNames( REFIID riid, LPOLESTR* rgsNames, UINT cNames, LCID lcid, DISPID *rgDispId ) { return E_NOTIMPL; } STDMETHODIMP Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr ) { switch ( dispIdMember) { case 0x1: if ( pDispParams->cArgs!=1 ) return DISP_E_BADPARAMCOUNT; if ( pDispParams->cNamedArgs ) return DISP_E_NONAMEDARGS; HRESULT hr; VARIANTARG var; VariantInit( &var ); hr = VariantChangeTypeEx( &var, &(pDispParams->rgvarg[0]), lcid, 0, VT_I4 ); if ( FAILED( hr ) ) return DISP_E_BADVARTYPE; ComputationComplete( var.lVal ); break; default: DisplayMessage( "Error" ); break; } return S_OK; } STDMETHODIMP ComputationComplete( long lResult ) { char szMsg[128]; sprintf( szMsg, "The result is %d", lResult ); DisplayMessage( szMsg ); return S_OK; } }; Tag: 編程博客 發(fā)表于 09:24:54 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 讓CC++圖形程序獨立運行 - [ C++ ] 作者:star2002 日期:2000-8-18 8:36:41 C/C++語言提供了十分豐富的圖形函數(shù),圖形函數(shù)文件為Graphics.h,使用圖形函數(shù)前須先將屏幕設置為圖形模式,C/C++語言提供了下面的函數(shù): void far initgraph(int far *GD,int far *GM,char *P); 其中,GD和GM分別表示圖形驅(qū)動程序和圖形模式,P指圖形驅(qū)動程序所在的目錄路徑。 圖形驅(qū)動程序由Borland公司(對于Turbo C和Borland C++)提供,同時C/C++語言還提供了退出圖形狀態(tài)的函數(shù)closegraph(),格式為: void far closegraph(void); 許你經(jīng)常在用C/C++語言編寫一些圖形程序,但是總不能脫離C/C++語言環(huán)境獨立運行,我們怎樣來解決呢?下面是實現(xiàn)圖形程序獨立運行的具體步驟: 1.將驅(qū)動程序EGAVGA.BGI轉(zhuǎn)換成目標文件EGAVGA.OBJ: C:/TC>BGIOBJ EGAVGA 按同樣的辦法,將字體文件*.CHR轉(zhuǎn)換成目標文件*.OBJ: C:/TC>BGIOBJ TRIP C:/TC>BGIOBJ LITT C:/TC>BGIOBJ SANS C:/TC>BGIOBJ GOTH 2.將上述建立的OBJ文件加入到GRAPHICS.LIB庫文件中,具體方法如下: C:/TC>TLINK C:/TC/LIB/GRAPHICS.LIB+EGAVGA C:/TC>TLINK C:/TC/LIB/GRAPHICS.LIB+TRIP C:/TC>TLINK C:/TC/LIB/GRAPHICS.LIB+LITT C:/TC>TLINK C:/TC/LIB/GRAPHICS.LIB+SANS C:/TC>TLINK C:/TC/LIB/GRAPHICS.LIB+GOTH 也可以使用TLIB、PRJ程序代替TLINK。 3.在程序中調(diào)用initgraph()函數(shù)前,應加上如下語句: registerbgidriver(EGAVGA-driver); 它通知連接程序把EGAVGA驅(qū)動程序裝入用戶的執(zhí)行程序中,同樣在裝入字體文件之前要加上如下語句: registerbgifont(字體文件名); 4.通過上述處理后,編譯連接后的執(zhí)行程序就可以在任何目錄下運行了。這時,將屏幕初始化為圖形模式的函數(shù)可改寫為: void InitGra(void) {int GD=DETECT,GM; registerbgidriver(EGAVGA_driver); registerbgifont(triplex_font); registerbgifont(small_font); registerbgifont(sansserif_font); registerbgifont(gothic_font); initgraph(&GD,&GM,""); } 按照以上步驟,就能實現(xiàn)圖形程序的獨立運行 Tag: 編程博客 發(fā)表于 09:23:15 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 讓VC中的非模式屬性表PropertySheet出現(xiàn)OKCancelApply按鈕 - [ VC專欄 ] 作者:茶館主人 日期:2001-6-3 20:55:08 讓VC中的非模式屬性表PropertySheet出現(xiàn)OK/Cancel/Apply按鈕 北京商即通數(shù)碼科技有限公司 張宏 很多VC程序員都遇到過這個問題,當建立一個非模式的屬性表(不是向?qū)J?時,此時正常用DoModal()調(diào)用時可以出現(xiàn)的OK/Cancel/Apply等按鈕全都不見了,真讓人郁悶!筆者查找了很多資料,均沒有正確的答案,最后,筆者自己分析,在CPropertySheet調(diào)用初始化對話框CPropertySheet::OnInitDialog()時由于m_psh中自動設置了PSH_MODELESS屬性,導致自動調(diào)整對話框大小,隱藏了對話框中的OK按鈕部分,因此,筆者考慮以下解決辦法: 1.從CPropertySheet派生一個自己的屬性表類,將要加入的頁面作為其成員變量: class CMySheet : public CPropertySheet { DECLARE_DYNAMIC(CMySheet) // Construction public: CMySheet(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); CMySheet(LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); // Attributes public: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMySheet) public: virtual BOOL OnInitDialog(); //}}AFX_VIRTUAL // Implementation public: virtual ~CMySheet(); // Generated message map functions protected: //{{AFX_MSG(CMySheet) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG DECLARE_MESSAGE_MAP() private: void AddPages(); //添加屬性頁 CPage2 page2; //定義屬性頁變量 CPage1 page1; }; 2.添加屬性頁: void CMySheet::AddPages() { AddPage(&page1); AddPage(&page2); } CMySheet::CMySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) :CPropertySheet(nIDCaption, pParentWnd, iSelectPage) { AddPages(); } CMySheet::CMySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) :CPropertySheet(pszCaption, pParentWnd, iSelectPage) { AddPages(); } 3.在屬性頁的初始化對話框中拉大對話框高度,并且將OK/Cancel/Apply按鈕顯示、激活。 BOOL CMySheet::OnInitDialog() { BOOL bResult = CPropertySheet::OnInitDialog(); RECT rc; // 調(diào)整屬性頁對話框的大小 GetWindowRect (&rc); rc.bottom += 30; //窗口向下拉30點,讓OK按扭可以顯示出來 MoveWindow (&rc); //調(diào)整窗口 GetDlgItem(IDOK)->ShowWindow(SW_SHOW); //顯示隱藏的OK按鈕 GetDlgItem(IDOK)->EnableWindow(); //激活OK按鈕 GetDlgItem(IDCANCEL)->ShowWindow(SW_SHOW); //顯示隱藏的Cancel按鈕 GetDlgItem(IDCANCEL)->EnableWindow(); //激活Cancel按鈕 GetDlgItem(ID_APPLY_NOW)->ShowWindow(SW_SHOW); //顯示Apply按鈕 GetDlgItem(ID_APPLY_NOW)->EnableWindow(); //激活Apply按鈕 return bResult; } 好了,在主對話框中加入一個測試按鈕,加入一個CmySheet *sh指針成員變量,并且加入以下代碼: CTestPropertySheetDlg::CTestPropertySheetDlg(CWnd* pParent /*=NULL*/) : CDialog(CTestPropertySheetDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); sh=NULL; } void CTestPropertySheetDlg::OnButton1() { sh=new CMySheet("測試對話框"); sh->Create(this); } void CTestPropertySheetDlg::OnDestroy() { CDialog::OnDestroy(); if (sh) delete sh; } 編譯工程并運行,你看到了什么?OK/Cancel/Apply全都出來了! 可是,點擊OK按鈕看看?怎么?不會關(guān)閉對話框!!! >:-((( 怎么辦?是非模式對話框沒有響應OK按鈕嗎?不是,當前的各屬性頁已經(jīng)得到了OK按鈕事件,但是屬性表沒有對OK按鈕響應,加上對事件的處理以后就可以了: BOOL CMySheet::OnCommand(WPARAM wParam, LPARAM lParam) { if (HIWORD (wParam) == BN_CLICKED) { switch (LOWORD (wParam)) { case IDOK: PressButton (PSBTN_OK); DestroyWindow (); return (TRUE); case ID_APPLY_NOW: // Apply PressButton (PSBTN_APPLYNOW); return (TRUE); case IDCANCEL: PressButton (PSBTN_CANCEL); DestroyWindow (); return (TRUE); case IDHELP: PressButton (PSBTN_HELP); return (TRUE); } } return CPropertySheet::OnCommand(wParam, lParam); } 現(xiàn)在再編譯試試看,一切OK了。 Tag: 編程博客 發(fā)表于 09:22:01 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 如何更改用戶密碼 - [ VC專欄 ] 作者:wgenry email: wgenry@sina.com 日期:2000-8-24 8:19:29 如果你使用ADSI的話 大概應該是這樣的 Set obja = GetObject path ’path 的格式為WINNT://<Domain>/Users/<User>,如果用戶在Users下的話 obja.ChangePassword OldPwd,newPwd 如果用ISAPI或者ASP Component STDMETHODIMP CPwdMgr::ChangePassword(BSTR Domain, BSTR UserName, BSTR OldPwd, BSTR NewPwd, VARIANT_BOOL *RetVal) { HRESULT hr; LPWSTR wUserName; LPWSTR wComputerName = NULL; // default to local machine LPWSTR wDomain; LPWSTR wOldPassword; LPWSTR wNewPassword; USER_INFO_1003 pi1003; NET_API_STATUS nas; _bstr_t bstrDomain,bstrUser,bstrOldPwd,bstrNewPwd; bstrDomain = Domain; bstrUser = UserName; bstrOldPwd = OldPwd; bstrNewPwd = NewPwd; wDomain = (wchar_t*)bstrDomain; wUserName = (wchar_t*)bstrUser; wOldPassword = (wchar_t*)bstrOldPwd; wNewPassword = (wchar_t*)bstrNewPwd; nas = NetGetDCName( NULL, wDomain, (LPBYTE *)&wComputerName ); if(nas != NERR_Success) { if (nas == NERR_DCNotFound) AtlReportError(CLSID_PwdMgr,"Could not find the domain controller for the domain",IID_IPwdMgr,nas); if (nas == ERROR_INVALID_NAME) AtlReportError(CLSID_PwdMgr,"The name could not be found",IID_IPwdMgr,nas); *RetVal = VARIANT_FALSE; return E_FAIL; } if(wOldPassword == NULL) { pi1003.usri1003_password = wNewPassword; nas = NetUserSetInfo( wComputerName, // computer name wUserName, // username 1003, // info level (LPBYTE)&pi1003, // new info NULL ); if (nas != NERR_Success) { switch(nas) { case ERROR_ACCESS_DENIED: AtlReportError(CLSID_PwdMgr,"The user does not have access to the requested information",IID_IPwdMgr,nas); break; case ERROR_INVALID_PARAMETER: AtlReportError(CLSID_PwdMgr,"One of the function parameters is invalid. For more information, see the following Remarks section",IID_IPwdMgr,nas); break; case NERR_InvalidComputer: AtlReportError(CLSID_PwdMgr,"The computer name is invalid",IID_IPwdMgr,nas); break; case NERR_NotPrimary: AtlReportError(CLSID_PwdMgr,"The operation is allowed only on the primary domain controller of the domain",IID_IPwdMgr,nas); break; case NERR_SpeGroupOp: AtlReportError(CLSID_PwdMgr,"The operation is not allowed on specified special groups, which are user groups, admin groups, local groups, or guest groups",IID_IPwdMgr,nas); break; case NERR_LastAdmin: AtlReportError(CLSID_PwdMgr,"The operation is not allowed on the last administrative account",IID_IPwdMgr,nas); break; case NERR_BadPassword: AtlReportError(CLSID_PwdMgr,"The share name or password is invalid",IID_IPwdMgr,nas); break; case NERR_PasswordTooShort: AtlReportError(CLSID_PwdMgr,"The password is shorter than required. (The password could also be too long, be too recent in its change history, not have enough unique characters, or not meet another password policy requirement.)",IID_IPwdMgr,nas); break; case NERR_UserNotFound: AtlReportError(CLSID_PwdMgr,"The user name could not be found",IID_IPwdMgr,nas); break; } } } else { nas = NetUserChangePassword( wComputerName, wUserName, wOldPassword, wNewPassword ); if (nas != NERR_Success) { switch(nas) { case ERROR_ACCESS_DENIED: AtlReportError(CLSID_PwdMgr,"The user does not have access to the requested information",IID_IPwdMgr,nas); break; case ERROR_INVALID_PASSWORD : AtlReportError(CLSID_PwdMgr,"The user has entered an invalid password",IID_IPwdMgr,nas); break; case NERR_InvalidComputer: AtlReportError(CLSID_PwdMgr,"The computer name is invalid",IID_IPwdMgr,nas); break; case NERR_NotPrimary: AtlRepor Tag: 編程博客 發(fā)表于 09:21:22 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 如何用VC++和VFP進行ActiveX數(shù)據(jù)通訊 - [ VC專欄 ] 作者:SKYHORSEBJ email: XUEY@CIDC.COM.CN 日期:2001-7-4 17:31:33 在進行軟件開發(fā)的過程中,如何在不同的編程工具之間進行數(shù)據(jù)交換和通訊,需要進行不斷的探索和總結(jié)。我們在開發(fā)機械CAD仿真軟件的過程中,遇到了在VC++中讀取和修改Visual Foxpro中數(shù)據(jù)的問題。經(jīng)過許多次的試驗,我們通過采用自動服務器(ActiveX Automation)的方法圓滿解決了這個問題。 ---- 自動服務器,以前稱為OLE Automation,后來稱為ActiveX OLE Automation,就是編寫能被其他程序調(diào)用的代碼。其他程序不是以DLL的孤立方式而是直接調(diào)用自動服務器的用戶代碼。這其中比較難理解的概念是:自動服務器用戶代碼向其他應用程序揭示了屬性(變量)和方法(函數(shù))。以下將以整型和雙精度(對浮點型同樣適用)的數(shù)據(jù)傳遞為例,講述如何用ActiveX Automation在VC++和Visual Foxpro之間進行數(shù)據(jù)通訊,例子中的編程工具為VC++ 5.0和Visual Foxpro 5.0。 ---- 一.在Visual Foxpro中創(chuàng)建自動服務器 ---- 1. 在Visual Foxpro中定義服務器類(此例中為CDATA類)首先在某目錄下新建一工程,在工程管理器中選擇代碼欄,同一目錄下新建一程序(如MyServer.prg),并在此程序文件中定義服務器類。 *File Name: MyServer.prg DEFINE CLASS CData AS Custom OLEPUBLIC *對VC++而言, para1為整型, para2為double型 para1=123 para2=123.123 PROCEDURE ChangeData this.para1=this.para1*2 this.para2=this.para2*2 RETURN ENDPROC ENDDEFINE ---- 2. 將上述程序聯(lián)編為可執(zhí)行程序(如MyServer.exe) ---- 選中程序MyServer,點擊“連編”按鈕,選擇“連編可執(zhí)行程序”選項,并按確定,便可生成可執(zhí)行程序。 ---- 二.在VC++中對自動服務器進行測試 ---- 1.關(guān)閉Visual Foxpro,在VC++中選擇菜單項“File-New”,再選擇“Projects”中的“MFC AppWizard (exe)”選項,隨后按默認方式生成“Dialog Based”的工程項目(此例中工程名為MyTest)。 ---- 2.在MyTest.cpp中的APP類的InitInstance()函數(shù)開頭加入OLE使能 BOOL CMyTestApp::InitInstance() { BOOL OleEnable=AfxOleInit(); if(!OleEnable) return FALSE; …… } ---- 3.在ClassWizard中選“Automation”中的“Add Class-From a type library”。在“Import from type library”對話框中找到剛才所創(chuàng)建的Visual Foxpro工程目錄下的tlb文件(如MyServer.tlb)并選擇“打開”按鈕,會有提示說明將要從Lib中生成CDATA類,點擊OK按鈕加以確認,將自動在項目中加入與CDATA類有關(guān)的文件MyServer.cpp和MyServer.h。在ClassView中可查看CDATA類的函數(shù),如GetPara1()、SetPara1()和CHANGEDATA()等。這里要注意類名CDATA和函數(shù)名CHANGEDATA()的大小寫請參看具體的頭文件MyServer.h。 ---- 4.在對話框類(此例中為CMyTestDlg)的頭文件MyTestDlg.h的開頭部分,將CDATA類的頭文件MyServer.h包含進來。隨后定義CDATA類的實例m_data作為對話框類的成員變量。 // MyTestDlg.h : header file #include "myserver.h" …… class CMyTestDlg : public CDialog { // Construction public: CMyTestDlg(CWnd* pParent = NULL); // standard constructor private: CDATA m_data; //定義CDATA類的實例m_data …… } …… ---- 5.在對話框的初始化部分(如InitDialog()函數(shù)中)加入 m_data.CreateDispatch(“MyServer.CDATA); ---- 6.使用自動服務器的通訊編程 ---- 此例中,我們在對話框中設置一命令按鈕“Test”,通過點擊該按鈕來對自動服務器進行測試。 void CMyTestDlg::OnButtonTest() { //首先利用CDATA類的GetPara1() 等取值函數(shù)取出Foxpro中的變量值, //再利用CDATA類SetPara1() 等賦值函數(shù)來修改Foxpro中的這些變量值 //也可以在VC++中調(diào)用CDATA 類的函數(shù)CHANGEDATA()來修改變量值 //定義tagVARIANT型變量, 請參看有關(guān)tagVARINAT的幫助 tagVARIANT mypara1, mypara2; mypara1=m_data.GetPara1(); //讀取Foxpro中的變量值para1 mypara2=m_data.GetPara2(); //讀取Foxpro中的變量值para2 //檢驗讀取數(shù)據(jù)是否正確(Foxpro設定為123和123.123) if(mypara1.iVal==123) MessageBox("mypara1.iVal=123"); if Tag: 編程博客 發(fā)表于 09:20:03 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 什么是C++ - [ C++ ] 作者:rick1126 email: rickzhang@sina.com 日期:8/20/2001 7:20:10 PM C++ 是脫胎自 C 語言的一種中級語言. 從計算機角度看, 它可以嵌入ASM等低端語言; 從面向?qū)ο蟮某绦蛟O計角度看, 它有具備OOP的三個基本特征 -- 抽象, 封裝和繼承; 同時從市場角度來看, 它又不是純面向?qū)ο? 其實那些純粹的面向?qū)ο笳Z言的陣地只是在實驗室. 比較C語言. C++ 的幾個顯著變化或者解決的問題就是 1. 名字空間的問題, 原始的C語言使用公共的名字空間, 這樣無論是開發(fā)本人還是第三方團隊都面臨變量名字耗盡的問題. 而C++提供獨立的名字空間, 而且對象的引入也為名字空間提供了進一步劃分 2. 代碼復用的問題, C語言使用函數(shù)庫的方式或者DLL方式實現(xiàn)代碼復用, 在接口穩(wěn)定的前提下實現(xiàn)內(nèi)部修改和數(shù)據(jù)及其實現(xiàn)的封裝. C++提供了類庫機制實現(xiàn)了具有層次的代碼復用, 和多種繼承機制, 同時重載等各種機制提供了進一步的復用實現(xiàn). 使得類庫和代碼更加容易維護, 雖然建立類庫在人員, 組織等各個方面還是比較麻煩的. 3. 安全機制. 因為有了類機制, 有一些初始化操作可以自動實現(xiàn) 4. 效率問題. 因為C語言本質(zhì)上是站在計算機立場的非常注重效率的問題, 但是事物總是具備矛盾的兩面, 過于偏重效率和軟件危機的出現(xiàn), 反而增加了程序設計的難度. 而OOA的現(xiàn)實世界角度的考慮問題更加貼近自然, 使得代碼或者程序更加具備穩(wěn)定性, 可擴展性和可維護性. 為此, 和經(jīng)典物理同量子物理一樣. C/C++ 今天在不同領域各自發(fā)揮著最大的效率. BTW: 希望各位多多跟貼. 注意主題, 不要跑火車. Tag: 編程博客 發(fā)表于 09:18:57 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 隱藏鼠標 - [ VC專欄 ] 作者:hxfwsk email: hxfwsk@hotmail.com 日期:8/2/2001 4:41:09 PM 如何實現(xiàn)象“超級解霸”中的自動隱藏鼠標功能呢?當我們欣賞VCD時,屏幕中的鼠標常常會影響觀賞效果。當一段時間內(nèi),用戶沒有任何輸入的情況下就自動隱藏鼠標,一旦用戶進行任何輸入立即重新顯示出鼠標即可。程序段如下: 請先添加一個Timer組件,再設置Timer組件的Interval屬性為1000, //---------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; bool MouseHide; void MouseDo(); //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { MouseHide=true; } //--------------------------------------------------------------------- void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { MouseDo(); } //--------------------------------------------------------------------- void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { MouseDo(); } //--------------------------------------------------------------------- void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { MouseDo(); } //--------------------------------------------------------------------- void __fastcall TForm1::Timer1Timer(TObject *Sender) { MouseHide=true; Screen->Cursor=crNone;// 隱藏鼠標 Timer1->Enabled=false; } //--------------------------------------------------------------------- void MouseDo() { if(MouseHide) { Screen->Cursor=crDefault;//顯示鼠標 MouseHide=false; } else Form1->Timer1->Enabled=true; Tag: 編程博客 發(fā)表于 09:15:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 用c寫cgi(轉(zhuǎn)) - [ C語言 ] 作者:chache email: cyzhx@263.net 日期:2000-10-24 2:03:05 三、From輸入的分析和解碼 1.分析名字/值對 當用戶提交一個HTML Form時,Web瀏覽器首先對Form中的數(shù)據(jù)以名字/值對的形式進行編 碼,并發(fā)送給Web服務器,然后由Web服務器傳遞給CGI程序。其格式如下: name1=value1&name2=value2&name3=value3&name4=value4&... 其中名字是Form中定義的INPUT、SELECT或TExtAREA等標置(Tag)名字,值是用戶輸入或選 擇的標置值。這種格式即為URL編碼,程序中需要對其進行分析和解碼。要分析這種數(shù)據(jù)流,C GI程序必須首先將數(shù)據(jù)流分解成一組組的名字/值對。這可以通過在輸入流中查找下面的兩個 字符來完成。 每當找到字符=,標志著一個Form變量名字的結(jié)束;每當找到字符& ,標志著一個Form變量 值的結(jié)束。請注意輸入數(shù)據(jù)的最后一個變量的值不以&結(jié)束。 一旦名字/值對分解后,還必須將輸入中的一些特殊字符轉(zhuǎn)換成相應的ASCII字符。這些特 殊字符是: +:將+轉(zhuǎn)換成空格符; %xx:用其十六進制ASCII碼值表示的特殊字符。根據(jù)值xx將其轉(zhuǎn)換成相應的ASCII字符。 對Form變量名和變量值都要進行這種轉(zhuǎn)換。下面是一個對Form數(shù)據(jù)進行分析并將結(jié)果回 送給Web服務器的CGI程序。 #include <stdio.h> #include <stdlib.h> #include <strings.h> int htoi(char *); main() { int i,n; char c; printf (″Contenttype: text/plain/n/n″); n=0; if (getenv(″CONTENT-LENGTH″)) n=atoi(getenv(″CONTENT-LENGTH″)); for (i=0; i<n;i++){ int is-eq=0; c=getchar(); switch (c){ case ′&′: c=′/n′; break; case ′+′: c=′ ′; break; case ′%′:{ char s[3]; s[0]=getchar(); s[1]=getchar(); s[2]=0; c=htoi(s); i+=2; } break; case ′=′: c=′:′; is-eq=1; break; }; putchar(c); if (is-eq) putchar(′ ′); } putchar (′/n′); fflush(stdout); } /* convert hex string to int */ int htoi(char *s) { char *digits=″0123456789ABCDEF″; if (islower (s[0])) s[0]=toupper(s[0]); if (islower (s[1])) s[1]=toupper(s[1]); return 16 * (strchr(digits, s[0]) -strchr (digits,′0′) ) +(strchr(digits,s[1])-strchr(digits,′0′)); } 上面的程序首先輸出一個MIME頭信息給Web服務器,檢查輸入中的字符數(shù),并循環(huán)檢查每一 個字符。當發(fā)現(xiàn)字符為&時,意味著一個名字/值對的結(jié)束,程序輸出一個空行;當發(fā)現(xiàn)字符為+ 時,將它轉(zhuǎn)換成空格; 當發(fā)現(xiàn)字符為%時,意味著一個兩字符的十六進制值的開始,調(diào)用htoi() 函數(shù)將隨后的兩個字符轉(zhuǎn)換為相應的ASCII字符;當發(fā)現(xiàn)字符為=時,意味著一個名字/值對的名 字部分的結(jié)束,并將它轉(zhuǎn)換成字符:。最后將轉(zhuǎn)換后的字符輸出給Web服務器。 四、產(chǎn)生HTML輸出 CGI程序產(chǎn)生的輸出由兩部分組成:MIME頭信息和實際的信息。兩部分之間以一個空行分 開。我們已經(jīng)看到怎樣使用MIME頭信息″Cont enttype:text/plain/n/n″和printf()、put char()等函數(shù)調(diào)用來輸 出純ASCII文本給Web服務器。實際上,我們也可以使用MIME頭信息″ C ontenttype:text/html/n/n″來輸出HTML源代碼給Web服務器。請注意任何MIME頭信息后必 須有一個空行。一旦發(fā)送這個MIME頭信息給We b服務器后,Web瀏覽器將認為隨后的文本輸出 為HTML源代碼,在HTML源代碼中可以使用任何HTML結(jié)構(gòu),如超鏈、圖像、Form,及對其他CGI程 序的調(diào)用。也就是說,我們可以在CGI程序中動態(tài)產(chǎn)生HTML源代碼輸出 ,下面是一個簡單的例 子。 #include <stdio.h> #include <string.h> main() { printf(″Contenttype:text/html/n/n″); printf(″<html>/n″); printf(″<head><title>an HTML Page From a CGI</title></h ead&g t/n″); printf(″<body><br>/n″); printf(″<h2> This is an HTML page generated from with i n a CGI program.. .</h2>/n″); printf(″<hr><p>/n″); printf(″<a href="../output.html#two"><b> Go back to out put.html pa ge < /b></a>/n″); printf(″</body>/n″); printf(″</html>/n″); fflush(stdout); } 上面的CGI程序簡單地用printf()函數(shù)來產(chǎn)生HTML源代碼。請注意在輸出的字符串中如果 有雙引號,在其前面必須有一個后斜字符/, 這是因為整個HTML代碼串已經(jīng)在雙引號內(nèi),所以H TML代碼串中的雙引號符必須用一個后斜字符/來轉(zhuǎn)義。 五、結(jié)束語 本文詳細分析了用C語言進行CGI程序設計的方法、過程和技巧。C語言的CGI程序雖然執(zhí) 行速度快、可靠性高,但是相對于Perl語 Tag: 編程博客 發(fā)表于 09:14:04 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 用vc6.0編服務器與客戶機互相傳送消息的程序 - [ VC專欄 ] 作者:SKYHORSEBJ email: XUEY@CIDC.COM.CN 日期:2001-7-4 17:34:53 首先介紹服務器程序: ---- 1.創(chuàng)建一個名為"server"的項目,單文檔界面. ---- 2.在serverview.h中加入代碼: #include "winsock.h" 添加變量: CSize sizeTotal;//控制滾動條 intcount;//信息條數(shù) CString m_data[1000];//信息存放 char Hostname[260]; char Hostaddress[20];//主機IP地址 SOCKET m_sock; HANDLE m_hListenThread;//線程 BOOL m_bInitialized;//是否初始化 WSADATAWSAData; BOOL flag; SOCKADDR_IN saClnt; int saClntLen; BOOL Isconnect;//是否連接 ---- 3.在serverview.cpp中重載CServerView()構(gòu)造器,創(chuàng)建并綁定嵌套字: CServerView::CServerView() { // TODO: add construction code here Isconnect=FALSE; flag=FALSE; sizeTotal.cy=350; sizeTotal.cx=300; m_hListenThread; count=5; int status; WSADATA wsaData; m_data[0]="initializing Windows Sockets DLL...."; if((status=WSAStartup(0x0101,&wsaData))==0) { m_data[0]+="Succeeded"; m_bInitialized=TRUE; } else { m_bInitialized=FALSE; } m_sock=socket(AF_INET,SOCK_DGRAM,0); m_data[1]="Creating socket...."; if(m_sock==INVALID_SOCKET) { m_data[1]+="Failed"; } m_data[1]+="Succeeded"; m_data[2]="Binding socket...."; sockaddr_in sa; sa.sin_family=AF_INET; sa.sin_addr.S_un.S_addr=htonl(INADDR_ANY); sa.sin_port=htons(5050); if(bind(m_sock,(PSOCKADDR)&sa,sizeof (sa))==SOCKET_ERROR) { m_data[2]+="Failed"; closesocket(m_sock); } m_data[2]+="Succeeded"; m_data[3]="Creating listener thread...."; unsigned long idThread; m_hListenThread=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)Listen,(void *) this,0,&idThread); if(m_hListenThread) {m_data[3]+="Succeeded"; m_data[4]+="Listening...."; } else m_data[4]+="Failed"; } ---- 4.在析構(gòu)函數(shù)中完成必需的清除操作: CServerView::~CServerView() { if(m_bInitialized) WSACleanup(); closesocket(m_sock); if(m_hListenThread) ::TerminateThread(m_hListenThread,0); } ---- 5.定義接收和處理消息的線程: long WINAPI Listen(CServerView *pView) { char msg[2000]=""; intnchar; SOCKADDR_IN saClnt; int saClntLen; while(1) { saClntLen=sizeof(saClnt); nchar=recvfrom(pView->m_sock,msg,1024,0, (PSOCKADDR)&saClnt,&saClntLen); if(nchar<0) { pView->m_data[pView->count++]+ ="Error in recvfrom/n"; pView->InvalidateRect(NULL); } else { switch(msg[0]) { case’A’: wsprintf(msg,"A: Client from %s attached/n",inet_ntoa(saClnt.sin_addr)); pView->m_data[pView->count++]=msg; pView->flag=TRUE; pView->InvalidateRect(NULL); pView->Isconnect=TRUE; pView->saClnt=saClnt; pView->saClntLen=saClntLen; sendto(pView->m_sock,msg,1024,0, (PSOCKADDR)&saClnt,saClntLen); break; case ’D’: wsprintf(msg,"D: Client form %s detached/n",inet_ntoa(saClnt.sin_addr)); pView->m_data[pView->count++]=msg; pView->flag=TRUE; pView->InvalidateRect(NULL); pView->Isconnect=FALSE; sendto(pView->m_sock,msg,1024,0, (PSOCKADDR)&saClnt,saClntLen); break; case ’R’: saClntLen=sizeof(saClnt); pView->m_data[pView->count++]=msg; pView->flag=TRUE; pView->InvalidateRect(NULL); break; default: break; } } } return(0); } ---- 6.在程序菜單項中添加"本機IP地址": void CServerView::OnIp() { int WSAReturn; WSAReturn=WSAStartup( 0x0101, &WSAData ); if( WSAReturn == 0 ){ gethostname( Hostname, 260 ); struct hostent *pHostEnt; pHostEnt = gethostbyname( Hostname); if( pHostEnt != NULL ){ wsprintf( Hostaddress, "%d.%d.%d.%d", ( pHostEnt->h_addr_list[0][0] & 0x00ff ), ( pHostEnt->h_addr_list[0][1] & 0x00ff ), ( pHostEnt->h_addr_list[0][2] & 0x00ff ), ( pHostEnt->h_addr_list[0][3] & 0x00ff ) ); CString out; out.Format(Hostaddress); AfxMessageBox(out); } } } ---- 7.在程序菜單中添加"發(fā)送消息": void CServerView::OnSendmessage() { // TODO: Add your command handler code here char msg[2000]; Csend Sendmessage; if(Sendmessage.DoModal() ==IDOK&&!Sendmessage.m_Message.IsEmpty()) { wsprintf(msg,"R: "+Sendmessage.m_Message); sendto(m_sock,msg,1024,0, (PSOCKADDR)&saClnt,saClntLen); m_data[count++]=Sendmessage.m_Message; flag=TRUE; InvalidateRect(NULL); } } ---- 8.為發(fā)送消息項添加一 Tag: 編程博客 發(fā)表于 09:13:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦 2005-10-26 有關(guān)ActiveX控件安全注冊的例子 - [ VC專欄 ] 作者:rick1126 email: rickzhang@sina.com 日期:2001-3-26 11:56:16 #include <comcat.h> #include <afxctl.h> #include <objsafe.h> ... / // DllRegisterServer - Adds entries to the system registry /* 原來的代碼(被注釋) STDAPI DllRegisterServer(void) { // registers object, typelib and all interfaces in typelib return _Module.RegisterServer(TRUE); } / // DllUnregisterServer - Removes entries from the system registry STDAPI DllUnregisterServer(void) { return _Module.UnregisterServer(TRUE); } */ //用途: 注冊組件分類 //說明: 組件安全性種類就是通過組件分類的注冊才得以設置組件的安全性 HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription){ //初始化ICatRegister對象實例指針 ICatRegister* pcr = NULL ; HRESULT hr = S_OK ; //獲得ICatRegister對象實例 //說明: 這個接口原來注冊組件分類 hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr); if (FAILED(hr)) return hr; //初始化分類信息 //說明: 確保注冊 HKCR/Component Categories/{..catid...} CATEGORYINFO catinfo; catinfo.catid = catid; catinfo.lcid = 0x0409 ; // english //說明: 確保提供的描述不會超長, 僅僅復制前127個字符 int len = wcslen(catDescription); if (len>127) len = 127; wcsncpy(catinfo.szDescription, catDescription, len); // 確保描述使用"/0"結(jié)束 catinfo.szDescription[len] = ’/0’; hr = pcr->RegisterCategories(1, &catinfo); pcr->Release(); return hr; } //用途: 在已經(jīng)存在的組件分類中進行接口類的注冊 HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid) { ICatRegister* pcr = NULL ; HRESULT hr = S_OK ; //獲得CCM的ICatRegister接口 hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr); if (SUCCEEDED(hr)) { //在組件分類之中注冊接口類 CATID rgcatid[1] ; rgcatid[0] = catid; hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid); } if (pcr != NULL) pcr->Release(); return hr; } //用途: 反注冊已存在組件分類中的接口類 HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid){ ICatRegister* pcr = NULL ; HRESULT hr = S_OK ; //獲得CCM的ICatRegister接口 hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr); if (SUCCEEDED(hr)) { //注銷已存在的組件分類中的接口類 CATID rgcatid[1] ; rgcatid[0] = catid; hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid); } if (pcr != NULL) pcr->Release(); return hr; } //注冊服務器 STDAPI DllRegisterServer(void){ HRESULT hr; // return for safety functions AFX_MANAGE_STATE(_afxModuleAddrThis); /* 原來的代碼 if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid)) return ResultFromScode(SELFREG_E_TYPELIB); if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE)) return ResultFromScode(SELFREG_E_CLASS); */ if (FAILED(_Module.RegisterServer(TRUE))){ AfxMessageBox("注冊類型庫失敗"); } //創(chuàng)建初始化安全組件分類 hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data!"); if (FAILED(hr)) return hr; //在上面的分組之中注冊接口類 hr = RegisterCLSIDInCategory(CLSID_psSub, CATID_SafeForInitializing); if (FAILED(hr)) return hr; //創(chuàng)建腳本編程安全組件分類 hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls safely scriptable!"); if (FAILED(hr)) return hr; //在上面的分組之中注冊接口類 hr = RegisterCLSIDInCategory(CLSID_psSub, CATID_SafeForScripting); if (FAILED(hr)) return hr; return NOERROR; } //用途: 反注冊服務器 STDAPI DllUnregisterServer(void) { HRESULT hr; // HResult used by Safet Tag:
總結(jié)
以上是生活随笔 為你收集整理的VC函数对象模板 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。