• <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>

            2010年8月31日

            The article is from http://www.java-samples.com/showtutorial.php?tutorialid=591

            To set all the bytes in a block of memory to a particular value, use memset(). The function prototype is

            void * memset(void *dest, int c, size_t count);
            

            The argument dest points to the block of memory. c is the value to set, and count is the number of bytes, starting at dest, to be set. Note that while c is a type int, it is treated as a type char. In other words, only the low-order byte is used, and you can specify values of c only in the range 0 through 255.

            Use memset() to initialize a block of memory to a specified value. Because this function can use only a type char as the initialization value, it is not useful for working with blocks of data types other than type char, except when you want to initialize to 0. In other words, it wouldn't be efficient to use memset() to initialize an array of type int to the value 99, but you could initialize all array elements to the value 0. memset() will be demonstrated in program below.

            The memcpy() Function

            memcpy() copies bytes of data between memory blocks, sometimes called buffers. This function doesn't care about the type of data being copied--it simply makes an exact byte-for-byte copy. The function prototype is

            void *memcpy(void *dest, void *src, size_t count);
            

            The arguments dest and src point to the destination and source memory blocks, respectively. count specifies the number of bytes to be copied. The return value is dest. If the two blocks of memory overlap, the function might not operate properly--some of the data in src might be overwritten before being copied. Use the memmove() function, discussed next, to handle overlapping memory blocks. memcpy() will be demonstrated in program below.

            The memmove() Function

            memmove() is very much like memcpy(), copying a specified number of bytes from one memory block to another. It's more flexible, however, because it can handle overlapping memory blocks properly. Because memmove() can do everything memcpy() can do with the added flexibility of dealing with overlapping blocks, you rarely, if ever, should have a reason to use memcpy(). The prototype is

            void *memmove(void *dest, void *src, size_t count);
            

            dest and src point to the destination and source memory blocks, and count specifies the number of bytes to be copied. The return value is dest. If the blocks overlap, this function ensures that the source data in the overlapped region is copied before being overwritten. Sample program below demonstrates memset(), memcpy(), and memmove().

            A demonstration of memset(), memcpy(), and memmove().

            1: /* Demonstrating memset(), memcpy(), and memmove(). */
            2:
            3: #include <stdio.h>
            4: #include <string.h>
            4:
            5: char message1[60] = "Four score and seven years ago ...";
            6: char message2[60] = "abcdefghijklmnopqrstuvwxyz";
            7: char temp[60];
            8:
            9: main()
            10: {
            11:    printf("\nmessage1[] before memset():\t%s", message1);
            12:    memset(message1 + 5, `@', 10);
            13:    printf("\nmessage1[] after memset():\t%s", message1);
            14:
            15:    strcpy(temp, message2);
            16:    printf("\n\nOriginal message: %s", temp);
            17:    memcpy(temp + 4, temp + 16, 10);
            18:    printf("\nAfter memcpy() without overlap:\t%s", temp);
            19:    strcpy(temp, message2);
            20:    memcpy(temp + 6, temp + 4, 10);
            21:    printf("\nAfter memcpy() with overlap:\t%s", temp);
            22:
            23:    strcpy(temp, message2);
            24:    printf("\n\nOriginal message: %s", temp);
            25:    memmove(temp + 4, temp + 16, 10);
            26:    printf("\nAfter memmove() without overlap:\t%s", temp);
            27:    strcpy(temp, message2);
            28:    memmove(temp + 6, temp + 4, 10);
            29:    printf("\nAfter memmove() with overlap:\t%s\n", temp);
            30:
            31: }
            message1[] before memset():     Four score and seven years ago ...
            message1[] after memset():      Four @@@@@@@@@@seven years ago ...
            Original message: abcdefghijklmnopqrstuvwxyz
            After memcpy() without overlap: abcdqrstuvwxyzopqrstuvwxyz
            After memcpy() with overlap:    abcdefefefefefefqrstuvwxyz
            Original message: abcdefghijklmnopqrstuvwxyz
            After memmove() without overlap:        abcdqrstuvwxyzopqrstuvwxyz
            After memmove() with overlap:   abcdefefghijklmnqrstuvwxyz
            

            ANALYSIS: The operation of memset() is straightforward. Note how the pointer notation message1 + 5 is used to specify that memset() is to start setting characters at the sixth character in message1[] (remember, arrays are zero-based). As a result, the 6th through 15th characters in message1[] have been changed to @.

            When source and destination do not overlap, memcpy() works fine. The 10 characters of temp[] starting at position 17 (the letters q through z) have been copied to positions 5 though 14, where the letters e though n were originally located. If, however, the source and destination overlap, things are different. When the function tries to copy 10 characters starting at position 4 to position 6, an overlap of 8 positions occurs. You might expect the letters e through n to be copied over the letters g through p. Instead, the letters e and f are repeated five times.

            If there's no overlap, memmove() works just like memcpy(). With overlap, however, memmove() copies the original source characters to the destination.

            posted @ 2010-08-31 11:06 lhking 閱讀(548) | 評(píng)論 (0)編輯 收藏

            2010年6月26日

            Vc++6.0項(xiàng)目遷到vs2005 應(yīng)該注意的問題
            www.firnow.com    時(shí)間 : 2010-06-06  作者:佚名   編輯:壹枝雪糕 點(diǎn)擊:  1176 [ 評(píng)論 ]
            -
            -
            綜合 資源 電子書 社區(qū)   1.如果MessageBox("aa") 報(bào)錯(cuò),將其要改成 MessageBox(_TEXT("aa")).我喜歡用MessageBox來調(diào)試程序,尤其是在寫腳本時(shí),當(dāng)你不知道程序有沒有執(zhí)行該條語句,以及執(zhí)行完該條語句后某個(gè)變量的值發(fā)生了什么變化,在該條語句前后各加一個(gè)MessageBox(str),一目了然了吧 .

            2.pow(2,10)   要改成  pow((double)2,10)或pow(2.0,10)

                   說明:6.0中用到math.h pow()函數(shù)時(shí),有這個(gè)原型 double pow(int _X,int _Y) 但如果用VC++ 2005的話,pow()的第一個(gè)參數(shù)就不能再使用int型態(tài),只能使用float、double、long double,VC++ 2005在編譯時(shí)會(huì)做type checking,然後就過不了,報(bào)error C2668

            3.Itoa方法名要改成  _Itoa_s

            4.error C2440:“static_cast” 無法從“void (__thiscall CChatManagerDlg::* )(WPARAM,LPARAM)”轉(zhuǎn)換為“LRESULT (__thiscall CWnd::* ),出錯(cuò)處在ON_MESSAGE(WM_SETPLAY,OnSetPlay)

            解答:將void CVideoBaseView::OnSetPlay(WPARAM wp,LPARAM lp)  改成LRESULT CVideoBaseView::OnSetPlay(WPARAM wp,LPARAM lp){

            LRESULT result = Default();

            //你原來的代碼

            return result;}

            5.找不到MFC80D.DLL

            解決:“工程屬性”->“link”->“manifesto file”->“$(IntDir)\$(TargetFileName).intermediate.manifest” 值     改成    $(IntDir)\$(TargetFileName).manifest

            文章出處:飛諾網(wǎng)(www.firnow.com):http://dev.firnow.com/course/3_program/vc/vc_js/200879/132413.html

            posted @ 2010-06-26 09:22 lhking 閱讀(398) | 評(píng)論 (0)編輯 收藏

            2010年6月24日

            根據(jù)MSDN的描述,采用如下的代碼來實(shí)現(xiàn)阻止關(guān)機(jī),結(jié)果發(fā)現(xiàn)在有的機(jī)器上能夠阻止關(guān)機(jī),在有的機(jī)器上卻不能阻止(雖然能看到彈出的MessageBox,但還來不及反應(yīng),馬上就關(guān)機(jī)了)。(都是WinXP SP2的機(jī)器)

            view plaincopy to clipboardprint?
            LRESULT CPreventShutdownDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)  
            {  
                if (WM_QUERYENDSESSION == message)  
                {  
                    AfxMessageBox(_T("呵呵,不許關(guān)機(jī)!"));  
                    return FALSE;  // 根據(jù)MSDN,WM_QUERYENDSESSION 返回FALSE則取消關(guān)機(jī)  
                }  
             
                return CDialog::WindowProc(message, wParam, lParam);  

            LRESULT CPreventShutdownDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
            {
                if (WM_QUERYENDSESSION == message)
                {
                    AfxMessageBox(_T("呵呵,不許關(guān)機(jī)!"));
                    return FALSE;  // 根據(jù)MSDN,WM_QUERYENDSESSION 返回FALSE則取消關(guān)機(jī)
                }

                return CDialog::WindowProc(message, wParam, lParam);
            }

            是什么原因在某些機(jī)器上無法阻止關(guān)機(jī)呢?

            回憶關(guān)機(jī)時(shí)經(jīng)常遇到的場景:

            1. 如果某個(gè)進(jìn)程失去響應(yīng),關(guān)機(jī)的時(shí)候會(huì)提示"...沒有響應(yīng),是否結(jié)束"

            2. 使用記事本修改了文檔,在沒有保存的情況下進(jìn)行關(guān)機(jī),普通情況會(huì)提示是否進(jìn)行保存。

            1這種情況不好模擬,但是2是很好模擬的。于是在不能阻止關(guān)機(jī)的機(jī)器上這樣進(jìn)行測試,發(fā)現(xiàn)雖然也彈出了是否保存的對(duì)話框,但是還是馬上就關(guān)機(jī)了。

            果然,和程序無關(guān),應(yīng)該是機(jī)器設(shè)置的問題。于是想到了一個(gè)很流行的詞:"快速關(guān)機(jī)"

            到網(wǎng)上google了一下,發(fā)現(xiàn)快速關(guān)機(jī)是通過如下的方式實(shí)現(xiàn)的:

            HKEY-CURRENT-USER\Control Panel\Desktop\AutoEndTasks  值為1表示快速關(guān)機(jī)

                                                                                                    普通情況值為0或這個(gè)鍵值不存在

            到不能阻止快速關(guān)機(jī)的機(jī)器上一看,果然這個(gè)鍵值為1.

            改為0后再運(yùn)行程序,就都能阻止關(guān)機(jī)了。

            【結(jié)論】阻止關(guān)機(jī)需要兩步才能完美的實(shí)現(xiàn),而不僅僅是MSDN中描述的2)

                        1) 在程序中先刪除這個(gè)鍵值(HKEY-CURRENT-USER\Control Panel\Desktop\AutoEndTasks)

                        2) 處理 WM_QUERYENDSESSION 時(shí)返回FALSE

             

            本文來自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/skyxie/archive/2009/06/09/4255767.aspx

            posted @ 2010-06-24 11:03 lhking 閱讀(2699) | 評(píng)論 (1)編輯 收藏

            2010年6月23日

            查看未被delete掉的內(nèi)存,在輸出窗口中查看
            1
             #define _CRTDBG_MAP_ALLOC
             2 #include <stdlib.h>
             3 #include <crtdbg.h>
             4 #include <windows.h>
             5 
             6 int wmain(vint argc , wchar_t* args[])
             7 {
             8     // 這里運(yùn)行程序,并在下面的函數(shù)調(diào)用之前delete掉所有new的東西
             9     _CrtDumpMemoryLeaks();
            10     return 0;
            11 }
            posted @ 2010-06-23 23:14 lhking 閱讀(298) | 評(píng)論 (0)編輯 收藏

            要實(shí)現(xiàn)對(duì)一個(gè)程序的進(jìn)程注入,然后對(duì)被注入的進(jìn)程進(jìn)行控制,首先需要查找到要注入的進(jìn)程ID。如何獲取的進(jìn)程ID呢?windows提供了一個(gè)API只要知道了這個(gè)進(jìn)程里面的一個(gè)窗口句柄,就可以找到找到該進(jìn)程ID。函數(shù)形式如下:DWORD GetWindowThreadProcessId(
              HWND hWnd,
              LPDWORD lpdwProcessId
            );

            那如何獲取這個(gè)窗口的句柄呢?很自然我們可以想到這么一個(gè)函數(shù),函數(shù)形式如下:

            HWND FindWindowEx(     
                HWND hwndParent,
                HWND hwndChildAfter,
                LPCTSTR lpszClass,
                LPCTSTR lpszWindow
            );

            hwndParent:指向一個(gè)待搜索窗口的父窗。

            hwndChildAfter:子窗口的句柄。

            lpszClass:窗口的類名。

            lpszWindow:窗口的標(biāo)題名。

            例如,本示例工程要找到一個(gè)對(duì)話框里的編輯框,并對(duì)這個(gè)編輯框進(jìn)行注入。查找過程如下:

                HWND hWndChild = NULL;
                while(1)
                {
                    // 查找對(duì)話框窗口,且這個(gè)對(duì)話框窗口的標(biāo)題名為“TestDlg”
                    HWND hDlg = FindWindowEx(0, NULL, "#32770", "TestDlg");
                    if(hDlg == NULL)
                    {
                        printf("沒有找到該對(duì)話框窗口!\n");
                        exit(1);
                    }
                    else
                    {
                        // 查找這個(gè)對(duì)話框窗口中的edit控件
                        hWndChild = FindWindowEx(hDlg, NULL, "Edit",NULL);
                        if(hWndChild != NULL)
                        {
                            break; // 找到這個(gè)編輯框,現(xiàn)在要對(duì)這個(gè)編輯框進(jìn)行注入
                        }
                    }
                }

                // 根據(jù)查找出的窗口,查詢進(jìn)程
                DWORD dwQQGameId;
                HANDLE hProcessQQGame;
                if(!GetWindowThreadProcessId(hWndChild,&dwQQGameId))
                {
                    printf("Error in GetWindowThreadProcessId():%d\n",GetLastError());
                    exit(1);
                }
            找到這個(gè)進(jìn)程后,然后就要對(duì)這個(gè)進(jìn)程進(jìn)行注入。但是,你別忘記了,當(dāng)你在其他進(jìn)程中獲取另外進(jìn)程的窗口句柄,你是沒有辦法操作這個(gè)句柄的。為什么呢?每個(gè)進(jìn)程都被賦予它自己的虛擬地址空間。對(duì)于3 2位進(jìn)程來說,這個(gè)地址空間是4 G B,因
            為3 2位指針可以擁有從0 x 0 0 0 0 0 0 0 0至0 x F F F F F F F F之間的任何一個(gè)值。這使得一個(gè)指針能夠擁有4 294 967 296個(gè)值中的一個(gè)值,它覆蓋了一個(gè)進(jìn)程的4 G B虛擬空間的范圍。對(duì)于6 4位進(jìn)程來說,這個(gè)地址空間是1 6 E B(1 01 8字節(jié)),因?yàn)? 4位指針可以擁有從0 x 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0至0 x F F F F F F F F F F F F F F F F之間的任何值。這使得一個(gè)指針可以擁有18 446 744 073 709 551 616個(gè)值中的一個(gè)值,它覆蓋了一個(gè)進(jìn)程的1 6 E B虛擬空間的范圍。這是相當(dāng)大的一個(gè)范圍。由于每個(gè)進(jìn)程可以接收它自己的私有的地址空間,因此當(dāng)進(jìn)程中的一個(gè)線程正在運(yùn)行時(shí),該線程可以訪問只屬于它的進(jìn)程的內(nèi)存。屬于所有其他進(jìn)程的內(nèi)存則隱藏著,并且不能被正在運(yùn)行的線程訪問。注意在Windows 2000中,屬于操作系統(tǒng)本身的內(nèi)存也是隱藏的,正在運(yùn)行的線程無法訪問。這意味著線程常常不能訪問操作系統(tǒng)的數(shù)據(jù)。Windows 98中,屬于操作系統(tǒng)的內(nèi)存是不隱藏的,正在運(yùn)行的線程可以訪問。因此,正在運(yùn)行的線程常常可以訪問操作系統(tǒng)的數(shù)據(jù),也可以破壞操作系統(tǒng)(從而有可能導(dǎo)致操作系統(tǒng)崩潰)。在Windows 98中,一個(gè)進(jìn)程的線程不可能訪問屬于另一個(gè)進(jìn)程的內(nèi)存。前面說過,每個(gè)進(jìn)程有它自己的私有地址空間。進(jìn)程A可能有一個(gè)存放在它的地址空間中的數(shù)據(jù)結(jié)構(gòu),地址是0 x 1 2 3 4 5 6 7 8,而進(jìn)程B則有一個(gè)完全不同的數(shù)據(jù)結(jié)構(gòu)存放在它的地址空間中,地址是0 x 1 2 3 4 5 6 7 8。當(dāng)進(jìn)程A中運(yùn)行的線程訪問地址為0 x 1 2 3 4 5 6 7 8的內(nèi)存時(shí),這些線程訪問的是進(jìn)程A的數(shù)據(jù)結(jié)構(gòu)。當(dāng)進(jìn)程B中運(yùn)行的線程訪問地址為0 x 1 2 3 4 5 6 7 8的內(nèi)存時(shí),這些線程訪問的是進(jìn)程B的數(shù)據(jù)結(jié)構(gòu)。進(jìn)程A中運(yùn)行的線程不能訪問進(jìn)程B的地址空間中的數(shù)據(jù)結(jié)構(gòu),反之亦然。

            這樣看來,若想對(duì)這個(gè)窗口句柄進(jìn)行操作,得想方設(shè)法使我們能夠進(jìn)入到原宿主進(jìn)程中,然后執(zhí)行我們的操作。這個(gè)就好象一個(gè)寄生蟲想要破壞人體的機(jī)能,必須得進(jìn)入我們的體內(nèi),寄生在我們的組織上才能夠產(chǎn)生作用。現(xiàn)在關(guān)鍵是如何寄生到宿主中呢?

            通常,任何進(jìn)程都可以通過LoadLibrary動(dòng)態(tài)地加載DLL,但是我們?nèi)绾螐?qiáng)制一個(gè)外部進(jìn)程調(diào)用該函數(shù)呢?答案是CreateRemoteThread。
            讓我們先來看看LoadLibrary和FreeLibrary的函數(shù)聲明:

            HINSTANCE LoadLibrary(
              LPCTSTR lpLibFileName   // address of filename of library module
            );

            BOOL FreeLibrary(
              HMODULE hLibModule      // handle to loaded library module
            );

            再和CreateRemoteThread的線程過程(thread procedure)ThreadProc比較一下:
            DWORD WINAPI ThreadProc(
              LPVOID lpParameter   // thread data
            );

                你會(huì)發(fā)現(xiàn)所有的函數(shù)都有同樣的調(diào)用約定(calling convention)、都接受一個(gè)32位的參數(shù)并且返回值類型的大小也一樣。也就是說,我們可以把LoadLibrary/FreeLibrary的指針作為參數(shù)傳遞給CrateRemoteThread。

                然而,還有兩個(gè)問題(參考下面對(duì)CreateRemoteThread的說明)

                1. 傳遞給ThreadProc的lpStartAddress 參數(shù)必須為遠(yuǎn)程進(jìn)程中的線程過程的起始地址。
                2. 如果把ThreadProc的lpParameter參數(shù)當(dāng)做一個(gè)普通的32位整數(shù)(FreeLibrary把它當(dāng)做HMODULE)那么沒有如何問題,但是如果把它當(dāng)做一個(gè)指針(LoadLibrary把它當(dāng)做一個(gè)char*),它就必須指向遠(yuǎn)程進(jìn)程中的內(nèi)存數(shù)據(jù)。

                第一個(gè)問題其實(shí)已經(jīng)迎刃而解了,因?yàn)長oadLibrary和FreeLibrary都是存在于kernel32.dll中的函數(shù),而kernel32可以保證任何“正常”進(jìn)程中都存在,且其加載地址都是一樣的。(參看附錄A)于是LoadLibrary/FreeLibrary在任何進(jìn)程中的地址都是一樣的,這就保證了傳遞給遠(yuǎn)程進(jìn)程的指針是個(gè)有效的指針。

                第二個(gè)問題也很簡單:把DLL的文件名(LodLibrary的參數(shù))用WriteProcessMemory復(fù)制到遠(yuǎn)程進(jìn)程。

                所以,使用CreateRemoteThread和LoadLibrary技術(shù)的步驟如下:
                1. 得到遠(yuǎn)程進(jìn)程的HANDLE(使用OpenProcess)。
                2. 在遠(yuǎn)程進(jìn)程中為DLL文件名分配內(nèi)存(VirtualAllocEx)。
                3. 把DLL的文件名(全路徑)寫到分配的內(nèi)存中(WriteProcessMemory)
                4. 使用CreateRemoteThread和LoadLibrary把你的DLL映射近遠(yuǎn)程進(jìn)程。
                5. 等待遠(yuǎn)程線程結(jié)束(WaitForSingleObject),即等待LoadLibrary返回。也就是說當(dāng)我們的DllMain(是以DLL_PROCESS_ATTACH為參數(shù)調(diào)用的)返回時(shí)遠(yuǎn)程線程也就立即結(jié)束了。
                6. 取回遠(yuǎn)程線程的結(jié)束碼(GetExitCodeThtread),即LoadLibrary的返回值――我們DLL加載后的基地址(HMODULE)。
                7. 釋放第2步分配的內(nèi)存(VirtualFreeEx)。
                8. 用CreateRemoteThread和FreeLibrary把DLL從遠(yuǎn)程進(jìn)程中卸載。調(diào)用時(shí)傳遞第6步取得的HMODULE給FreeLibrary(通過CreateRemoteThread的lpParameter參數(shù))。
                9. 等待線程的結(jié)束(WaitSingleObject)。

            主要代碼如下:

            #include<stdio.h>
            #include<conio.h>
            #include<windows.h>

            void main()
            {
                HWND hWndChild = NULL;
                while(1)
                {
                    // 查找對(duì)話框窗口,且這個(gè)對(duì)話框窗口的標(biāo)題名為“TestDlg”
                    HWND hDlg = FindWindowEx(0, NULL, "#32770", "TestDlg");
                    if(hDlg == NULL)
                    {
                        printf("沒有找到該對(duì)話框窗口!\n");
                        exit(1);
                    }
                    else
                    {
                        // 查找這個(gè)對(duì)話框窗口中的edit控件
                        hWndChild = FindWindowEx(hDlg, NULL, "Edit",NULL);
                        if(hWndChild != NULL)
                        {
                            break; // 找到這個(gè)編輯框,現(xiàn)在要對(duì)這個(gè)編輯框進(jìn)行注入
                        }
                    }
                }

                // 根據(jù)查找出的窗口,查詢進(jìn)程
                DWORD dwQQGameId;
                HANDLE hProcessQQGame;
                if(!GetWindowThreadProcessId(hWndChild,&dwQQGameId))
                {
                    printf("Error in GetWindowThreadProcessId():%d\n",GetLastError());
                    exit(1);
                }


                HINSTANCE hDll = NULL;
                typedef void(*LP_SET_HEDIT_FUN)(HWND);
                LP_SET_HEDIT_FUN m_SethEdit = NULL;
                char DllPath[MAX_PATH] = "D:\\進(jìn)程注入測試工程\\Bin\\automessagedll.dll";
                hDll = LoadLibrary(DllPath);
                if(hDll)
                {
                    m_SethEdit = (LP_SET_HEDIT_FUN)GetProcAddress(hDll,"SethEdit");
                }
                if(m_SethEdit)
                {
                    m_SethEdit(hWndChild);
                }
                else
                {
                    printf("Can not load SethEdit in the dll(%d).\n",GetLastError());
                }

             

                if( (hProcessQQGame = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwQQGameId)) == NULL)
                {
                    printf("Error in OpenProcess():%d\n",GetLastError());
                    getch();
                    exit(1);
                }

                int cb = (1+lstrlen(DllPath))* sizeof(char);

                char* RemoteLibFile = (char*)VirtualAllocEx(hProcessQQGame,NULL,cb,MEM_COMMIT,PAGE_READWRITE);
                if(RemoteLibFile == NULL)
                {
                    printf("Error in VirtualAllocEx():%d\n",GetLastError());
                    getch();
                    exit(1);
                }
                if( (WriteProcessMemory(hProcessQQGame,RemoteLibFile,(LPVOID)DllPath,cb,NULL)) == 0)
                {
                    printf("Error in WriteProcessMemory():%d\n",GetLastError());
                    getch();
                    exit(1);
                }


                PTHREAD_START_ROUTINE pfnStartAddr;
                pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"),"LoadLibraryA");


                HANDLE hThread = CreateRemoteThread(hProcessQQGame,NULL,0,pfnStartAddr,RemoteLibFile,0,NULL);
                if(hThread == NULL)
                {
                    printf("Error in CreateRemoteThread():%d",GetLastError());
                    getch();
                    exit(1);
                }

                WaitForSingleObject(hThread,INFINITE);


                CloseHandle(hThread);
                VirtualFreeEx(hProcessQQGame,RemoteLibFile,0,MEM_RELEASE);
                CloseHandle(hProcessQQGame);
            }

             

            本文來自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/kissyfish/archive/2008/12/07/3462055.aspx

            posted @ 2010-06-23 15:33 lhking 閱讀(1219) | 評(píng)論 (0)編輯 收藏

            下載文件要用到操作系統(tǒng)的API函數(shù),下面是一個(gè)WINDOWS系統(tǒng)中的實(shí)現(xiàn):

            //---------------------------------------------------------------------------
            #include "stdafx.h"
            #include <stdio.h>
            #include <windows.h>
            #include <wininet.h>
            #define MAXBLOCKSIZE 1024
            #pragma comment( lib, "wininet.lib" ) ;

            void download(const char *Url,const char *save_as)/*將Url指向的地址的文件下載到save_as指向的本地文件*/
            {
             byte Temp[MAXBLOCKSIZE];
             ULONG Number = 1;

             FILE *stream;
             HINTERNET hSession = InternetOpen(_T("RookIE/1.0"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
             if (hSession != NULL)
             {
              HINTERNET handle2 = InternetOpenUrl(hSession,_T(Url), NULL, 0, INTERNET_FLAG_DONT_CACHE, 0);
              if (handle2 != NULL)
              {


               if( (stream = fopen( save_as, "wb" )) != NULL )
               {
                while (Number > 0)
                {
                 InternetReadFile(handle2, Temp, MAXBLOCKSIZE - 1, &Number);

                 fwrite(Temp, sizeof (char), Number , stream);
                }
                fclose( stream );
               }

               InternetCloseHandle(handle2);
               handle2 = NULL;
              }
              InternetCloseHandle(hSession);
              hSession = NULL;
             }
            }

            int main(int argc, char* argv[]){

             download("*調(diào)用示例,下載百度的首頁到c:\index.html文件*/
             return 0;
            }

             

            方法一:
            SetTimer(NULL, 0, 1000, (TIMERPROC)Timer2Proc);

            VOID CALLBACK Timer2Proc(
                   HWND hWnd, // handle of window for timer messages
                   UINT uMsg, // WM_TIMER message
                   UINT idEvent, // timer identifier
                   DWORD dwTime // current system time
                   )
            {
             return;
            }

            方法二:
            // DLL中的線程函數(shù)可以象這樣使用Timer
            UINT ThreadProc(LPVOID)
            {

             SetTimer(NULL, 1, 5000, NULL);
             MSG msg;
             // PeekMessage 強(qiáng)制系統(tǒng)為該線程建立消息棧
             PeekMessage(&msg, NULL, NULL, NULL, FALSE);
             while (GetMessage(&msg, NULL, NULL, NULL))
             {
              switch (msg.message)
              {
              case WM_TIMER:
               {
                // 這里每5秒鐘執(zhí)行一次
               }
               break;
              }
              //TranslateMessage(&msg);
              //DispatchMessage(&msg);
             }
             KillTimer(NULL, 1);
             return 0;
            }

            方法三:
            創(chuàng)建一個(gè)線程, 反復(fù)讀系統(tǒng)時(shí)間不就可以了? 如果定時(shí)要求不嚴(yán),用Sleep就可以了
            UINT TimerThread(LPVOID pama)
            {
             UINT oldTickCount, newTickCount;
             oldTickCount = GetTickCount();
             while(TRUE)
             {
              while(TRUE)
              {
               newTickCount = GetTickCount();
               if(newTickCount - oldTickCount >= 100)
               {
                oldTickCount = newTickCount;
                break;
               }
              }
              TimeProc();
             }
             return 0;
            }
            大約每100ms 調(diào)用一次TimeProc();

            posted @ 2010-06-23 14:57 lhking 閱讀(3021) | 評(píng)論 (0)編輯 收藏

            2010年6月22日

            MFC is basicly a library of OO wrapper classes that wrap the Win32 api, and provide objects for the basic window components (windows, buttons, checkboxes etc..). Essentially it is the win32 api objectified.

            Also MFC provides some classes that resemble classes found in the STL. As MFC was made before STL was fully standardised.

            My knowledge is incomplete. But that is the basic Idea.



             User Rating: 1019   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

            The difference between Win32 and MFC are pretty straightforward:

            The Windows API (Win32) uses a C interface to access windows functionality. It requires that you write all of your own code to manage windows and message handling. It is quite straightforward but you will need a good reference, like MSDN, and some good tutorials or samples to get started.

            In contrast, MFC, which stands for Microsoft Foundation Classes, are a collection of C++ classes which encapsulate the Win32 API. MFC has some wizards which make the initial creation of a program quick and easy, but I have to admit the learning curve of MFC can sometimes be frustrating as Microsoft seems to have done everything in a way that can at times seem counter-intuitive.

            Whenever I write an application I write it in MFC but I have been writing applications in MFC for a long time. If all you want is a message loop and a window handle for a game, use Win32. If you want to write a larger application like an editor, maybe MFC is the right tool.

            Ideally, I would suggest skipping both Win32 and MFC and writing tools in .NET. I do not have any personal experience in it but people I work with sure can get a lot done using it. It may well be worth investigation.

            Best of luck,

            - S

             User Rating: 1352   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

            Quote:
            Original post by Sphet

            Whenever I write an application I write it in MFC but I have been writing applications in MFC for a long time. If all you want is a message loop and a window handle for a game, use Win32. If you want to write a larger application like an editor, maybe MFC is the right tool.

            - S


            I am planning to write an interactive 3D environment does that mean using WIN32 application is a better tool for it?

            also is it possible to use openGL for oject creation and DirectXinput for the interactive control?
            please give me some suggestion



            millions of thanks

             User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

            Quote:
            Original post by muimui1911
            I am planning to write an interactive 3D environment does that mean using WIN32 application is a better tool for it?

            For a game Win32 is usually better.
            I think I have also heard that MFC doesn't work well in fullscreen.

            Quote:
            Original post by muimui1911
            also is it possible to use openGL for oject creation and DirectXinput for the interactive control?

            You can render with opengl and use directinput for input.

            ____________________________________________________________
            Programmers Resource Central

             User Rating: 1107   |  Rate This User  Send Private MessageView ProfileView GD Showcase Entries Report this Post to a Moderator | Link

            what about mouse movement like shooting games?

            how can i do that, please give me some direction

             User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

            You can use directinput for mouse movement. Or you can use GetCursorPos(POINT *p);

            ____________________________________________________________
            Programmers Resource Central

             User Rating: 1107   |  Rate This User  Send Private MessageView ProfileView GD Showcase Entries Report this Post to a Moderator | Link

            How do i use that? can you give me some example and much clearer direction

            millions of thanks

             User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

            msdn
            Though if you want a camera class look here and here.
            posted @ 2010-06-22 11:43 lhking 閱讀(338) | 評(píng)論 (0)編輯 收藏

            2010年6月21日

            對(duì)于眾多人提出的c/c++中指針難學(xué)的問題做個(gè)總結(jié):

              指針學(xué)習(xí)不好關(guān)鍵是概念不清造成的,說的簡單點(diǎn)就是書沒有認(rèn)真看,指針的學(xué)習(xí)猶如人在學(xué)習(xí)饒口令不多看多學(xué)多練是不行的,下面是兩個(gè)很經(jīng)典的例子,很多書上都有,對(duì)于學(xué)習(xí)的重點(diǎn)在于理解*x和x的理解,他們并不相同,*x所表示的其實(shí)就是變量a本身,x表示的是變量a在內(nèi)存中的地址,如果想明白可以輸出觀察cout<<*x"|"x;,當(dāng)定義了int *x;后對(duì)x=&a的理解的問題。仔細(xì)閱讀和聯(lián)系下面的兩個(gè)例子我想指針問題就不是難點(diǎn)了!

            #include <stdio.h>

            main()
            {
            int a,b; /* 定義a,b兩個(gè)整形變量用于輸入兩個(gè)整數(shù) */
            int *point_1,*point_2,*temp_point; /* 定義三個(gè)指針變量 */
            scanf("%d,%d",&a,&b); /* 格式化輸入a,b的值 */
            point_1=&a; /* 把指針變量point_1的值指向變量a的地址 */
            point_2=&b; /* 把指針變量point_2的值指向變量b的地址 */
            if (a<b)
            {
                 temp_point=point_1; /* 這里的temp_point是用于臨時(shí)存儲(chǔ)point_1的值也就是變量a的地址的 */
                 point_1=point_2; /* 把point_2的值賦予point_1 */
                 point_2=temp_point;
                 /* 由于point_1的值已經(jīng)改變無法找到,利用前面臨時(shí)存儲(chǔ)的也就是temp_point找回原point_1的值賦予point_2,打到把point_1和point_2值對(duì)換的目的*/
            }
            printf("%d,%d",*point_1,*point_2); /* 利用*point_1和*point_2也就是分辨指向b和a的方法把值顯示自愛屏幕上 */
            }

            /* 此題需要注意和了解是的此法并沒有改變變量a,b的值只是利用指針變量分別存儲(chǔ)a和b的地址,然后再把那兩個(gè)指針變量的值對(duì)換一下其實(shí)就是存儲(chǔ)在
            指針變量里面a與b的地址對(duì)換,在利用*point_1和*point_2的方式把調(diào)換后的值顯示出來這里的*point_1實(shí)際就是a,此中算法并非真的改變a,b的值,而是
            利用指針進(jìn)行地址交換達(dá)到大小排序的目的.
            */



            #include <stdio.h>

            main()
            {
            int a,b; /* 定義a,b兩個(gè)整形變量用于輸入兩個(gè)整數(shù) */
            int *point_1,*point_2; /* 定義三個(gè)指針變量 */
            scanf("%d,%d",&a,&b); /* 格式化輸入a,b的值 */
            point_1 = &a; /* 把指針變量point_1的值指向變量a的地址 */
            point_2 = &b; /* 把指針變量point_2的值指向變量b的地址 */
            compositor(point_1,point_2); /* 調(diào)用自定義的排序涵數(shù),把a(bǔ),b的地址傳遞給point_1和point_2 */
            printf("%d,%d",a,b); /* 打印出a,b的值 */
            }

            static compositor(p1,p2)
            int *p1,*p2; /* 定義形式參數(shù)p1,p2為指針變量 */
            {
            int temp; /* 建立臨時(shí)存儲(chǔ)變量 */
                 if (*p1<*p2) /* 如果*p1<p2,注意這里的*p1和*p2其實(shí)就是a和b */
                 {
                     temp = *p1; /* 利用變量temp用于臨時(shí)存儲(chǔ)*p1和就是a的值 */
                     *p1 = *p2; /* 將*p1的值也就是a的值換成*p2的值也就是b的值,等價(jià)于a=b */
                     *p2 = temp; /* 將*p2的值也就是temp的值等價(jià)于b=temp */
                 }
            }

            /* 注意:此題與上題不同的是,直接改變了a于b的值達(dá)到真實(shí)改變的目的 */

            posted @ 2010-06-21 23:02 lhking 閱讀(238) | 評(píng)論 (0)編輯 收藏
            VC常用數(shù)據(jù)類型轉(zhuǎn)換詳解
            我們先定義一些常見類型變量借以說明
            int i = 100;
            long l = 2001;
            float f=300.2;
            double d=12345.119;
            char username[]="程佩君";
            char temp[200];
            char *buf;
            CString str;
            _variant_t v1;
            _bstr_t v2;
            一、其它數(shù)據(jù)類型轉(zhuǎn)換為字符串

            短整型(int)
            itoa(i,temp,10);///將i轉(zhuǎn)換為字符串放入temp中,最后一個(gè)數(shù)字表示十進(jìn)制
            itoa(i,temp,2); ///按二進(jìn)制方式轉(zhuǎn)換
            長整型(long)
            ltoa(l,temp,10);
            浮點(diǎn)數(shù)(float,double)
            用fcvt可以完成轉(zhuǎn)換,這是MSDN中的例子:
            int decimal, sign;
            char *buffer;
            double source = 3.1415926535;
            buffer = _fcvt( source, 7, &decimal, &sign );
            運(yùn)行結(jié)果:source: 3.1415926535 buffer: '31415927' decimal: 1 sign: 0
            decimal表示小數(shù)點(diǎn)的位置,sign表示符號(hào):0為正數(shù),1為負(fù)數(shù)
            CString變量
            str = "2008北京奧運(yùn)";
            buf = (LPSTR)(LPCTSTR)str;
            BSTR變量
            BSTR bstrValue = ::SysAllocString(L"程序員");
            char * buf = _com_util::ConvertBSTRToString(bstrValue);
            SysFreeString(bstrValue);
            AfxMessageBox(buf);
            delete(buf);
            CComBSTR變量
            CComBSTR bstrVar("test");
            char *buf = _com_util::ConvertBSTRToString(bstrVar.m_str);
            AfxMessageBox(buf);
            delete(buf);
            _bstr_t變量
            _bstr_t類型是對(duì)BSTR的封裝,因?yàn)橐呀?jīng)重載了=操作符,所以很容易使用
            _bstr_t bstrVar("test");
            const char *buf = bstrVar;///不要修改buf中的內(nèi)容
            AfxMessageBox(buf);

            通用方法(針對(duì)非COM數(shù)據(jù)類型)
            用sprintf完成轉(zhuǎn)換
            char buffer[200];
            char c = '1';
            int   i = 35;
            long j = 1000;
            float f = 1.7320534f;
            sprintf( buffer, "%c",c);
            sprintf( buffer, "%d",i);
            sprintf( buffer, "%d",j);
            sprintf( buffer, "%f",f);
            二、字符串轉(zhuǎn)換為其它數(shù)據(jù)類型
            strcpy(temp,"123");
            短整型(int)
            i = atoi(temp);
            長整型(long)
            l = atol(temp);
            浮點(diǎn)(double)
            d = atof(temp);
            CString變量
            CString name = temp;
            BSTR變量
            BSTR bstrValue = ::SysAllocString(L"程序員");
            ...///完成對(duì)bstrValue的使用
            SysFreeString(bstrValue);
            CComBSTR變量
            CComBSTR類型變量可以直接賦值
            CComBSTR bstrVar1("test");
            CComBSTR bstrVar2(temp);
            _bstr_t變量
            _bstr_t類型的變量可以直接賦值
            _bstr_t bstrVar1("test");
            _bstr_t bstrVar2(temp);

            三、其它數(shù)據(jù)類型轉(zhuǎn)換到CString
            使用CString的成員函數(shù)Format來轉(zhuǎn)換,例如:

            整數(shù)(int)
            str.Format("%d",i);
            浮點(diǎn)數(shù)(float)
            str.Format("%f",i);
            字符串指針(char *)等已經(jīng)被CString構(gòu)造函數(shù)支持的數(shù)據(jù)類型可以直接賦值
            str = username;
            對(duì)于Format所不支持的數(shù)據(jù)類型,可以通過上面所說的關(guān)于其它數(shù)據(jù)類型轉(zhuǎn)化到char *的方法先轉(zhuǎn)到char *,然后賦值給CString變量。
            四、BSTR、_bstr_t與CComBSTR

            CComBSTR 是ATL對(duì)BSTR的封裝,_bstr_t是C++對(duì)BSTR的封裝,BSTR是32位指針,但并不直接指向字串的緩沖區(qū)。
            char *轉(zhuǎn)換到BSTR可以這樣:
            BSTR b=_com_util::ConvertStringToBSTR("數(shù)據(jù)");///使用前需要加上comutil.h和comsupp.lib
            SysFreeString(bstrValue);
            反之可以使用
            char *p=_com_util::ConvertBSTRToString(b);
            delete p;
            具體可以參考一,二段落里的具體說明。
            CComBSTR與_bstr_t對(duì)大量的操作符進(jìn)行了重載,可以直接進(jìn)行=,!=,==等操作,所以使用非常方便。
            特別是_bstr_t,建議大家使用它。

            五、VARIANT 、_variant_t 與 COleVariant

            VARIANT的結(jié)構(gòu)可以參考頭文件VC98\Include\OAIDL.H中關(guān)于結(jié)構(gòu)體tagVARIANT的定義。
            對(duì)于VARIANT變量的賦值:首先給vt成員賦值,指明數(shù)據(jù)類型,再對(duì)聯(lián)合結(jié)構(gòu)中相同數(shù)據(jù)類型的變量賦值,舉個(gè)例子:
            VARIANT va;
            int a=2001;
            va.vt=VT_I4;///指明整型數(shù)據(jù)
            va.lVal=a; ///賦值
            對(duì)于不馬上賦值的VARIANT,最好先用Void VariantInit(VARIANTARG FAR* pvarg);進(jìn)行初始化,其本質(zhì)是將vt設(shè)置為VT_EMPTY,下表我們列舉vt與常用數(shù)據(jù)的對(duì)應(yīng)關(guān)系:
            Byte bVal; // VT_UI1.
            Short iVal; // VT_I2.
            long lVal; // VT_I4.
            float fltVal; // VT_R4.
            double dblVal; // VT_R8.
            VARIANT_BOOL boolVal; // VT_BOOL.
            SCODE scode; // VT_ERROR.
            CY cyVal; // VT_CY.
            DATE date; // VT_DATE.
            BSTR bstrVal; // VT_BSTR.
            DECIMAL FAR* pdecVal // VT_BYREF|VT_DECIMAL.
            IUnknown FAR* punkVal; // VT_UNKNOWN.
            IDispatch FAR* pdispVal; // VT_DISPATCH.
            SAFEARRAY FAR* parray; // VT_ARRAY|*.
            Byte FAR* pbVal; // VT_BYREF|VT_UI1.
            short FAR* piVal; // VT_BYREF|VT_I2.
            long FAR* plVal; // VT_BYREF|VT_I4.
            float FAR* pfltVal; // VT_BYREF|VT_R4.
            double FAR* pdblVal; // VT_BYREF|VT_R8.
            VARIANT_BOOL FAR* pboolVal; // VT_BYREF|VT_BOOL.
            SCODE FAR* pscode; // VT_BYREF|VT_ERROR.
            CY FAR* pcyVal; // VT_BYREF|VT_CY.
            DATE FAR* pdate; // VT_BYREF|VT_DATE.
            BSTR FAR* pbstrVal; // VT_BYREF|VT_BSTR.
            IUnknown FAR* FAR* ppunkVal; // VT_BYREF|VT_UNKNOWN.
            IDispatch FAR* FAR* ppdispVal; // VT_BYREF|VT_DISPATCH.
            SAFEARRAY FAR* FAR* pparray; // VT_ARRAY|*.
            VARIANT FAR* pvarVal; // VT_BYREF|VT_VARIANT.
            void FAR* byref; // Generic ByRef.
            char cVal; // VT_I1.
            unsigned short uiVal; // VT_UI2.
            unsigned long ulVal; // VT_UI4.
            int intVal; // VT_INT.
            unsigned int uintVal; // VT_UINT.
            char FAR * pcVal; // VT_BYREF|VT_I1.
            unsigned short FAR * puiVal; // VT_BYREF|VT_UI2.
            unsigned long FAR * pulVal; // VT_BYREF|VT_UI4.
            int FAR * pintVal; // VT_BYREF|VT_INT.
            unsigned int FAR * puintVal; //VT_BYREF|VT_UINT.

            _variant_t是VARIANT的封裝類,其賦值可以使用強(qiáng)制類型轉(zhuǎn)換,其構(gòu)造函數(shù)會(huì)自動(dòng)處理這些數(shù)據(jù)類型。
            使用時(shí)需加上#include <comdef.h>
            例如:
            long l=222;
            ing i=100;
            _variant_t lVal(l);
            lVal = (long)i;

            COleVariant的使用與_variant_t的方法基本一樣,請(qǐng)參考如下例子:
            COleVariant v3 = "字符串", v4 = (long)1999;
            CString str =(BSTR)v3.pbstrVal;
            long i = v4.lVal;

            六、其它一些COM數(shù)據(jù)類型
            根據(jù)ProgID得到CLSID
            HRESULT CLSIDFromProgID( LPCOLESTR lpszProgID,LPCLSID pclsid);
            CLSID clsid;
            CLSIDFromProgID( L"MAPI.Folder",&clsid);
            根據(jù)CLSID得到ProgID
            WINOLEAPI ProgIDFromCLSID( REFCLSID clsid,LPOLESTR * lplpszProgID);
            例如我們已經(jīng)定義了 CLSID_IApplication,下面的代碼得到ProgID
            LPOLESTR pProgID = 0;
            ProgIDFromCLSID( CLSID_IApplication,&pProgID);
            ...///可以使用pProgID
            CoTaskMemFree(pProgID);//不要忘記釋放
            七、ANSI與Unicode
            Unicode稱為寬字符型字串,COM里使用的都是Unicode字符串。
            將ANSI轉(zhuǎn)換到Unicode
            (1)通過L這個(gè)宏來實(shí)現(xiàn),例如: CLSIDFromProgID( L"MAPI.Folder",&clsid);
            (2)通過MultiByteToWideChar函數(shù)實(shí)現(xiàn)轉(zhuǎn)換,例如:
            char *szProgID = "MAPI.Folder";
            WCHAR szWideProgID[128];
            CLSID clsid;
            long lLen = MultiByteToWideChar(CP_ACP,0,szProgID,strlen(szProgID),szWideProgID,sizeof(szWideProgID));
            szWideProgID[lLen] = '\0';
            (3)通過A2W宏來實(shí)現(xiàn),例如:
            USES_CONVERSION;
            CLSIDFromProgID( A2W(szProgID),&clsid);
            將Unicode轉(zhuǎn)換到ANSI
            (1)使用WideCharToMultiByte,例如:
            // 假設(shè)已經(jīng)有了一個(gè)Unicode 串 wszSomeString...
            char szANSIString [MAX_PATH];
            WideCharToMultiByte ( CP_ACP, WC_COMPOSITECHECK, wszSomeString, -1, szANSIString, sizeof(szANSIString), NULL, NULL );
            (2)使用W2A宏來實(shí)現(xiàn),例如:
            USES_CONVERSION;
            pTemp=W2A(wszSomeString);
            八、其它
            對(duì)消息的處理中我們經(jīng)常需要將WPARAM或LPARAM等32位數(shù)據(jù)(DWORD)分解成兩個(gè)16位數(shù)據(jù)(WORD),例如:
            LPARAM lParam;
            WORD loValue = LOWORD(lParam);///取低16位
            WORD hiValue = HIWORD(lParam);///取高16位

            對(duì)于16位的數(shù)據(jù)(WORD)我們可以用同樣的方法分解成高低兩個(gè)8位數(shù)據(jù)(BYTE),例如:
            WORD wValue;
            BYTE loValue = LOBYTE(wValue);///取低8位
            BYTE hiValue = HIBYTE(wValue);///取高8位

            兩個(gè)16位數(shù)據(jù)(WORD)合成32位數(shù)據(jù)(DWORD,LRESULT,LPARAM,或WPARAM)
            LONG MAKELONG( WORD wLow, WORD wHigh );
            WPARAM MAKEWPARAM( WORD wLow, WORD wHigh );
            LPARAM MAKELPARAM( WORD wLow, WORD wHigh );
            LRESULT MAKELRESULT( WORD wLow, WORD wHigh );

            兩個(gè)8位的數(shù)據(jù)(BYTE)合成16位的數(shù)據(jù)(WORD)
            WORD MAKEWORD( BYTE bLow, BYTE bHigh );

            從R(red),G(green),B(blue)三色得到COLORREF類型的顏色值
            COLORREF RGB( BYTE byRed,BYTE byGreen,BYTE byBlue );
            例如COLORREF bkcolor = RGB(0x22,0x98,0x34);

            從COLORREF類型的顏色值得到RGB三個(gè)顏色值
            BYTE Red = GetRValue(bkcolor); ///得到紅顏色
            BYTE Green = GetGValue(bkcolor); ///得到綠顏色
            BYTE Blue = GetBValue(bkcolor); ///得到蘭顏色

            九、注意事項(xiàng)
            假如需要使用到ConvertBSTRToString此類函數(shù),需要加上頭文件comutil.h,并在setting中加入comsupp.lib或者直接加上#pragma comment( lib, "comsupp.lib" )

            posted @ 2010-06-21 22:59 lhking 閱讀(304) | 評(píng)論 (0)編輯 收藏
            僅列出標(biāo)題  下一頁

            導(dǎo)航

            <2010年6月>
            303112345
            6789101112
            13141516171819
            20212223242526
            27282930123
            45678910

            統(tǒng)計(jì)

            常用鏈接

            留言簿

            隨筆檔案

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            一本色道久久88—综合亚洲精品| 久久久久人妻精品一区| 开心久久婷婷综合中文字幕| 久久久国产亚洲精品| 久久人做人爽一区二区三区| 精品无码久久久久国产| 久久青青草原亚洲av无码| 狠狠综合久久AV一区二区三区 | 久久婷婷成人综合色综合| 色综合久久中文综合网| 97视频久久久| 久久青青草原精品影院| 四虎国产精品成人免费久久| 九九久久自然熟的香蕉图片| 久久久久久极精品久久久| 国产三级久久久精品麻豆三级| 久久精品二区| 久久国产精品久久| 7777久久久国产精品消防器材| 久久99精品久久久久久9蜜桃| 日日躁夜夜躁狠狠久久AV| 亚洲精品99久久久久中文字幕 | 亚洲精品无码久久千人斩| 久久久久久噜噜精品免费直播| 久久国产亚洲精品无码| 中文字幕乱码久久午夜| 久久成人国产精品一区二区| 狠狠色丁香久久婷婷综| 亚洲AV无码1区2区久久 | 亚洲国产高清精品线久久 | 99久久亚洲综合精品成人| 久久久久亚洲av无码专区| 伊人久久大香线蕉综合影院首页| 理论片午午伦夜理片久久| 久久se这里只有精品| 国产2021久久精品| segui久久国产精品| 国内精品久久九九国产精品| 久久Av无码精品人妻系列| 久久亚洲春色中文字幕久久久| 日韩久久久久久中文人妻 |