• <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>
            春暖花開(kāi)
            雪化了,花開(kāi)了,春天來(lái)了
            posts - 149,comments - 125,trackbacks - 0

            摘自:http://www.diybl.com/course/3_program/c++/cppjs/2008426/111619.html
              
                  去年11月的MSDN雜志曾刊登過(guò)一篇文章 Break Free of Code Deadlocks in Critical Sections Under Windows ,Matt Pietrek 和 Russ Osterlund 兩位對(duì)臨界區(qū)(Critical Section)的內(nèi)部實(shí)現(xiàn)做了一次簡(jiǎn)短的介紹,但點(diǎn)到為止,沒(méi)有繼續(xù)深入下去,當(dāng)時(shí)給我的感覺(jué)就是癢癢的,呵呵,于是用IDA和SoftIce大致分析了一下臨界區(qū)的實(shí)現(xiàn),大致弄明白了原理后也就沒(méi)有深究。現(xiàn)在乘著Win2k源碼的東風(fēng),重新分析一下這塊的內(nèi)容,做個(gè)小小的總結(jié)吧 :P
                 臨界區(qū)(Critical Section)是Win32中提供的一種輕量級(jí)的同步機(jī)制,與互斥(Mutex)和事件(Event)等內(nèi)核同步對(duì)象相比,臨界區(qū)是完全在用戶(hù)態(tài)維護(hù)的,所以?xún)H能在同一進(jìn)程內(nèi)供線程同步使用,但也因此無(wú)需在使用時(shí)進(jìn)行用戶(hù)態(tài)和核心態(tài)之間的切換,工作效率大大高于其它同步機(jī)制。
                 臨界區(qū)的使用方法非常簡(jiǎn)單,使用 InitializeCriticalSection 或 InitializeCriticalSectionAndSpinCount 函數(shù)初始化一個(gè) CRITICAL_SECTION 結(jié)構(gòu);使用 SetCriticalSectionSpinCount 函數(shù)設(shè)置臨界區(qū)的Spin計(jì)數(shù)器;然后使用 EnterCriticalSection 或 TryEnterCriticalSection 獲取臨界區(qū)的所有權(quán);完成需要同步的操作后,使用 LeaveCriticalSection 函數(shù)釋放臨界區(qū);最后使用 DeleteCriticalSection 函數(shù)析構(gòu)臨界區(qū)結(jié)構(gòu)。
                 以下是MSDN中提供的一個(gè)簡(jiǎn)單的例子:

                以下為引用:

             // Global variable
             CRITICAL_SECTION CriticalSection;

             void main()
             {
                 ...

                 // Initialize the critical section one time only.
                 if (!InitializeCriticalSectionAndSpinCount(&CriticalSection, 0x80000400) )
                     return;
                 ...

                 // Release resources used by the critical section object.
                 DeleteCriticalSection(&CriticalSection)
             }

             DWORD WINAPI ThreadProc( LPVOID lpParameter )
             {
                 ...

                 // Request ownership of the critical section.
                 EnterCriticalSection(&CriticalSection);

                 // Access the shared resource.

                 // Release ownership of the critical section.
                 LeaveCriticalSection(&CriticalSection);

                 ...
             }

                 首先看看構(gòu)造和析構(gòu)臨界區(qū)結(jié)構(gòu)的函數(shù)。
                 InitializeCriticalSection 函數(shù)(ntosdll esource.c:1210)實(shí)際上是調(diào)用 InitializeCriticalSectionAndSpinCount 函數(shù)(resource.c:1266)完成功能的,只不過(guò)傳入一個(gè)值為0的初始Spin計(jì)數(shù)器;InitializeCriticalSectionAndSpinCount 函數(shù)主要完成兩部分工作:初始化 RTL_CRITICAL_SECTION 結(jié)構(gòu)和 RTL_CRITICAL_SECTION_DEBUG 結(jié)構(gòu)。前者是臨界區(qū)的核心結(jié)構(gòu),下面將著重討論;后者是調(diào)試用結(jié)構(gòu),Matt 那篇文章里面分析的很清楚了,我這兒就不羅嗦了 :P
                 RTL_CRITICAL_SECTION結(jié)構(gòu)在winnt.h中定義如下:

            以下為引用:

             typedef struct _RTL_CRITICAL_SECTION {
                 PRTL_CRITICAL_SECTION_DEBUG DebugInfo;

                 //
                 //  The following three fields control entering and exiting the critical
                 //  section for the resource
                 //

                 LONG LockCount;
                 LONG RecursionCount;
                 HANDLE OwningThread;        // from the thread''s

            ClientId->UniqueThread
                 HANDLE LockSemaphore;
                 ULONG_PTR SpinCount;        // force size on 64-bit systems when packed
             } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;

                 InitializeCriticalSectionAndSpinCount 函數(shù)中首先對(duì)臨界區(qū)結(jié)構(gòu)進(jìn)行了初始化

                 DebugInfo 字段指向初始化臨界區(qū)時(shí)分配的RTL_CRITICAL_SECTION_DEBUG結(jié)構(gòu);
                 LockCount 字段是臨界區(qū)中最重要的字段,初始值為-1,當(dāng)臨界區(qū)被獲取(Hold)時(shí)此字段大于等于0;
                 RecursionCount 字段保存當(dāng)前臨界區(qū)所有者線程的獲取緩沖區(qū)嵌套層數(shù),初始值為0;
                 OwningThread 字段保存當(dāng)前臨界區(qū)所有者線程的句柄,初始值為0;
                 LockSemaphore 字段實(shí)際上是一個(gè)auto-reset的事件句柄,用于喚醒等待獲取臨界區(qū)的阻塞線程,初始值為0;
                 SpinCount 字段用于在多處理器環(huán)境下完成輕量級(jí)的CPU見(jiàn)同步,單處理器時(shí)沒(méi)有使用(初始值為0),多處理器時(shí)設(shè)置為SpinCount參數(shù)值(最大為MAX_SPIN_COUNT=0x00ffffff)。此外 RtlSetCriticalSectionSpinCount 函數(shù)(resource.c:1374)的代碼與這兒設(shè)置SpinCount的代碼完全一樣。

                 初始化臨界區(qū)結(jié)構(gòu)后,函數(shù)會(huì)根據(jù)SpinCount參數(shù)的一個(gè)標(biāo)志位判斷是否需要預(yù)先初始化 LockSemaphore 字段,如果需要?jiǎng)t使用NtCreateEvent創(chuàng)建一個(gè)具有訪問(wèn)權(quán)限的同步用事件核心對(duì)象,初始狀態(tài)為沒(méi)有激發(fā)。這一初始化本來(lái)是在 EnterCriticalSection 函數(shù)中完成的,將之顯式提前可以進(jìn)一步優(yōu)化 EnterCriticalSection 函數(shù)的性能。
                 值得注意的是,這一特性?xún)H對(duì)Win2k有效。MSDN里面說(shuō)明如下:

            以下為引用:

             Windows 2000:  If the high-order bit is set, the function preallocates the event used by the EnterCriticalSection function. Do not set this bit if you are creating a large number of critical section objects, because it will consume a significant amount of nonpaged pool. This flag is not necessary on Windows XP and later, and it is ignored.

                 與之對(duì)應(yīng)的 DeleteCriticalSection 函數(shù)完成關(guān)閉事件句柄和是否調(diào)試結(jié)構(gòu)的功能。

                 臨界區(qū)真正的核心代碼在win2kprivate tosdlli386critsect.asm里面,包括_RtlEnterCriticalSection、_RtlTryEnterCriticalSection和_RtlLeaveCriticalSection三個(gè)函數(shù)。

                 _RtlEnterCriticalSection 函數(shù) (critsect.asm:85) 首先檢查SpinCount是否為0,如果不為0則處理多處理器架構(gòu)下的問(wèn)題[分支1];如為0則使用原子操作給LockCount加一,并判斷是否其值為0。如果加一后LockCount大于0,則此臨界區(qū)已經(jīng)被獲取[分支2];如為0則獲取當(dāng)前線程TEB中的線程句柄,保存在臨界區(qū)的OwningThread字段中,并將RecursionCount設(shè)置為1。調(diào)試版本則調(diào)用RtlpCriticalSectionIsOwned函數(shù)在調(diào)試模式下驗(yàn)證此緩沖區(qū)是被當(dāng)前線程獲取的,否則在調(diào)試模式下激活調(diào)試器。最后還會(huì)更新TEB的CountOfOwnedCriticalSections計(jì)數(shù)器,以及臨界區(qū)調(diào)試結(jié)構(gòu)中的EntryCount字段。
                 如果此臨界區(qū)已經(jīng)被獲取[分支2],則判斷獲取臨界區(qū)的線程句柄是否與當(dāng)前線程相符。如果是同一線程則直接將RecursionCount和調(diào)試結(jié)構(gòu)的EntryCount字段加一;如果不是當(dāng)前線程,則調(diào)用RtlpWaitForCriticalSection函數(shù)等待此臨界區(qū),并從頭開(kāi)始執(zhí)行獲取臨界區(qū)的程序。
                 多CPU情況的分支處理方式類(lèi)似,只是多了對(duì)SpinCount的雙重檢查處理。

                 接著的_RtlTryEnterCriticalSection(critsect.asm:343)函數(shù)是一個(gè)輕量級(jí)的嘗試獲取臨界區(qū)的函數(shù)。偽代碼如下:

            以下為引用:

             if(CriticalSection->LockCount == -1)
             {
               // 臨界區(qū)可用
               CriticalSection->LockCount = 0;
               CriticalSection->OwningThread = TEB->ClientID;
               CriticalSection->RecursionCount = 1;

               return TRUE;
             }
             else
             {
               if(CriticalSection->OwningThread == TEB->ClientID)
               {
                 // 臨界區(qū)是當(dāng)前線程獲取
                 CriticalSection->LockCount++;
                 CriticalSection->RecursionCount++;

                 return TRUE;
               }
               else
               {
                 // 臨界區(qū)已被其它線程獲取
                 return FALSE;
               }
             }
             
             

             

             

                 最后的_RtlLeaveCriticalSection(critsect.asm:271)函數(shù)釋放已獲取的臨界區(qū),實(shí)現(xiàn)就比較簡(jiǎn)單了,實(shí)際上就是對(duì)嵌套計(jì)數(shù)器和鎖定計(jì)數(shù)器進(jìn)行操作。偽代碼如下:

             

            以下為引用:

             if(--CriticalSection->RecursionCount == 0)
             {
            bsp;  // 臨界區(qū)已不再被使用
               CriticalSection->OwningThread = 0;
             

               if(--CriticalSection->LockCount)
               {
                 // 仍有線程鎖定在臨界區(qū)上
                 _RtlpUnWaitCriticalSection(CriticalSection)
               }
             }
             else
             {
               --CriticalSection->LockCount
             }

            posted @ 2008-12-01 14:05 Sandy 閱讀(1828) | 評(píng)論 (0)編輯 收藏
            一、宏中“#”和“##”的用法:

                    一般用法:使用“#”把宏參數(shù)變?yōu)橐粋€(gè)字符串,用”##”把兩個(gè)宏參數(shù)結(jié)合在一起

                   例子:

            #include <iostream>
            using namespace std;

            #define TEST1(x) (cout<<id##x<<endl);
            #define TEST2(p) (cout<<#p<<endl);
            int main()
            {
                
            int id1 = 1001;
                
            int id2 = 1002;
                TEST1(
            1);    // == cout<< id1 << endl;
                TEST2(2);    // == cout<< "2" << endl;
                TEST1(2);    // == cout<< id2 << endl;

                system(
            "pause");
                
            return 0;
            }

            二、防止一個(gè)頭文件被重復(fù)包含
                    #ifndef COMDEF_H
                    #define COMDEF_H
                    //頭文件內(nèi)容
                    #endif
                當(dāng)你所建的工程有多個(gè)源文件組成時(shí),很可能會(huì)在多個(gè)文件里頭包含了同一個(gè)頭文件,如果借用上面的宏定義就能夠避免同一個(gè)頭文件被重復(fù)包含時(shí)進(jìn)行多次編譯。因?yàn)楫?dāng)它編譯第一個(gè)頭文件時(shí)總是沒(méi)有定義#define COMDEF_H,那么它將編譯一遍頭文件中所有的內(nèi)容,包括定義#define COMDEF_H。這樣編譯再往下進(jìn)行時(shí)如果遇到同樣要編譯的頭文件,那么由于語(yǔ)句#ifndef COMDEF_H的存在它將不再重復(fù)的編譯這個(gè)頭文件。

            三、常用的宏定義
              __DATE__
              進(jìn)行預(yù)處理的日期(“Mmm dd yyyy”形式的字符串文字)

              __FILE__
              代表當(dāng)前源代碼文件名的字符串文字

              __LINE__
              代表當(dāng)前源代碼中的行號(hào)的整數(shù)常量

              __TIME__
              源文件編譯時(shí)間,格式微“hh:mm:ss”

            參考文章:
               C中的預(yù)編譯宏定義  http://blog.readnovel.com/article/htm/tid_900939.html
               C標(biāo)準(zhǔn)中一些預(yù)定義的宏 http://www.programfan.com/article/2883.html
               C語(yǔ)言常用宏定義技巧  http://blog.21ic.com/user1/3074/archives/2008/51567.html
               C語(yǔ)言宏定義技巧(常用宏定義) http://blog.21ic.com/user1/69/archives/2006/13695.html
               宏定義:http://blog.csdn.net/believefym/archive/2007/10/21/1836162.aspx

            好好學(xué)習(xí)!
             
            posted @ 2008-12-01 13:54 Sandy 閱讀(1896) | 評(píng)論 (0)編輯 收藏
            好文章,大家一起分享。

            一直對(duì)extern "c"不是很明白。今天,看了一篇文章《C++中extern “C”含義深層探索》,對(duì)這個(gè)問(wèn)題終于有所認(rèn)識(shí)。轉(zhuǎn)過(guò)來(lái)與大家分享。

            鏈接:http://developer.51cto.com/art/200510/9066.htm
            作者:宋寶華

            1.引言
            C++語(yǔ)言的創(chuàng)建初衷是“a better C”,但是這并不意味著C++中類(lèi)似C語(yǔ)言的全局變量和函數(shù)所采用的編譯和連接方式與C語(yǔ)言完全相同。作為一種欲與C兼容的語(yǔ)言,C++保留了一部分過(guò)程式語(yǔ)言的特點(diǎn)(被世人稱(chēng)為“不徹底地面向?qū)ο?#8221;),因而它可以定義不屬于任何類(lèi)的全局變量和函數(shù)。但是,C++畢竟是一種面向?qū)ο蟮某绦蛟O(shè)計(jì)語(yǔ)言,為了支持函數(shù)的重載,C++對(duì)全局函數(shù)的處理方式與C有明顯的不同。
            2.從標(biāo)準(zhǔn)頭文件說(shuō)起

            某企業(yè)曾經(jīng)給出如下的一道面試題:
            面試題:為什么標(biāo)準(zhǔn)頭文件都有類(lèi)似以下的結(jié)構(gòu)?
            #ifndef __INCvxWorksh
            #define __INCvxWorksh
            #ifdef __cplusplus
            extern "C" {
            #endif
            /*...*/
            #ifdef __cplusplus
            }
            #endif
            #endif /* __INCvxWorksh */
            分析
            顯然,頭文件中的編譯宏“#ifndef __INCvxWorksh、#define __INCvxWorksh、#endif” 的作用是防止該頭文件被重復(fù)引用。
            那么
            #ifdef __cplusplus
            extern "C" {
            #endif
            #ifdef __cplusplus
            }
            #endif
            的作用又是什么呢?我們將在下文一一道來(lái)。

            3.深層揭密extern "C"

            extern "C" 包含雙重含義,從字面上即可得到:首先,被它修飾的目標(biāo)是“extern”的;其次,被它修飾的目標(biāo)是“C”的。讓我們來(lái)詳細(xì)解讀這兩重含義。
            被extern "C"限定的函數(shù)或變量是extern類(lèi)型的;
            extern是C/C++語(yǔ)言中表明函數(shù)和全局變量作用范圍(可見(jiàn)性)的關(guān)鍵字,該關(guān)鍵字告訴編譯器,其聲明的函數(shù)和變量可以在本模塊或其它模塊中使用。記住,下列語(yǔ)句:
            extern int a;
            僅僅是一個(gè)變量的聲明,其并不是在定義變量a,并未為a分配內(nèi)存空間。變量a在所有模塊中作為一種全局變量只能被定義一次,否則會(huì)出現(xiàn)連接錯(cuò)誤。
            通常,在模塊的頭文件中對(duì)本模塊提供給其它模塊引用的函數(shù)和全局變量以關(guān)鍵字extern聲明。例如,如果模塊B欲引用該模塊A中定義的全局變量和函數(shù)時(shí)只需包含模塊A的頭文件即可。這樣,模塊B中調(diào)用模塊A中的函數(shù)時(shí),在編譯階段,模塊B雖然找不到該函數(shù),但是并不會(huì)報(bào)錯(cuò);它會(huì)在連接階段中從模塊A編譯生成的目標(biāo)代碼中找到此函數(shù)。
            與extern對(duì)應(yīng)的關(guān)鍵字是static,被它修飾的全局變量和函數(shù)只能在本模塊中使用。因此,一個(gè)函數(shù)或變量只可能被本模塊使用時(shí),其不可能被extern “C”修飾。
            被extern "C"修飾的變量和函數(shù)是按照C語(yǔ)言方式編譯和連接的;
            未加extern “C”聲明時(shí)的編譯方式
            首先看看C++中對(duì)類(lèi)似C的函數(shù)是怎樣編譯的。
            作為一種面向?qū)ο蟮恼Z(yǔ)言,C++支持函數(shù)重載,而過(guò)程式語(yǔ)言C則不支持。函數(shù)被C++編譯后在符號(hào)庫(kù)中的名字與C語(yǔ)言的不同。例如,假設(shè)某個(gè)函數(shù)的原型為:
            void foo( int x, int y );
            該函數(shù)被C編譯器編譯后在符號(hào)庫(kù)中的名字為_(kāi)foo,而C++編譯器則會(huì)產(chǎn)生像_foo_int_int之類(lèi)的名字(不同的編譯器可能生成的名字不同,但是都采用了相同的機(jī)制,生成的新名字稱(chēng)為“mangled name”)。
            foo_int_int這樣的名字包含了函數(shù)名、函數(shù)參數(shù)數(shù)量及類(lèi)型信息,C++就是靠這種機(jī)制來(lái)實(shí)現(xiàn)函數(shù)重載的。例如,在C++中,函數(shù)void foo( int x, int y )與void foo( int x, float y )編譯生成的符號(hào)是不相同的,后者為_(kāi)foo_int_float。

            同樣地,C++中的變量除支持局部變量外,還支持類(lèi)成員變量和全局變量。用戶(hù)所編寫(xiě)程序的類(lèi)成員變量可能與全局變量同名,我們以"."來(lái)區(qū)分。而本質(zhì)上,編譯器在進(jìn)行編譯時(shí),與函數(shù)的處理相似,也為類(lèi)中的變量取了一個(gè)獨(dú)一無(wú)二的名字,這個(gè)名字與用戶(hù)程序中同名的全局變量名字不同。
            未加extern "C"聲明時(shí)的連接方式
            假設(shè)在C++中,模塊A的頭文件如下:
            // 模塊A頭文件 moduleA.h
            #ifndef MODULE_A_H
            #define MODULE_A_H
            int foo( int x, int y );
            #endif
            在模塊B中引用該函數(shù):
            // 模塊B實(shí)現(xiàn)文件 moduleB.cpp
            #include "moduleA.h"
            foo(2,3);

            實(shí)際上,在連接階段,連接器會(huì)從模塊A生成的目標(biāo)文件moduleA.obj中尋找_foo_int_int這樣的符號(hào)!
            加extern "C"聲明后的編譯和連接方式
            加extern "C"聲明后,模塊A的頭文件變?yōu)椋?br>// 模塊A頭文件 moduleA.h
            #ifndef MODULE_A_H
            #define MODULE_A_H
            extern "C" int foo( int x, int y );
            #endif
            在模塊B的實(shí)現(xiàn)文件中仍然調(diào)用foo( 2,3 ),其結(jié)果是:
            (1)模塊A編譯生成foo的目標(biāo)代碼時(shí),沒(méi)有對(duì)其名字進(jìn)行特殊處理,采用了C語(yǔ)言的方式;
            (2)連接器在為模塊B的目標(biāo)代碼尋找foo(2,3)調(diào)用時(shí),尋找的是未經(jīng)修改的符號(hào)名_foo。
            如果在模塊A中函數(shù)聲明了foo為extern "C"類(lèi)型,而模塊B中包含的是extern int foo( int x, int y ) ,則模塊B找不到模塊A中的函數(shù);反之亦然。
            所以,可以用一句話概括extern “C”這個(gè)聲明的真實(shí)目的(任何語(yǔ)言中的任何語(yǔ)法特性的誕生都不是隨意而為的,來(lái)源于真實(shí)世界的需求驅(qū)動(dòng)。我們?cè)谒伎紗?wèn)題時(shí),不能只停留在這個(gè)語(yǔ)言是怎么做的,還要問(wèn)一問(wèn)它為什么要這么做,動(dòng)機(jī)是什么,這樣我們可以更深入地理解許多問(wèn)題):
            實(shí)現(xiàn)C++與C及其它語(yǔ)言的混合編程。

            明白了C++中extern "C"的設(shè)立動(dòng)機(jī),我們下面來(lái)具體分析extern "C"通常的使用技巧。

            4.extern "C"的慣用法
            (1)在C++中引用C語(yǔ)言中的函數(shù)和變量,在包含C語(yǔ)言頭文件(假設(shè)為cExample.h)時(shí),需進(jìn)行下列處理:
            extern "C"
            {
            #include "cExample.h"
            }
            而在C語(yǔ)言的頭文件中,對(duì)其外部函數(shù)只能指定為extern類(lèi)型,C語(yǔ)言中不支持extern "C"聲明,在.c文件中包含了extern "C"時(shí)會(huì)出現(xiàn)編譯語(yǔ)法錯(cuò)誤。
            筆者編寫(xiě)的C++引用C函數(shù)例子工程中包含的三個(gè)文件的源代碼如下:
            /* c語(yǔ)言頭文件:cExample.h */
            #ifndef C_EXAMPLE_H
            #define C_EXAMPLE_H
            extern int add(int x,int y);
            #endif
            /* c語(yǔ)言實(shí)現(xiàn)文件:cExample.c */
            #include "cExample.h"
            int add( int x, int y )
            {
            return x + y;
            }
            // c++實(shí)現(xiàn)文件,調(diào)用add:cppFile.cpp
            extern "C"
            {
            #include "cExample.h"
            }
            int main(int argc, char* argv[])
            {
            add(2,3);
            return 0;
            }
            如果C++調(diào)用一個(gè)C語(yǔ)言編寫(xiě)的.DLL時(shí),當(dāng)包括.DLL的頭文件或聲明接口函數(shù)時(shí),應(yīng)加extern "C" { }。
            (2)在C中引用C++語(yǔ)言中的函數(shù)和變量時(shí),C++的頭文件需添加extern "C",但是在C語(yǔ)言中不能直接引用聲明了extern "C"的該頭文件,應(yīng)該僅將C文件中將C++中定義的extern "C"函數(shù)聲明為extern類(lèi)型。

            筆者編寫(xiě)的C引用C++函數(shù)例子工程中包含的三個(gè)文件的源代碼如下:
            //C++頭文件 cppExample.h
            #ifndef CPP_EXAMPLE_H
            #define CPP_EXAMPLE_H
            extern "C" int add( int x, int y );
            #endif
            //C++實(shí)現(xiàn)文件 cppExample.cpp
            #include "cppExample.h"
            int add( int x, int y )
            {
            return x + y;
            }
            /* C實(shí)現(xiàn)文件 cFile.c
            /* 這樣會(huì)編譯出錯(cuò):#include "cExample.h" */
            extern int add( int x, int y );
            int main( int argc, char* argv[] )
            {
            add( 2, 3 );
            return 0;
            }
            如果深入理解了第3節(jié)中所闡述的extern "C"在編譯和連接階段發(fā)揮的作用,就能真正理解本節(jié)所闡述的從C++引用C函數(shù)和C引用C++函數(shù)的慣用法。

            posted @ 2008-12-01 11:43 Sandy 閱讀(337) | 評(píng)論 (0)編輯 收藏
              MUI,其英文全拼為:Multilingual User Interface。這幾天思考如何運(yùn)用多語(yǔ)言的問(wèn)題,查到了一些相關(guān)資料,貼出來(lái)與大家分享。
               
               Multilingual User Interface (MUI) 
               http://msdn.microsoft.com/en-us/library/aa913592.aspx
               The Multilingual User Interface (MUI) allows users to change the language of the user interface (UI). To make this possible, the MUI uses a single core binary that includes the system default language, together with one resource dynamic-link library (DLL) for each additional target language. The target device boots with the system default language and then a new user-selected language goes into effect after a soft reset. This switch requires recreating windows, menus, and dialog boxes with the newly loaded resources. In addition, to be considered successful, the language switch must display these elements with the correct fonts and with the correct locale-specific information. 
               
               In  This Section
               For All Platforms: 
               Multilingual User Interface (MUI) Application Development
               Provides an overview of the MUI architecture. Provides instructions on how to work with fonts in a multilingual user-interface environment and shows how to use MUI with applications. 
               Multilingual User Interface (MUI) Reference
               Provides reference pages for the MUI application programming interface.
                For Windows Embedded CE: 
                Multilingual User Interface (MUI) OS Design Development
                Provides information about the MUI support that is helpful when designing and developing a Windows Embedded CE OS. This includes dependency information, the modules and components that implement MUI, and MUI implementation considerations. 
                How to Create a Multilingual Run-time Image Using MUI
                Demonstrates how to create a run-time image in both French and English by using MUI.
                Multilingual User Interface (MUI) Registry Settings
                Provides registry-related information for MUI.
                Multilingual User Interface (MUI) Migration
                Provides information about factors to consider when migrating to a newer version of Windows Embedded CE

            posted @ 2008-11-23 11:07 Sandy 閱讀(2071) | 評(píng)論 (0)編輯 收藏
                    
                  總在快樂(lè)的時(shí)候,感到微微的惶恐
                 在開(kāi)懷大笑時(shí),留下感動(dòng)的淚水
                 我無(wú)法相信單純的幸福
                 對(duì)人生的起伏悲苦,既坦然又不安
                                           ————摘自幾米漫畫(huà)

                    摘了這么幾句與大家分享。心情煩惱得時(shí)候,會(huì)看看漫畫(huà),緩解一些心情。如果你也有心煩意亂的時(shí)候,看看漫畫(huà),或者看看喜劇,開(kāi)懷的一笑,讓你從你煩惱中脫離。
                    最近心情也相當(dāng)壓抑,甚至萬(wàn)分郁悶。周末了,看到這么幾句,心有所感,與大家分享。
            posted @ 2008-11-22 00:24 Sandy 閱讀(586) | 評(píng)論 (0)編輯 收藏
            如何添加代碼注釋?zhuān)?br>這個(gè)我一直沒(méi)有搞懂。自己隨便涂鴉,也懶得加注釋。但是真正參加項(xiàng)目,有時(shí)也會(huì)找理由不添注釋。看了一些書(shū),參加一些培訓(xùn),有的人說(shuō),加注釋好,有人說(shuō)加注釋不好。好有好的地方,壞也有壞的味道。對(duì)于我這個(gè)初來(lái)乍到之人來(lái)說(shuō),反而倒是非常迷惑。
            最近看到一篇文章“添加代碼注釋13個(gè)技巧”,也解除了心中的部分疑團(tuán)。貼在這里與大家分享,也備以后參考。
            鏈接:
            http://sunxinhe.yo2.cn/articles/%E3%80%90%E8%BD%AC%E3%80%91%E6%B7%BB%E5%8A%A0%E4%BB%A3%E7%A0%81%E6%B3%A8%E9%87%8A13%E4%B8%AA%E6%8A%80%E5%B7%A7.html

            添加代碼注釋13個(gè)技巧

            作者:José M. Aguilar(西班牙語(yǔ))
            英文譯者:Timm Martin
            中文譯者:numenzq

            下面的13個(gè)技巧向你展示如何添加代碼注釋?zhuān)@些技巧都很容易理解和記憶。

            1. 逐層注釋
            為每個(gè)代碼塊添加注釋?zhuān)⒃诿恳粚邮褂媒y(tǒng)一的注釋方法和風(fēng)格。例如:
            針對(duì)每個(gè)類(lèi):包括摘要信息、作者信息、以及最近修改日期等
            針對(duì)每個(gè)方法:包括用途、功能、參數(shù)和返回值等
            在團(tuán)隊(duì)工作中,采用標(biāo)準(zhǔn)化的注釋尤為重要。當(dāng)然,使用注釋規(guī)范和工具(例如C#里的XML,Java里的Javadoc)可以更好的推動(dòng)注釋工作完成得更好。
            2. 使用分段注釋
            如果有多個(gè)代碼塊,而每個(gè)代碼塊完成一個(gè)單一任務(wù),則在每個(gè)代碼塊前添加一個(gè)注釋來(lái)向讀者說(shuō)明這段代碼的功能。例子如下:

            // Check that all data records
            // are correct
            foreach (Record record in records)
            {
            if (rec.checkStatus()==Status.OK)
            {
            . . .
            }
            }
            // Now we begin to perform
            // transactions
            Context ctx = new ApplicationContext();
            ctx.BeginTransaction();
            . . .

            3. 在代碼行后添加注釋
            如果多行代碼的每行都要添加注釋?zhuān)瑒t在每行代碼后添加該行的注釋?zhuān)@將很容易理解。例如:

            const MAX_ITEMS = 10; // maximum number of packets
            const MASK = 0x1F;    // mask bit TCP

            在分隔代碼和注釋時(shí),有的開(kāi)發(fā)者使用tab鍵,而另一些則使用空格鍵。然而由于tab鍵在各編輯器和IDE工具之間的表現(xiàn)不一致,因此最好的方法還是使用空格鍵。

            4. 不要侮辱讀者的智慧

            避免以下顯而易見(jiàn)的注釋?zhuān)?/font>

            if (a == 5)      // if a equals 5
            counter = 0; // set the counter to zero

            寫(xiě)這些無(wú)用的注釋會(huì)浪費(fèi)你的時(shí)間,并將轉(zhuǎn)移讀者對(duì)該代碼細(xì)節(jié)的理解。

            5. 禮貌點(diǎn)
            避免粗魯?shù)淖⑨專(zhuān)纾?#8220;注意,愚蠢的使用者才會(huì)輸入一個(gè)負(fù)數(shù)”或“剛修復(fù)的這個(gè)問(wèn)題出于最初的無(wú)能開(kāi)發(fā)者之手”。這樣的注釋能夠反映到它的作者是多么的拙劣,你也永遠(yuǎn)不知道誰(shuí)將會(huì)閱讀這些注釋?zhuān)赡苁牵耗愕睦习澹蛻?hù),或者是你剛才侮辱過(guò)的無(wú)能開(kāi)發(fā)者。

            6. 關(guān)注要點(diǎn)

            不要寫(xiě)過(guò)多的需要轉(zhuǎn)意且不易理解的注釋。避免ASCII藝術(shù),搞笑,詩(shī)情畫(huà)意,hyperverbosity的注釋。簡(jiǎn)而言之,保持注釋簡(jiǎn)單直接。

            7. 使用一致的注釋風(fēng)格
            一些人堅(jiān)信注釋?xiě)?yīng)該寫(xiě)到能被非編程者理解的程度。而其他的人則認(rèn)為注釋只要能 被開(kāi)發(fā)人員理解就行了。無(wú)論如何,Successful Strategies for Commenting Code已經(jīng)規(guī)定和闡述了注釋的一致性和針對(duì)的讀者。就個(gè)人而言,我懷疑大部分非編程人員將會(huì)去閱讀代碼,因此注釋?xiě)?yīng)該是針對(duì)其他的開(kāi)發(fā)者而言。

            8. 使用特有的標(biāo)簽
            在一個(gè)團(tuán)隊(duì)工作中工作時(shí),為了便于與其它程序員溝通,應(yīng)該采用一致的標(biāo)簽集進(jìn)行注釋。例如,在很多團(tuán)隊(duì)中用TODO標(biāo)簽表示該代碼段還需要額外的工作。

            int Estimate(int x, int y)
            {
            // TODO: implement the calculations
            return 0;
            }

            注釋標(biāo)簽切忌不要用于解釋代碼,它只是引起注意或傳遞信息。如果你使用這個(gè)技巧,記得追蹤并確認(rèn)這些信息所表示的是什么。

            9. 在代碼時(shí)添加注釋
            在寫(xiě)代碼時(shí)就添加注釋?zhuān)@時(shí)在你腦海里的是清晰完整的思路。如果在代碼最后再添 加同樣注釋?zhuān)鼘⒍嗷ㄙM(fèi)你一倍的時(shí)間。而“我沒(méi)有時(shí)間寫(xiě)注釋”,“我很忙”和“項(xiàng)目已經(jīng)延期了”這都是不愿寫(xiě)注釋而找的借口。一些開(kāi)發(fā)者覺(jué)得應(yīng)該 write comments before code,用于理清頭緒。例如:
            public void ProcessOrder()
            {
            // Make sure the products are available
            // Check that the customer is valid
            // Send the order to the store
            // Generate bill
            }

            10. 為自己注釋代碼

            當(dāng)注釋代碼時(shí),要考慮到不僅將來(lái)維護(hù)你代碼的開(kāi)發(fā)人員要看,而且你自己也可能要看。用Phil Haack大師的話來(lái)說(shuō)就是:“一旦一行代碼顯示屏幕上,你也就成了這段代碼的維護(hù)者”。因此,對(duì)于我們寫(xiě)得好(差)的注釋而言,我們將是第一個(gè)受益者(受害者)。

            11. 同時(shí)更新代碼和注釋

            如果注釋沒(méi)有跟隨代碼的變化而變化,及時(shí)是正確的注釋也沒(méi)有用。代碼和注釋?xiě)?yīng)該同步變化,否則這樣的注釋將對(duì)維護(hù)你代碼的開(kāi)發(fā)者帶來(lái)更大的困難。使用重構(gòu)工具時(shí)應(yīng)特別注意,它只會(huì)自動(dòng)更新代碼而不會(huì)修改注釋?zhuān)虼藨?yīng)該立即停止使用重構(gòu)工具。

            12. 注釋的黃金規(guī)則:易讀的代碼
            對(duì)于開(kāi)發(fā)者的一個(gè)基本原則就是:讓你的代碼為己解釋。雖然有些人懷疑這會(huì)讓那些不愿意寫(xiě)注釋的開(kāi)發(fā)者鉆空子,不過(guò)這樣的代碼真的會(huì)使你容易理解,還不需要額外維護(hù)注釋。例如在Fluid Interfaces文章里向你展示的代碼一樣:

            Calculator calc = new Calculator();
            calc.Set(0);
            calc.Add(10);
            calc.Multiply(2);
            calc.Subtract(4);
            Console.WriteLine( "Result: {0}", calc.Get() );

            在這個(gè)例子中,注釋是不需要的,否則可能就違反了技巧4。為了使代碼更容易理解,你可以考慮使用適當(dāng)?shù)拿?(Ottinger's Rules里講解得相當(dāng)好),確保正確的縮進(jìn),并且采用coding style guides,違背這個(gè)技巧可能的結(jié)果就像是注釋在為不好的代碼apologize。

            13. 與同事分享技巧
            雖然技巧10已經(jīng)向我們表明了我們是如何從好的注釋中直接受益,這些技巧將讓所有開(kāi)發(fā)者受益,特別是團(tuán)隊(duì)中一起工作的同事。因此,為了編寫(xiě)出更容易理解和維護(hù)的代碼,嘗試自由的和你的同事分享這些注釋技巧。


            好東西拿出來(lái)一起分享
            posted @ 2008-11-20 09:38 Sandy 閱讀(1131) | 評(píng)論 (1)編輯 收藏

            今天突然遇到Active Sync 4.5 setup.msi這個(gè)工具在windows vista系統(tǒng)上裝不上這個(gè)問(wèn)題,查了一下,原來(lái)在windows vista上,不再采用Active Sync ,而是采用了drvupdate-x86.exe,具體名字叫做Microsoft Windows Mobile 設(shè)備中心6.1。微軟對(duì)其的描述是:
            使用 Windows Mobile 設(shè)備中心,您可以建立新的合作關(guān)系,與 Windows Mobile 設(shè)備(Windows Mobile 2003 或更高版本)同步音樂(lè)、圖片和視頻,并對(duì)其進(jìn)行管理。Windows Mobile 設(shè)備中心與高效的商務(wù)數(shù)據(jù)同步平臺(tái)緊密結(jié)合,提供了令人耳目一新的用戶(hù)體驗(yàn)。Windows Mobile 設(shè)備中心可以幫助您快速建立新的合作關(guān)系,同步重要的商務(wù)信息(例如電子郵件、聯(lián)系人和日歷約會(huì)),輕松管理同步設(shè)置,以及在設(shè)備與 PC 間傳送商業(yè)文檔。
            這個(gè)主要是用于vista系統(tǒng)的。下載地址是
            http://www.microsoft.com/downloads/details.aspx?familyid=46F72DF1-E46A-4A5F-A791-09F07AAA1914&displaylang=zh-cn

            也可以建議大家去搜一下,我是在新浪上下載的。
            鏈接:http://down1.tech.sina.com.cn/download/down_contents/1183219200/35965.shtml

            posted @ 2008-11-19 19:37 Sandy 閱讀(1067) | 評(píng)論 (0)編輯 收藏

             

                    在csdn上閑逛,看到一個(gè)這樣的問(wèn)題:如何在PPC上實(shí)現(xiàn)多語(yǔ)言的程序列表中的名稱(chēng)在編譯時(shí)自動(dòng)切換

                    這個(gè)曾經(jīng)讓我相當(dāng)苦惱,看到這個(gè)自然不會(huì)放過(guò)。


                     一位牛人很簡(jiǎn)單的回答:
                
                  參考MUIHello 例子: 

                   C:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Smartphone SDK\Samples\CPP\Win32\Muihello\app\app.sln 
                  C:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Smartphone SDK\Samples\CPP\Win32\Muihello\German_resfile\german_resfile.sln 
                  C:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Smartphone SDK\Samples\CPP\Win32\Muihello\Resfile\resfile.sln

                  Samples竟然有多語(yǔ)言的例子,讓我相當(dāng)?shù)捏@訝!
                 學(xué)習(xí)了一下,比我自己的方法簡(jiǎn)單很多,看來(lái)需要好好學(xué)習(xí)SDK中提供的例子。

                 這個(gè)例子會(huì)生成muihello.exe.0409.mui,這其實(shí)是一個(gè)DLL資源文件,有人說(shuō)這是一種命名規(guī)則。在不同的平臺(tái)上就調(diào)用不同的資源,實(shí)現(xiàn)多語(yǔ)言。

                  在resfile.cpp文件中

            #include "windows.h"

            /////////////////////////////////////////////////////////////////////////////
            // DLL Entry Point

            extern "C"
            BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
            {
                
            return TRUE; 
            }

                 還有一個(gè)文件resfile.def
                 
            LIBRARY      "muihello.exe.0409.mui"

            EXPORTS

                  而且resource.h是共用一個(gè)的。

                嘗試了一下,蠻好。
            posted @ 2008-11-18 22:22 Sandy 閱讀(1439) | 評(píng)論 (0)編輯 收藏

            Burning    by Maria Arredondo

            Passion is sweet

            Love makes weak

            You said you cherished freedom so

            You refused to let it go

            Follow your fate

            Love and hate

            Never failed to seize the day

            Don’t give yourself away

            Oh when the night falls

            And you’re all alone

            In your deepest sleep

            What are you dreaming of

            My skin is still burning from your touch

            Oh I just can’t get enough

            I said I wouldn’t ask for much

            But your eyes are dangerous

            So the world keeps spinning in my head

            Can we drop this masquerade

            I can’t predict where it ends

            If you’ re the rock I’ll crush against

            Trapped in a crowd

            Music is loud

            I said I loved my freedom too

            Now I’m not so sure I do

            All eyes on you

            Wings so true

            Better quit while you're a head

            Now I’m not so sure I am

            Oh when the night falls

            And you’re all alone

            In your deepest sleep

            What are you dreaming of

            My skin is still burning from your touch

            Oh I just can’t get enough

            I said I wouldn’t ask for much

            But your eyes are dangerous

            So the world keeps spinning in my head

            Can we drop this masquerade

            I can’t predict where it ends

            If you’ re the rock I’ll crush against

            My soul, my heart

            If you’re near or if you’re far

            My life, my love

            You can have it all

            posted @ 2008-11-12 09:18 Sandy 閱讀(163) | 評(píng)論 (0)編輯 收藏

            下面摘自http://www.shnenglu.com/woaidongmao/archive/2008/11/03/65897.html

            看到他們的在爭(zhēng)論很有意思,我不是很懂。

            有利還是有弊呢?


            EXT_ASSERT將ASSERT與if結(jié)合在一起

            ASSERT在DEBUG程序時(shí)候幫了太多太多忙,不過(guò)在ASSERT判斷傳入?yún)?shù)后,還需要if再按相同條件判斷一遍,不符合規(guī)則return,這樣才是正確的邏輯。但這樣代碼難看,且工作重復(fù)無(wú)趣,又容易出現(xiàn)差漏。

            剛弄了個(gè)簡(jiǎn)單EXT_ASSERT宏,按我的理解應(yīng)該可以解決問(wèn)題,但不確定是否有漏洞,發(fā)出來(lái)大家一起瞄瞄。

             

            #define RET_VOID
            #define EX_ASSERT(exp, ret) {ASSERT(exp);if(!(exp))return(ret);}

             

            BOOL CXXX::FunXXX(const data* p_data)
            {
               EXT_ASSERT(p_data, FALSE);//---- 返回BOOL型

            }

            int CXXX::FunXXX(const data* p_data)
            {
               EXT_ASSERT(p_data, -1);//---- 返回int型

            }

            const retdata* CXXX::FunXXX(const data* p_data)
            {
                EXT_ASSERT(p_data, NULL);//---- 返回NULL指針

            }

            retdata CXXX::FunXXX(const data* p_data)
            {
                EXT_ASSERT(p_data, retdata());//---- 返回空對(duì)象

            }

            void CXXX::FunXXX(const data* p_data)
            {
                EXT_ASSERT(p_data, RET_VOID);//---- 僅僅return

            }

            posted on 2008-11-03 23:34 肥仔 閱讀(333) 評(píng)論(7)  編輯 收藏 引用 所屬分類(lèi): C++存檔

            評(píng)論

            # re: EXT_ASSERT將ASSERT與if結(jié)合在一起  回復(fù)  更多評(píng)論   

            哥們兒,如果你是說(shuō)MFC里的ASSERT的話(看你的類(lèi)命名風(fēng)格,估計(jì)是吧),在retail build里,ASSERT是完全不會(huì)被放到代碼里的。你這樣用ASSERT,把ASSERT和if條件綁在一起就等于把處理錯(cuò)誤的斷言和正常程序邏輯綁在了一起,不是一個(gè)好的設(shè)計(jì)。如果一定要這么干,也該是綁VERIFY,至少在retail build里VERIFY里的邏輯還會(huì)被執(zhí)行。

            ASSERT應(yīng)該拿來(lái)斷言程序正常執(zhí)行完全不可能出現(xiàn)的錯(cuò)誤(這些錯(cuò)誤會(huì)在debug build里出現(xiàn)是因?yàn)楫?dāng)前程序還不完善),在正常邏輯中,他們是不應(yīng)該用程序邏輯去handle的錯(cuò)誤,所以一句ASSERT夠了。
            2008-11-04 05:27 | www.helpsoff.com.cn

            # re: EXT_ASSERT將ASSERT與if結(jié)合在一起  回復(fù)  更多評(píng)論   

            @www.helpsoff.com.cn
            我在Imperfect C++中看到過(guò)相同的言論。
            不過(guò)我的應(yīng)用是,常常用ASSERT檢測(cè)參數(shù)的合法性,ASSERT之后,當(dāng)然還要if一把了,對(duì)于ASSERT和if不要放在一起這種觀點(diǎn),我不是很認(rèn)同,我覺(jué)得放在一起很好用的。

            另外,在Release下,ASSERT沒(méi)了,但是if留下了,這是需要的效果。
            2008-11-04 10:45 | 肥仔

            # re: EXT_ASSERT將ASSERT與if結(jié)合在一起  回復(fù)  更多評(píng)論   

            我不會(huì)這么用,斷言的目的去那了。
            2008-11-04 11:30 | Touchsoft

            # re: EXT_ASSERT將ASSERT與if結(jié)合在一起  回復(fù)  更多評(píng)論   

            @肥仔
            哥們兒,你還是沒(méi)理解,ASSERT的不是拿來(lái)干這個(gè)的。你愛(ài)怎樣玩就怎樣玩吧,反正自己的代碼自己維護(hù),其他人的意見(jiàn)聽(tīng)不聽(tīng)在你。
            2008-11-04 12:29 | www.helpsoff.com.cn

            # re: EXT_ASSERT將ASSERT與if結(jié)合在一起  回復(fù)  更多評(píng)論   

            @www.helpsoff.com.cn
            謝謝你的意見(jiàn),但是不采納。原因有3點(diǎn)經(jīng)歷:

            1、ASSERT判斷函數(shù)參數(shù)合法性,調(diào)試時(shí)會(huì)幫了很大的忙;
            2、if判段函數(shù)參數(shù)合法性,是健壯性的一部分;
            3、ASSERT和if 合在一起,不覺(jué)得有任何不妥,且ASSERT不出現(xiàn)在Release中,這正是需要的。

            可能涉及到的一個(gè)爭(zhēng)論是,檢測(cè)參數(shù)合法形是調(diào)用者,還是被調(diào)用者的責(zé)任?
            C/C++的主流是調(diào)用者保證參數(shù)的合法性,被調(diào)用者不檢測(cè)參數(shù)合法性,這就是為什么認(rèn)為,只要ASSERT,不需要if了。
            strcpy(szBuf, NULL)之所以讓一個(gè)程序崩潰也是這個(gè)原因,但是為什么要讓它崩潰?能夠不崩潰,繼續(xù)執(zhí)行豈不是更好嗎?
            2008-11-04 13:44 | 肥仔

            # re: EXT_ASSERT將ASSERT與if結(jié)合在一起  回復(fù)  更多評(píng)論   

            1) 沒(méi)人否認(rèn)ASSERT的用處;
            2) 需要if判斷處理的參數(shù)和用ASSERT斷言的不合法參數(shù),不應(yīng)屬于一個(gè)范疇,不應(yīng)該混合在一起處理;
            3) 代碼不管怎么寫(xiě)在沒(méi)遇到問(wèn)題前都不會(huì)有什么不妥,自己覺(jué)得好就好吧。

            你當(dāng)然可以去寫(xiě)一個(gè)萬(wàn)能的strcpy,但是如何能保證你的strcpy是真正的“萬(wàn)能”的呢?不崩潰繼續(xù)執(zhí)行倒是沒(méi)問(wèn)題,但是出問(wèn)題的真正根源在哪里呢,你這樣做不就掩蓋了問(wèn)題嗎?應(yīng)該做的是出現(xiàn)這樣的問(wèn)題時(shí),能有用且有效的指出錯(cuò)誤,而不是做garbage in, garbage out。

            設(shè)計(jì)代碼,不去扯那些玩得出花花的設(shè)計(jì)模式,有些很基本很直白的原則,比如說(shuō)“garbage in, garbage out”,比如高內(nèi)聚/低耦合...說(shuō)多了也沒(méi)意思,樓主愛(ài)怎么玩怎么玩,大家都是這么過(guò)來(lái)的,其中的東西自己去體會(huì)了。
            2008-11-04 15:35 | www.helpsoff.com.cn

            # re: EXT_ASSERT將ASSERT與if結(jié)合在一起  回復(fù)  更多評(píng)論   

            @www.helpsoff.com.cn
            程序以外,人生很多地方都需要與別人探討,對(duì)于不合己見(jiàn)者,請(qǐng)不必太在懷,更沒(méi)必要帶著情緒和語(yǔ)氣,擺出姿態(tài)。這樣才能贏得更多的合作,我想我的這幾句話還算中肯。
            2008-11-04 16:32 | 肥仔
            posted @ 2008-11-04 18:28 Sandy 閱讀(405) | 評(píng)論 (0)編輯 收藏
            僅列出標(biāo)題
            共15頁(yè): First 7 8 9 10 11 12 13 14 15 
            久久婷婷色综合一区二区| 丰满少妇人妻久久久久久4| 一级女性全黄久久生活片免费| 久久青草国产手机看片福利盒子| 久久艹国产| 久久精品国产亚洲AV无码偷窥| 久久精品国产91久久麻豆自制| 伊人久久大香线蕉综合网站| 久久青青草原精品国产| 久久久久亚洲AV无码去区首| 亚洲精品tv久久久久久久久| 精品熟女少妇aⅴ免费久久| 国内精品久久久久影院一蜜桃 | 91久久精一区二区三区大全| 久久精品国产亚洲精品| 久久精品中文无码资源站| 久久综合精品国产一区二区三区| 91精品国产乱码久久久久久 | 亚洲va久久久噜噜噜久久天堂| 国产精品免费久久久久久久久 | 久久久久久毛片免费播放| 欧美日韩成人精品久久久免费看 | 久久久久久无码国产精品中文字幕| 久久久久久久久久久久中文字幕| 久久综合伊人77777麻豆| 久久99精品免费一区二区| 久久综合久久综合久久| 久久精品无码午夜福利理论片| 久久国产劲爆AV内射—百度| 欧美日韩成人精品久久久免费看| 国产精品久久久99| 爱做久久久久久| 久久99精品国产99久久6| 久久久久九九精品影院| 久久精品国产第一区二区| 久久久精品久久久久特色影视| 99久久精品免费国产大片| 精品国产婷婷久久久| 久久夜色撩人精品国产小说| 久久精品国产亚洲一区二区三区| 久久久久久国产精品无码下载 |