日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

VC函数对象模板

發布時間:2024/3/13 c/c++ 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 VC函数对象模板 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • 2005-10-26

    編程技巧 函數對象模板 - [C++]

    作者:rick1126
    email: rickzhang@sina.com.cn
    日期:2001-4-15 9:48:59
    FUNCTION OBJECT BASES
    要將書寫函數對象的進程簡單化, 標準庫提供兩個類模板作為這樣的對象的基類: std::unary_function 和 std::binary_function. 它們都在頭文件 < functional > 中聲明. 根據其命名, unary_function 提供接收一個參數的基函數而 binary_function 提供一個接收兩個參數的基函數.

    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;
    };

    這些模板不提供任何有用的函數體, 它們只是確保參數和返回類型具有統一的命名. 在下面的例子里面, 謂詞 is_vowel 表示一個參數, 繼承自 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: 編程博客 發表于 09:44:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    編程技巧 使用一個模板類實現對于類成員函數的回調執行(編譯自Topica) - [C++]

    作者:rick1126
    email: rickzhang@sina.com
    日期:2001-4-13 9:23:39
    A GENERIC CALLBACK DISPATCHER
    可以創建一個通用的回調模板類進行成員函數的自動回調. 這樣的一個模板將將類作為其成員函數的第一個參數, 第二個參數是一個指向類成員函數的指針. 關鍵在于將第二個參數基于第一個參數如下:

    template < class T, void (T::*F)() > class callback {/**/};

    該模板的實現十分簡單: 它具備一個針對T的引用, 就是所需調用的成員函數的宿主類, 一個跟在其和一個稱之為execute()的成員函數.:

    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;
    };

    要通過一個成員指針調用成員函數, 你必須具有一個針對確定的對象的引用. 這就是為什么模板需要一個 T& 作為成員變量. 現在你需要使用回調模板來執行一個類 A 的成員函數:

    class A
    {
    public:
    void f();
    };

    你不能使用變量操作成員函數地址, 為此使用 & 操作來獲得函數地址. 最后, 傳遞該成員函數的數組對象給模板對象.:

    int main()
    {
    A a; /*first, create an object*/
    callback < A, &A::f > c(a); /*instantiate template*/
    c.execute(); /*invoke a.f()*/
    }

    你可以使用回調模板類結合任意類型的類, 只要其成員函數具有同樣的形式.
    -----------
    Danny Kalev Tag: 編程博客 發表于 09:43:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    撥號上網程序(轉) - [VC專欄]

    作者:chache
    email: cyzhx@263.net
    日期:2000-10-24 1:58:04
    大家知道,在Netants、DownLoad Expert等軟件中都帶有定時撥號上網下載軟件的功能。而
    一般用戶的撥號上網,利用的是Windows的Remote Access Service(RAS,遠程訪問服務)。
    下面介紹一下其在Visual C++下的實現。
      Visual C++為我們提供了包含RAS API聲明的“ras.h″頭文件。要在程序中實現撥號
    上網功能,其大致過程如下:
      1. 利用Modem撥號進行連接,應使用RasDial函數。
      其聲明如下:
      DWORD Ras Dial(LPRASDIALEXTENSIONS lpRas DialExtensions,LPCTSTR lpszPhoneboo
    k,LPRASDIALPARAMS lp Ras DialParams,DWORD dw Notifier Type,LPVOID lpv Notifier,
      LPHRASCONN lph Ras Conn )
      參數說明:
      lpRasDialExtensions和lpszPhonebook:僅在Windows NT下有效,在Windows 95下,這
    兩個參數被忽略。
      lpRasDialParams:這個參數很重要,它指向一個RASDIALPARAMS結構,該結構包含以下
    幾個成員:
      dwSize:應設定為sizeof(RASDIALPARAMS);
      szEntryName和szPhoneNumber:這兩個參數有聯系,szEntryName可以指定要建立的連接
    ,比方說“我的連接”等等,這是處理用戶已經在“撥號網絡”里建立的連接的。這時,Mo
    dem將撥打你在“我的連接”中設定的ISP號碼,此時szPhoneNumber成員設為空字符串“”即
    可;如果你要在程序中自行指定要撥打的ISP號碼的話,szEntryName可以設定為空字符串“
    ”,此時應設置szPhoneNumber為你的ISP號碼(169,663等),特別的,對于用201電話卡來
    上網的情況,可以設為“201,,,賬號,密碼#,,ISP號碼#”(其中“,”表示停頓一段時
    間(以等待確認賬號,密碼等),你可以根據自己所在位置的線路狀況自行調節。
      SzCallBackNumber,szDomain:設為空串“”即可。
      SzUserName,szPassword:登錄用戶名和密碼。如169公用賬號guest,guest。
      其他成員不必設置。
      DwNotifierType:指定是由窗口還是由回調函數來處理確認消息。通過確認消息我們可
    以得到RasDial過程的當前狀態。如“正在打開段口”,“正在驗證用戶名和密碼”等。也可
    設為NULL。
      dwNotifier:指定處理確認消息的窗口或回調函數。也可設為NULL。
      LphRasConn:指向一個類型為HRASCONN的變量。在調用RasDial前必須指定為NULL,Ras
    Dial若成功返回,則將RAS連接的句柄存放于它所指向的變量中。我們也可以通過此句柄來斷
    開連接。
      只要在程序中適當位置調用RasDial函數即可建立連接。
      2. 理確認消息以得到撥號過程的當前狀態。
      我們以指定窗口來處理確認消息為例說明如何得到撥號過程的當前狀態。
      在處理確認消息的對話框類(或視圖類等)的實現代碼中加入:
      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()
      加入成員函數處理消息:
      LRESULT CDialInfo::OnRasDialEvent(WPARAM wp, LPARAM lp)
      {
      RASCONNSTATE rasstate= (RASCONNSTATE)wp;
      CListBox *info =(CListBox *)GetDlgItem(IDC_INFOLIST);
      //用ListBox 控件(ID為IDC-INFOLIST)來顯示狀態)
      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連接的句柄。
      //在調用RasDial時用指向m_hRasConn的指針作為lphRasConn參數。
      //既然用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: 編程博客 發表于 09:42:02 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    詞法分析的C實現(做編譯器的時候很有用) - [C語言]

    作者:skyhorsebj
    email: XUEY@CIDC.COM.CN
    日期:2001-7-3 12:41:52


    這里以開始定義的PASCAL語言子集的源程序作為詞法分析程序的輸入數據。
    在詞法分析中,自文件頭開始掃描源程序字符,一旦發現符合"單詞"定義的源程
    序字符串時,將它翻譯成固定長度的單詞內部表示,并查填適當的信息表。經過
    詞法分析后,源程序字符串(源程序的外部表示)被翻譯成具有等長信息的單詞
    串(源程序的內部表示),并產生兩個表格:常數表和標識符表,它們分別包含
    了源程序中的所有常數和所有標識符。

    下面就詞法分析程序中的主要變量進行說明:
    FILE fp :文件指針,用于指向要分析的PASCAL源程序;
    char *key[8]:指針數組,用于指向關鍵字表;
    char *border[6]:指針數組,用于指向符號表;
    char *arithmetic[4]:指針數組,指向算術運算符表;
    char *relation[6]:指針數組,指向關系運算符表;
    char *consts[20]:指針數組,指向常數表;
    char *label[20]:指針數組,指向標識符表;
    int constnum,labelnum:整型變量,分別用于存放當前常數個數和標
    識符個數。

    程序中的主要子函數:
    alphaprocess:關鍵字和標識符處理子函數;
    digitprocess:數字處理函數;
    otherprocess:其他字符處理函數;
    search:查找子函數;

    下面簡要分析一下詞法分析程序的運行流程:

    主函數main():
    打開要分析的PASCAL源程序,若不能正確打開,則報錯。
    先從源程序中讀入一個字符ch,然后進行如下處理:
    1、ch是字符:轉入關鍵字和標識符處理子函數;
    2、ch是數字:轉入數字處理函數;
    3、ch是其他字符:轉入其他字符處理子函數;
    結束。

    關鍵字和標識符處理子函數alphaprocess(char buffer);
    1、將buffer送入臨時數組alphatp[0],再讀入一個字符至buffer;
    2、判斷buffer是否為字符或數字,若是,則alphatp[1]=buffer;
    3、重復1,2,直到2判斷為假;在alphatp末尾添加’/0’;
    4、調用search()子函數,在關鍵字表中匹配alphatp,若匹配成功,則返回序號;
    5、調用search,在標識符表中匹配alphatp,若匹配成功,則返回序號;
    6、在標識符表中添加alphatp,并返回序號;

    其余子函數的處理方式于alphaprocess類似,此處不再贅述。

    [程序調試]

    現有PASCAL程序清單如下:
    BEGIN
    IF I=1 THEN
    I:=I+1 #
    ELSE *&^
    IF I=2 THEN
    I:=I+11;
    END.

    運行詞法分析程序后,顯示如下結果:

    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

    結果完全正確。

    源程序:
    #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: 編程博客 發表于 09:41:30 | 閱讀全文 | 評論 1 | 編輯 | 推薦
  • 2005-10-26

    從C到C++看對象的產生 - [C++]

    作者:rick1126
    email: rickzhang@sina.com
    日期:8/8/2001 4:20:33 PM
    1. 對象解決了數據和方法的封裝以及變量的名字空間問題
    1) 名字空間
    以前的C里面, 所有變量包括DLL都共享同一個名字空間, 為此你不能保證每一個第三方提供的DLL都是互不沖突的.
    2) 封裝, 抽象, 繼承, 多態
    [封裝]
    封裝是針對對象而言的, 以前我們封裝數據和相應操作的方法是利用DLL, 現在我們可以使用對象將相關數據封裝起來. 對象比較DLL更加符合我們顯示世界的認知單位
    [抽象]
    抽象就是將現實世界中的對象進行一般化, 為此我們通常在進行系統分析和設計的時候, 將最最特殊的問題抽象成為類型 -- 注意, 特殊就是我們所關心的元素量最少, 最簡單, 由簡到繁的設計方式使得我們的系統更具擴展性.
    [繼承]
    繼承使得對象之間有了聯系和層次. 通過向類型添加需要關心的元素, 新的類型派生出來.
    [多態]
    多態是現實世界的一種對待問題的方式

    2. 從結構的角度看待對象
    1) 類就是具有生命力的結構
    結構是來自C的用戶自定義類型方式, 加上方法就使得結構實例有了自己的"行為"能力, 成為"活生生"的對象. 這使得它具備了邏輯上的一種認識層次. 從計算機角度看, 結構就是2進制數據的結構化存儲, 是對于內存空間的一種單元化使用, 添加了方法, 就是附加了相對應的函數指針, 有了這種認識, 對于我們以后學習COM涉及的虛函數和VTable都是很有幫助的. class和structure的區別僅僅在于出現的前后和默認存取類型的不同(class--private, structure--public), 所以我們以后接觸到的COM的interface就是structure的宏定義而已

    上面就是目前我對于類和對象的粗淺認識, 希望各位網友指正. Tag: 編程博客 發表于 09:40:41 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    鼠標屏幕取詞原理 - [VC專欄]

    作者:獨孤九劍
    email: mikaiyue@sina.com
    日期:6/21/2001 10:21:49 AM
    鼠標屏幕取詞 原理
    “鼠標屏幕取詞”技術是在電子字典中得到廣泛地應用的,如四通利方和金山詞霸等軟件,這個技術看似簡單,其實在windows系統中實現卻是非常復雜的,總的來說有兩種實現方式:
    第一種:采用截獲對部分gdi的api調用來實現,如textout,textouta等。
    第二種:對每個設備上下文(dc)做一分copy,并跟蹤所有修改上下文(dc)的操作。
    第二種方法更強大,但兼容性不好,而第一種方法使用的截獲windowsapi的調用,這項技術的強大可能遠遠超出了您的想象,毫不夸張的說,利用windowsapi攔截技術,你可以改造整個操作系統,事實上很多外掛式windows中文平臺就是這么實現的!而這項技術也正是這篇文章的主題。
    截windowsapi的調用,具體的說來也可以分為兩種方法:
    第一種方法通過直接改寫winapi 在內存中的映像,嵌入匯編代碼,使之被調用時跳轉到指定的地址運行來截獲;第二種方法則改寫iat(import address table 輸入地址表),重定向winapi函數的調用來實現對winapi的截獲。
    第一種方法的實現較為繁瑣,而且在win95、98下面更有難度,這是因為雖然微軟說win16的api只是為了兼容性才保留下來,程序員應該盡可能地調用32位的api,實際上根本就不是這樣!win 9x內部的大部分32位api經過變換調用了同名的16位api,也就是說我們需要在攔截的函數中嵌入16位匯編代碼!
    我們將要介紹的是第二種攔截方法,這種方法在win95、98和nt下面運行都比較穩定,兼容性較好。由于需要用到關于windows虛擬內存的管理、打破進程邊界墻、向應用程序的進程空間中注入代碼、pe(portable executable)文件格式和iat(輸入地址表)等較底層的知識,所以我們先對涉及到的這些知識大概地做一個介紹,最后會給出攔截部分的關鍵代碼。
    先說windows虛擬內存的管理。windows9x給每一個進程分配了4gb的地址空間,對于nt來說,這個數字是2gb,系統保留了2gb到 4gb之間的地址空間禁止進程訪問,而在win9x中,2gb到4gb這部分虛擬地址空間實際上是由所有的win32進程所共享的,這部分地址空間加載了共享win32 dll、內存映射文件和vxd、內存管理器和文件系統碼,win9x中這部分對于每一個進程都是可見的,這也是win9x操作系統不夠健壯的原因。win9x中為16位操作系統保留了0到4mb的地址空間,而在4mb到2gb之間也就是win32進程私有的地址空間,由于 每個進程的地址空間都是相對獨立的,也就是說,如果程序想截獲其它進程中的api調用,就必須打破進程邊界墻,向其它的進程中注入截獲api調用的代碼,這項工作我們交給鉤子函數(setwindowshookex)來完成,關于如何創建一個包含系統鉤子的動態鏈接庫,《電腦高手雜志》在第?期已經有過專題介紹了,這里就不贅述了。所有系統鉤子的函數必須要在動態庫里,這樣的話,當進程隱式或顯式調用一個動態庫里的函數時,系統會把這個動態庫映射到這個進程的虛擬地址空間里,這使得dll成為進程的一部分,以這個進程的身份執行,使用這個進程的堆棧,也就是說動態鏈接庫中的代碼被鉤子函數注入了其它gui進程的地址空間(非gui進程,鉤子函數就無能為力了),
    當包含鉤子的dll注入其它進程后,就可以取得映射到這個進程虛擬內存里的各個模塊(exe和dll)的基地址,如:
    hmodule hmodule=getmodulehandle(“mypro.exe”);
    在mfc程序中,我們可以用afxgetinstancehandle()函數來得到模塊的基地址。exe和dll被映射到虛擬內存空間的什么地方是由它們的基地址決定的。它們的基地址是在鏈接時由鏈接器決定的。當你新建一個win32工程時,vc++鏈接器使用缺省的基地址0x00400000。可以通過鏈接器的base選項改變模塊的基地址。exe通常被映射到虛擬內存的0x00400000處,dll也隨之有不同的基地址,通常被映射到不同進程
    的相同的虛擬地址空間處。
    系統將exe和dll原封不動映射到虛擬內存空間中,它們在內存中的結構與磁盤上的靜態文件結構是一樣的。即pe (portable executable) 文件格式。我們得到了進程模塊的基地址以后,就可以根據pe文件的格式窮舉這個模塊的image_import_descriptor數組,看看進程空間中是否引入了我們需要截獲的函數所在的動態鏈接庫,比如需要截獲“textouta”,就必須檢查“gdi32.dll”是否被引入了。說到這里,我們有必要介紹一下pe文件的格式,如右圖,這是pe文件格式的大致框圖,最前面是文件頭,我們不必理會,從pe file optional header后面開始,就是文件中各個段的說明,說明后面才是真正的段數據,而實際上我們關心的只有一個段,那就是“.idata”段,這個段中包含了所有的引入函數信息,還有iat(import address table)的rva(relative virtual address)地址。
    說到這里,截獲windowsapi的整個原理就要真相大白了。實際上所有進程對給定的api函數的調用總是通過pe文件的一個地方來轉移的,這就是一個該模塊(可以是exe或dll)的“.idata”段中的iat輸入地址表(import address table)。在那里有所有本模塊調用的其它dll的函數名及地址。對其它dll的函數調用實際上只是跳轉到輸入 Tag: 編程博客 發表于 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++呢?好象是在那本書上看到過這樣的話:業余的程序員用vb;聰明的程序員用delphi;真正的程序員用vc++. pp從很早前就想成為一名程序員,又怪pp天生愚笨,想了好久還是就看上vc++了! 雖然聽說vc難了點,可pp是不畏懼這些的!....嘻嘻...又說了好多廢話.
    pp可是做事情有三分的沖動的,剛剛加入C鳥幫,馬上就真的干了起來,瞧..從大堆光盤上找來了久違的Y版vc++光盤,迫不及待的就點了setup,...嘎吱...嘎吱..PP的3.2G的硬盤又在叫囂了,哎!找到工作就讓你下崗!
    VC到是裝好了,可要學習什么了?聽說VC可以有很多用處的啊!見上連上qq向各位大哥大嫂問了問,得知其中的MFC可算是VC的最大特點,也能輕車熟路...哈哈...看中你了!
    目標鎖定!開始找資料!PP告訴大家一個的消息,自從前周被"程序員大本營2000"騙去了半月生活費后PP的鍋都不能揭了,哪里有錢買書啊!....只好連上網到什么yesky,vckbase也下了寫東東...一個字...看!
    看了良久,PP也是個丈二和尚,干脆就聽chache的教導來個實際的.實踐實踐.
    打開VC編輯器,呵呵還算是不陌生,和以前的tc的菜單都差不多,和interdev也很相試,ok沒有問題!打開FILE,在new選項卡上選projects毫不憂郁的用MFC APPWIZARD(EXE)就新建了一個工程.看見屏幕的左邊,出現了三個標簽。InfoView / ClassView / FileView 。ClassView 標簽列出了好多看不懂的類來,FileView 標簽給出了項目中文件的列表。看文件列表把PP下了一跳,有到幾個文件,一個一個打開文件看看...O...我的天啦!...大哥你在哪里?...怎么像main()或是winmain()的都看不到!怎么一回事.這個時候就只有看當下來的電子圖書了!書上說: "用VC++的MFC庫編程與傳統上使用 C 語言直接訪問 Windows API不同是 MFC 已經包含和壓縮了所有標準的"樣板文件"代碼,這些代碼是所有用 C 編寫的 Windows 程序所必需的." 嘻嘻...難道說MFC里面的"樣板文件"里就包含了winmain(),我們不需要在寫這樣的程序了?現在就姑且認為是吧.
    在看代碼,發現好多從來都沒有見過的標注,用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內存也該下課了!..開始連接了...哦..我的天啦..怎么有好多錯誤,說是什么標識沒有定義..怎么搞的????又只好問問在線的大哥了..原來還沒有告訴項目要使用MFC庫。按照joker2000說的選擇"Project"菜單的"Settings"。在出現的對話框中選擇"General"標簽。在"Microsoft Foundation Classes"組合框中,選擇"Use MFC in a Shared DLL"后! 重新連接..good !..能夠運行了...好有成就感啊!PP還在沾沾自喜....旁邊一個室友來了一句:這樣的東西用VB就需要 Tag: 編程博客 發表于 09:38:01 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    vc開發的域名查詢組件 - [VC專欄]

    作者:小牧
    email: amumy@sina.com
    日期:7/31/2001 12:57:55 AM
    [#FF0000]轉[/#]


    一個用vc開發的域名查詢組件(源代碼及說明)

    關鍵詞:Visual C++

    最近經常見到有人問如何在asp中查詢域名是否被注冊,所以寫了這個組件,主要原理就是向gopher站點的whois服務器發送whois請求,由于沒有太多時間,所以很簡陋,目前只能實現向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版是因為是在是太簡陋了,目前只能查詢國內注冊的站點,也就是以cn結尾的站點。另外輸出未做處理,需要在外部進行再包裝。實在沒有時間。)

    日期:2000/9/15日

    作者:bigeagle


    使用方法(以asp調用為例)

    <%
    dim m_objDomainInfo

    ’創建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: 編程博客 發表于 09:37:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    Visual C++實現文件間批量轉換功能 - [VC專欄]

    作者:skyhorsebj
    email: XUEY@CIDC.COM.CN
    日期:2001-7-3 18:07:19
    全部代碼用Visual C++6.0在Windows95/98/2000下編譯通過。


      首先用MFC AppWizard生成一個SDI風格的應用程序test,生成過程中全部使用缺省設置。

      其次,利用資源編輯器,在主菜單“文件”下增加一個菜單項“轉換”,屬性為:

       ID:ID_CONVERT

       Caption: 轉換

       Prompt: 在不同格式文件之間進行轉換/n轉換文件

      然后用“CTRL-W”熱鍵激活MFC ClassWizard,為CmainFrame類增加響應ID_CONVERT消息的命令函數OnConvert()。加入轉換功能的代碼如下所示:

       void CMainFrame::OnConvert()
        {
         LPMALLOC pMalloc;//利用shell擴展功能
         BROWSEINFO bi;
         if (SUCCEEDED(SHGetMalloc(&pMalloc)))//為生成目錄選擇對話框分配自由內存
          {
           ZeroMemory(&bi,sizeof(bi));//清零分配的空間
           char pszDirName[MAX_PATH];//存放選擇的目錄名
           LPITEMIDLIST pidl;
           bi.hwndOwner = GetSafeHwnd();
           bi.pidlRoot = NULL;
           bi.pszDisplayName = pszDirName;
           bi.lpszTitle = _T("選擇要批量轉換文件所在的目錄");
           bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
           bi.lpfn = NULL;
           bi.lParam = 0;
           if ((pidl = ::SHBrowseForFolder(&bi)) != NULL)//調用選擇目錄對話框
            {
             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://把文件名轉換為小寫
                  strconv.MakeLower();
                  file://把*.ch1類型的文件轉換為*.txt
                  strconv.Replace(".ch1",".txt");
                  file://打開*.ch1類型的文件作為源文件
                  SourceFile.Open(strsour,CFile::modeRead);
                  file://打開*.txt類型的文件作為目標文件
                  TargetFile.Open(strconv,CFile::modeCreate|CFile::modeWrite);

                  file://此處調用*.ch1類型的文件的解碼函數
                  file://此處調用轉換成文本文件的函數
                  file://文件使用完畢,要關閉
                  SourceFile.Close();
                  TargetFile.Close();
                 }while(bfindresult);
                 MessageBox("轉換完畢!","轉換完畢!",MB_OK);
                }
              else
               {
                MessageBox("沒找到CH1文件","沒找到",MB_OK);
               }
              findch1.Close();//關閉這個搜索
             }
            pMalloc->Free(pidl);//釋放使用完的資源
            }
           pMalloc->Release();//釋放使用完的資源
          }
         }

      編譯并運行程序,選擇“文件”菜單下的“轉換”命令, 選擇一個目錄就完成了對此目錄下所有具有.ch1擴展名的文件的轉換工作。

    Tag: 編程博客 發表于 09:36:01 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    Visual C++的程序設計技巧(轉) - [VC專欄]

    作者:skyhorsebj
    email: XUEY@CIDC.COM.CN
    日期:2001-7-3 18:12:19
    Microsoft Visual C++是一種可視化編程語言,因功能強大而受到廣大程序設計人員的青睞。但是,由于VC++的應用程序框架結構非常復雜,使得許多初學者望而卻步。本文通過對設置視圖背景顏色和改變對話框標題的幾種實現方法的分析研究,揭示了VC++程序代碼執行時的一些本質特征和有關的程序設計技巧,對理解MFC庫的結構和Windows操作系統的內部工作方式提供了一定的幫助。
    設置視圖背景顏色
    對于VC++文檔、視結構中的視圖,從用戶的角度來看,只是可以改變大小、位置的普通窗口,同其他基于Windows應用程序的窗口是一樣的;從程序員的角度來看,視圖并不是普通的窗口,而是從MFC庫中CView類派生的類對象。像任何VC++對象一樣,視圖對象的行為由類的成員函數(數據成員)決定,包括派生類中應用程序定義的函數和從基類繼承來的函數。
    提出問題
    視圖的背景一般來說是白色的,在缺省情況下,它和系統定義的顏色COLOR_WINDOW是一致的。設計者一般會希望自己的程序可以讓用戶輕松地改變窗口背景顏色,或是用漂亮的圖片來充填背景。我們可以用Windows函數SetSysColors來重新指定COLOR_WINDOW所對應的實際顏色,來達到改變視圖背景顏色的目的。但這樣會同時改變其他應用程序的視圖窗口背景,使得整個Windows系統的顏色設置產生混亂。另外,我們可能會用以下方法來設置視圖的背景顏色,即在CView的OnDraw函數中添寫如下一段程序代碼:
    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);

    }
    這樣可以達到改變當前應用程序的視圖背景的目的,但同時也產生了一些不良影響,使得程序運行效果不盡如人意。
    分析問題
    我們知道,在VC++的文檔、視結構中,CView的OnDraw函數用于實現絕大部分圖形繪制的工作。如果用戶改變窗口尺寸,或者顯示隱藏的區域,OnDraw函數都將被調用來重畫窗口。并且,當程序文檔中的數據發生改變時,一般必須通過調用視圖的Invalidate(或InvalidateRect)成員函數來通知Windows所發生的改變,對Invalidate的調用也會觸發對OnDraw函數的調用。正因為OnDraw函數被頻繁調用,所以在其執行時,每次都刷新填充一次視圖客戶區域,便會使屏幕不穩定,產生閃爍現象。
    筆者通過對VC++應用程序框架結構和Windows消息映射系統的仔細研究,找到另外一種改變視圖背景的方法,其執行效果比上述兩種方法都好。其實在程序調用OnDraw函數之前,會觸發一個Windows消息:WM_ERASEBKGND,以擦除視圖刷新區域。在缺省情況下,Windows系統使用視圖窗口注冊時窗口類中的成員hbrBackground所描述的畫刷來擦除屏幕,這一般會將屏幕刷新成COLOR_WINDOW所對應的顏色。因此,在OnDraw函數中設置背景顏色的執行過程是這樣的:先將屏幕刷新成COLOR_WINDOW所對應的顏色,接著又在OnDraw函數中填充其他顏色,這正是產生屏幕閃爍的根本原因。
    解決問題
    通過上述分析,我們應將視圖背景顏色填充移到Windows消息:WM_ERASEBKGND所對應的消息映射函數中,而不是在OnDraw函數中。我們可以通過下列步驟實現這一過程:在文檔類中增加一成員變量m_viewBkColor保存當前背景顏色,同時增加兩個成員函數GetViewBkColor和SetViewBkColor對其進行讀寫操作。這樣做的好處是可以對m_viewBkColor成員進行序列化,將其和文檔聯系在一起,打開某一文檔時,其背景將和上一次程序操作該文檔時的背景保持一致。在視圖類中為視圖的Windows消息WM_ERASEBKGND增加消息映射函數OnEraseBkgnd,代碼如下:
    BOOL CTestView::OnEraseBkgnd(CDC* pDC)
    {
    CRect rect;
    CBrush brush;
    brush.CreateSolidBrush(GetDocument()->GetViewBkColor());
    pDC->GetClipBox(rect);
    pDC->FillRect(rect,&brush);
    return true;
    }
    在該函數中不需要對客戶區域矩形進行設備坐標到邏輯坐標的轉換,并且Windows在調用該函數時會自動進行裁剪區域的計算,使得需要刷新的屏幕面積達到最小。這樣我們可以在程序中通過設計下列菜單函數輕松地改變視圖背景的顏色,而且運行效果相當令人滿意。
    void CTestView::OnChangeViewBkcolor()
    {
    CColorDialog cdlg;
    if(cdlg.DoModal()==IDOK)
    {
    GetDocument()->SetViewBkColor
    (cdlg.GetColor());
    InvalidateRect(NULL);
    }
    }
    改變對話框標題
    提出問題
    在VC++程序設計過程中經常會遇到這樣的情況:執行程序的多個地方需要調用同一個對話框,但在不同的情況下希望給對話框加上不同的標題。開始我們可能會用下面的一段程序以達到這一目的:
    CTestDialog dlg;
    dlg.SetWindowText(“標題-1");
    dlg.DoModal();
    利用上述辦法,我們本希望在程序不同的地方,通過設置函數SetWindowText不同的參數,以達到使同一對 Tag: 編程博客 發表于 09:35:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    Winsocket網絡編程談 - [VC專欄]

    作者:五一
    日期:00-7-7 下午 02:01:48
    (作者:李其 2000年07月07日 13:34)

      Winsocket編程是非常復雜的,這令一般人望而生畏。但如果你想編寫這樣的程序,又不懂得相關知識,怎么辦呢?Delphi的網絡組件庫中為我們提供了關于實現網絡通信的組件,其中ClientSocket和ServerSocket組件使我們能夠很方便地編寫出自己的網絡通信和資源共享程序。

      一、設置Winsocket屬性

      在Delphi 4.0中,將Winsocket細分為兩種組件:ClientSocket和ServerSocket,它們分別作為客戶端和服務器端的組件。通過這兩種組件之間的通信,再加上輔助的應用程序代碼,就可以實現一個簡單的通信程序。當然,如果你想在客戶端程序中再引入ServerSocket的話,那么客戶端程序就可以充當服務器了,可以對其他的客戶端程序的請求進行響應。

      如果正在編寫服務器端程序,就必須設置ServerSocket組件的Port屬性。設置此參數主要是因為在同一臺計算機上可能運行著多個服務器程序,而它們可能總在不停地接受來自于遠程客戶端程序的連接請求。也可以設置Service屬性,它指示了ServerSocket所提供的服務類型,比如:FTP、HTTP等,然后設置Active屬性為True。

      如果正在編寫客戶端程序,則設置ClientServer組件的屬性就多一些。Port屬性應設置成和服務器端的Port屬性值一致,另外Host的屬性必須正確設置,它是一個只讀屬性,在設計時不可用。Host指示了客戶程序所要連接的遠程服務器的主機名。也可以設置Address屬性,也就是遠程主機的IP地址。

      二、建立與遠程計算機的連接

      要在遠程計算機系統之間進行數據傳輸,首先必須在通信的兩臺主機之間建立連接。

      服務器端的ServerSocket組件調用Open方法初始化Socket連接,同時也就設置了Active屬性為True,將ServerSocket組件設置成偵聽模式,隨時偵測是否有連接請求。

      如果服務器接受了客戶程序的連接請求,則觸發OnAccept事件,如下代碼就是處理接受連接后服務器程序所要做的工作。

      procedure Myform..ServerSocketAccept(Sender: TObject,Socket: TCustomWinSocket);

      begin

      IsServer := True;

      end;

      在客戶端程序中,ClientSocket組件則設置Port、Host等必須的屬性,然后設置Active屬性為True,提出連接請求。

      三、計算機之間的數據傳輸

      一旦服務器端接受了客戶機方面的連接請求,客戶機就可以發送數據。這時,在客戶機和服務器之間就擁有了一個Socket,通過此Socket雙方實現通信。所以Socket屬性很重要,它又擁有很多的方法,用其中的幾個簡單的方法,就可以實現數據的發送和接收。

      客戶機端用如下形式:ClientSocket1.socket.sendtext(’string you want to send’);

      在服務器端采用如下形式:ServerSocket1.socket.recievetext( str: string);

      此函數返回接收到的字符串的長度,將字符串存儲在變量str中。

      上述是數據傳輸的最簡單的例子,你還可以采用Socket屬性所提供的其他方法來實現復雜的數據傳輸。





    Tag: 編程博客 發表于 09:34:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    WINDOWS高級窗口的客戶區域拖動技術及其應用(轉載) - [VC專欄]

    作者:chache
    email: cyzhx@263.net
    日期:2000-10-23 17:30:50

    作者:宋立波


      WINDOWS應用程序窗口一般包括兩種:普通窗口和常居頂層的無標題條高級窗口。前者是
    由WINDOWS內部功能定制的,它具有WINDOWS應用程序窗口的所有普通特性:具有標題條、窗
    口邊框、最大化按鈕、最小化按鈕和系統默認的快捷鍵及鼠標支持功能等,利用鼠標左鍵拖
    動該種窗口的標題條可以在屏幕上任意移動窗口,當鼠標光標停在窗口邊框上時可以改變窗
    口大小;后者是一種定制的高級窗口,它不具有普通窗口的任何屬性,整個窗口的控制必須
    由編程者來一一確定,使用這種窗口的典型實例有WINDOWS中的IME輸入法應用程序、UCWIN4
    .0平臺、各種浮動工具箱、OFFICE中的桌面工具欄和第三方開發的漢字輸入平臺等。

      WINDOWS 這種無標題條常居頂層高級窗口的一個顯著特點是,不需改變窗口大小但必須
    具有窗口的客戶區域拖動功能。由于普通窗口的拖動功能是由系統來完成的,編制普通的應
    用程序根據無須考慮客戶區域拖動問題,因此一般編程人員很難遇到這個問題,更談不上如
    何實現這一功能了。開發者往往希望自己開發出來的軟件具有經典軟件中的窗口客戶區域拖
    動功能,筆者曾經利用模仿系統鼠標點擊標題條拖動窗口和WINDOWS系統內部提供的API發送
    函數發送內部拖動命令來實現無標題常居頂層高級窗口的客戶拖動功能,結果都不理想。后
    來只好在窗口函數中通過直接處理WM_LBUTTONDOWN、WM_MOUSEMOVE和WM_LBUTTONUP消息,自
    行控制窗口拖動的客戶命令區、拖動開始、窗口移動、拖動虛框繪制、虛框移動和拖動結束
    等過程,來實現高級頂層窗口的客戶區域拖動方案。下面就自己實踐經驗詳細介紹實現該方
    案的具體方法和主要技巧。

      一、WINDOWS檢測客戶拖動命令及鼠標光標動態提示的實現方法

      WINDOWS 無標題條常居頂層高級窗口的客戶區域一般分為兩種:特定客戶命令區域和非
    特定客戶命令區域。特定客戶命令區域是指利用"RECT"定義的特定子矩形區域,窗口函數對
    發生在該區域內的鼠標命令進行檢測并處理;非特定客戶命令區域是指沒有明確定義的窗口
    客戶區域部分,即所有特定客戶命令區域之外的部分,窗口函數根據實際需要來確定是否對
    該區域內發生的鼠標命令進行處理。實現常居頂層高級窗口拖動功能的首要問題,是如何檢
    測和處理特定客戶命令區域和非特定客戶命令區域內的鼠標命令,以及如何利用鼠標光標來
    動態提示用戶此時可以進行窗口的拖動操作。

      1、在特定客戶區域檢測鼠標命令的方法

      當窗口中設置了實現拖動功能的圖標命令按鈕時,就必須在資源文件中定義命令按鈕的
    特定客戶區域,該區域一般也就是顯示命令按鈕中圖標的矩形區域,這個區域的定義方法為
    "RECT DragRT",其中DragRT為定義的檢測鼠標命令矩形區域,它用DragRT.LEFT、DragRT.T
    OP、DragRT.RIGHT和DragRT.BOTTOM四個參數來描述矩形區域相對于窗口客戶區域左上角的相
    對坐標值,這四個參數必須事先定義具體的數值,也可以利用"SETRECT"函數直接填充。

      窗口函數在處理鼠標消息WM_LBUTTONDOWN時,在接收系統傳遞的鼠標位置參數lParam后
    ,通過MAKEPOINT( )函數將其轉換為窗口坐標值,利用判斷某坐標點是否位于特定矩形區域
    內的函數PtInRect(),就可以判斷鼠標指針是否點擊在拖動命令按鈕之內,從而完成窗口拖
    動功能的啟動任務。其描述性功能代碼示例如下:

      case WM_LBUTTONDOWN://鼠標光標點擊處理

      POINT pt;//鼠標在屏幕上位置指針,包括pt.X和pt.Y兩個參數,

       //該指針值利用MAKEPOINT通過lParam參數轉換而來

      pt=MAKEPOINT(lParam); //獲取鼠標當前屏幕位置指針

      if(PtInRect(&DragRT,pt)){//判斷鼠標是否點擊在拖動按鈕內

       //實現鼠標拖動窗口方案的啟動功能

      } else {

       //進行其它特定或非特定命令客戶區域判斷處理

      }

      break;

      2、在非特定客戶區域檢測鼠標命令的方法

      當窗口應用程序中采取了非特定客戶區域拖動方法時,必須在資源文件中事先確定各個
    特定客戶區域的矩形坐標,這時非特定客戶區域是不規則的區域,它需要根據實際的應用程
    序窗口及各個命令按鈕矩形區域來確定,也就是各個命令按鈕相對于窗口矩形區域的“非”
    子集。窗口函數在處理鼠標消息WM_LBUTTONDOWN時,首先利用函數PtInRect()判斷當前鼠標
    指針是否點擊在各個命令按鈕矩形區域內,如果未點擊在任何命令按鈕區域內,則可確定鼠
    標點擊在非特定客戶區域內,從而實現窗口拖動功能的啟動。其描述性功能代碼示例如下:


      case WM_LBUTTONDOWN: //鼠標光標點擊處理

      POINT pt; //定義鼠標在屏幕上的位置指針

      pt=MAKEPOINT(lParam); //取得鼠標光標當前位置指針

      for(i=0;i

       if(PtInRect(&DragRT[i],pt)){//DragRT[i]為按鈕矩形數組

       break; //鼠標點擊在其它按鈕上中斷

       }

      }

      if(i

       //鼠標點擊在其它特定客戶區域內則處理其它按 Tag: 編程博客 發表于 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);

    一些開發者即使針對傳值變量也用 const :

    void f(const int n); /*n is passed by value, why const?*/

    const 是否真的必要? 不, 不需要. 記住, 在你使用傳值變量的時候, 調用函數不會修改變量值而僅僅復制它. 進一步講, 根據 C++ 標準, Top-level cv-qualification 前綴是被忽略的. 讓我們解釋這個術語: "cv-qualification" 指常量和非穩定. "Top-level" 意味著參數不是一個組合或者非完整的類型, 比如: 不是指針, 引用或者數組. 這樣:

    void f(int const param1);

    還是作為下列方式對待:

    void f(int param1);

    為此, 傳遞一個類型為 ’const int’ 類型的參數給 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 *. 這樣, 不能傳遞類型為"一個指向常量整數的指針" 給第一個函數 f().

    void f(int *p1); /*non const version*/
    int n=0;
    const int *p=&n;
    f(p); /*error, cannot convert ’const int *’ to ’int *’*/

    作為一個規則, 如果變量以傳值方式傳遞或者返回不能聲明為常量, 只有針對組合類型使用常量類型.
    -----------
    Danny Kalev Tag: 編程博客 發表于 09:32:26 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    非法探取密碼的原理及其防范(轉) - [VC專欄]

    作者:九流
    email: molimin@163.net
    日期:8/8/2001 11:59:25 AM
    一、非法獲取Password的原理:
    Edit控件是Windows的一個標準控件,當把其Password屬性設為True時,就會將輸入的內容屏蔽為星號,從而達到保護的目的。雖然我們看來都是星號,但程序中的Edit控件實際仍是用戶輸入的密碼,應用程序可以獲取該控件中的密碼,其他應用程序也可以通過向其發送WM_GETTEXT或EM_GETLINE消息來獲取Edit控件中的內容。黑客程序正是利用Edit控件的這個特性,當發現當前探測的窗口是Edit控件并且具有ES_PASSWORD屬性時,則通過SendMessage向此窗口發送WM_GETTEXT或EM_GETLINE消息,這樣Edit框中的內容就一目了然了。
    二、黑客軟件工作方法:
    首先要取得當前的窗口,并判斷是否是Edit控件,一般多通過鼠標來指定要探測的窗口,例如在WM_MOUSEMOVE消息的響應函數中進行判斷,現列舉代碼片段如下:
    //將客戶坐標轉換成屏幕坐標
    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向此控件發送WM_GETTEXT消息
    ::SendMessage(hwndCurr, WM_GETTEXT, 255, (LPARAM)szText); //密碼已保存在szText中
    m_strPassword = szText;
    }
    }
    }
    }
    }
    上述代碼中值得注意的有以下幾個關鍵地方:
    ClientToScreen(&point);
    CWnd* pWnd = CWnd::WindowFromPoint(point);
    HWND hwndCurr = pWnd->GetSafeHwnd();
    這三句代碼可以獲取當前鼠標位置所在窗口的窗口句柄,在SendMessage中要用到的。
    ::SendMessage(hwndCurr, WM_GETTEXT, 255, (LPARAM)szText);
    這便是真正起作用的SendMessage了,其第一個參數指定了要接收消息的窗口句柄,我們已經通過上面的代碼獲取到了,第二個參數就是讓Edit控件返回字符的WM_GETTEXT消息了,并將得到的內容保存在szText中。
    三、防范措施
    既然我們搞清除了黑客軟件普遍采取的手法,那我們自然能制訂出一套防范其攻擊的措施來。下面我們就要對Password進行保護。
    從以上分析我們可以看出:Edit控件的漏洞主要在于沒有對發送WM_GETTEXT或EM_GETLINE消息者的身份進行檢查,只要能找到Edit窗口句柄,任何進程都可獲取其內容。所以必須要對發送消息者的身份進行驗證,這里給出一種方法來驗證發送消息者的身份是否合法:
    1.創建新CEdit類
    從CEdit繼承一個子類CPasswordEdit,申明全局變量g_bSenderIdentity表明消息發送者的身份:
    BOOL g_bSenderIdentity;
    然后響應CWnd的虛函數DefWindowProc,在這個回調函數中進行身份驗證:
    LRESULTCPasswordEdit::DefWindowProc (UINTmessage,WPARAMwParam,LPARAMlParam)
    {
    //對Edit的內容獲取必須通過以下兩個消息之一
    if((message==WM_GETTEXT) ||(message==EM_GETLINE))
    {
    //檢查是否為合法
    if(!g_bSenderIdentity)
    {
    //非法獲取,顯示信息
    AfxMessageBox(_T ("報告:正在試圖竊取密碼!"));
    return 0;
    }
    //合法獲取
    g_bSenderIdentity=FALSE;
    }
    return CEdit::DefWindowProc (message,wParam,lParam);
    }
    2.在數據輸入對話框中做些處理
    在對話框中申明一個類成員m_edtPassword:
    CpasswordEdit m_edtPassword;
    然后在對話框的OnInitDialog()中加入下列代碼:
    m_edtPassword.SubclassDlgItem(IDC_EDIT_PASSWORD,this);
    將控制與新類做關聯。
    之后要在對話框的數據交換函數中將身份設為合法:
    void CDlgInput::DoDataExchange (CDataExchange*pDX)
    {
    //如果獲取數據
    //注意:對于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輸入框就擁有了合法身份,會受到保護。
    結論:
    以上的方法僅針對VC程序,對于其他語言如VB、Delphi等語言,需要借助VC做一個Password的ActiveX控件,實現方法與上述方法基本類似。以上程序均用VisualC++6.0編制調試通過。
    Tag: 編程博客 發表于 09:31:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    構建穩定的服務器端組件的七個步驟(轉) - [VC專欄]

    作者:poolnet
    email: poolnet@sina.com
    日期:2001-6-19 8:36:36
    實現健壯性能的規則

    Hank Marquis
    來自于Enterprise Solutions for Microsoft BackOffice and Windows NT Magazine

    在你的服務器上安裝了微軟IIS(Internet Information Server),你就可以發揮ASP(Active Server Pages)的優勢了,ASP利用ActiveX組件來為你的網絡應用完成所有種類的工作。盡管你可以在HTML和有ASP頁面的IIS里面使用許多ActiveX組件,服務器端組件也不是運行在一臺服務器上的普通組件。它在運行時不會告訴你同需要特別關照的產品服務器有關的任何信息。你將無法做任何事情去改變其對服務器性能、安全和穩定性的影響。對服務器端的組件的不恰當選擇可能會導致一些問題,包括速度的明顯下降,安全漏洞或者其它更惡劣的問題。

    客戶端的組件在用戶計算機上執行。客戶端組件包括絕大多數我們現在已經了解的一些流行組件:標簽控件,文本框,命令按鈕,格子等。這些組件可以通過<OBJECT>標簽和(或)HTML對象語法來包含在客戶端HTML代碼中。

    多數的有用的客戶端組件會提供特定種類的用戶界面。記住,使用客戶端組件就意味著真實組件已經被傳到客戶計算機上。尋常的做法就是把組件下載到客戶計算機上。當然,用戶不得不等待下載過程,而且客戶計算機必須被配置為允許下載。

    與此形成對比的是,服務器端的組件在服務器計算機上執行。服務器端組件也為用戶做一些工作,但卻是在服務器上運行的。你必須認識到這個差異并且相應地編制代碼。服務器端組件為你的整個應用程序封裝了一些邏輯或功能。

    當一個用戶使用應用程序時,他將不會真正看到服務器端的組件。這些組件大多數都可以通過需要使用組件的ASP腳本中的<OBJECT>標識來被包含。你同樣可以通過服務器的CreateObject語法來包含服務器端的組件。

    建造健壯的組件

    用于創建健壯組件的好材料并不多。但是,我在這里向大家推薦七個關鍵步驟,它可以幫助你創建穩定和安全的服務器端組件,可以很優雅地縮放并且維持性能。在創建一個服務器端網絡應用時,你需要把穩定,安全和性能放在你心目中的首要位置。

    服務器端組件不應該具有GUI(圖形用戶界面)。因為服務器端組件是在服務器上運行,網絡應用的用戶是看不到可能彈出的任何對話的。你的組件需要能夠同腳本和其它組件進行交流,卻無需同用戶交流。避免所有的消息框和其它任何圖形的用戶界面單元。你必須開發利用返回結果來同狀態和其它模塊信息進行交流的代碼。如果什么東西出問題,不要拋出一個錯誤消息或者使用一個消息框,可以返回一個狀態變量。你需要做的最后一件事是鎖定忙碌服務器等待OK按鈕被按下。


    服務器端組件不得被傳遞引用或者傳遞引用給對象。普遍的做法是把控制作為一個參數傳遞給其它過程或組件。這包括其它對象的引用,比如RecordSets。盡管如此,向網絡中的組件傳遞引用可能導致速度明顯下降,使一個繁忙的服務器更加緩慢,網絡應用程序在響應用戶需求時也表現得更慢。


    服務器端組件應該盡可能地少含方法和屬性。每一個方法或屬性的調用都需要大量處理。因此,一個編寫的好的服務器端組件應該幾乎不含明顯的方法和屬性。組件含有的那些方法和屬性會帶來更多的參數。具有很多參數的調用越少,性能就越好,尤其是你的網絡應用程序需要支持許多用戶時。這個技巧和許多開發人員的經驗是相反的。盡量少的使用帶有許多參數的調用也會帶來另外一些問題,這使得編碼和調試更加困難,但是速度上的改進是與付出的努力相當的。


    服務器端組件必須實現恰當的線程模型。利用單線程組件可能導致服務器限制一個線程的會話,這將帶來速度的明顯下降。應該選擇VB的房間模型線程選項并且努力避免單線程組件。但是,VB不能創建你可以在Visual C++里發現的具有線程選擇范圍的組件,。這一點也表明VB不是一種很合適這項工作的開發語言。


    服務器端組件應該使用早期綁定。如果你的服務器應用程序要擴容,這顯得特別重要。早期綁定的對象在編譯時就擁有引用解析,可以節省不少執行時間。


    服務器端組件不能使用在應用程序或會話作用域的聲明中。請注意你的控件是如何被限定作用域的。作用域描述了如何創建一個組件的實例,這對你的服務端組件的成功起著關鍵作用。正如上月所討論的那樣,存在三種級別的作用域:頁面級,會話級和應用程序級。頁面級作用域對象可以用頁面本身的HTML和ASP腳本代碼來創建。頁面級作用域組件的最佳性能可以通過使用房間線程來得到。而對應用程序級和會話級作用域組件來說,可以通過使用ATL組件的雙線程模型來得到。同作用域結合的線程模型也影響服務器的安全性能。例如,一個利用應用程序級作用域的房間線程組件在系統安全環境里運行,但并不是當前用戶的安全環境。這對那些具有安全意識的人來說可能是一個問題。


    為了速度,服務器端組件應該是進程中組件;為了穩定,則應該是進程外組件。有兩種方式去創建COM(OLE)服務器--進程中和進程外。在VB里,你用EXE或DLL擴展名去編譯服務器。具有DLL擴展名的OLE服務器就被稱為進程中服務器;而具有EXE擴展名 Tag: 編程博客 發表于 09:30:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    關于PostMessage函數的中文幫助文件 - [VC專欄]

    作者:hxfwsk
    email: hxfwsk@hotmail.com
    日期:6/18/2001 2:54:50 PM
    關于PostMessage函數的中文幫助文件

    PostMessage函數放置(發送)一個消息到一個隨著創建窗體而創建的消息隊列,而且不會等待線程處理這個消息就返回。消息隊列中的消息會通過調用GetMessage或PeekMessage函數取得。

    BOOL PostMessage(

    HWND hWnd, // 目標窗口句柄
    UINT Msg, // 要發送的消息
    WPARAM wParam, // 第一個消息參數
    LPARAM lParam // 第二個消息參數
    );


    參數

    hWnd

    Identifies the window whose window procedure is to receive the message. Two values have special meanings:
    接收消息的窗口標識。兩個值有特定的意義。

    值         意義
    HWND_BROADCAST  消息被發送到所有系統頂級窗口,包含不可用的和不可視的獨立的窗口,重疊窗口,彈出         窗口。不會被傳遞到子窗口。
    NULL      設置為此參數時,函數作用類似于PostThreadMessage函數使用dwThreadId參數,代表當前         線程 

    Msg

     要發送的消息

    wParam
     附屬的消息信息  
    lParam
     附屬的消息信息  

    返回值

    成功返回非零值
    失敗返回0,可通過GetLastError函數取得出借信息 Tag: 編程博客 發表于 09:29:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    關于ShellExecute函數的中文說明 - [VC專欄]

    作者:hxfwsk
    email: hxfwsk@hotmail.com
    日期:6/18/2001 2:49:35 PM
    關于ShellExecute函數的中文說明


    ShellExecute 函數 打開或打印一個指定的文件。文件可以是可執行文件也可以是一個文檔。請查看關于ShellExecuteEx的幫助。
    HINSTANCE ShellExecute(

    HWND hwnd, // 主窗口句柄
    LPCTSTR lpOperation, // 字符串指針,指定要執行的操作
    LPCTSTR lpFile, // 字符串指針,指定文件名或目錄名
    LPCTSTR lpParameters, // 字符串指針,指定傳給可執行文件的參數   LPCTSTR lpDirectory, // 字符串指針,指定缺省目錄
    INT nShowCmd // 文件顯示模式
    );


    參數

    hwnd

    指定一個主窗體。這個窗體與應用程序產生的message boxes。例如,

    lpOperation
    一個非空的字符串指針,指定操作方式。有以下操作方式可用
    字符串意義
    "open"
    該函數打開由lpFile指定的文件,文件可以是一個可執行文件,也可以是文檔文件,也可以是一個要打開的目錄。
    "print"
    該函數打印由lpFile指定的文件。文件應該是一個文檔文件。如果是一個可執行文件則運行這個文件就象指定用"opne"操作方式一樣。
    "explore"
    函數打開瀏覽由lpFile指定的目錄窗口。

    如果該參數為NULL,則相當于使用"open"操作方式。

    lpFile

    一個非空字符串指定要打開或打印的文件,或者是要打開瀏覽的目錄名。該函數可以打開一個可執行文件或一個文檔文件,也可以打印一個文件。


    lpParameters

    如果lpFile指定一個可執行文件,則lpParameters 是一個指向非空字符串的指針,代表要傳給這個應用程序的參數。
    如果lpFile指定一個文檔文件,則其應該為空。

    lpDirectory

    非空字符串指定缺省目錄 Tag: 編程博客 發表于 09:28:26 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    回調方式的事件實現 - [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 //回調接口
    {
    //事件對應的方法
    [helpstring("method ComputationComplete")] HRESULT ComputationComplete( long lResult );
    };

    [
    object,
    uuid(CE4BD5E1-B808-4617-91F0-2B4728290D4F),

    helpstring("IMath Interface"),
    pointer_default(unique)
    ]
    interface IMath : IUnknown
    {
    //組件自身方法, 如果需要觸發事件, 需要在適當的地方添加
    /*
    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 );
    //回調接口維護方法
    // 其實其中的ICallBack只是一個ATL的公開的回調接口, 需要組件提供一個成員變量保存這個ICallBack實例
    // 下列函數的相應實現:
    /*
    //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: 編程博客 發表于 09:27:39 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    基于MFC的大型數據文件處理方法 - [VC專欄]

    作者:SKYHORSEBJ
    email: XUEY@CIDC.COM.CN
    日期:2001-7-4 17:30:36
    在Visual C++中,MFC(微軟基礎類庫)提供了CFile和CStdio
    File兩個類來進行程序中的文件輸入輸出操作。Cfile類提供了基于二
    進制流的文件操作,功能類似于C語言中的fread()和fwrite()函
    數。CStdioFile提供了基于字符串流的文件操作,功能類似于C語言中
    的fgets()和fputs()函數。但是,使用這兩個類進行文件操作時
    ,對于一次文件讀寫的數據量的大小必須限制在65535字節以內。其原
    因是在VC中訪問大于65535字節的緩沖區需要Huge型指針,而在CFile
    和CStdioFile類中,使用的是Far型的指針。由于Far型指針不具有跨
    段尋址的能力,因此限制了一次文件讀寫的長度小于65535字節。如果
    傳遞給CFile和CStdioFile兩個類的成員函數的數據緩沖區的大小大于
    65535字節的時候,VC就會產生ASSERT錯誤。
    筆者在使用Visual C++進行多媒體程序設計的時候,由于程序
    處理的數據量非常大,所以需要頻繁地讀寫大于65535字節的數據。在
    使用CFile和CStdioFile類處理巨型數據的時候一般是分段讀寫,筆者
    感到這樣的處理方法非常地繁瑣,同時容易導致程序編制錯誤。筆者
    在查閱了相關的文獻以后,找到了使用Visual C++直接讀寫巨型數
    據的方法。
    在MFC的CFile類中提供了兩個未載入文檔的函數,其原型聲明在
    AFX.H中。函數原型如下:
    DWORD CFile::ReadHuge(void FAR *lpBuffer,DWORD dwCo
    unt);
    void CFile::WriteHuge(const void FAR*lpBuffer,DWORD
    dwCount);
    在這兩個函數內部使用的都是Huge型指針來對傳遞的緩沖區進行
    尋址,因此可以讀寫大于65535字節的巨型數據。
    對于ReadHuge()和WriteHuge()函數需要的巨型緩沖區可以使
    用Windows的API函數GobalAlloc()來創建。
    作為一個例子,下面的程序段演示了通過使用Read Tag: 編程博客 發表于 09:26:27 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    利用鍵盤鉤子在Windows平臺下捕獲鍵盤動作 - [VC專欄]

    作者:skyhorsebj
    email: XUEY@CIDC.COM.CN
    日期:2001-7-3 18:10:43
    一。我們可以在應用程序中毫不費力的捕獲在本程序窗口上所進行的鍵盤操作,但如果我們想要將此程序作成一個監控程序,捕獲在Windows平臺下任意窗口上的鍵盤操作,就需要借助于全局鉤子來實現了。
    二、系統鉤子和DLL
    鉤子的本質是一段用以處理系統消息的程序,通過系統調用,將其掛入系統。鉤子的種類有很多,每種鉤子可以截獲并處理相應的消息,每當特定的消息發出,在到達目的窗口之前,鉤子程序先行截獲該消息、得到對此消息的控制權。此時在鉤子函數中就可以對截獲的消息進行加工處理,甚至可以強制結束消息的傳遞。
    在本程序中我們需要捕獲在任意窗口上的鍵盤輸入,這就需要采用全局鉤子以便攔截整個系統的消息,而全局鉤子函數必須以DLL(動態連接庫)為載體進行封裝,VC6中有三種形式的MFC DLL可供選擇,即Regular statically linked to MFC DLL(標準靜態鏈接MFC DLL)、Regular using the shared MFC DLL(標準動態鏈接MFC DLL)以及Extension MFC DLL(擴展MFC DLL)。 在本程序中為方便起見采用了標準靜態連接MFC DLL。
    三、鍵盤鉤子程序示例
    本示例程序用到全局鉤子函數,程序分兩部分:可執行程序KeyHook和動態連接庫LaunchDLL。
    1、首先編制MFC擴展動態連接庫LaunchDLL.dll:
    (1)選擇MFC AppWizard(DLL)創建項目LaunchDLL;在接下來的選項中選擇Regular statically linked to MFC DLL(標準靜態鏈接MFC DLL)。
    (2)在LaunchDLL.h中添加宏定義和待導出函數的聲明:
    #define DllExport __declspec(dllexport)
    ……
    DllExport void WINAPI InstallLaunchEv();
    ……
    class CLaunchDLLApp : public CWinApp
    {
    public:
    CLaunchDLLApp();
    Tag: 編程博客 發表于 09:25:26 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    連接點的事件實現 - [VC專欄]

    作者:rick1126
    email: rickzhang@sina.com
    日期:7/7/2001 6:41:45 PM
    服務端
    1. 首先保證你創建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: 編程博客 發表于 09:24:54 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    讓CC++圖形程序獨立運行 - [C++]

    作者:star2002
    日期:2000-8-18 8:36:41
    C/C++語言提供了十分豐富的圖形函數,圖形函數文件為Graphics.h,使用圖形函數前須先將屏幕設置為圖形模式,C/C++語言提供了下面的函數:
      void far initgraph(int far *GD,int far *GM,char *P);
      其中,GD和GM分別表示圖形驅動程序和圖形模式,P指圖形驅動程序所在的目錄路徑。
      圖形驅動程序由Borland公司(對于Turbo C和Borland C++)提供,同時C/C++語言還提供了退出圖形狀態的函數closegraph(),格式為:
      void far closegraph(void);
      許你經常在用C/C++語言編寫一些圖形程序,但是總不能脫離C/C++語言環境獨立運行,我們怎樣來解決呢?下面是實現圖形程序獨立運行的具體步驟:
      1.將驅動程序EGAVGA.BGI轉換成目標文件EGAVGA.OBJ:
      C:/TC>BGIOBJ EGAVGA
      按同樣的辦法,將字體文件*.CHR轉換成目標文件*.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.在程序中調用initgraph()函數前,應加上如下語句:
      registerbgidriver(EGAVGA-driver);
      它通知連接程序把EGAVGA驅動程序裝入用戶的執行程序中,同樣在裝入字體文件之前要加上如下語句:
      registerbgifont(字體文件名);
      4.通過上述處理后,編譯連接后的執行程序就可以在任何目錄下運行了。這時,將屏幕初始化為圖形模式的函數可改寫為:
      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,"");
      }
      按照以上步驟,就能實現圖形程序的獨立運行 Tag: 編程博客 發表于 09:23:15 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    讓VC中的非模式屬性表PropertySheet出現OKCancelApply按鈕 - [VC專欄]

    作者:茶館主人
    日期:2001-6-3 20:55:08
    讓VC中的非模式屬性表PropertySheet出現OK/Cancel/Apply按鈕

    北京商即通數碼科技有限公司 張宏

    很多VC程序員都遇到過這個問題,當建立一個非模式的屬性表(不是向導模式)時,此時正常用DoModal()調用時可以出現的OK/Cancel/Apply等按鈕全都不見了,真讓人郁悶!筆者查找了很多資料,均沒有正確的答案,最后,筆者自己分析,在CPropertySheet調用初始化對話框CPropertySheet::OnInitDialog()時由于m_psh中自動設置了PSH_MODELESS屬性,導致自動調整對話框大小,隱藏了對話框中的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;

    // 調整屬性頁對話框的大小
    GetWindowRect (&rc);
    rc.bottom += 30; //窗口向下拉30點,讓OK按扭可以顯示出來
    MoveWindow (&rc); //調整窗口
    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按鈕看看?怎么?不會關閉對話框!!! >:-(((
    怎么辦?是非模式對話框沒有響應OK按鈕嗎?不是,當前的各屬性頁已經得到了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);
    }

    現在再編譯試試看,一切OK了。

    Tag: 編程博客 發表于 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: 編程博客 發表于 09:21:22 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    如何用VC++和VFP進行ActiveX數據通訊 - [VC專欄]

    作者:SKYHORSEBJ
    email: XUEY@CIDC.COM.CN
    日期:2001-7-4 17:31:33
    在進行軟件開發的過程中,如何在不同的編程工具之間進行數據交換和通訊,需要進行不斷的探索和總結。我們在開發機械CAD仿真軟件的過程中,遇到了在VC++中讀取和修改Visual Foxpro中數據的問題。經過許多次的試驗,我們通過采用自動服務器(ActiveX Automation)的方法圓滿解決了這個問題。

    ---- 自動服務器,以前稱為OLE Automation,后來稱為ActiveX OLE Automation,就是編寫能被其他程序調用的代碼。其他程序不是以DLL的孤立方式而是直接調用自動服務器的用戶代碼。這其中比較難理解的概念是:自動服務器用戶代碼向其他應用程序揭示了屬性(變量)和方法(函數)。以下將以整型和雙精度(對浮點型同樣適用)的數據傳遞為例,講述如何用ActiveX Automation在VC++和Visual Foxpro之間進行數據通訊,例子中的編程工具為VC++ 5.0和Visual Foxpro 5.0。

    ---- 一.在Visual Foxpro中創建自動服務器

    ---- 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. 將上述程序聯編為可執行程序(如MyServer.exe)

    ---- 選中程序MyServer,點擊“連編”按鈕,選擇“連編可執行程序”選項,并按確定,便可生成可執行程序。

    ---- 二.在VC++中對自動服務器進行測試

    ---- 1.關閉Visual Foxpro,在VC++中選擇菜單項“File-New”,再選擇“Projects”中的“MFC AppWizard (exe)”選項,隨后按默認方式生成“Dialog Based”的工程項目(此例中工程名為MyTest)。

    ---- 2.在MyTest.cpp中的APP類的InitInstance()函數開頭加入OLE使能

    BOOL CMyTestApp::InitInstance()
    {
    BOOL OleEnable=AfxOleInit();
    if(!OleEnable) return FALSE;
    ……
    }

    ---- 3.在ClassWizard中選“Automation”中的“Add Class-From a type library”。在“Import from type library”對話框中找到剛才所創建的Visual Foxpro工程目錄下的tlb文件(如MyServer.tlb)并選擇“打開”按鈕,會有提示說明將要從Lib中生成CDATA類,點擊OK按鈕加以確認,將自動在項目中加入與CDATA類有關的文件MyServer.cpp和MyServer.h。在ClassView中可查看CDATA類的函數,如GetPara1()、SetPara1()和CHANGEDATA()等。這里要注意類名CDATA和函數名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()函數中)加入

    m_data.CreateDispatch(“MyServer.CDATA);

    ---- 6.使用自動服務器的通訊編程

    ---- 此例中,我們在對話框中設置一命令按鈕“Test”,通過點擊該按鈕來對自動服務器進行測試。

    void CMyTestDlg::OnButtonTest()
    {
    //首先利用CDATA類的GetPara1()
    等取值函數取出Foxpro中的變量值,
    //再利用CDATA類SetPara1()
    等賦值函數來修改Foxpro中的這些變量值
    //也可以在VC++中調用CDATA
    類的函數CHANGEDATA()來修改變量值
    //定義tagVARIANT型變量,
    請參看有關tagVARINAT的幫助
    tagVARIANT mypara1, mypara2;
    mypara1=m_data.GetPara1();
    //讀取Foxpro中的變量值para1
    mypara2=m_data.GetPara2();
    //讀取Foxpro中的變量值para2
    //檢驗讀取數據是否正確(Foxpro設定為123和123.123)
    if(mypara1.iVal==123)
    MessageBox("mypara1.iVal=123");
    if Tag: 編程博客 發表于 09:20:03 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    什么是C++ - [C++]

    作者:rick1126
    email: rickzhang@sina.com
    日期:8/20/2001 7:20:10 PM
    C++ 是脫胎自 C 語言的一種中級語言. 從計算機角度看, 它可以嵌入ASM等低端語言; 從面向對象的程序設計角度看, 它有具備OOP的三個基本特征 -- 抽象, 封裝和繼承; 同時從市場角度來看, 它又不是純面向對象, 其實那些純粹的面向對象語言的陣地只是在實驗室.

    比較C語言. C++ 的幾個顯著變化或者解決的問題就是
    1. 名字空間的問題, 原始的C語言使用公共的名字空間, 這樣無論是開發本人還是第三方團隊都面臨變量名字耗盡的問題. 而C++提供獨立的名字空間, 而且對象的引入也為名字空間提供了進一步劃分

    2. 代碼復用的問題, C語言使用函數庫的方式或者DLL方式實現代碼復用, 在接口穩定的前提下實現內部修改和數據及其實現的封裝. C++提供了類庫機制實現了具有層次的代碼復用, 和多種繼承機制, 同時重載等各種機制提供了進一步的復用實現. 使得類庫和代碼更加容易維護, 雖然建立類庫在人員, 組織等各個方面還是比較麻煩的.

    3. 安全機制. 因為有了類機制, 有一些初始化操作可以自動實現

    4. 效率問題. 因為C語言本質上是站在計算機立場的非常注重效率的問題, 但是事物總是具備矛盾的兩面, 過于偏重效率和軟件危機的出現, 反而增加了程序設計的難度. 而OOA的現實世界角度的考慮問題更加貼近自然, 使得代碼或者程序更加具備穩定性, 可擴展性和可維護性.

    為此, 和經典物理同量子物理一樣. C/C++ 今天在不同領域各自發揮著最大的效率.

    BTW: 希望各位多多跟貼. 注意主題, 不要跑火車. Tag: 編程博客 發表于 09:18:57 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    隱藏鼠標 - [VC專欄]

    作者:hxfwsk
    email: hxfwsk@hotmail.com
    日期:8/2/2001 4:41:09 PM
    如何實現象“超級解霸”中的自動隱藏鼠標功能呢?當我們欣賞VCD時,屏幕中的鼠標常常會影響觀賞效果。當一段時間內,用戶沒有任何輸入的情況下就自動隱藏鼠標,一旦用戶進行任何輸入立即重新顯示出鼠標即可。程序段如下:
    請先添加一個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: 編程博客 發表于 09:15:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    用c寫cgi(轉) - [C語言]

    作者:chache
    email: cyzhx@263.net
    日期:2000-10-24 2:03:05
    三、From輸入的分析和解碼

      1.分析名字/值對

      當用戶提交一個HTML Form時,Web瀏覽器首先對Form中的數據以名字/值對的形式進行編
    碼,并發送給Web服務器,然后由Web服務器傳遞給CGI程序。其格式如下:
      name1=value1&name2=value2&name3=value3&name4=value4&...
      其中名字是Form中定義的INPUT、SELECT或TExtAREA等標置(Tag)名字,值是用戶輸入或選
    擇的標置值。這種格式即為URL編碼,程序中需要對其進行分析和解碼。要分析這種數據流,C
    GI程序必須首先將數據流分解成一組組的名字/值對。這可以通過在輸入流中查找下面的兩個
    字符來完成。
      每當找到字符=,標志著一個Form變量名字的結束;每當找到字符& ,標志著一個Form變量
    值的結束。請注意輸入數據的最后一個變量的值不以&結束。
      一旦名字/值對分解后,還必須將輸入中的一些特殊字符轉換成相應的ASCII字符。這些特
    殊字符是:
      +:將+轉換成空格符;
      %xx:用其十六進制ASCII碼值表示的特殊字符。根據值xx將其轉換成相應的ASCII字符。
      對Form變量名和變量值都要進行這種轉換。下面是一個對Form數據進行分析并將結果回
    送給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服務器,檢查輸入中的字符數,并循環檢查每一
    個字符。當發現字符為&時,意味著一個名字/值對的結束,程序輸出一個空行;當發現字符為+
    時,將它轉換成空格; 當發現字符為%時,意味著一個兩字符的十六進制值的開始,調用htoi()
    函數將隨后的兩個字符轉換為相應的ASCII字符;當發現字符為=時,意味著一個名字/值對的名
    字部分的結束,并將它轉換成字符:。最后將轉換后的字符輸出給Web服務器。
      四、產生HTML輸出

      CGI程序產生的輸出由兩部分組成:MIME頭信息和實際的信息。兩部分之間以一個空行分
    開。我們已經看到怎樣使用MIME頭信息″Cont enttype:text/plain/n/n″和printf()、put
    char()等函數調用來輸 出純ASCII文本給Web服務器。實際上,我們也可以使用MIME頭信息″
    C ontenttype:text/html/n/n″來輸出HTML源代碼給Web服務器。請注意任何MIME頭信息后必
    須有一個空行。一旦發送這個MIME頭信息給We b服務器后,Web瀏覽器將認為隨后的文本輸出
    為HTML源代碼,在HTML源代碼中可以使用任何HTML結構,如超鏈、圖像、Form,及對其他CGI程
    序的調用。也就是說,我們可以在CGI程序中動態產生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()函數來產生HTML源代碼。請注意在輸出的字符串中如果
    有雙引號,在其前面必須有一個后斜字符/, 這是因為整個HTML代碼串已經在雙引號內,所以H
    TML代碼串中的雙引號符必須用一個后斜字符/來轉義。


      五、結束語

      本文詳細分析了用C語言進行CGI程序設計的方法、過程和技巧。C語言的CGI程序雖然執
    行速度快、可靠性高,但是相對于Perl語 Tag: 編程博客 發表于 09:14:04 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    用vc6.0編服務器與客戶機互相傳送消息的程序 - [VC專欄]

    作者:SKYHORSEBJ
    email: XUEY@CIDC.COM.CN
    日期:2001-7-4 17:34:53
    首先介紹服務器程序:

    ---- 1.創建一個名為"server"的項目,單文檔界面.

    ---- 2.在serverview.h中加入代碼:

    #include "winsock.h"
    添加變量:
    CSize sizeTotal;//控制滾動條
    intcount;//信息條數
    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()構造器,創建并綁定嵌套字:

    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.在析構函數中完成必需的清除操作:

    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.在程序菜單中添加"發送消息":

    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.為發送消息項添加一 Tag: 編程博客 發表于 09:13:00 | 閱讀全文 | 評論 0 | 編輯 | 推薦
  • 2005-10-26

    有關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"結束
    catinfo.szDescription[len] = ’/0’;

    hr = pcr->RegisterCategories(1, &catinfo);
    pcr->Release();

    return hr;
    }


    //用途: 在已經存在的組件分類中進行接口類的注冊
    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("注冊類型庫失敗");
    }

    //創建初始化安全組件分類
    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;

    //創建腳本編程安全組件分類
    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:

總結

以上是生活随笔為你收集整理的VC函数对象模板的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。