• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            用SkinMagic工具包創建換皮膚程序
            作者:北京林業大學 李少杰

            下載本文示例工程

            代碼運行效果圖如下:




            以前看到瑞星和金山詞霸有換皮膚功能,很是羨慕,自己也想做個換皮膚的程序,但畢竟自己能力有限,以前在此處看到一篇介紹換皮膚功能的文章,但只能應用在對話框程序上。我也試過像BCGCBar這樣的大型軟件,給我的感覺是軟件老是出問題,應用起來也很復雜。在年前我就看到本站有SkinMagic軟件包,但當時不知怎么用,發了貼子也沒人回答。可能是很少有人用的緣故吧,本站也未更新此軟件包。偶然的一次機會,讓我知道了怎樣來用它,
            而且編譯出來的軟件體積很小,所以在這里向大家介紹一下,希望對大家有些幫助。
            如何使用:
            ① 新建工程后,將SkinMagic包中的SkinMagicLib.h、SkinMagicLib.lib、DETOURS.lib拷貝到所在文件夾下,點擊Project->Add To Project->Files,包含到工程中。
            ② 在Resource View中點擊Import 菜單引入幾個Skin二進制文件放在相同的“SKINMAGIC”文件夾下,分別給起一個名字(見源程序)。
            ③ 在stdafx.h中加入#include "SkinMagicLib.h"
            ④ 在此處添加如下內容

            if (!ProcessShellCommand(cmdInfo))
            return FALSE;
            /////////////////////////////////////////////////////////////////////////////////////////
            VERIFY( 1 == InitSkinMagicLib( AfxGetInstanceHandle(), "Demo" ,NULL,NULL ) );//初始化類庫
            VERIFY( 1 == LoadSkinFromResource( AfxGetInstanceHandle()  , "KROMO" ,"SKINMAGIC") );//從資源中加載皮膚
            VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd , "MainFrame" ));
            VERIFY( 1 == SetDialogSkin( "Dialog" ) );
            ((CMainFrame*)m_pMainWnd)->m_bSkinned = TRUE;
            ((CMainFrame*)m_pMainWnd)->m_nIndex = 0;
            ////////////////////////////////////////////////////////////////////////////////////////////
            m_pMainWnd->ShowWindow(SW_SHOW);
            m_pMainWnd->UpdateWindow();
            
            ⑤ 在MainFrame中加入換皮膚菜單,及相應的函數,在函數中加載皮膚。
            void CMainFrame::OnDevior()
            {
            LoadSkinFromResource( AfxGetInstanceHandle()  , "DEVIOR" ,"SKINMAGIC") ;
            }
            
            到此為止,完美的換皮膚程序就出來了。
            posted @ 2009-05-21 09:32 wrh 閱讀(276) | 評論 (0)編輯 收藏

            文章導讀:  [準備工作]  1、將SkinMagicTrial.dll放置在調試目錄  2、設置庫文件目錄,在項目[連接器]的[附加依賴項]中加入庫SkinMagicTrial.lib  3、在項目的stdafx.h文件中加入頭文件 #include "SkinMagicLib.h"  [創建過程]  1、初始化SkinMagic庫: 

              [準備工作]

              1、將SkinMagicTrial.dll放置在調試目錄

              2、設置庫文件目錄,在項目[連接器]的[附加依賴項]中加入庫SkinMagicTrial.lib

              3、在項目的stdafx.h文件中加入頭文件 #include "SkinMagicLib.h"

              [創建過程]

              1、初始化SkinMagic庫:

              要使用SkinMagic,這一步必不可少。在應用程序類的InitInstance()函數中行加入如下代碼(粗體部分):

              CWinApp::InitInstance();

              VERIFY( 1 == InitSkinMagicLib(AfxGetInstanceHandle(), NULL ,

              NULL, NULL ));

              說明:

              int InitSkinMagicLib( //初始化SkinMagic工具庫
              HINSTANCE hInstance, //應用程序句柄
              char* szApplication , //皮膚文件中定義的應用程序名,置為NULL即可
              char* szRegCode, //SkinMagic的使用注冊碼。若無置為NULL
              char* szReserved2 //保留位,為NULL
              );

              2、調入皮膚文件:

              皮膚的調用有兩種方法,一是直接從皮膚文件中調用,另一種方法是從資源文件中調用,分別說明如下:

              1)從皮膚文件中調用皮膚:緊接上句,加入如下代碼

              VERIFY( 1 == LoadSkinFile("corona.smf"));

              2)從資源文件中調用皮膚:

              VERIFY(1 == LoadSkinFromResource(NULL,"FUTURA","skin"));

              說明:

            int LoadSkinFromResource(
              HMODULE hModule, //包含皮膚文件的模塊句柄,若NULL表面在本模塊中
             char* lpSkinName , //皮膚資源的名稱
              char* lpType); //資源的類型

              3、為窗口添加皮膚:

              1)為標準窗口(擁有標題欄、系統菜單、可變大小等特征,比如文檔/視圖結構和有菜單的對話框)添加皮膚,通常用于主窗口。在應用程序類的InitInstance()函數的底部加入如下代碼:

              VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd , "MainFrame" ));

              m_pMainWnd->ShowWindow(SW_SHOW);

              m_pMainWnd->UpdateWindow();

              說明:

              int SetWindowSkin(
              HWND hWnd, //要使用皮膚的窗口句柄
              char* lpSkinName //為skinFrameWnd對象指定的名稱
              );

              2)為對話框添加皮膚

              在對話框顯示之前調用,通常在應用程序初始化函數中調用

              VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd , "MainFrame" ));

              VERIFY( 1 == SetDialogSkin( "Dialog" ) );

              m_pMainWnd->ShowWindow(SW_SHOW);

              m_pMainWnd->UpdateWindow();

              說明:

              int SetDialogSkin(
              char* lpSkinName //為skinFrameWnd對象指定的名稱
              );
              使用該函數后,以后程序創建的對話框都將使用該皮膚,但對話框大小不可變。
            3)為單個對話框窗口添加皮膚,例如在對話框視圖中:重載對話框視圖的創建函數OnCreate,加入如下代碼:

              VERIFY( 1 == SetSingleDialogSkin( m_hWnd, "Dialog" ) );

              EnableWindowScrollbarSkin( m_hWnd , SB_BOTH );

              說明:

              int SetSingleDialogSkin(
              HWND hWnd, //要使用皮膚的窗口句柄
              char* lpSkinName //為skinFrameWnd對象指定的名稱
              );
              int EnableWindowScrollbarSkin( //為滾動條添加皮膚
              HWND hWnd, //要使用皮膚的窗口句柄
              int* fnBar //要使用皮膚的滾動條,SB_BOTH表明是橫豎都是用皮膚
              );

              4、釋放SkinMagic資源
             
              重載應用程序的ExitInstance()函數,添加如下代碼:

              ExitSkinMagicLib();

            posted @ 2009-05-20 20:57 wrh 閱讀(482) | 評論 (0)編輯 收藏
            如果n <= 0,返回NULL
            如果n == 1,返回"",也就是一個空串。
            如果成功返回值等于string,也就是獲得的字符串的首地址。
            如果出錯,或者讀到FILE的結尾,返回NULL.

            以下是這個函數的實現:

            /***
            *fgets.c - get string from a file
            *
            * Copyright (c) Microsoft Corporation. All rights reserved.
            *
            *Purpose:
            * defines fgets() - read a string from a file
            *
            *******************************************************************************/

            #include <cruntime.h>
            #include <stdio.h>
            #include <dbgint.h>
            #include <file2.h>
            #include <internal.h>
            #include <mtdll.h>
            #include <tchar.h>

            /***
            *char *fgets(string, count, stream) - input string from a stream
            *
            *Purpose:
            * get a string, up to count-1 chars or '\n', whichever comes first,
            * append '\0' and put the whole thing into string. the '\n' IS included
            * in the string. if count<=1 no input is requested. if EOF is found
            * immediately, return NULL. if EOF found after chars read, let EOF
            * finish the string as '\n' would.
            *
            *Entry:
            * char *string - pointer to place to store string
            * int count - max characters to place at string (include \0)
            * FILE *stream - stream to read from
            *
            *Exit:
            * returns string with text read from file in it.
            * if count <= 0 return NULL
            * if count == 1 put null string in string
            * returns NULL if error or end-of-file found immediately
            *
            *Exceptions:
            *
            *******************************************************************************/

            _TSCHAR * __cdecl _fgetts (
            _TSCHAR *string,
            int count,
            FILE *str
            )
            {
            REG1 FILE *stream;
            REG2 _TSCHAR *pointer = string;
            _TSCHAR *retval = string;
            int ch;

            _VALIDATE_RETURN(( string != NULL ) || ( count == 0 ), EINVAL, NULL);
            _VALIDATE_RETURN(( count >= 0 ), EINVAL, NULL);
            _VALIDATE_RETURN(( str != NULL ), EINVAL, NULL);

            if (count == 0)
            {
            return NULL;
            }

            /* The C Standard states the input buffer should remain
            unchanged if EOF is encountered immediately. Hence we
            do not blank out the input buffer here */

            /* Init stream pointer */
            stream = str;

            _lock_str(stream);
            __try {

            #ifndef _UNICODE
            _VALIDATE_STREAM_ANSI_SETRET(stream, EINVAL, retval, NULL);
            #endif /* _UNICODE */
            if(retval!=NULL)
            {
            while (--count)
            {
            if ((ch = _fgettc_nolock(stream)) == _TEOF)
            {
            if (pointer == string) {
            retval=NULL;
            goto done;
            }

            break;
            }

            if ((*pointer++ = (_TSCHAR)ch) == _T('\n'))
            break;
            }
            *pointer = _T('\0');
            }


            /* Common return */
            done:

            ; }
            __finally {
            _unlock_str(stream);
            }

            return(retval);
            }
            posted @ 2009-05-20 09:22 wrh 閱讀(771) | 評論 (0)編輯 收藏
            F1: 幫助 
            Ctrl+O :Open 
            Ctrl+P :Print 
            Ctrl+N :New 
            Ctrl+Shift+F2 :清除所有書簽 
            F2 :上一個書簽 
            Shift+F2 :上一個書簽 
            Alt+F2 :編輯書簽 
            Ctrl+F2 :添加/刪除一個書簽 
            F12 :Goto definition 
            Shift+F12 :Goto reference 
            Ctrl+'Num+' :Displays the next symbol definition or reference 
            Ctrl+'Num-' :Displays the previous symbol definition or reference 
            Ctrl+J/K :尋找上一個/下一個預編譯條件 
            Ctrl+Shift+J/K :尋找上一個/下一個預編譯條件并將這一塊選定 
            Ctrl+End :文檔尾 
            Ctrl+Shift+End :選定從當前位置到文檔尾 
            Ctrl+Home :文檔頭 
            Ctrl+Shift+Home :選定從當前位置到文檔頭 
            Ctrl+B/Alt+F9 :編輯斷點 
            Alt+F3/Ctrl+F :查找 
            F3 :查找下一個 
            Shift+F3 :查找上一個 
            Ctrl+]/Ctrl+E :尋找下一半括弧 
            Ctrl+Shift+] :尋找下一半括弧并選定括弧之間的部分(包括括弧) 
            Ctrl+Shift+E :尋找下一半括弧并選定括弧之間的部分(包括括弧) 
            F4 :尋找下一個錯誤/警告位置 
            Shift+F4 :尋找上一個錯誤/警告位置 
            Shift+Home :選定從當前位置到行首 
            Shift+End :選定從當前位置到行尾 
            Ctrl+L :剪切當前行 
            Ctrl+Shift+L :刪除當前行 
            Alt+Shift+T :交換當前行和上一行 
            Ctrl+Alt+T :Brings up the completion list box 
            Shift+PageDown :選定從當前位置到下一頁當前位置 
            Shift+PageUp :選定從當前位置到上一頁當前位置 
            Ctrl+Shift+Space:顯示函數參數的Tooltip 
            Ctrl+Z/Alt+Backspace :Undo 
            Ctrl+Shift+Z/Ctrl+Y :Redo 
            F8 :當前位置變成選定區域的頭/尾(再移動光標或者點鼠標就會選定) 
            Ctrl+Shift+F8 :當前位置變成矩形選定區域的頭/尾(再移動光標或者點鼠標就會選定) 
            Alt+F8 :自動格式重排 
            Ctrl+G :Goto 
            Ctlr+X/Shift+Del:Cut 
            Ctrl+C/Ctrl+Ins :Copy 
            Ctrl+V/Shift+Ins:Paste 
            Ctrl+U :將選定區域轉換成小寫 
            Ctrl+Shift+U :將選定區域轉換成大寫 
            Ctrl+F8 :當前行變成選定區域的頭/尾(再移動上下光標或者點鼠標就會選定多行) 
            Ctrl+Shift+L :刪除從當前位置到行尾 
            Ctrl+Shift+8 :將所有Tab變成`或者還原 
            Ctrl+T :顯示變量類型 
            Ctrl+↑ :向上滾屏 
            Ctrl+↓ :向下滾屏 
            Ctrl+Del :刪除當前單詞的后半截(以光標為分割) 
            Ctrl+Backspace :刪除當前單詞的前半截(以光標為分割) 
            Ctrl+← :移到前一個單詞 
            Ctrl+→ :移到后一個單詞 
            Ctrl+Shift+← :選定當前位置到前一個單詞 
            Ctrl+Shift+→ :選定當前位置到后一個單詞 
            Ctrl+Shift+T :將本單詞和上一個單詞互換
            posted @ 2009-04-24 15:48 wrh 閱讀(270) | 評論 (0)編輯 收藏
            數學函數,所在函數庫為math.h、stdlib.h、string.h、float.h    
              ----------------------------------------------------------------------------------------------------------  
               
               
              int   abs(int   i)   返回整型參數i的絕對值    
              double   cabs(struct   complex   znum)   返回復數znum的絕對值    
              double   fabs(double   x)   返回雙精度參數x的絕對值    
              long   labs(long   n)   返回長整型參數n的絕對值    
              double   exp(double   x)   返回指數函數ex的值    
              double   frexp(double   value,int   *eptr)   返回value=x*2n中x的值,n存貯在eptr中    
              double   ldexp(double   value,int   exp);   返回value*2exp的值    
              double   log(double   x)   返回logex的值    
              double   log10(double   x)   返回log10x的值    
              double   pow(double   x,double   y)   返回xy的值    
              double   pow10(int   p)   返回10p的值    
              double   sqrt(double   x)   返回x的開方    
              double   acos(double   x)   返回x的反余弦cos-1(x)值,x為弧度    
              double   asin(double   x)   返回x的反正弦sin-1(x)值,x為弧度    
              double   atan(double   x)   返回x的反正切tan-1(x)值,x為弧度    
              double   atan2(double   y,double   x)   返回y/x的反正切tan-1(x)值,y的x為弧度    
              double   cos(double   x)   返回x的余弦cos(x)值,x為弧度    
              double   sin(double   x)   返回x的正弦sin(x)值,x為弧度    
              double   tan(double   x)   返回x的正切tan(x)值,x為弧度    
              double   cosh(double   x)   返回x的雙曲余弦cosh(x)值,x為弧度    
              double   sinh(double   x)   返回x的雙曲正弦sinh(x)值,x為弧度    
              double   tanh(double   x)   返回x的雙曲正切tanh(x)值,x為弧度    
              double   hypot(double   x,double   y)   返回直角三角形斜邊的長度(z),   x和y為直角邊的長度,z2=x2+y2    
              double   ceil(double   x)   返回不小于x的最小整數    
              double   floor(double   x)   返回不大于x的最大整數    
              void   srand(unsigned   seed)   初始化隨機數發生器    
              int   rand()   產生一個隨機數并返回這個數    
              double   poly(double   x,int   n,double   c[])   從參數產生一個多項式    
              double   modf(double   value,double   *iptr)   將雙精度數value分解成尾數和階    
              double   fmod(double   x,double   y)   返回x/y的余數    
              double   frexp(double   value,int   *eptr)   將雙精度數value分成尾數和階    
              double   atof(char   *nptr)   將字符串nptr轉換成浮點數并返回這個浮點數    
              double   atoi(char   *nptr)   將字符串nptr轉換成整數并返回這個整數    
              double   atol(char   *nptr)   將字符串nptr轉換成長整數并返回這個整數    
              char   *ecvt(double   value,int   ndigit,int   *decpt,int   *sign)    
              將浮點數value轉換成字符串并返回該字符串    
              char   *fcvt(double   value,int   ndigit,int   *decpt,int   *sign)    
              將浮點數value轉換成字符串并返回該字符串    
              char   *gcvt(double   value,int   ndigit,char   *buf)    
              將數value轉換成字符串并存于buf中,并返回buf的指針    
              char   *ultoa(unsigned   long   value,char   *string,int   radix)    
              將無符號整型數value轉換成字符串并返回該字符串,radix為轉換時所用基數    
              char   *ltoa(long   value,char   *string,int   radix)    
              將長整型數value轉換成字符串并返回該字符串,radix為轉換時所用基數    
              char   *itoa(int   value,char   *string,int   radix)    
              將整數value轉換成字符串存入string,radix為轉換時所用基數    
              double   atof(char   *nptr)   將字符串nptr轉換成雙精度數,并返回這個數,錯誤返回0    
              int   atoi(char   *nptr)   將字符串nptr轉換成整型數,   并返回這個數,錯誤返回0    
              long   atol(char   *nptr)   將字符串nptr轉換成長整型數,并返回這個數,錯誤返回0    
              double   strtod(char   *str,char   **endptr)將字符串str轉換成雙精度數,并返回這個數,    
              long   strtol(char   *str,char   **endptr,int   base)將字符串str轉換成長整型數,   并返回這個數,    
              int   matherr(struct   exception   *e)   用戶修改數學錯誤返回信息函數(沒有必要使用)    
              double   _matherr(_mexcep   why,char   *fun,double   *arg1p,   double   *arg2p,double   retval)    
              用戶修改數學錯誤返回信息函數(沒有必要使用)    
              unsigned   int   _clear87()   清除浮點狀態字并返回原來的浮點狀態    
              void   _fpreset()   重新初使化浮點數學程序包    
              unsigned   int   _status87()   返回浮點狀態字
            posted @ 2009-04-15 10:03 wrh 閱讀(514) | 評論 (0)編輯 收藏

            在VC++6.0中missing function header (old-style formal list?)解決方法

            該函數的函數頭后邊加了分號

            去掉即可

            例如:void fun();{}就會出現那種情況

            posted @ 2009-03-27 10:37 wrh 閱讀(2054) | 評論 (0)編輯 收藏

            VC中沒有現成的函數來選擇一個文件夾,但這是經常會用到的,怎么辦?
            自動動手,豐衣足食!

            使用SHBrowseForFolder,代碼如下:

            #include
              
            int SelFolder(HWND hParent, CString &strFolder)
            {
                strFolder.Empty();
             
                LPMALLOC lpMalloc;
             
                if (::SHGetMalloc(&lpMalloc) != NOERROR) return 0;
             
                char szDisplayName[_MAX_PATH];
                char szBuffer[_MAX_PATH];
                BROWSEINFO browseInfo;
                browseInfo.hwndOwner = hParent;
                browseInfo.pidlRoot = NULL; // set root at Desktop
                browseInfo.pszDisplayName = szDisplayName;
                browseInfo.lpszTitle = "Select a folder";
                browseInfo.ulFlags = BIF_RETURNFSANCESTORS|BIF_RETURNONLYFSDIRS;
                browseInfo.lpfn = NULL;
                browseInfo.lParam = 0;
             
                LPITEMIDLIST lpItemIDList;
                if ((lpItemIDList = ::SHBrowseForFolder(&browseInfo)) != NULL)
                {
                    // Get the path of the selected folder from the    item ID list.
                    if (::SHGetPathFromIDList(lpItemIDList, szBuffer))
                    {
                        // At this point, szBuffer contains the path the user chose.
                        if (szBuffer[0] == ´\0´) return 0;
             
                        // We have a path in szBuffer! Return it.
                        strFolder = szBuffer;
                        return 1;
                    }
                    else return 1; // strResult is empty
             
                    lpMalloc->Free(lpItemIDList);
                    lpMalloc->Release();
                }
               
             return 1;
            }

             

            //////調用:

            void CMusic1Dlg::OnOK()
            {
             // TODO: Add extra validation here
             CString str;

             HWND m_hWnd = GetSafeHwnd();
             
             SelFolder(m_hWnd,str);

             m_list.AddString(str);
            // CDialog::OnOK();
            }

            //------------------------------------------------------------------------------------------------------

            //_________________________________________________________________

            “選擇文件夾”對話框的封裝


            我們經常需要用到“選擇文件夾”對話框,相應的API已經很好用,但稍嫌麻煩,所以我專門將其封裝了一下,力求一步到位。

            函數封裝如下:
            /*****************************************************************
            ** 函數名:GetPath
            ** 輸 入: 無
            ** 輸 出: CString strPath
            **        strPath非空, 表示用戶選擇的文件夾路徑
            **        strPath為空, 表示用戶點擊了“取消”鍵,取消選擇
            ** 功能描述:顯示“選擇文件夾”對話框,讓用戶選擇文件夾
            ****************************************************************/

            CString GetPath()
            {
             CString strPath = "";
             BROWSEINFO bInfo;
             ZeroMemory(&bInfo, sizeof(bInfo));
             bInfo.hwndOwner = m_hWnd;
             bInfo.lpszTitle = _T("請選擇路徑: ");
             bInfo.ulFlags = BIF_RETURNONLYFSDIRS;   
             
             LPITEMIDLIST lpDlist; //用來保存返回信息的IDList
             lpDlist = SHBrowseForFolder(&bInfo) ; //顯示選擇對話框
             if(lpDlist != NULL)  //用戶按了確定按鈕
             {
              TCHAR chPath[255]; //用來存儲路徑的字符串
              SHGetPathFromIDList(lpDlist, chPath);//把項目標識列表轉化成字符串
              strPath = chPath; //將TCHAR類型的字符串轉換為CString類型的字符串
             }
             return strPath;
            }

            調用時只需要用到以下代碼:
            CString strPath = GetPath();
            則strPath為用戶選擇的文件夾路徑。如果用戶點擊了對話框的取消鍵,則strPath為空字符串("");

            posted @ 2009-03-14 10:02 wrh 閱讀(5229) | 評論 (1)編輯 收藏
            char   path[MAX_PATH];  
              GetModuleFileName(NULL,path,MAX_PATH);

            GetModuleFileName(   AfxGetInstanceHandle(),szPath,MAX_PATH);


            GetModuleFileNameEx  
              The   GetModuleFileNameEx   function   retrieves   the   fully   qualified   path   for   the   specified   module.    
               
              DWORD   GetModuleFileNameEx(  
                  HANDLE   hProcess,         //   handle   to   the   process  
                  HMODULE   hModule,         //   handle   to   the   module  
                  LPTSTR   lpFilename,     //   buffer   that   receives   the   path  
                  DWORD   nSize                   //   size   of   the   buffer  
              );  
                 
              Parameters  
              hProcess    
              Handle   to   the   process   that   contains   the   module.    
              hModule    
              Handle   to   the   module.    
              lpFilename    
              Pointer   to   the   buffer   that   receives   the   fully   qualified   path   to   the   module.    
              nSize    
              Specifies   the   size,   in   bytes,   of   the   lpFilename   buffer.    
              Return   Value  
              If   the   function   succeeds,   the   return   value   specifies   the   length   of   the   string   copied   to   the   buffer.    
               
              If   the   function   fails,   the   return   value   is   zero.   To   get   extended   error   information,   call   GetLastError.    
               
              See   Also  
              Process   Status   Helper   Overview,   PSAPI   Functions,   EnumProcesses,   GetModuleBaseName     
               
            posted @ 2009-03-14 10:00 wrh 閱讀(1493) | 評論 (0)編輯 收藏

            文件的打開(fopen函數)

            fopen函數用來打開一個文件,其調用的一般形式為:
            文件指針名=fopen(文件名,使用文件方式);
            其中,
            “文件指針名”必須是被說明為FILE 類型的指針變量;
            “文件名”是被打開文件的文件名;
            “使用文件方式”是指文件的類型和操作要求。
            “文件名”是字符串常量或字符串數組。
            例如:
            FILE *fp;
            fp=("file a","r");
            其意義是在當前目錄下打開文件file a,只允許進行“讀”操作,并使fp指向該文件。
            又如:
            FILE *fphzk
            fphzk=("c:\\hzk16","rb")
            其意義是打開C驅動器磁盤的根目錄下的文件hzk16,這是一個二進制文件,只允許按二進制方式進行讀操作。兩個反斜線“\\ ”中的第一個表示轉義字符,第二個表示根目錄。

            使用文件的方式共有12種,下面給出了它們的符號和意義。
            文件使用方式 意義
            “rt” 只讀打開一個文本文件,只允許讀數據
            “wt” 只寫打開或建立一個文本文件,只允許寫數據
            “at” 追加打開一個文本文件,并在文件末尾寫數據
            “rb” 只讀打開一個二進制文件,只允許讀數據
            “wb” 只寫打開或建立一個二進制文件,只允許寫數據
            “ab” 追加打開一個二進制文件,并在文件末尾寫數據
            “rt+” 讀寫打開一個文本文件,允許讀和寫
            “wt+” 讀寫打開或建立一個文本文件,允許讀寫
            “at+” 讀寫打開一個文本文件,允許讀,或在文件末追加數據
            “rb+” 讀寫打開一個二進制文件,允許讀和寫
            “wb+” 讀寫打開或建立一個二進制文件,允許讀和寫
            “ab+” 讀寫打開一個二進制文件,允許讀,或在文件末追加數據

            對于文件使用方式有以下幾點說明:
            1) 文件使用方式由r,w,a,t,b,+六個字符拼成,各字符的含義是:
            r(read): 讀
            w(write): 寫
            a(append): 追加
            t(text): 文本文件,可省略不寫
            b(banary): 二進制文件
            +: 讀和寫
            2) 凡用“r”打開一個文件時,該文件必須已經存在,且只能從該文件讀出。
            3) 用“w”打開的文件只能向該文件寫入。若打開的文件不存在,則以指定的文件名建立該文件,若打開的文件已經存在,則將該文件刪去,重建一個新文件。
            4) 若要向一個已存在的文件追加新的信息,只能用“a”方式打開文件。但此時該文件必須是存在的,否則將會出錯。
            5) 在打開一個文件時,如果出錯,fopen將返回一個空指針值NULL。在程序中可以用這一信息來判別是否完成打開文件的工作,并作相應的處理。因此常用以下程序段打開文件:
            6) if((fp=fopen("c:\\hzk16","rb")==NULL)
            {
            printf("\nerror on open c:\\hzk16 file!");
            getch();
            exit(1);
            }

            這段程序的意義是,如果返回的指針為空,表示不能打開C盤根目錄下的hzk16文件,則給出提示信息“error on open c:\ hzk16 file!”,下一行getch()的功能是從鍵盤輸入一個字符,但不在屏幕上顯示。在這里,該行的作用是等待,只有當用戶從鍵盤敲任一鍵時,程序才繼續執行,因此用戶可利用這個等待時間閱讀出錯提示。敲鍵后執行exit(1)退出程序。

            7) 把一個文本文件讀入內存時,要將ASCII碼轉換成二進制碼,而把文件以文本方式寫入磁盤時,也要把二進制碼轉換成ASCII碼,因此文本文件的讀寫要花費較多的轉換時間。對二進制文件的讀寫不存在這種轉換。

            8) 標準輸入文件(鍵盤),標準輸出文件(顯示器),標準出錯輸出(出錯信息)是由系統打開的,可直接使用。

            posted @ 2009-03-13 13:08 wrh 閱讀(9371) | 評論 (0)編輯 收藏
            隊列消息和非隊列消息
               
            從消息的發送途徑來看,消息可以分成2種:隊列消息和非隊列消息。消息隊列由可以分成系統消息隊列和線程消息隊列。系統消息隊列由Windows維護,線程消息隊列則由每個GUI線程自己進行維護,為避免給non-GUI現成創建消息隊列,所有線程產生時并沒有消息隊列,僅當線程第一次調用GDI函數數系統給線程創建一個消息隊列。隊列消息送到系統消息隊列,然后到線程消息隊列;非隊列消息直接送給目的窗口過程。
                 對于隊列消息,最常見的是鼠標和鍵盤觸發的消息,例如WM_MOUSERMOVE,WM_CHAR等消息,還有一些其它的消息,例如:WM_PAINT、WM_TIMER和WM_QUIT。當鼠標、鍵盤事件被觸發后,相應的鼠標或鍵盤驅動程序就會把這些事件轉換成相應的消息,然后輸送到系統消息隊列,由Windows系統去進行處理。Windows系統則在適當的時機,從系統消息隊列中取出一個消息,根據前面我們所說的MSG消息結構確定消息是要被送往那個窗口,然后把取出的消息送往創建窗口的線程的相應隊列,下面的事情就該由線程消息隊列操心了,Windows開始忙自己的事情去了。線程看到自己的消息隊列中有消息,就從隊列中取出來,通過操作系統發送到合適的窗口過程去處理。
                 一般來講,系統總是將消息Post在消息隊列的末尾。這樣保證窗口以先進先出的順序接受消息。然而,WM_PAINT是一個例外,同一個窗口的多個 WM_PAINT被合并成一個 WM_PAINT 消息, 合并所有的無效區域到一個無效區域。合并WM_PAIN的目的是為了減少刷新窗口的次數。
                非隊列消息將會繞過系統隊列和消息隊列,直接將消息發送到窗口過程,。系統發送非隊列消息通知窗口,系統發送消息通知窗口。 例如,當用戶激活一個窗口系統發送WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR。這些消息通知窗口它被激活了。非隊列消息也可以由當應用程序調用系統函數產生。例如,當程序調用SetWindowPos系統發送WM_WINDOWPOSCHANGED消息。一些函數也發送非隊列消息,例如下面我們要談到的函數。
                
            消息的發送
                 了解了上面的這些基礎理論之后,我們就可以進行一下簡單的消息發送與接收。
                 把一個消息發送到窗口有3種方式:發送、寄送和廣播。
                 發送消息的函數有SendMessage、SendMessageCallback、SendNotifyMessage、SendMessageTimeout;寄送消息的函數主要有PostMessage、PostThreadMessage、PostQuitMessage;廣播消息的函數我知道的只有BroadcastSystemMessage、BroadcastSystemMessageEx。
                 SendMessage的原型如下:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam),這個函數主要是向一個或多個窗口發送一條消息,一直等到消息被處理之后才會返回。不過需要注意的是,如果接收消息的窗口是同一個應用程序的一部分,那么這個窗口的窗口函數就被作為一個子程序馬上被調用;如果接收消息的窗口是被另外的線程所創建的,那么窗口系統就切換到相應的線程并且調用相應的窗口函數,這條消息不會被放進目標應用程序隊列中。函數的返回值是由接收消息的窗口的窗口函數返回,返回的值取決于被發送的消息。
                 PostMessage的原型如下:BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam),該函數把一條消息放置到創建hWnd窗口的線程的消息隊列中,該函數不等消息被處理就馬上將控制返回。需要注意的是,如果hWnd參數為HWND_BROADCAST,那么,消息將被寄送給系統中的所有的重疊窗口和彈出窗口,但是子窗口不會收到該消息;如果hWnd參數為NULL,則該函數類似于將dwThreadID參數設置成當前線程的標志來調用PostThreadMEssage函數。
              從上面的這2個具有代表性的函數,我們可以看出消息的發送方式和寄送方式的區別所在:被發送的消息是否會被立即處理,函數是否立即返回。被發送的消息會被立即處理,處理完畢后函數才會返回;被寄送的消息不會被立即處理,他被放到一個先進先出的隊列中,一直等到應用程序空線的時候才會被處理,不過函數放置消息后立即返回。
              實際上,發送消息到一個窗口處理過程和直接調用窗口處理過程之間并沒有太大的區別,他們直接的唯一區別就在于你可以要求操作系統截獲所有被發送的消息,但是不能夠截獲對窗口處理過程的直接調用。
              以寄送方式發送的消息通常是與用戶輸入事件相對應的,因為這些事件不是十分緊迫,可以進行緩慢的緩沖處理,例如鼠標、鍵盤消息會被寄送,而按鈕等消息則會被發送。
              廣播消息用得比較少,BroadcastSystemMessage函數原型如下:
                  long BroadcastSystemMessage(DWORD dwFlags,LPDWORD lpdwRecipients,UINT uiMessage,WPARAM wParam,LPARAM lParam);該函數可以向指定的接收者發送一條消息,這些接收者可以是應用程序、可安裝的驅動程序、網絡驅動程序、系統級別的設備驅動消息和他們的任意組合。需要注意的是,如果dwFlags參數是BSF_QUERY并且至少一個接收者返回了BROADCAST_QUERY_DENY,則返回值為0,如果沒有指定BSF_QUERY,則函數將消息發送給所有接收者,并且忽略其返回值。

            消息的接收
             
            消息的接收主要有3個函數:GetMessage、PeekMessage、WaitMessage。
              GetMessage原型如下:BOOL GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax);該函數用來獲取與hWnd參數所指定的窗口相關的且wMsgFilterMin和wMsgFilterMax參數所給出的消息值范圍內的消息。需要注意的是,如果hWnd為NULL,則GetMessage獲取屬于調用該函數應用程序的任一窗口的消息,如果wMsgFilterMin和wMsgFilterMax都是0,則GetMessage就返回所有可得到的消息。函數獲取之后將刪除消息隊列中的除WM_PAINT消息之外的其他消息,至于WM_PAINT則只有在其處理之后才被刪除。
               PeekMessage原型如下:BOOL PeekMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg);該函數用于查看應用程序的消息隊列,如果其中有消息就將其放入lpMsg所指的結構中,不過,與GetMessage不同的是,PeekMessage函數不會等到有消息放入隊列時才返回。同樣,如果hWnd為NULL,則PeekMessage獲取屬于調用該函數應用程序的任一窗口的消息,如果hWnd=-1,那么函數只返回把hWnd參數為NULL的PostAppMessage函數送去的消息。如果wMsgFilterMin和wMsgFilterMax都是0,則PeekMessage就返回所有可得到的消息。函數獲取之后將刪除消息隊列中的除WM_PAINT消息之外的其他消息,至于WM_PAINT則只有在其處理之后才被刪除。
               WaitMessage原型如下:BOOL VaitMessage();當一個應用程序無事可做時,該函數就將控制權交給另外的應用程序,同時將該應用程序掛起,直到一個新的消息被放入應用程序的隊列之中才返回。

            消息的處理
              接下來我們談一下消息的處理,首先我們來看一下VC中的消息泵:
            while(GetMessage(&msg, NULL, 0, 0))
            {
                   if(!TranslateAccelerator(msg.hWnd, hAccelTable, &msg))
                  {
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                   }
            }

               首先,GetMessage從進程的主線程的消息隊列中獲取一個消息并將它復制到MSG結構,如果隊列中沒有消息,則GetMessage函數將等待一個消息的到來以后才返回。 如果你將一個窗口句柄作為第二個參數傳入GetMessage,那么只有指定窗口的的消息可以從隊列中獲得。GetMessage也可以從消息隊列中過濾消息只接受消息隊列中落在范圍內的消息。這時候就要利用GetMessage/PeekMessage指定一個消息過濾器。這個過濾器是一個消息標識符的范圍或者是一個窗體句柄,或者兩者同時指定。當應用程序要查找一個后入消息隊列的消息是很有用。WM_KEYFIRST 和 WM_KEYLAST 常量用于接受所有的鍵盤消息。 WM_MOUSEFIRST 和 WM_MOUSELAST 常量用于接受所有的鼠標消息。
             然后TranslateAccelerator判斷該消息是不是一個按鍵消息并且是一個加速鍵消息,如果是,則該函數將把幾個按鍵消息轉換成一個加速鍵消息傳遞給窗口的回調函數。處理了加速鍵之后,函數TranslateMessage將把兩個按鍵消息WM_KEYDOWN和WM_KEYUP轉換成一個WM_CHAR,不過需要注意的是,消息WM_KEYDOWN,WM_KEYUP仍然將傳遞給窗口的回調函數。    
             處理完之后,DispatchMessage函數將把此消息發送給該消息指定的窗口中已設定的回調函數。如果消息是WM_QUIT,則GetMessage返回0,從而退出循環體。應用程序可以使用PostQuitMessage來結束自己的消息循環。通常在主窗口的WM_DESTROY消息中調用。
             下面我們舉一個常見的小例子來說明這個消息泵的運用:
            if (::PeekMessage(&msg, m_hWnd, WM_KEYFIRST,WM_KEYLAST, PM_REMOVE))
            {
                      if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)...
            }
              這里我們接受所有的鍵盤消息,所以就用WM_KEYFIRST 和 WM_KEYLAST作為參數。最后一個參數可以是PM_NOREMOVE 或者 PM_REMOVE,表示消息信息是否應該從消息隊列中刪除。                
               所以這段小代碼就是判斷是否按下了Esc鍵,如果是就進行處理。

            窗口過程
             窗口過程是一個用于處理所有發送到這個窗口的消息的函數。任何一個窗口類都有一個窗口過程。同一個類的窗口使用同樣的窗口過程來響應消息。 系統發送消息給窗口過程將消息數據作為參數傳遞給他,消息到來之后,按照消息類型排序進行處理,其中的參數則用來區分不同的消息,窗口過程使用參數產生合適行為。
             一個窗口過程不經常忽略消息,如果他不處理,它會將消息傳回到執行默認的處理。窗口過程通過調用DefWindowProc來做這個處理。窗口過程必須return一個值作為它的消息處理結果。大多數窗口只處理小部分消息和將其他的通過DefWindowProc傳遞給系統做默認的處理。窗口過程被所有屬于同一個類的窗口共享,能為不同的窗口處理消息。下面我們來看一下具體的實例:

            LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
            {
             int wmId, wmEvent;
             PAINTSTRUCT ps;
             HDC hdc;
             TCHAR szHello[MAX_LOADSTRING];
             LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

             switch (message)
             {
              case WM_COMMAND:
                     wmId    = LOWORD(wParam);
                     wmEvent = HIWORD(wParam);
                     // Parse the menu selections:
                     switch (wmId)
                     {
                      case IDM_ABOUT:
                         DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
                         break;
                      case IDM_EXIT:
                         DestroyWindow(hWnd);
                         break;
                      default:
                         return DefWindowProc(hWnd, message, wParam, lParam);
                     }
               break;

              case WM_PAINT:
                     hdc = BeginPaint(hWnd, &ps);
                     // TODO: Add any drawing code here...
                     RECT rt;
                     GetClientRect(hWnd, &rt);
                     DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
                     EndPaint(hWnd, &ps);
                     break;

              case WM_DESTROY:
                     PostQuitMessage(0);
                     break;
              default:
                     return DefWindowProc(hWnd, message, wParam, lParam);
              }
              return 0;
            }

            消息分流器
              通常的窗口過程是通過一個switch語句來實現的,這個事情很煩,有沒有更簡便的方法呢?有,那就是消息分流器,利用消息分流器,我們可以把switch語句分成更小的函數,每一個消息都對應一個小函數,這樣做的好處就是對消息更容易管理。
              之所以被稱為消息分流器,就是因為它可以對任何消息進行分流。下面我們做一個函數就很清楚了:
            void MsgCracker(HWND hWnd,int id,HWND hWndCtl,UINT codeNotify)
            {
                  switch(id)
                  {
                 case ID_A:
                              if(codeNotify==EN_CHANGE)...
                              break;
                 case ID_B:
                              if(codeNotify==BN_CLICKED)...
                              break;
                         ....
                   }
            }
            然后我們修改一下窗口過程:
            LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
            {
                   switch(message)
                  {
                         HANDLE_MSG(hWnd,WM_COMMAND,MsgCracker);
                         HANDLE_MSG(hWnd,WM_DESTROY,MsgCracker);
                       default:
                                return DefWindowProc(hWnd, message, wParam, lParam);
               }
              return 0;
            }
            在WindowsX.h中定義了如下的HANDLE_MSG宏:
               #define HANDLE_MSG(hwnd,msg,fn) \
                         switch(msg): return HANDLE_##msg((hwnd),(wParam),(lParam),(fn));
            實際上,HANDLE_WM_XXXX都是宏,例如:HANDLE_MSG(hWnd,WM_COMMAND,MsgCracker);將被轉換成如下定義:
               #define HANDLE_WM_COMMAND(hwnd,wParam,lParam,fn)\
                         ((fn)((hwnd),(int)(LOWORD(wParam)),(HWND)(lParam),(UINT)HIWORD(wParam)),0L);
            好了,事情到了這一步,應該一切都明朗了。
            不過,我們發現在windowsx.h里面還有一個宏:FORWARD_WM_XXXX,我們還是那WM_COMMAND為例,進行分析:
               #define FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \
                 (void)(fn)((hwnd), WM_COMMAND, MAKEWPARAM((UINT)(id),(UINT)(codeNotify)), (LPARAM)(HWND)(hwndCtl))
            所以實際上,FORWARD_WM_XXXX將消息參數進行了重新構造,生成了wParam && lParam,然后調用了我們定義的函數。
            好了,事情到這里也算是也段落了,下次我們在分析消息在MFC中的處理。

            posted @ 2009-02-21 08:37 wrh 閱讀(438) | 評論 (0)編輯 收藏
            僅列出標題
            共25頁: First 13 14 15 16 17 18 19 20 21 Last 

            導航

            <2010年5月>
            2526272829301
            2345678
            9101112131415
            16171819202122
            23242526272829
            303112345

            統計

            常用鏈接

            留言簿(19)

            隨筆檔案

            文章檔案

            收藏夾

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            一本一本久久a久久综合精品蜜桃 一本一道久久综合狠狠老 | 久久久久久人妻无码| 亚洲精品成人网久久久久久| 久久精品国产第一区二区| 亚洲国产日韩综合久久精品| 亚洲中文字幕无码久久精品1 | 久久久久久极精品久久久 | 99精品国产免费久久久久久下载| 狠狠色丁香婷婷综合久久来| 久久久久女教师免费一区| 久久人妻少妇嫩草AV蜜桃| 久久99精品国产麻豆婷婷| 狠狠色综合网站久久久久久久高清| 97精品久久天干天天天按摩| 久久亚洲精品国产精品婷婷| 久久久久久狠狠丁香| 亚洲欧美伊人久久综合一区二区| 久久五月精品中文字幕| 国产成人综合久久精品尤物| 国产亚洲婷婷香蕉久久精品| 久久精品成人欧美大片| 欧美午夜A∨大片久久| 久久精品中文字幕第23页| 无码人妻精品一区二区三区久久久| 久久青青草原精品国产软件| 大蕉久久伊人中文字幕| 国产精品久久成人影院| 精品久久久久久中文字幕人妻最新| 久久精品一本到99热免费| 亚洲国产香蕉人人爽成AV片久久 | 日本一区精品久久久久影院| 99久久精品午夜一区二区| 无码日韩人妻精品久久蜜桃| 中文字幕精品久久| 久久这里都是精品| 国内精品伊人久久久影院| 无码人妻久久一区二区三区蜜桃| 久久婷婷五月综合97色直播 | 久久久久久久亚洲Av无码| 久久九九兔免费精品6| 亚洲国产一成人久久精品|