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

            先調用GetWindowRect后再調用ScreenToClient,這個時候得到的rect和直接使用GetClientRect得到的值是相等的。有時候需要獲得窗口矩形的大小和客戶區矩形的大小二者的值,故需要分別調用GetWindowRect和GetClientRect。如果只需要獲得客戶區矩形的大小,調用GetClientRect就行了。GetWindowRect和GetClientRect函數的說明如下:

            CWnd::GetClientRect  
                void GetClientRect( LPRECT lpRect ) const;
            Parameters:
            lpRect
                Points to a RECT structure or a CRect object to receive the client coordinates. The left and top members will be 0. The right and bottom members will contain the width and height of the window.
            Remarks:
                Copies the client coordinates of the CWnd client area into the structure pointed to by lpRect. The client coordinates specify the upper-left and lower-right corners of the client area. Since client coordinates are relative to the upper-left corners of the CWnd client area, the coordinates of the upper-left corner are (0,0).

            CWnd::GetWindowRect
            void GetWindowRect( LPRECT lpRect ) const;
            Parameters:
            lpRect
            Points to a CRect object or a RECT structure that will receive the screen coordinates of the upper-left and lower-right corners.
            Remarks:
            Copies the dimensions of the bounding rectangle of the CWnd object to the structure pointed to by lpRect. The dimensions are given in screen coordinates relative to the upper-left corner of the display screen. The dimensions of the caption, border, and scroll bars, if present, are included.



            GetWindowRect() 得到的是在屏幕坐標系下的RECT;(即以屏幕左上角為原點
            GetClientRect() 得到的是在客戶區坐標系下的RECT; (即以所在窗口左上角為原點

            GetWindowRect()取的是整個窗口的矩形;
            GetClientRect()取的僅是客戶區的矩形,也就是說不包括標題欄,外框等;

            第一個函數獲得的是窗口在屏幕上的位置,得到的結果可能是這樣CRect(10,10,240,240);
            第二個函數和它不同,它只獲得了客戶區的大小,因此得到的結果總是這樣CRect(0,0,width,height);

            ScreenToClient() 就是把屏幕坐標系下的RECT坐標轉換為客戶區坐標系下的RECT坐標。

             

            The GetClientRect function retrieves the coordinates of a window's client area. The client coordinates specify the upper-left and lower-right corners of the client area. Because client coordinates are relative to the upper-left corner of a window's client area, the coordinates of the upper-left corner are (0,0).

            GetClientRect得到的是客戶區的大小,也就是說這樣得到的左上角永遠是(0,0)

            The GetWindowRect function retrieves the dimensions of the bounding rectangle of the specified window. The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.

            GetWindowRect 是窗口相對于整個屏幕的坐標,屏幕左上點為0,0

            相互轉化用ScreenToClient 或者 ClientToScreen

            ClientToScreen
            The ClientToScreen function converts the client coordinates of a specified point to screen coordinates.
            BOOL ClientToScreen(
               HWND hWnd,        // window handle for source coordinates
               LPPOINT lpPoint   // pointer to structure containing screen coordinates
            );

            Parameters
            hWnd
            Handle to the window whose client area is used for the conversion.
            lpPoint
            Pointer to a POINT structure that contains the client coordinates to be converted. The new screen coordinates are copied into this structure if the function succeeds.
            Return Values
            If the function succeeds, the return value is nonzero.

            If the function fails, the return value is zero.


            雖然存在調用GetWindowRect后再調用ScreenToClient==GetClientRect,但ScreenToClient()和ClientToScreen()兩者都是屬于WINDOWS API函數,可能是存在一定的冗余設計,但意義不同。
            不過在.Net Framework下對WINDOWS API函數進行了重新整理和優化,在獲取控件或窗口的屏幕坐標和客戶區坐標時更方便的多,只需要得到與控件或窗口相對應屏幕坐標和客戶區坐標屬性值就可以了

            ScreenToClient
            The ScreenToClient function converts the screen coordinates of a specified point on the screen to client coordinates.
            BOOL ScreenToClient(
               HWND hWnd,         // window handle for source coordinates
               LPPOINT lpPoint    // address of structure containing coordinates
            );
            Parameters:
            hWnd
            Handle to the window whose client area will be used for the conversion.
            lpPoint
            Pointer to a POINT structure that contains the screen coordinates to be converted.
            Return Values:
            If the function succeeds, the return value is nonzero.
            If the function fails, the return value is zero.
            posted @ 2011-04-01 11:30 wrh 閱讀(960) | 評論 (1)編輯 收藏
            Creating   a   Template   in   Memory
            Applications   sometimes   adapt   or   modify   the   content   of   dialog   boxes   depending   on   the   current   state   of   the   data   being   processed.   In   such   cases,   it   is   not   practical   to   provide   all   possible   dialog   box   templates   as   resources   in   the   application 's   executable   file.   But   creating   templates   in   memory   gives   the   application   more   flexibility   to   adapt   to   any   circumstances.  

            In   the   following   example,   the   application   creates   a   template   in   memory   for   a   modal   dialog   box   that   contains   a   message   and   OK   and   Help   buttons.  

            In   a   dialog   template,   all   character   strings,   such   as   the   dialog   box   and   button   titles,   must   be   Unicode   strings.   This   example   uses   the   MultiByteToWideChar   function   to   generate   these   Unicode   strings,   because   Windows   95/98   and   Windows   NT/Windows   2000   support   MultiByteToWideChar  

            The   DLGITEMTEMPLATE   structures   in   a   dialog   template   must   be   aligned   on   DWORD   boundaries.   To   align   these   structures,   this   example   uses   a   helper   routine   that   takes   an   input   pointer   and   returns   the   closest   pointer   that   is   aligned   on   a   DWORD   boundary.

            #define   ID_HELP       150
            #define   ID_TEXT       200

            LPWORD   lpwAlign   (   LPWORD   lpIn)
            {
                    ULONG   ul;

                    ul   =   (ULONG)   lpIn;
                    ul   +=3;
                    ul   > > =2;
                    ul   < <=2;
                    return   (LPWORD)   ul;
            }

            LRESULT   DisplayMyMessage(HINSTANCE   hinst,   HWND   hwndOwner,  
                    LPSTR   lpszMessage)
            {
                    HGLOBAL   hgbl;
                    LPDLGTEMPLATE   lpdt;
                    LPDLGITEMTEMPLATE   lpdit;
                    LPWORD   lpw;
                    LPWSTR   lpwsz;
                    LRESULT   ret;
                    int   nchar;

                    hgbl   =   GlobalAlloc(GMEM_ZEROINIT,   1024);
                    if   (!hgbl)
                            return   -1;
             
                    lpdt   =   (LPDLGTEMPLATE)GlobalLock(hgbl);
             
                    //   Define   a   dialog   box.
             
                    lpdt-> style   =   WS_POPUP   |   WS_BORDER   |   WS_SYSMENU
                                                  |   DS_MODALFRAME   |   WS_CAPTION;
                    lpdt-> cdit   =   3;     //   number   of   controls
                    lpdt-> x     =   10;     lpdt-> y     =   10;
                    lpdt-> cx   =   100;   lpdt-> cy   =   100;

                    lpw   =   (LPWORD)   (lpdt   +   1);
                    *lpw++   =   0;       //   no   menu
                    *lpw++   =   0;       //   predefined   dialog   box   class   (by   default)

                    lpwsz   =   (LPWSTR)   lpw;
                    nchar   =   1+   MultiByteToWideChar   (CP_ACP,   0,   "My   Dialog ",  
                                                                                    -1,   lpwsz,   50);
                    lpw       +=   nchar;

                    //-----------------------
                    //   Define   an   OK   button.
                    //-----------------------
                    lpw   =   lpwAlign   (lpw);   //   align   DLGITEMTEMPLATE   on   DWORD   boundary
                    lpdit   =   (LPDLGITEMTEMPLATE)   lpw;
                    lpdit-> x     =   10;   lpdit-> y     =   70;
                    lpdit-> cx   =   80;   lpdit-> cy   =   20;
                    lpdit-> id   =   IDOK;     //   OK   button   identifier
                    lpdit-> style   =   WS_CHILD   |   WS_VISIBLE   |   BS_DEFPUSHBUTTON;

                    lpw   =   (LPWORD)   (lpdit   +   1);
                    *lpw++   =   0xFFFF;
                    *lpw++   =   0x0080;         //   button   class

                    lpwsz   =   (LPWSTR)   lpw;
                    nchar   =   1+MultiByteToWideChar   (CP_ACP,   0,   "OK ",   -1,   lpwsz,   50);
                    lpw       +=   nchar;
                    lpw   =   lpwAlign   (lpw);   //   align   creation   data   on   DWORD   boundary
                    *lpw++   =   0;                       //   no   creation   data

                    //-----------------------
                    //   Define   a   Help   button.
                    //-----------------------
                    lpw   =   lpwAlign   (lpw);   //   align   DLGITEMTEMPLATE   on   DWORD   boundary
                    lpdit   =   (LPDLGITEMTEMPLATE)   lpw;
                    lpdit-> x     =   55;   lpdit-> y     =   10;
                    lpdit-> cx   =   40;   lpdit-> cy   =   20;
                    lpdit-> id   =   ID_HELP;         //   Help   button   identifier
                    lpdit-> style   =   WS_CHILD   |   WS_VISIBLE   |   BS_PUSHBUTTON;

                    lpw   =   (LPWORD)   (lpdit   +   1);
                    *lpw++   =   0xFFFF;
                    *lpw++   =   0x0080;                                   //   button   class   atom

                    lpwsz   =   (LPWSTR)   lpw;
                    nchar   =   1+MultiByteToWideChar   (CP_ACP,   0,   "Help ",   -1,   lpwsz,   50);
                    lpw       +=   nchar;
                    lpw   =   lpwAlign   (lpw);   //   align   creation   data   on   DWORD   boundary
                    *lpw++   =   0;                       //   no   creation   data

                    //-----------------------
                    //   Define   a   static   text   control.
                    //-----------------------
                    lpw   =   lpwAlign   (lpw);   //   align   DLGITEMTEMPLATE   on   DWORD   boundary
                    lpdit   =   (LPDLGITEMTEMPLATE)   lpw;
                    lpdit-> x     =   10;   lpdit-> y     =   10;
                    lpdit-> cx   =   40;   lpdit-> cy   =   20;
                    lpdit-> id   =   ID_TEXT;     //   text   identifier
                    lpdit-> style   =   WS_CHILD   |   WS_VISIBLE   |   SS_LEFT;

                    lpw   =   (LPWORD)   (lpdit   +   1);
                    *lpw++   =   0xFFFF;
                    *lpw++   =   0x0082;                                                   //   static   class

                    for   (lpwsz   =   (LPWSTR)lpw;        
                            *lpwsz++   =   (WCHAR)   *lpszMessage++;
                    );
                    lpw   =   (LPWORD)lpwsz;
                    lpw   =   lpwAlign   (lpw);   //   align   creation   data   on   DWORD   boundary
                    *lpw++   =   0;                       //   no   creation   data

                    GlobalUnlock(hgbl);  
                    ret   =   DialogBoxIndirect(hinst,   (LPDLGTEMPLATE)   hgbl,  
                            hwndOwner,   (DLGPROC)   DialogProc);  
                    GlobalFree(hgbl);  
                    return   ret;  
            }
            posted @ 2011-03-24 10:53 wrh 閱讀(634) | 評論 (0)編輯 收藏

            各位經驗豐富的學者專家老師們:
                你們好!
                大家都知道大字體gbcbig.shp是AutoCAD本地化時需要的一個字體定義形文件,其轉化為gbcbig.shx后可被AutoCAD調用。現在我正在做一項工作,想將這種.SHX文件轉換成.aa文件,以擴展.shx格式文件的使用范圍,說明一下:.aa文件是ThinkDesign中的字體文件定義格式。我想實現他們三者(.shp,.shx,.aa)之間的相互轉化.目前已經基本實現了這個目標,具體包括:shx-->shp  shp-->aa
            shx-->aa 。在實現將shp-->aa/shx-->aa 中,我需要知道.shp/.shx文件中字高的定義。
            在AutoCAD幫助文件中有如下解釋:
            *0,4,font-name
            above,below,modes,0
            其中,above 值指出大寫字母從基線向上延伸的矢量長度,below 指出小寫字母從基線向下延伸的距離。基線的概念與紙面書寫時的基準線相似。這些值定義了基本字符尺寸,用作 TEXT 命令中指定高度的縮放比例。
            舉個例子:
            *BIGFONT 7019,1,161,254
            *0,4,工程漢字字符集 1998.1. FAW/Autodesk CTC CBX(0293)
            0,64,2,0
            在實現將shp轉化aa和將shx轉化aa 中,我將字高規定為max(above,below),在gbcbig中具體表現為max(0,64),除了gbcbig這個字體定義外,其他都還算合適,問題就出在gbcbig上,因為gbcbig中有一個子形*142,具體是這樣定義的:
            *142,14,起始描述(比例系數加入和起點調整)
            4,9,3,102,2,14,8,(-34,-80),2,8,(0,-5),0
            這就有一個問題,如果我把max(0,64)當成是字高的話,對于一個具體的字的定義來說,比如*48112,57,火
            7,142,5,2,8,(29,51),1,8,(-8,-30),8,(-15,-18),2,8,(49,5),1,8,(7,0),2,8,(-29,81),
            1,8,(-4,-40),2,8,(-17,19),1,8,(9,-21),2,8,(10,7),1,8,(24,-47),2,8,(-7,61),1,8,(-13,-19),7,143,0
            這個字在CAD中顯示出來就是一個正常顯示的9/102大小的字,非常的小,難以辨識。
            我現在需要解決這個字體縮放問題。為什么這個gbcbig字體顯示結果會是這樣小呢,我懷疑是我把字高的定義搞錯了,查了很多資料,也沒有答案,特請大家幫忙。
                                
            問題1:字體的形定義中字高是如何定義的
            問題2:為什么一般的普通大字體(非擴展大字體)文件,比如
            *BIGFONT 5887,1,128,255
            *0,4,FS791127 Copyright (c) 1991 by Top One Technology Inc., Taipei., Taiwan.
            48,0,2,0
            *BIGFONT 8009,3,161,163,166,166,176,247
            *0,4,HZ 1/6/92
            127,0,2,0
            中的編碼0的定義部分前兩位是:第一位是非0,第二位是0;而gbcbig中編碼0的定義部分前兩位卻是反過來的:0,64?是偶然還是另有其他解釋呢?







            一問:為什么不能顯示漢字?或輸入的漢字變成了問號
            答:原因可能是:
            1. 對應的字型沒有使用漢字字體,如HZTXT.SHX等;
            2. 當前系統中沒有漢字字體形文件;應將所用到的形文件復制AutoCAD的字體目錄中(一般為...\FONTS\);
            3. 對于某些符號,如希臘字母等,同樣必須使用對應的字體形文件,否則會顯示成?號。

            二問:為什么輸入的文字高度無法改變
            答:使用的字型的高度值不為0時,
            DTEXT命令書寫文本時都不提示輸入高度
            這樣寫出來的文本高度是不變的
            包括使用該字型進行的尺寸標注。

            三問:如何改變已經存在的字體格式?
            答:如果想改變已有文字的大小、字體、高寬比例、間距、傾斜角度、插入點等,
            最好利用“特性DDMODIFY)”命令(前提是你已經定義好了許多文字格式)。
            點擊“特性”命令,點擊要修改的文字,回車,
            出現“修改文字”窗口,
            選擇要修改的項目進行修改即可。

            四問:可以使用系統字體嗎,如宋體、楷體等?
            答:雖然ACAD R14能夠使用*.TTF漢字字體文件,
            可是這種字體太花費CPU時間,
            對于檔次稍低的電腦,
            顯示速度(如使用實時縮放命令時)實在太慢。
            建議檔次低的電腦還是使用*.shx文件好。
            在漢字*.shx文件當中,
            推薦使用大恒或浩辰公司為ACADR12配套的HZ*.shx字體文件,
            但在不同機器上沒有相應字體會引起漢字顯示問題。
            當然為美觀起見少量使用系統字庫也未嘗不可。

            五問 何替換找不到的原文字體?
            復制要替換的字庫為將被替換的字庫名,如:打開一幅圖,提示未找到字體jd,你想用hztxt.shx替換它,那么你可以去找AutoCAD字體文件夾(font)把里面的hztxt.shx 復制一份,重新命名為jd.shx,然后在把XX.shx放到font里面,在重新打開此圖就可以了。以后如果你打開的圖包含jd這樣你機子里沒有的字體,就再也不會不停的要你找字體替換了。

            posted @ 2011-03-23 09:42 wrh 閱讀(3095) | 評論 (0)編輯 收藏

            使用字體的基本術語,會讓設計過程中的交流變得非常容易。這里是一些基本的術語,讓你的交流能夠更深入,而不是“嗯,那里,那個,那個黑色的小玩意……”小寫e的"字懷"(“字谷”)有時候也被稱為是字“眼”,如果你還想更全面的了解其他術語,可以去圖書館,或者是參考下面的網絡資源。(譯注:很遺憾,原文中鏈接的一些資源已經無法訪問了。但我們可以用google找到其他的資源。這些術語很重要,如果你希望閱讀西方的第一手的字體設計研究資料,這是必須跨越的一關。但目前在國內的設計界似乎還沒有一個統一的翻譯,不少書籍的翻譯都是各行其是,讓讀者也無所適從。有時間我會找一篇比較完整的來翻譯。)

            http://www.adobe.com/type/topics/glossary.html
            http://gmunch.home.pipeline.com/typo-L/faq/anat.htm
            http://www.google.cn/search?client=aff-cs-maxthon&ie=UTF-8&oe=UTF-8&hl=zh-CN&q=typography%20anatomy&um=1&sa=N&tab=iw

            posted @ 2011-03-18 15:15 wrh 閱讀(273) | 評論 (0)編輯 收藏

            所有的漢字或者英文都是下面的原理,
            由左至右,每8個點占用一個字節,最后不足8個字節的占用一個字節,而且從最高位向最低位排列。
            生成的字庫說明:(以12×12例子)


            一個漢字占用字節數:12÷8=1····4也就是占用了2×12=24個字節。
            編碼排序A0A0→A0FE A1A0→A2FE依次排列。
            以12×12字庫的“我”為例:“我”的編碼為CED2,所以在漢字排在CEH-AOH=2EH區的D2H-A0H=32H個。所以在12×12字庫的起始位置就是[{FE-A0}*2EH+32H]*24=104976開始的24個字節就是我的點陣模。
            其他的類推即可。
            英文點陣也是如此推理。

            在DOS程序中使用點陣字庫的方法

            回到頂部

                首先需要理解的是點陣字庫是一個數據文件,在這個數據文件里面保存了所有文字的點陣數據.至于什么是點陣,我想我不講大家都知道 的,使用過"文曲星"之類的電子辭典吧,那個的液晶顯示器上面顯示的漢子就能夠明顯的看出"點陣"的痕跡.在 PC 機上也是如此,文字也是由點陣來組成了,不同的是,PC機顯示器的顯示分辨率更高,高到了我們肉眼無法區分的地步,因此"點陣"的痕跡也就不那么明顯了.

                點陣、矩陣、位圖這三個概念在本質上是有聯系的,從某種程度上來講,這三個就是同義詞.點陣從本質上講就是單色位圖,他使用一個比特來表示一個點,如果這 個比特為0,表示某個位置沒有點,如果為1表示某個位置有點.矩陣和位圖有著密不可分的聯系,矩陣其實是位圖的數學抽象,是一個二維的陣列.位圖就是這種 二維的陣列,這個陣列中的 (x,y) 位置上的數據代表的就是對原始圖形進行采樣量化后的顏色值.但是,另一方面,我們要面對的問題是,計算機中數據的存放都是一維的,線性的.因此,我們需要 將二維的數據線性化到一維里面去.通常的做法就是將二維數據按行順序的存放,這樣就線性化到了一維.

                那么點陣字的數據存放細節到底是怎么樣的呢.其實也十分的簡單,舉個例子最能說明問題.比如說 16*16 的點陣,也就是說每一行有16個點,由于一個點使用一個比特來表示,如果這個比特的值為1,則表示這個位置有點,如果這個比特的值為0,則表示這個位置沒 有點,那么一行也就需要16個比特,而8個比特就是一個字節,也就是說,這個點陣中,一行的數據需要兩個字節來存放.第一行的前八個點的數據存放在點陣數 據的第一個字節里面,第一行的后面八個點的數據存放在點陣數據的第二個字節里面,第二行的前八個點的數據存放在點陣數據的第三個字節里面,…,然后后 面的就以此類推了.這樣我們可以計算出存放一個點陣總共需要32個字節.看看下面這個圖形化的例子:

                | |1| | | | | | | | | | |1| | | |

                | | |1|1| |1|1|1|1|1|1|1|1|1| | |

                | | | |1| | | | | | | | |1| | | |

                |1| | | | | |1| | | | | |1| | | |

                | |1|1| | | |1| | | | | |1| | | |

                | | |1| | | |1| | | | |1| | | | |

                | | | | |1| | |1| | | |1| | | | |

                | | | |1| | | |1| | |1| | | | | |

                | | |1| | | | | |1| |1| | | | | |

                |1|1|1| | | | | | |1| | | | | | |

                | | |1| | | | | |1| |1| | | | | |

                | | |1| | | | |1| | | |1| | | | |

                | | |1| | | |1| | | | | |1| | | |

                | | |1| | |1| | | | | | |1|1|1| |

                | | | | |1| | | | | | | | |1| | |

                | | | | | | | | | | | | | | | | |

                可以看出這是一個"漢"字的點陣,當然文本的方式效果不是很好.根據上面的原則,我們可以寫出這個點陣的點陣數 據:0x40,0x08,0x37,0xfc,0x10,0x08,…, 當然寫這個確實很麻煩所以我不再繼續下去.我這樣做,也只是為了向你說明,在點陣字庫中,每一個點陣的數據就是按照這種方式存放的.

                當然也存在著不規則的點陣,這里說的不規則,指的是點陣的寬度不是8的倍數,比如 12*12 的點陣,那么這樣的點陣數據又是如何存放的呢?其實也很簡單,每一行的前面8個點存放在一個字節里面,每一行的剩下的4點就使用一個字節來存放,也就是說 剩下的4個點將占用一個字節的高4位,而這個字節的低4位沒有使用,全部都默認的為零.這樣做當然顯得有點浪費,不過卻能夠便于我們進行存放和尋址.對于 其他不規則的點陣,也是按照這個原則進行處理的.這樣我們可以得出一個 m*n 的點陣所占用的字節數為 (m+7)/8*n.

                在明白了以上所講的以后,我們可以寫出一個顯示一個任意大小的點陣字模的函數,這個函數的功能是輸出一個寬度為w,高度為h的字模到屏幕的 (x,y) 坐標出,文字的顏色為 color,文字的點陣數據為 pdata 所指:

                /*輸出字模的函數*/

                void _draw_model(char *pdata, int w, int h, int x, int y, int color)

                {

                int     i;    /* 控制行 */

                int     j;    /* 控制一行中的8個點 */

                int     k;    /* 一行中的第幾個"8個點"了 */

                int     nc;   /* 到點陣數據的第幾個字節了 */

                int     cols; /* 控制列 */

                BYTE    static mask[8]={128, 64, 32, 16, 8, 4, 2, 1}; /* 位屏蔽字 */

                w = (w + 7) / 8 * 8; /* 重新計算w */

                nc = 0;

                for (i=0; i<h; i++)

                {

                cols = 0;

                for (k=0; k<w/8; k++)

                {

                for (j=0; j<8; j++)

                {

                if (pdata[nc]&mask[j])

                putpixel(x+cols, y+i, color);

                cols++;

                }

                nc++;

                }

                }

                }

                代碼很簡單,不用怎么講解就能看懂,代碼可能不是最優化的,但是應該是最易讀懂的.其中的 putpixel 函數,使用的是TC提供的 Graphics 中的畫點函數.使用這個函數就可以完成點陣任意大小的點陣字模的輸出.

                接下來的問題就是如何在漢子庫中尋址某個漢子的點陣數據了.要解決這個問題,首先需要了解漢字在計算機中是如何表示的.在計算機中英文可以使用 ASCII 碼來表示,而漢字使用的是擴展 ASCII 碼,并且使用兩個擴展 ASCII 碼來表示一個漢字.一個 ASCII 碼使用一個字節表示,所謂擴展 ASCII 碼,也就是 ASCII 碼的最高位是1的 ASCII 碼,簡單的說就是碼值大于等于 128 的 ASCII 碼.一個漢字由兩個擴展 ASCII 碼組成,第一個擴展 ASCII 碼用來存放區碼,第二個擴展 ASCII 碼用來存放位碼.在 GB2312-80 標準中,將所有的漢字分為94個區,每個區有94個位可以存放94個漢字,形成了人們常說的區位碼,這樣總共就有 94*94=8836 個漢字.在點陣字庫中,漢字點陣數據就是按照這個區位的順序來存放的,也就是最先存放的是第一個區的漢字點陣數據,在每一個區中有是按照位的順序來存放 的.在漢字的內碼中,漢字區位碼的存放實在擴展 ASCII 基礎上存放的,并且將區碼和位碼都加上了32,然后存放在兩個擴展 ASCII 碼中.具體的說就是:

                第一個擴展ASCII碼 = 128+32 + 漢字區碼

                第二個擴展ASCII嗎 = 128+32 + 漢字位碼

                如果用char hz[2]來表示一個漢字,那么我可以計算出這個漢字的區位碼為:

                區碼 = hz[0] - 128 - 32 = hz[0] - 160

                位碼 = hz[1] - 128 - 32 = hz[1] - 160.

                這樣,我們可以根據區位碼在文件中進行殉職了,尋址公式如下:

                漢字點陣數據在字庫文件中的偏移 = ((區碼-1) * 94 + 位碼) * 一個點陣字模占用的字節數

                在尋址以后,即可讀取漢字的點陣數據到緩沖區進行顯示了.以下是實現代碼:

                /* 輸出一個漢字的函數 */

                void _draw_hz(char hz[2], FILE *fp, int x, int y, int w, int h, int color)

                {

                char fONtbuf[128];   /* 足夠大的緩沖區,也可以動態分配 */

                int ch0 = (BYTE)hz[0]-0xA0; /* 區碼 */

                int ch1 = (BYTE)hz[1]-0xA0; /* 位碼 */

                /* 計算偏移 */

                long offset = (long)pf->_hz_buf_size * ((ch0 - 1) * 94 + ch1 - 1);

                fseek(fp, offset, SEEK_SET);              /* 進行尋址 */

                fread(fontbuf, 1, (w + 7) / 8 * h, fp);   /* 讀入點陣數據 */

                _draw_model(fontbuf, w, h, x, y, color); /* 繪制字模 */

                }

                以上介紹完了中文點陣字庫的原理,當然還有英文點陣字庫了.英文點陣字庫中單個點陣字模數據的存放方式與中文是一模一樣的,也就是對我們所寫的 _draw_model 函數同樣可以使用到英文字庫中.唯一不同的是對點陣字庫的尋址上.英文使用的就是 ASCII 碼,其碼值是0到127,尋址公式為:

                英文點陣數據在英文點陣字庫中的偏移 = 英文的ASCII碼 * 一個英文字模占用的字節數

                可以看到,區分中英文的關鍵就是,一個字符是 ASCII 碼還是擴展 ASCII 碼,如果是 ASCII 碼,其范圍是0到127,這樣是使用的英文字庫,如果是擴展 ASCII 碼,則與其后的另一個擴展 ASCII 碼組成漢字內碼,使用中文字庫進行顯示.只要正確區分 ASCII 碼的類型并進行分別的處理,也就能實現中英文字符串的混合輸出了.

            點陣字庫和矢量字庫的差別

            回到頂部

                我們都只知道,各種字符在電腦屏幕上都是以一些點來表示的,因此也叫點陣.最早的字庫就是直接把這些點存儲起來,就是點陣字庫.常見的漢字點陣字庫有 16x16, 24x24 等.點陣字庫也有很多種,主要區別在于其中存儲編碼的方式不同.點陣字庫的最大缺點就是它是固定分辨率的,也就是每種字庫都有固定的大小尺寸,在原始尺寸下使用,效果很好,但如果將其放大或縮小使用,效果就很糟糕了,就會出現我們通常說的鋸齒現象.因為需要的字體大小組合有無數種,我們也不可能為每種大小都定義一個點陣字庫.于是就出現了矢量字庫.

                矢量字庫

                矢量字庫是把每個字符的筆劃分解成各種直線和曲線,然后記下這些直線和曲線的參數,在顯示的時候,再根據具體的尺寸大小,畫出這些線條,就還原了原來的字符.它的好處就是可以隨意放大縮小而不失真.而且所需存儲量和字符大小無關.矢量字庫有很多種,區別在于他們采用的不同數學模型來描述組成字符的線條.常見的矢量字庫有 Type1字庫和Truetype字庫.

                在點陣字庫中,每個字符由一個位圖表示(如圖2.5所示),并把它用一個稱為字符掩膜的矩陣來表示,其中的每個元素都是一位二進制數,如果該位為1表示字符的筆畫經過此位,該像素置為字符顏色;如果該位為0,表示字符的筆畫不經過此位,該像素置為背景顏色.點陣字符的顯示分為兩步:首先從字庫中將它的位圖檢索出來,然后將檢索到的位圖寫到幀緩沖器中.

                在實際應用中,同一個字符有多種字體(如宋體、楷體等),每種字體又有多種大小型號,因此字庫的存儲空間十分龐大.為了減少存儲空間,一般采用壓縮技術.

                矢量字符記錄字符的筆畫信息而不是整個位圖,具有存儲空間小,美觀、變換方便等優點.例如:在AutoCAD中使用圖形實體-形(Shape)-來定義矢量字符,其中,采用了直線和圓弧作為基本的筆畫來對矢量字符進行描述. 對于字符的旋轉、放大、縮小等幾何變換,點陣字符需要對其位圖中的每個象素進行變換,而矢量字符則只需要對其幾何圖素進行變換就可以了,例如:對直線筆畫的兩個端點進行變換,對圓弧的起點、終點、半徑和圓心進行變換等等.

                矢量字符的顯示也分為兩步.首先從字庫中將它的字符信息.然后取出端點坐標,對其進行適當的幾何變換,再根據各端點的標志顯示出字符.

                輪廓字形法是當今國際上最流行的一種字符表示方法,其壓縮比大,且能保證字符質量.輪廓字形法采用直線、B樣條/Bezier曲線的集合來描述一個字符的輪廓線.輪廓線構成一個或若干個封閉的平面區域.輪廓線定義加上一些指示橫寬、豎寬、基點、基線等等控制信息就構成了字符的壓縮數據.

            如何使用Windows的系統字庫生成點陣字庫?

            回到頂部

                我的程序現在只能預覽一個漢字的不同字體的點陣表達.

                界面很簡單:   一個輸出點陣大小的選擇列表(8x8,16x16,24x24等),一個系統中已有的字體名稱列表,一個預覽按鈕,一塊畫圖顯示區域.

                得到字體列表的方法:(作者稱這一段是用來取回系統的字體,然后添加到下拉框中)

                //取字體名稱列表的回調函數,使用前要聲明一下該方法

                int   CALLBACK   MyEnumFONtProc(ENUMLOGFONTEX*   lpelf,NEWTEXTMETRICEX*   lpntm,DWORD   nFontType,long   lParam)

                {

                CFontPeekerDlg*   pWnd=(CFontPeekerDlg*)   lParam;

                if(pWnd)

                {

                if(   pWnd->m_combo_sfont.FindSTring(0,   lpelf->elfLogFont.lfFaceName)   <0   )

                pWnd->m_combo_sfont.AddString(lpelf->elfLogFont.lfFaceName);

                return   1;

                }

                return   0;

                }

                //說明:CFontPeekerDlg   是我的dialog的類名,   m_combo_sfont是列表名稱下拉combobox關聯的control變量

                //調用的地方     (******問題1:下面那個&lf怎么得到呢……)

                {

                ::EnumFontFamiliesEx((HDC)   dc,&lf,   (FONTENUMPROC)MyEnumFontProc,(LPARAM)   this,0);

                m_combo_sfont.SetCurSel(0);

                }

                字體預覽:

                如果點陣大小選擇16,顯示的時候就畫出16x16個方格.自定義一個類CMyStatic繼承自CStatic,用來畫圖.在CMyStatic的OnPaint()函數中計算并顯示.

                取得字體:

                常用的方法:用CreateFont創建字體,把字TextOut再用GetPixel()取點存入數組.   缺點:必須把字TextOut出來,能在屏幕上看見,不爽.

                我的方法,用這個函數:GetGlyphOutline(),可以得到一個字的輪廓矢量或者位圖.可以不用textout到屏幕,直接取得字模信息

                函數原型如下:

                DWORD   GetGlyphOutline(

                HDC   hdc,                     //畫圖設備句柄

                UINT   uChar,                 //將要讀取的字符/漢字

                UINT   uFormat,             //返回數據的格式(字的外形輪廓還是字的位圖)

                LPGLYPHMETRICS   lpgm,     //   GLYPHMETRICS結構地址,輸出參數

                DWORD   cbBuffer,       //輸出數據緩沖區的大小

                LPVOID   lpvBuffer,     //輸出數據緩沖區的地址

                CONST   MAT2   *lpmat2   //轉置矩陣的地址

                );

                說明:

                uChar字符需要判斷是否是漢字還是英文字符.中文占2個字節長度.

                lpgm是輸出函數,調用GetGlyphOutline()是無須給lpgm   賦值.

                lpmat2如果不需要轉置,將   eM11.value=1;   eM22.value=1;   即可.

                cbBuffer緩沖區的大小,可以先通過調用GetGlyphOutline(……lpgm,   0,   NULL,   mat);   來取得,然后動態分配lpvBuffer,再一次調用GetGlyphOutline,將信息存到lpvBuffer.   使用完畢后再釋放lpvBuffer.

                程序示例:(***問題2:用這段程序,我獲取的字符點陣總都是一樣的,不管什么字……)

                ……前面部分省略……

                GLYPHMETRICS   glyph;

                MAT2   m2;

                memset(&m2,   0,   sizeof(MAT2));

                m2.eM11.value   =   1;

                m2.eM22.value   =   1;

                //取得buffer的大小

                DWORD   cbBuf   =   dc.GetGlyphOutline(   nChar,   GGO_BITMAP,   &glyph,   0L,   NULL,   &m2);

                BYTE*   pBuf=NULL;

                //返回GDI_ERROR表示失敗.

                if(   cbBuf   !=   GDI_ERROR   )

                {

                pBuf   =   new   BYTE[cbBuf];

                //輸出位圖GGO_BITMAP   的信息.輸出信息4字節(DWORD)對齊

                dc.GetGlyphOutline(   nChar,   GGO_BITMAP,   &glyph,   cbBuf,   pBuf,   &m2);

                }

                else

                {

                if(m_pFont!=NULL)

                delete   m_pFont;

                return;

                }

                編程中遇到問題:

                一開始,GetGlyphOutline總是返回-1,getLastError顯示是"無法完成的功能",后來發現是因為調用之前沒有給hdc設置Font.

                后來能取得pBuf信息后,又開始郁悶,因為不太明白bitmap的結果是按什么排列的.后來跟蹤漢字"一"來調試(這個字簡單),注意到了glyph.gmBlackBoxX   其實就是輸出位圖的寬度,glyph.gmBlackBoxY就是高度.如果gmBlackBoxX=15,glyph.gmBlackBoxY=2,表示輸出的pBuf中有這些信息:位圖有2行信息,每一行使用15   bit來存儲信息.

                例如:我讀取"一":glyph.gmBlackBoxX   =   0x0e,glyph.gmBlackBoxY=0x2;     pBuf長度cbBuf=8   字節

                pBuf信息:       00   08   00   00   ff   fc   00   00

                字符寬度   0x0e=14     則   第一行信息為:           0000   0000   0000   100       (只取到前14位)

                第二行根據4字節對齊的規則,從0xff開始         1111   1111   1111   110

                看出"一"字了嗎?呵呵

                直到他的存儲之后就可以動手解析輸出的信息了.

                我定義了一個宏#define   BIT(n)     (1<<(n))     用來比較每一個位信息時使用

                后來又遇到了一個問題,就是小頭和大頭的問題了.在我的機器上是little   endian的形式,如果我用

                unsigned   long   *lptr   =   (unsigned   long*)pBuf;

                //j   from   0   to   15

                if(   *lptr   &   BIT(j)   )

                {

                //這時候如果想用j來表示寫1的位數,就錯了

                }

                因為從字節數組中轉化成unsigned   long型的時候,數值已經經過轉化了,像上例中,實際上是0x0800   在同BIT(j)比較.

                不多說了,比較之前轉化一下就可以了if(   htonl(*lptr)   &   BIT(j)   )

            Unicode中文點陣字庫的生成與使用

            回到頂部

                點陣字庫包含兩部分信息.首先是點陣字庫文件頭信息,它包含點陣字庫文字的字號、多少位表示一個像素,英文字母與符號的size、起始和結束unicode編碼、在文件中的起始偏移,漢字的size、起始和結束unicode編碼、在文件中的起始偏移.然后是真實的點陣數據,即一段段二進制串,每一串表示一個字母、符號或漢字的點陣信息.

                要生成點陣字庫必須有文字圖形的來源,我的方法是使用ttf字體.ttf字體的顯示采用的是SDL_ttf庫,這是開源圖形庫SDL的一個擴展庫,它使用的是libfreetype以讀取和繪制ttf字體.

                它提供了一個函數,通過傳入一個Unicode編碼便能輸出相應的文字的帶有alpha通道的位圖.那么我們可以掃描這個位圖以得到相應文字的點陣信息.由于帶有alpha通道,我們可以在點陣信息中也加入權值,使得點陣字庫也有反走樣效果.我采用兩位來表示一個點,這樣會有三級灰度(還有一個表示透明).

                點陣字庫的顯示首先需要將文件頭信息讀取出來,然后根據unicode編碼判斷在哪個區間內,然后用unicode編碼減去此區間的起始unicode編碼,算出相對偏移,并加上此區間的文件起始偏移得到文件的絕對偏移,然后讀出相應位數的數據,最后通過掃描這段二進制串,在屏幕的相應位置輸出點陣字型.

                顯示點陣字體需要頻繁讀取文件,因此最好做一個固定大小的緩存,采用LRU置換算法維護此緩存,以減少磁盤讀取.

            標準點陣字庫芯片

            回到頂部

            標準點陣字庫芯片的特點:

                1.內涵全國信標委授權的標準點陣字型數據、

                2.支持國標字符集GB2312(6,763漢字),GB18030(27,484漢字).

                3.支持多種點陣字型,包括11×12點,15×16點,24×24點,32×32點.

                4.免除了字庫燒錄和測試工序,并節省了2%以上的燒錄損耗.

                5.價格相當于空白FLASH價格

            標準點陣字庫芯片的種類和應用

            回到頂部

            51單片機的13×14點陣縮碼漢卡

            回到頂部

                我們歷時數載,開發成"51單片機13×14點陣縮碼漢卡",適用于目前國內外應用最為廣泛的MCSX-51及其兼容系列單片機.

                與此同時,還開發了13×14點陣漢字字模.13×14點陣字模,可完全與目前通用的16×16點陣漢字字模媲美,其在單片機和嵌入式系統的漢字顯示應用中也具有明顯的經濟價值和實用意義.

                1.單片機目前的漢字顯示

                信息交流的最主要方式之一即文字交流,但由于我國方塊漢字數量繁多,構形迥異,使漢字顯示一直是我國計算機普及的障礙.隨著計算機技術的迅速發展,PC機的漢字顯示已不成問題.但對于成本低、體積小、應用靈活且用量極為巨大的單片機而言,因其結構簡單,硬件資源十分有限,其漢字顯示仍面對著捉襟見肘,力不從心的窘境.

                目前單片機的漢字顯示有三種基本方法.

                ①采用標準字庫法.即將國標漢字庫固人ROM中,將單片機的硬件和軟件進行特別擴展后以顯示漢字.眾所周知,即使是16×16點陣標準字庫,也須占用200KB以上的單元內存,而就目前主流5l系列單片機而言,最大尋址范圍僅64KB,即使程序區與數據區合起來也僅128KB內存.因此,若不加特別的擴展設計,不要說檢字程序和用戶空間,僅字庫都裝不下.這種方法雖然可以方便地使用現成標準字庫,但卻需占用大量的硬件和軟件資源,增加很大一部分成本和設計難度,所以不經常使用.

                ②字模直接固化法.即將所顯示的漢字,依先后順序將其字模一一從標準字庫中提取后,重新固化,予以顯示.此法雖為簡捷,但只適于顯示少量漢字,且字模的制取繁瑣,軟件的修改維護都很困難.

                ③帶索引小字庫法.即將欲顯示文件中的漢字字模,從標準字庫中逐一提取固化,制成小型字庫,并按其在小字庫中的位置制成索引表,顯示時從索引表查出其新的字模取碼地址,取碼顯示.此方法雖比較靈活,可顯示較多的漢字,但仍然局限于只能顯示固定文件內容,且字模制取同樣麻煩.

                一種較新的單片機"漢字動態編碼與顯示方案"(見《單片機與嵌入式系統應用》雜志

                由上可見,目前單片機各種漢字顯示方案均不理想.標準字庫法,單片機不堪重負;而其它方法最大且又無法克服的缺點是,所顯示文字皆有局限.顯示內容也皆須專業人員設計而定,用戶難于更改.這便極大地限制了單片機在各個領域的開拓和應用.究其原因,皆為單片機本身無漢卡,而這也正是我們致力于"51漢卡"開發的初衷.

                2.13×14點陣漢字字模

                為墊定"5l漢卡"的字型基礎,首先開發成了l3×14點陣漢字字模.在目前通用的漢字字模中,最簡單的是16×16點陣字模.在微型打字機中,也偶見有12×12點陣字模,但實用中不多見.字模點陣數直接決定著每一漢字所占單元內存值,能否在保證字模準確、美觀的基礎上,尋找一種較少的點陣字模呢?這便是我們最初的想法.于是我們經過反復選擇比較,終于在國內首個推出了13×14點陣字模.此設計,一是基于我國漢字為方塊字,故其行、列值需相近;二是漢字多有對稱1生,故其列值宜奇不宜偶.設計實際表明,若行、列值很少,則難保證字模的準確性和美觀性.?

                13×14點陣字模,是以我國現行簡化字為準,并在此基礎上設計而成.與目前通用的漢字16×l6點陣字模相比,其準確性和美觀性并不遜色.然而其單字所占內存卻由32個單元降至26個單元;另外使得每個單字顯示由原來的256個像素降至l82個像素,使顯示成本和空間均減少近三分之一.100×200點陣LED字屏,可顯示16×l6點陣漢字72個,而l3×14點陣漢字便可顯示l05個,且顯示效果并無太大差異.這無疑對單片機和嵌入式系統漢字顯示產品的開發和應用,具有明顯的經濟價值和實用意義.

                3.51單片機13×14點陣縮碼漢卡

                "51漢卡"依據我國的漢字特點和單片機的快速構字功能,在13×14點陣字模基礎上,以縮碼形式開發而成單片機漢卡的開發,應以目前通用的主流單片機為研發對象,還應在囊括國標一、二級漢字及常用字符的前提下,使內存占用必須降至主流單片機可尋址范圍內,且需留有足夠的檢字程序和用戶應用空間.另外,字模設計必須準確、美觀.字模提取速度也必須滿足實用要求."51漢卡"的開發正是依據原則,并達到了以上各項要求.

                顧名思義,"51漢卡,即以MCS-51系列及其兼容單片機為研發對象.以51系列為代表的8位單片機,在過去、現在以及可以予見的將來,都將是嵌入式系統低端應用的主流機型.此乃業界專家的共識.

                "51漢卡"囊括了"GB2312-80"國標字庫的全部一、二級漢字,并增補漢字86個;同時包括了大、小英文字母、阿拉伯數字等160個常用字符和不到4KB的構字程序,卻僅總共占用了不足66KB的內存.每字平均約占9.8個單元,相對于16×16點陣每字占32單兀內存而言,尚不到其三分之一.這對于具有相互獨立的64KB程序區和64KB數據區的51系列單片機而言,若適當配置內存,可為檢字程序和用戶留出90%以上的程序空間及相當數量的數據空間,對于一般用戶的應用,都將綽綽有余.

                另外,為使"51漢卡''更便于使用和進一步節省內存,在上述基礎上又開發成一套簡化版本,刪去了部分較偏僻的二級漢字.簡化版本包括約5580個漢字,共占用內存58KB.實際上,按有關權威部門的統計,一般文本99%的文字是由2400個字寫成的,因此使用簡化版本,并配以簡單的造字程序,一般亦可滿足我們的使用要求.

                "51漢卡"所用字模,即我們開發的完全可與16×16點陣字模媲美的I3×14點陣漢字字模.字模提取速度是我們最為關心的問題之一.經測試及實際使用表明,"51漢卡''的提模速度完全可滿足單片機漢字顯示的實用要求.

                我們使用INTEL公司MCS-51經典系列87C51單片機在24MHz頻率下測試,平均字模提取速度為2.1ms/字.因人的視覺暫留時間為0.1s,無論理論還是實際使用都表明,50字字模提取并顯示,并無遲滯和待機之感.即使在1?2MHz頻率下,20字取模,即點即出,在一般拼音檢字和少量漢字顯示中,完全可滿足使用要求.隨著單片機技術的迅速發展,目前,INTEL公司、Atmel公司、philips公司、我國臺灣華邦等公司生產的MCS-51兼容單片機時鐘頻率可達33MHz,增強型可達40MHz,以至達60MHz;現市售的"STC89LE"系列單片機,最高頻率可達90MHz.這些芯片都完全能與MCS-51芯片兼容,對于更高需求的場合,更新升級也十分簡便.另外,在單片機和嵌入式系統中,文字顯示速度要求并不高,只要滿足換屏時的視覺要求即可.其漢字顯示字數,一般也不太多.如用LCD顯示屏,128×64點陣,才顯示32個字;192×64點陣才顯48個字;即使使用l3×14點陣字模,滿屏也才56個漢字.

                4."51漢卡"設計依據及說明

                "51漢卡"設計依據是,我國漢字雖然數量繁多,字型各異,但其中復合結構者占大部分,并素有"偏旁取義,正字取音"之說.如"寸"字與不同偏旁可組成"村"、"付"、"討"、"守"、"過"等字.因此"51漢卡"除單結構字基本以全碼設計外,復臺結構字多用相應的單體字及其偏旁,以結構代碼寫成.利用單片機快速的單元積木式構字程序,便可迅速生成字模代碼.這既保證了提碼速度,又節省了大量的漢卡內存.

                有關"51漢卡"的幾點說明如下:

                ①凡漢字庫中簡、繁體字都有的用簡體.如"後"以"后"代,"馀"以"余"代等;

                ②《新華字典》未收入字,多未收入,如"酏"、"鼽"等字,但"婧"、"弳"等字仍收入;

                ③對于多體字,一般以常用字代,如"摺"以"折"代,"鏇"以"旋,代等,但"吒"不以"咤"代,"讎"不以"仇"代等;

                ④對通常已由其它字取代的字,都以這些字代替,如"崠"以"東"代,"肛''以"船"代等;

                ⑤二級漢字中,不單獨構成漢字的偏旁未收入;

                ⑥依據名篇名著,生活用語等,增補漢字86個;

                ⑦收編大、小寫英文字母、阿拉伯數字、標點符號等各種常用字符160個.

                5."51單片機漢卡"應用舉例

                利用"51單片機漢卡",將使51系列單片機的漢字顯示輕而易舉,并可大為降低成本、體積和設計開發的難度,為單片機在生產控制、信息通信、文化教育和日常生活等領域,特別是計算機終端和手持產品的開發提供極大的便利和支持.?

                我們現已初步開發成"51漢卡"的"區位碼輸入法"和"拼音輸入法,檢字程序,并利用"51漢卡"成功地開發了帶有廉價單片機控制器的LED漢字顯示屏.這不僅大幅度降低了成本費用.而且用戶可以通過單片機控制器,隨心所欲地改變顯示內容.

                51硬件設計

                CPU--87C51、12MHz晶振.

             

                程序存儲器一1片EPROM?27C512.

                數據存儲器一1片EPROM?27C512;1片EEPROM28C64A;1片6116.

                控制器顯示屏一LCD?HY一19264B(深圳秋田視佳實業有限公司).

                LED屏選240×16點陣.

                本系統用標準小鍵盤檢字,一次可予選4000字;控制器LCD滿屏顯示l3×14點陣漢字56個;LED屏滿屏顯示漢字19個.

                地址分配及用途如表l所列.

                5.2程序設計框圖

                程序設計流程如圖1所示.本系統采用12MHz晶振,若LCD取滿屏56字,換屏時有約0.1s的延時,這對人的實際視覺并無大影響.

            標準點陣漢字字庫芯片

            回到頂部

                1 概述

                GT23L24M1W是一款內含24X24點陣的漢字庫芯片,支持GB18030國標漢字(含有國家信標委合法授

                權)及ASCII字符.排列格式為橫置橫排.用戶通過字符內碼,利用本手冊提供的方法計算出該字符點陣

                在芯片中的地址,可從該地址連續讀出字符點陣信息.

                1.1 芯片特點

                ●  數據總線: SPI 串行總線接口

                PLII 精簡地址并行總線接口

                ●  點陣排列方式:字節橫置橫排

                訪問速度:SPI 時鐘頻率:20MHz(max.)

                PLII 訪問速度:130ns(max.) @3.3V

                ●  工作電壓:2.7V~3.6V

                ●  電流:工作電流:12mA

                待機電流:10uA

                ●  封裝:SO20W

                ●  尺寸(SO20W):12.80mmX10.30mm

                ●  工作溫度:-20℃~85℃(SPI 模式下);-10℃~85℃(PLII 模式下)

                1.2 字庫內容

                字型樣張

                2 引腳描述與接口連接

                2.1 引腳名稱

                2.2 SPI 接口引腳描述

                串行數據輸出(SO):該信號用來把數據從芯片串行輸出,數據在時鐘的下降沿移出.

                串行數據輸入(SI):該信號用來把數據從串行輸入芯片,數據在時鐘的上升沿移入.

                串行時鐘輸入(SCLK):數據在時鐘上升沿移入,在下降沿移出.

                片選輸入(CS#):所有串行數據傳輸開始于CE#下降沿,CE#在傳輸期間必須保持為低電平,在兩條

                指令之間保持為高電平.

                總線掛起輸入(HOLD#):

                2.3 SPI 接口與主機接口電路示意圖

                SPI 與主機接口電路連接可以參考下圖(#HOLD管腳建議接 2K 電阻 3.3V 拉高).

                若是采用系統電壓為 5V的,則需要進行電平轉換匹配連接 GT23 芯片,可以參考下圖(#HOLD 管腳建議接 2K 電阻 3.3V 拉高).

                2.4 PLII 接口引腳描述

                2.5 PLII 接口與主機接口電路示意圖

                SPI/PLII_SEL(管腳內部有 100K 上拉電阻)接地,字庫芯片選擇 PLII 接口模式,與主機接口電路連接可以參考下圖.

                2.6 PLII 總線接口尋址說明

                在 PLII 總線模式下,芯片內部有 3個地址寄存器,主機需要把要讀取數據的地址寫入這 3個地址寄存器,然后再從數據寄存器中讀出數據.主機每讀一次數據寄存器,芯片內部的地址寄存器會自動增一,從而使主機只寫一次首地址,就可以連續讀取數據.

                3 字庫調用方法

                3.1 漢字點陣排列格式

                每個漢字在芯片中是以漢字點陣字模的形式存儲的,每個點用一個二進制位表示,存 1的點,當顯示

                時可以在屏幕上顯示亮點,存 0的點,則在屏幕上不顯示.點陣排列格式為橫置橫排:即一個字節的高位

                表示左面的點,低位表示右面的點(如果用戶按 word mode讀取點陣數據,請注意高低字節的順序),排

                滿一行的點后再排下一行.這樣把點陣信息用來直接在顯示器上按上述規則顯示,則將出現對應的漢字.

                3.1.1  24X24點漢字排列格式

                24X24 點漢字的信息需要 72個字節(BYTE 0 – BYTE 71)來表示.該 24X24 點漢字的點陣數據是

                橫置橫排的,其具體排列結構如下圖:

                命名規則:

                最大字符集及字數

                S:GB2312 6,763漢字

                M:GB18030 27,484漢字

                T:GB12345  6,866漢字

                BIG5  5,401 / 13,060漢字

                U:Unicode V3.0  27,484漢字

            posted @ 2011-03-18 15:01 wrh 閱讀(5075) | 評論 (0)編輯 收藏

            在c語言里可以用system()系統調用來處理

            :批處理 
            ShellExecute(null, "open ", 
                    "c:\\abc.bat ", " ", " ",SW_SHOW   ); 


                  


            深入淺出ShellExecute   
            譯者:徐景周(原作:Nishant   S) 

            Q:   如何打開一個應用程序?   ShellExecute(this-> m_hWnd, "open ", "calc.exe ", " ", " ",   SW_SHOW   ); 
            或   ShellExecute(this-> m_hWnd, "open ", "notepad.exe ", 
                    "c:\\MyLog.log ", " ",SW_SHOW   ); 
            正如您所看到的,我并沒有傳遞程序的完整路徑。 
            Q:   如何打開一個同系統程序相關連的文檔?   ShellExecute(this-> m_hWnd, "open ", 
                    "c:\\abc.txt ", " ", " ",SW_SHOW   ); 
            Q:   如何打開一個網頁?   ShellExecute(this-> m_hWnd, "open ", 
                    "http://www.google.com ", " ", " ",   SW_SHOW   ); 
            Q:   如何激活相關程序,發送EMAIL?   ShellExecute(this-> m_hWnd, "open ", 
                    "mailto:nishinapp@yahoo.com ", " ", " ",   SW_SHOW   ); 
            Q:   如何用系統打印機打印文檔?   ShellExecute(this-> m_hWnd, "print ", 
                    "c:\\abc.txt ", " ", " ",   SW_HIDE); 
            Q:   如何用系統查找功能來查找指定文件?   ShellExecute(m_hWnd, "find ", "d:\\nish ", 
                    NULL,NULL,SW_SHOW); 
            Q:   如何啟動一個程序,直到它運行結束?   SHELLEXECUTEINFO   ShExecInfo   =   {0}; 
            ShExecInfo.cbSize   =   sizeof(SHELLEXECUTEINFO); 
            ShExecInfo.fMask   =   SEE_MASK_NOCLOSEPROCESS; 
            ShExecInfo.hwnd   =   NULL; 
            ShExecInfo.lpVerb   =   NULL; 
            ShExecInfo.lpFile   =   "c:\\MyProgram.exe ";
            ShExecInfo.lpParameters   =   " ";
            ShExecInfo.lpDirectory   =   NULL; 
            ShExecInfo.nShow   =   SW_SHOW; 
            ShExecInfo.hInstApp   =   NULL;
            ShellExecuteEx(&ShExecInfo); 
            WaitForSingleObject(ShExecInfo.hProcess,INFINITE); 
            或:   PROCESS_INFORMATION   ProcessInfo;   
            STARTUPINFO   StartupInfo;   //This   is   an   [in]   parameter 
            ZeroMemory(&StartupInfo,   sizeof(StartupInfo)); 
            StartupInfo.cb   =   sizeof   StartupInfo   ;   //Only   compulsory   field 
            if(CreateProcess( "c:\\winnt\\notepad.exe ",   NULL,   
                    NULL,NULL,FALSE,0,NULL, 
                    NULL,&StartupInfo,&ProcessInfo)) 
            {   
                    WaitForSingleObject(ProcessInfo.hProcess,INFINITE); 
                    CloseHandle(ProcessInfo.hThread); 
                    CloseHandle(ProcessInfo.hProcess); 
            }     
            else 
            { 
                    MessageBox( "The   process   could   not   be   started... "); 
            } 

            Q:   如何顯示文件或文件夾的屬性?   SHELLEXECUTEINFO   ShExecInfo   ={0}; 
            ShExecInfo.cbSize   =   sizeof(SHELLEXECUTEINFO); 
            ShExecInfo.fMask   =   SEE_MASK_INVOKEIDLIST   ; 
            ShExecInfo.hwnd   =   NULL; 
            ShExecInfo.lpVerb   =   "properties "; 
            ShExecInfo.lpFile   =   "c:\\ ";   //can   be   a   file   as   well 
            ShExecInfo.lpParameters   =   " ";   
            ShExecInfo.lpDirectory   =   NULL; 
            ShExecInfo.nShow   =   SW_SHOW; 
            ShExecInfo.hInstApp   =   NULL;   
            ShellExecuteEx(&ShExecInfo); 
            posted @ 2011-03-09 13:42 wrh 閱讀(3459) | 評論 (3)編輯 收藏

            在圖形圖象處理編程過程中,雙緩沖是一種基本的技術。我們知道,如果窗體在響應WM_PAINT消息的時候要進行復雜的圖形處理,那么窗體在重繪時由于過頻的刷新而引起閃爍現象。解決這一問題的有效方法就是雙緩沖技術。

                因為窗體在刷新時,總要有一個擦除原來圖象的過程OnEraseBkgnd,它利用背景色填充窗體繪圖區,然后在調用新的繪圖代碼進行重繪,這樣一擦一寫造成了圖象顏色的反差。當WM_PAINT的響應很頻繁的時候,這種反差也就越發明顯。于是我們就看到了閃爍現象。

                我們會很自然的想到,避免背景色的填充是最直接的辦法。但是那樣的話,窗體上會變的一團糟。因為每次繪制圖象的時候都沒有將原來的圖象清除,造成了圖象的殘留,于是窗體重繪時,畫面往往會變的亂七八糟。所以單純的禁止背景重繪是不夠的。我們還要進行重新繪圖,但要求速度很快,于是我們想到了使用BitBlt函數。它可以支持圖形塊的復制,速度很快。我們可以先在內存中作圖,然后用此函數將做好的圖復制到前臺,同時禁止背景刷新,這樣就消除了閃爍。以上也就是雙緩沖繪圖的基本的思路。

                一、普通方法:

                先按普通做圖的方法進行編程。即在視類的OnDraw函數中添加繪圖代碼。在此我們繪制若干同心圓,代碼如下:
             CBCDoc* pDoc = GetDocument();

            ASSERT_VALID(pDoc);

            CPoint ptCenter;

            CRect rect,ellipseRect;

            GetClientRect(&rect);

            ptCenter = rect.CenterPoint();

            for(int i=20;i>0;i--)

            {

            ellipseRect.SetRect(ptCenter,ptCenter);

            ellipseRect.InflateRect(i*10,i*10);

            pDC->Ellipse(ellipseRect);

            }


                編譯運行程序,嘗試改變窗口大小,可以發現閃爍現象。

                二、雙緩沖方法:

                在雙緩沖方法中,首先要做的是屏蔽背景刷新。背景刷新其實是在響應WM_ERASEBKGND消息。我們在視類中添加對這個消息的響應,可以看到缺省的代碼如下:
             BOOL CMYView::OnEraseBkgnd(CDC* pDC)

            {

            return CView::OnEraseBkgnd(pDC);

            }


                是調用父類的OnEraseBkgnd函數,我們屏蔽此調用,只須直接return TRUE;即可。

                下面是內存緩沖作圖的步驟。
             CPoint ptCenter;

            CRect rect,ellipseRect;

            GetClientRect(&rect);

            ptCenter = rect.CenterPoint();

            CDC dcMem; //用于緩沖作圖的內存DC

            CBitmap bmp; //內存中承載臨時圖象的位圖

            dcMem.CreateCompatibleDC(pDC); //依附窗口DC創建兼容內存DC

            bmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());//創建兼容位圖

            dcMem.SelectObject(&bmp); //將位圖選擇進內存DC

            //按原來背景填充客戶區,不然會是黑色

            dcMem.FillSolidRect(rect,pDC->GetBkColor());

            for(int i=20;i>0;i--) //在內存DC上做同樣的同心圓圖象

            {

            ellipseRect.SetRect(ptCenter,ptCenter);

            ellipseRect.InflateRect(i*10,i*10);

            dcMem.Ellipse(ellipseRect);

            }

            pDC->BitBlt(0,0,rect.Width(),rect.Height(),

            &dcMem,0,0,SRCCOPY);//將內存DC上的圖象拷貝到前臺

            dcMem.DeleteDC(); //刪除DC

            bm.DeleteObject(); //刪除位圖


                由于復雜的畫圖操作轉入后臺,我們看到的是速度很快的復制操作,自然也就消除了閃爍現象。
                注意:bmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());

                這里面CreateCompatibleBitmap第一個參數不能用dcMem,這樣的話創建的是黑白位圖。如果你要創建彩色位圖,需要用pDC,它用來創建了內存DC. 詳細請見下面的MSDN:
             When a memory device context is created, it initially has a 1-by-1 monochrome bitmap selected into it. If this memory device context is used in CreateCompatibleBitmap, the bitmap that is created is a monochrome bitmap. To create a color bitmap, use the hDC that was used to create the memory device context, as shown in the following code:

            HDC memDC = CreateCompatibleDC ( hDC );

            HBITMAP memBM = CreateCompatibleBitmap ( hDC, nWidth, nHeight );

            SelectObject ( memDC, memBM );





            雙緩沖技術繪圖

              當數據量很大時,繪圖可能需要幾秒鐘甚至更長的時間,而且有時還會出現閃爍現象,為了解決這些問題,可采用雙緩沖技術來繪圖。
              雙緩沖即在內存中創建一個與屏幕繪圖區域一致的對象,先將圖形繪制到內存中的這個對象上,再一次性將這個對象上的圖形拷貝到屏幕上,這樣能大大加快繪圖的速度。雙緩沖實現過程如下:
              1、在內存中創建與畫布一致的緩沖區
              2、在緩沖區畫圖
              3、將緩沖區位圖拷貝到當前畫布上
              4、釋放內存緩沖區
              在圖形圖象處理編程過程中,雙緩沖是一種基本的技術。我們知道,如果窗體在響應WM_PAINT消息的時候要進行復雜的圖形處理,那么窗體在重繪時由于過頻的刷新而引起閃爍現象。解決這一問題的有效方法就是雙緩沖技術。因為窗體在刷新時,總要有一個擦除原來圖象的過程OnEraseBkgnd,它利用背景色填充窗體繪圖區,然后在調用新的繪圖代碼進行重繪,這樣一擦一寫造成了圖象顏色的反差。當WM_PAINT的響應很頻繁的時候,這種反差也就越發明顯。于是我們就看到了閃爍現象。 
              我們會很自然的想到,避免背景色的填充是最直接的辦法。但是那樣的話,窗體上會變的一團糟。因為每次繪制圖象的時候都沒有將原來的圖象清除,造 成了圖象的殘留,于是窗體重繪時,畫面往往會變的亂七八糟。所以單純的禁止背景重繪是不夠的。我們還要進行重新繪圖,但要求速度很快,于是我們想到了使用 BitBlt函數。它可以支持圖形塊的復制,速度很快。我們可以先在內存中作圖,然后用此函數將做好的圖復制到前臺,同時禁止背景刷新,這樣就消除了閃 爍。以上也就是雙緩沖繪圖的基本的思路。 
              首先給出實現的程序,然后再解釋,同樣是在OnDraw(CDC *pDC)中: 
              CDC MemDC; //首先定義一個顯示設備對象 
              CBitmap MemBitmap;//定義一個位圖對象 //隨后建立與屏幕顯示兼容的內存顯示設備 MemDC.CreateCompatibleDC(NULL); //這時還不能繪圖,因為沒有地方畫 ^_^ 
              //下面建立一個與屏幕顯示兼容的位圖,至于位圖的大小嘛,可以用窗口的大小,也可以自己定義
              (如:有滾動條時就要大于當前窗口的大小,在BitBlt時決定拷貝內存的哪部分到屏幕上)
              MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight); //將位圖選入到內存顯示設備中 //只有選入了位圖的內存顯示設備才有地方繪圖,畫到指定的位圖上 
              CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap); //先用背景色將位圖清除干凈,這里我用的是白色作為背景 //你也可以用自己應該用的顏色 
              MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255)); //繪圖 
              MemDC.MoveTo(……); MemDC.LineTo(……); //將內存中的圖拷貝到屏幕上進行顯示 
              pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY); //繪圖完成后的清理 //把前面的pOldBit選回來.在刪除MemBitmap之前要先從設備中移除它 
              MemDC.SelectObject(pOldBit); MemBitmap.DeleteObject(); MemDC.DeleteDC(); 雙緩沖(two way soft-closing)
            posted @ 2011-03-01 16:09 wrh 閱讀(6593) | 評論 (1)編輯 收藏

            4 畫圖
            在Windows中,繪圖一般在視圖窗口的客戶區進行,使用的是設備上下文類CDC中各種繪圖函數。
            1. 映射模式與坐標系
            1)默認映射模式
            映射模式(map mode)影響所有的圖形和文本繪制函數,它定義(將邏輯單位轉換為設備單位所使用的)度量單位和坐標方向,Windows總是用邏輯單位來繪圖。
            缺省情況下,繪圖的默認映射模式為MM_TEXT,其繪圖單位為像素(只要不打印輸出,屏幕繪圖使用該模式就夠了)。若窗口客戶區的寬和高分別為w和h像素,則其x坐標是從左到右,范圍為0 ~ w-1;y坐標是從上到下,范圍為0 ~ h-1。

            2)設置映射模式
            可以使用CDC類的成員函數GetMapMode和SetMapMode來獲得和設置當前的映射模式:
            int GetMapMode( ) const; // 返回當前的映射模式
            virtual int SetMapMode( int nMapMode ); // 返回先前的映射模式


            映射模式的nMapMode取值與含義
            符號常量 數字常量 x方向 y方向 邏輯單位的大小 
            MM_TEXT 1 向右 向下 像素 
            MM_LOMETRIC 2 向右 向上 0.1 mm 
            MM_HIMETRIC 3 向右 向上 0.01 mm 
            MM_LOENGLISH 4 向右 向上 0.01 in 
            MM_HIENGLISH 5 向右 向上 0.001 in 
            MM_TWIPS 6 向右 向上 1/1440 in 
            MM_ISOTROPIC 7 自定義 自定義 自定義 
            MM_ANISOTROPIC 8 自定義 自定義 自定義


            可見,除了兩種自定義映射模式外,x方向都是向右,y方向也只有MM_TEXT的向下,其余的都是向上,與數學上一致。除了MM_ANISOTROPIC外,其他所有映射模式的x與y方向的單位都是相同的。所有映射模式的邏輯坐標的原點(0, 0)最初都是在窗口的左上角,但在CScrollView的派生類中,MFC會隨用戶滾動文檔而自動調整邏輯原點的相對位置(改變視點的原點屬性)。
            3)自定義映射模式
            自定義映射模式MM_ISOTROPIC(各向同性,x與y方向的單位必須相同)和MM_ANISOTROPIC(各向異性,x與y方向的單位可以不同)的單位和方向,可以通過用CDC類的成員函數G/SetWindowExt和G/SetViewportExt來獲取/設置窗口和視口的大小來確定:
            CSize GetWindowExt( ) const;
            virtual CSize SetWindowExt( int cx, int cy );

            virtual CSize SetWindowExt( SIZE size );
            CSize GetViewportExt( ) const;
            virtual CSize SetViewportExt( int cx, int cy );

            virtual CSize SetViewportExt( SIZE size );
            其中,cx或size.cx和cy或size.cy分別為窗口/視口的寬度與高度(邏輯單位)。
            還可以用CDC類的成員函數SetViewportOrg來設置坐標原點的位置:
            virtual CPoint SetViewportOrg( int x, int y );
            CPoint SetViewportOrg( POINT point );
            例如
            void CDrawView::OnDraw(CDC* pDC) {
                   CRect rect;
                   GetClientRect(rect);
                   pDC->SetMapMode(MM_ANISOTROPIC);
                   pDC->SetWindowExt(1000,1000);
                   pDC->SetViewportExt(rect.right, -rect.bottom);

                   pDC->SetViewportOrg(rect.right / 2, rect.bottom /2);

                   pDC->Ellipse(CRect(-500, -500, 500, 500));

            }
            將當前的映射模式設置為各向異性自定義映射模式,窗口大小為1000個邏輯單位寬和1000個邏輯單位高,視口大小同當前客戶區,視口的坐標原點設置在當前客戶區的中央。由于使用了負數作為SetViewportExt函數的第2個參數,所以y軸方向是向上的。

            可見,圓被畫成了橢圓,x與y方向上的邏輯單位不相同。
            4)單位轉換
            對所有非MM_TEXT映射模式,有如下重要規則:
            <!--[if !supportLists]-->l         <!--[endif]-->CDC的成員函數(如各種繪圖函數)具有邏輯坐標參數

            <!--[if !supportLists]-->l         <!--[endif]-->CWnd的成員函數(如各種響應函數)具有設備坐標參數(如鼠標位置point)

            <!--[if !supportLists]-->l         <!--[endif]-->位置的測試操作(如CRect的PtInRect函數)只有使用設備坐標時才有效

            <!--[if !supportLists]-->l         <!--[endif]-->長期使用的值應該用邏輯坐標保存(如窗口滾動后保存的設備坐標就無效了)


            因此,為了使應用程序能夠正確工作,除MM_TEXT映射模式外,其他映射模式都需要進行單位轉換。下面是邏輯單位到設備單位(如像素)的轉換公式:
            x比例因子 = 視口寬度 / 窗口寬度
            y比例因子 = 視口高度 / 窗口高度
            設備x = 邏輯x * x比例因子 + x原點偏移量
            設備y = 邏輯y * y比例因子 + y原點偏移量
            Windows的GDI負責邏輯坐標和設備坐標之間的轉換,這可以調用CDC類的成員函數LPtoDP和DPtoLP來進行:
            void LPtoDP( LPPOINT lpPoints, int nCount = 1 ) const;

            void LPtoDP( LPRECT lpRect ) const;
            void LPtoDP( LPSIZE lpSize ) const;
            void DPtoLP( LPPOINT lpPoints, int nCount = 1 ) const;

            void DPtoLP( LPRECT lpRect ) const;
            void DPtoLP( LPSIZE lpSize ) const;
            例如:
            void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) {

                          CRect rect = m_rect; // 邏輯坐標

                          CClientDC dc(this);
                          dc.SetMapMode(MM_LOENGLISH);
                          dc.LPtoDP(rect); // 轉化成設備坐標
                   if (rect.PtInRect(point)) // 位置的測試操作只有使用設備坐標時才有效

                   ......
            }
            void CDrawView:: OnMouseMove (UINT nFlags, CPoint point) {

                   float t,y;

                          char buf[40];
                   CDC* pDC = GetDC();

            pDC->SetMapMode(MM_HIMETRIC);
                          pDC->DPtoLP(&point); // 轉化成邏輯坐標
            t = t1 + (point.x * dt) / w; sprintf(buf, "%.4fs", t); pSB->SetPaneText(xV, buf);

            y = (y0 - point.y) / dy; sprintf(buf, "%.4f", y); pSB->SetPaneText(yV, buf);
                   ......
            }
            2. 畫像素點
            畫像素點就是設置像素點的顏色,從前面3)(2)已知道這可由CDC的成員函數SetPixel來做,該函數的原型為:
            COLORREF SetPixel( int x, int y, COLORREF crColor ); 或

            COLORREF SetPixel( POINT point, COLORREF crColor );

            其中,x與y分別為像素點的橫坐標與縱坐標,crColor為像素的顏色值。例如
            pDC->SetPixel(i, j, RGB(r, g, b));

            3.畫線狀圖
            在Windows中,線狀圖必須用筆來畫(筆的創建與使用見前面的3)(3)),下面是CDC類中可以繪制線狀圖的常用成員函數:
            <!--[if !supportLists]-->l         <!--[endif]-->當前位置:設置當前位置為(x, y)或point:(返回值為原當前位置的坐標)

            CPoint MoveTo( int x, int y ); 或 CPoint MoveTo( POINT point );

            <!--[if !supportLists]-->l         <!--[endif]-->畫線:使用DC中的筆從當前位置畫線到點(x, y)或point:(若成功返回非0值):

            BOOL LineTo( int x, int y ); 或BOOL LineTo( POINT point );
            <!--[if !supportLists]-->l         <!--[endif]-->畫折線:使用DC中的筆,依次將點數組lpPoints中的nCount(≥2)個點連接起來,形成一條折線:

            BOOL Polyline( LPPOINT lpPoints, int nCount );
            <!--[if !supportLists]-->l         <!--[endif]-->畫多邊形:似畫折線,但還會將最后的點與第一個點相連形成多邊形,并用DC中的刷填充其內部區域:

            BOOL Polygon( LPPOINT lpPoints, int nCount );
            <!--[if !supportLists]-->l         <!--[endif]-->畫矩形:使用DC中的筆畫左上角為(x1, y1)、右下角為(x2, y2)或范圍為*lpRect的矩形的邊線,并用DC中的刷填充其內部區域:

            BOOL Rectangle( int x1, int y1, int x2, int y2 ); 或
            BOOL Rectangle( LPCRECT lpRect );
                          有時需要根據用戶給定的兩個任意點來重新構造左上角和右下角的點,例如:
                          rect = CRect(min(p0.x, point.x), min(p0.y, point.y), max(p0.x, point.x), max(p0.y, point.y));

            <!--[if !supportLists]-->l         <!--[endif]-->畫圓角矩形:使用DC中的筆畫左上角為(x1, y1)、右下角為(x2, y2)或范圍為*lpRect的矩形的邊線,并用寬x3或point.x高y3或point.y矩形的內接橢圓倒角,再用DC中的刷填充其內部區域:

            BOOL RoundRect( int x1, int y1, int x2, int y2, int x3, int y3 );
            BOOL RoundRect( LPCRECT lpRect, POINT point );
            例如:
            int d = min(rect.Width(), rect.Height()) / 4;

            pDC-> RoundRect(rect, CPoint(d, d));
            <!--[if !supportLists]-->l         <!--[endif]-->畫(橢)圓:使用DC中的筆在左上角為(x1, y1)、右下角為(x2, y2)或范圍為*lpRect的矩形中畫內接(橢)圓的邊線,并用DC中的刷填充其內部區域:

            BOOL Ellipse( int x1, int y1, int x2, int y2 );
            BOOL Ellipse( LPCRECT lpRect );
            注意,CDC中沒有畫圓的專用函數。在這里,圓是作為橢圓的(寬高相等)特例來畫的。
            <!--[if !supportLists]-->l         <!--[endif]-->畫弧:(x1, y1)與(x2, y2)或lpRect的含義同畫(橢)圓,(x3, y3)或ptStart為弧的起點,(x4, y4)或ptEnd為弧的終點:(逆時針方向旋轉)

            BOOL Arc( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );

            BOOL Arc( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
            BOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);

            BOOL ArcTo(LPCRECT lpRect, POINT ptStart, POINT ptEnd);
            畫圓弧:(其中(x, y)為圓心、nRadius為半徑、fStartAngle為起始角、fSweepAngle為弧段跨角)
            BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle);

            <!--[if !supportLists]-->l         <!--[endif]-->畫弓弦:參數的含義同上,只是用一根弦連接弧的起點和終點,形成一個弓形,并用DC中的刷填充其內部區域:

            BOOL Chord( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );

            BOOL Chord( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
            4.畫填充圖
            在Windows中,面狀圖必須用刷來填充(刷的創建與使用見前面的3)(4))。上面(2)中的Polygon、Rectangle、Ellipse和Chord等畫閉合線狀圖的函數,只要DC中的刷不是空刷,都可以用來畫對應的面狀圖(邊線用當前筆畫,內部用當前刷填充)。下面介紹的是CDC類中只能繪制面狀圖的其他常用成員函數:
            <!--[if !supportLists]-->l         <!--[endif]-->畫填充矩形:用指定的刷pBrush畫一個以lpRect為區域的填充矩形,無邊線,填充區域包括矩形的左邊界和上邊界,但不包括矩形的右邊界和下邊界:

            void FillRect( LPCRECT lpRect, CBrush* pBrush );
            <!--[if !supportLists]-->l         <!--[endif]-->畫單色填充矩形:似FillRect,但只能填充單色,不能填充條紋和圖案:

            void FillSolidRect( LPCRECT lpRect, COLORREF clr );
            void FillSolidRect( int x, int y, int cx, int cy, COLORREF clr );
            <!--[if !supportLists]-->l         <!--[endif]-->畫餅圖(扇形):參數含義同Arc,但將起點和終點都與外接矩形的中心相連接,形成一個扇形區域,用DC中的刷填充整個扇形區域,無另外的邊線:

            BOOL Pie( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );

            BOOL Pie( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
            <!--[if !supportLists]-->l         <!--[endif]-->畫拖動的矩形:先擦除線寬為sizeLast、填充刷為pBrushLast的原矩形lpRectLast,然后再以線寬為size、填充刷為pBrush畫新矩形lpRectLast。矩形的邊框用灰色的點虛線畫,缺省的填充刷為空刷:

            void DrawDragRect( LPCRECT lpRect, SIZE size, LPCRECT lpRectLast,

            SIZE sizeLast, CBrush* pBrush = NULL, CBrush* pBrushLast = NULL );

            如:pDC->DrawDragRect(rect, size, rect0, size);

            <!--[if !supportLists]-->l         <!--[endif]-->填充區域:

            <!--[if !supportLists]-->n     <!--[endif]-->用當前刷從點(x, y)開始向四周填充到顏色為crColor的邊界:

            BOOL FloodFill(int x, int y, COLORREF crColor); // 成功返回非0

            <!--[if !supportLists]-->n     <!--[endif]-->用當前刷從點(x, y)開始向四周填充:

            BOOL ExtFloodFill(int x, int y, COLORREF crColor,

            UINT nFillType); // 成功返回非0

            <!--[if !supportLists]-->u <!--[endif]-->nFillType = FLOODFILLBORDER:填充到顏色為crColor的邊界(同FloodFill);(用于填充內部顏色不同但邊界顏色相同的區域)
            <!--[if !supportLists]-->u <!--[endif]-->nFillType = FLOODFILLSURFACE:填充所有顏色為crColor的點,直到碰到非crColor顏色的點為止。(點(x, y)的顏色也必須為crColor),(用于填充內部顏色相同但邊界顏色可以不同的區域)。例如:
            pDC->ExtFloodFill(point.x, point.y, pDC->GetPixel(point), FLOODFILLSURFACE);

            5.清屏
            Windows沒有提供專門的清屏函數,可以調用CWnd的下面兩個函數調用來完成該功能:
            void Invalidate(BOOL bErase = TRUE);
            void UpdateWindow( );
            或調用CWnd的函數
            BOOL RedrawWindow(
               LPCRECT lpRectUpdate = NULL,

               CRgn* prgnUpdate = NULL,
               UINT flags = RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE

            );
            來完成。
            例如(菜單項ID_CLEAR的事件處理函數):
            CDrawView::OnClear() { // 調用OnDraw來清屏
                   //Invalidate();
                   //UpdateWindow( );
                   RedrawWindow( );
            }
            也可以用畫填充背景色矩形的方法來清屏,如:
                   RECT rect;
                   GetClientRect(&rect);
                   pDC->FillSolidRect(&rect, RGB(255, 255, 255));

            6.在控件上繪圖
            可以在對話框資源中放置圖片控件,并對其類型屬性選Frame。可在對話框的繪圖消息響應函數OnPaint或其他函數中,用CWnd類的函數GetDlgItem:
            CWnd* GetDlgItem( int nID ) const;
            來獲得圖片控件的窗口對象,再用函數GetDC:
            CDC* GetDC( );

            由窗口對象得到DC,然后就可以用該DC在控件中畫圖。如(在ID為IDC_HUESAT的圖片控件上畫調色板)
            void CColorDlg::OnPaint() 
            {
                   if (IsIconic()) {
                          ... ...
                   }
                   else {
                          CDialog::OnPaint();
                          int i, j;
                          BYTE r, g, b;
                          // get control window and DC of Hue&Saturation

                          CWnd *pWin = GetDlgItem(IDC_HUESAT);

                          CDC *pDC = pWin->GetDC();

                          // draw hue-saturation palette

                          for (i = 0; i < 360; i++)

                                 for (j = 0; j <= 255; j++) {

                                        HSLtoRGB(i, 255 - j, 128, r, g, b); // 自定義函數,見網絡硬盤的

            // res目錄中的ColTrans.cpp文件
                                        pDC->SetPixel(i, j, RGB(r, g, b));

                                 }
                          ... ...
                   }
            }
            在非Frame類靜態控件上繪圖,必須先按順序依次調用CWnd類的Invalidate和UpdateWindow函數后,再開始用DC畫圖。如在一個ID為IDC_COLOR的按鈕上繪圖:
            void CComDlgDlg::DrawColor()
            {
                   CWnd* pWnd = GetDlgItem(IDC_COLOR);

                   CDC* pDC = pWnd->GetDC();

                   CRect rect;

                   pWnd->GetClientRect(&rect);
                   pWnd->Invalidate();
                   pWnd->UpdateWindow();
                   pDC->FillRect(&rect, new CBrush(m_crCol));
            }

            若干說明:
            <!--[if !supportLists]-->l     <!--[endif]-->除了基于對話框的程序外,其他對話框類都需要自己添加(重寫型)消息響應函數OnInitDialog,來做一些必要的初始化對話框的工作。添加方法是:先在項目區選中“類視圖”頁,再選中對應的對話框類,然后在屬性窗口的“重寫”頁中添加該函數;

            <!--[if !supportLists]-->l     <!--[endif]-->為了使在運行時能夠不斷及時更新控件的顯示(主要是自己加的顯式代碼),可以將自己繪制控件的所有代碼都全部加入對話框類的消息響應函數OnPaint中。在需要時(例如在繪圖參數修改后),自己調用CWnd的Invalidate和UpdateWindow函數,請求系統刷新對話框和控件的顯示。因為控件也是窗口,控件類都是CWnd的派生類。所以在對話框和控件中,可以像在視圖類中一樣,調用各種CWnd的成員函數。

            <!--[if !supportLists]-->l     <!--[endif]-->一般的對話框類,缺省時都沒有明寫出OnPaint函數。可以自己在對話框類中添加WM_PAINT消息的響應函數OnPaint來進行一些繪圖工作。

            <!--[if !supportLists]-->l     <!--[endif]-->為了在鼠標指向按鈕時,讓按鈕上自己繪制的圖形不被消去,可以設置按鈕控件的“Owner Draw”屬性為“True”。

            <!--[if !supportLists]-->l     <!--[endif]-->如果希望非按鈕控件(如圖片控件和靜態文本等),也可以響應鼠標消息(如單擊、雙擊等),需要設置控件的“Notify”屬性為“True”。

            <!--[if !supportLists]-->l     <!--[endif]-->使用OnPaint函數在對話框客戶區的空白處(無控件的地方)繪制自己的圖形,必須屏蔽掉其中缺省的對對話框基類的OnPaint函數的調用:

            //CDialog::OnPaint();
            <!--[if !supportLists]-->l     <!--[endif]-->對話框的背景色,可以用CWnd類的成員函數:

            DWORD GetSysColor( int nIndex);
            得到,其中的nIndex取為COLOR_BTNFACE。例如:
            dc.SetBkColor(GetSysColor(COLOR_BTNFACE));

            下面是部分例子代碼:(其中FillColor和ShowImg為自定義的成員函數)
            void CSetDlg::OnBnClickedPenColor()
            {
                   // TODO: 在此添加控件通知處理程序代碼
                   CColorDialog colDlg(m_crLineColor);

                   if (colDlg.DoModal() == IDOK) {

                          m_crLineColor = colDlg.GetColor();

                          Invalidate();
                          UpdateWindow();
                   }
            }
            // ……
            void CSetDlg::OnPaint()
            {
                   CPaintDC dc(this); // device context for painting

                   // TODO: 在此處添加消息處理程序代碼
                   // 不為繪圖消息調用 CDialog::OnPaint()
                   FillColor(IDC_PEN_COLOR, m_crLineColor);

                   FillColor(IDC_BRUSH_COLOR, m_crBrushColor);

                   if(m_pBitmap0 != NULL) ShowImg(IDC_BRUSH_IMG, m_hBmp0);

                   else if(m_pBitmap != NULL) ShowImg(IDC_BRUSH_IMG, m_hBmp);

            }
            void CSetDlg::FillColor(UINT id, COLORREF col)

            {
                   CWnd* pWnd = GetDlgItem(id);

                   CDC* pDC = pWnd->GetDC();

                   pDC->SelectObject(new CPen(PS_SOLID, 1, RGB(0, 0, 0)));

                   pDC->SelectObject(new CBrush(col));

                   CRect rect; 
                   pWnd->GetClientRect(&rect);
                   pWnd->Invalidate();
                   pWnd->UpdateWindow();
                   pDC->RoundRect(&rect, CPoint(8, 8));

            }
            void CSetDlg::ShowImg(UINT ID, HBITMAP hBmp)

            {
                   CWnd* pWnd = GetDlgItem(ID);

                   CDC* pDC = pWnd->GetDC();

                   CRect rect; 
                   pWnd->GetClientRect(&rect);
                   pWnd->Invalidate();
                   pWnd->UpdateWindow();
                   BITMAP bs;
                   GetObject(hBmp, sizeof(bs), &bs);

                   CDC dc;
                   if(dc.CreateCompatibleDC(pDC)) {

                          int x0, y0, w, h;
                          float rx = (float)bs.bmWidth / rect.right,

                                 ry = (float)bs.bmHeight / rect.bottom;

                          if (rx >= ry) {

                                 x0 = 0; w = rect.right;

                                 h = (int)(bs.bmHeight / rx + 0.5);

                                 y0 = (rect.bottom - h) / 2;

                          }
                          else {
                                 y0 = 0; h = rect.bottom;

                                 w = (int)(bs.bmWidth / ry + 0.5);

                                 x0 = (rect.right - w) / 2;

                          }
                          ::SelectObject(dc.GetSafeHdc(), hBmp);

                          pDC->SetStretchBltMode(HALFTONE);
                          pDC->StretchBlt(x0, y0, w, h, &dc, 0, 0, bs.bmWidth, bs.bmHeight, SRCCOPY);

                          SetDlgItemInt(IDC_W, bs.bmWidth);

                          SetDlgItemInt(IDC_H, bs.bmHeight);

                   }
            }
            //……
            5 設置繪圖屬性
            除了映射模式外,還有許多繪圖屬性可以設置,如背景、繪圖方式、多邊形填充方式、畫弧方向、刷原點等。
            1.背景
            1)背景色
            當背景模式為不透明時,背景色決定線狀圖的空隙顏色(如虛線中的空隙、條紋刷的空隙和文字的空隙),可以使用CDC類的成員函數GetBkColor和SetBkColor來獲得和設置當前的背景顏色:
            COLORREF GetBkColor( ) const; // 返回當前的背景色
            virtual COLORREF SetBkColor( COLORREF crColor ); // 返回先前的背景色
                                                                                          // 若出錯返回0x80000000
            2)背景模式
            背景模式影響有空隙的線狀圖的空隙(如虛線中的空隙、條紋刷的空隙和文字的空隙)用什么辦法填充。可以使用CDC類的成員函數GetBkMode和SetBkMode來獲得和設置當前的背景模式:
            int GetBkMode( ) const; // 返回當前背景模式
            int SetBkMode( int nBkMode ); // 返回先前背景模式
            背景模式的取值
            nBkMode值 名稱 作用 
            OPAQUE 不透明的(缺省值) 空隙用背景色填充 
            TRANSPARENT 透明的 空隙處保持原背景圖不變

            2. 繪圖模式
            繪圖模式(drawing mode)指前景色的混合方式,它決定新畫圖的筆和刷的顏色(pbCol)如何與原有圖的顏色(scCol)相結合而得到結果像素色(pixel)。
            1)設置繪圖模式
            可使用CDC類的成員函數SetROP2 (ROP = Raster OPeration光柵操作)來設置繪圖模式:
            int SetROP2( int nDrawMode );

            其中,nDrawMode可取值:
            繪圖模式nDrawMode的取值
            符號常量 作用 運算結果 
            R2_BLACK 黑色 pixel = black 
            R2_WHITE 白色 pixel = white 
            R2_NOP 不變 pixel = scCol 
            R2_NOT 反色 pixel = ~scCol 
            R2_COPYPEN 覆蓋 pixel = pbCol 
            R2_NOTCOPYPEN 反色覆蓋 pixel = ~pbCol 
            R2_MERGEPENNOT 反色或 pixel = ~scCol | pbCol 
            R2_MERGENOTPEN 或反色 pixel = scCol | ~pbCol 
            R2_MASKNOTPEN 與反色 pixel = scCol & ~pbCol 
            R2_MERGEPEN 或 pixel = scCol | pbCol 
            R2_NOTMERGEPEN 或非 pixel = ~(scCol | pbCol) 
            R2_MASKPEN 與 pixel = scCol & pbCol 
            R2_NOTMASKPEN 與非 pixel = ~(scCol & pbCol) 
            R2_XORPEN 異或 pixel = scCol ^ pbCol 
            R2_NOTXORPEN 異或非 pixel = ~(scCol ^ pbCol)

            其中,R2_COPYPEN(覆蓋)為缺省繪圖模式,R2_XORPEN(異或)較常用。
            2)畫移動圖形
            為了能畫移動的位置標識(如十字、一字)和隨鼠標移動畫動態圖形(如直線、矩形、橢圓),必須在不破壞原有背景圖形的基礎上移動這些圖形。
            移動圖形采用的是異或畫圖方法,移動圖形的過程為:異或畫圖、在原位置再異或化圖(擦除)、在新位置異或畫圖、……。

                   pGrayPen = new CPen(PS_DOT, 0, RGB(128, 128, 128));

            pDC->SetBkMode(TRANSPARENT);
                   pOldPen = pDC->SelectObject(pGrayPen);
            pDC->SelectStockObject(NULL_BRUSH);
                   pDC->SetROP2(R2_XORPEN);
                   if (m_bErase) pDC->Ellipse(rect0);
                   pDC->Ellipse(rect);
                   pDC->SetROP2(R2_COPYPEN);
                   pDC->SelectObject(pOldPen);
                   rect0 = rect;
            較完整的拖放動態畫圖的例子,可參照下面的“3. 拖放畫動態直線”部分。
            3)其他屬性
            <!--[if !supportLists]-->l         <!--[endif]-->多邊形填充方式:可使用CDC類的成員函數GetPolyFillMode和SetPolyFillMode來確定多邊形的填充方式:

            int GetPolyFillMode( ) const;
            int SetPolyFillMode( int nPolyFillMode );
            其中nPolyFillMode 可取值ALTERNATE(交替——填充奇數邊和偶數邊之間的區域,缺省值)或WINDING(纏繞——根據多邊形邊的走向來確定是否填充一區域)
            <!--[if !supportLists]-->l         <!--[endif]-->畫弧方向:可使用CDC類的成員函數GetArcDirection和SetArcDirection來確定Arc、Chord、Pie等函數的畫弧方向:

            int GetArcDirection( ) const;
            int SetArcDirection( int nArcDirection );
            其中,nArcDirection可取值AD_COUNTERCLOCKWISE(逆時針方向,缺省值)和AD_CLOCKWISE(順時針方向)
            <!--[if !supportLists]-->l         <!--[endif]-->刷原點:可使用CDC類的成員函數GetBrushOrg和SetBrushOrg來確定可填充繪圖函數的條紋或圖案刷的起點:(缺省值為客戶區左上角的坐標原點(0, 0))

            CPoint GetBrushOrg( ) const;
            CPoint SetBrushOrg( int x, int y );
            CPoint SetBrushOrg( POINT point );
            3.拖放畫動態直線
            下面是一個較完整的拖放動態畫直線的例子:
            // 類變量
            class CDrawView : public CView { 
                   //……
            protected:
                   BOOL m_bLButtonDown, m_bErase; // 判斷是否按下左鼠標鍵

            //和是否需要擦除圖形的類變量
                   CPoint p0, pm; // 記錄直線起點和動態終點的類變量

                   CPen * pGrayPen, * pLinePen; // 定義灰色和直線筆

                   //……
            }
            // 構造函數
            CDrawView::CDrawView() {
                   m_bLButtonDown = FALSE; // 設左鼠標鍵按下為假

                   m_bErase = FALSE; // 設需要擦除為假

                   pGrayPen = new CPen(PS_SOLID, 0, RGB(128, 128, 128));// 創建灰色筆

                   pLinePen = new CPen(PS_SOLID, 0, RGB(255, 0, 0));// 創建紅色的直線筆

            }
            // 鼠標消息響應函數
            void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) {

                   m_bLButtonDown = TRUE; // 設左鼠標鍵按下為真

                   SetCapture(); // 設置鼠標捕獲

                   // SetCursor(LoadCursor(NULL, IDC_CROSS)); // 設置鼠標為十字

                   p0 = point; // 保存矩形左上角

                   pm = p0; // 讓矩形右下角等于左上角
                   CView::OnLButtonDown(nFlags, point);

            }
            void CDrawView::OnMouseMove(UINT nFlags, CPoint point) {

                   SetCursor(LoadCursor(NULL, IDC_CROSS)); // 設置鼠標為十字

                   if (m_bLButtonDown) { // 左鼠標鍵按下為真

                          CDC* pDC = GetDC(); // 獲取設備上下文

                          pDC->SelectObject(pGrayPen);// 選取灰色筆
                          pDC->SetROP2(R2_XORPEN);// 設置為異或繪圖方式
                          if (m_bErase) { // 需要擦除為真

                                 pDC->MoveTo(p0); pDC->LineTo(pm); // 擦除原直線

                          }
                          else // 需要擦除為假

                                 m_bErase = TRUE; // 設需要擦除為真
                          pDC->MoveTo(p0); pDC->LineTo(point); // 繪制新直線

                          pm = point; // 記錄老終點

                          ReleaseDC(pDC); // 釋放設備上下文

                   }
                   CView::OnMouseMove(nFlags, point);

            }
            void CDrawView::OnLButtonUp(UINT nFlags, CPoint point) {

                   ReleaseCapture(); // 釋放鼠標捕獲

                   if (m_bLButtonDown) { // 左鼠標鍵按下為真

                          CDC* pDC = GetDC(); // 獲取設備上下文

                          pDC->SelectObject(pGrayPen);// 選取灰色筆
                          pDC->SetROP2(R2_XORPEN); // 設置為異或繪圖方式
                          pDC->MoveTo(p0); pDC->LineTo(pm); // 擦除原直線

                          pDC->SelectObject(pLinePen); // 選擇直線筆
                          pDC->SetROP2(R2_COPYPEN);// 設置為覆蓋繪圖方式
                          pDC->MoveTo(p0); pDC->LineTo(point); // 繪制最終的直線

                          m_bLButtonDown = FALSE; // 重設左鼠標鍵按下為假

                          m_bErase = FALSE; // 重需要擦除為假

                          ReleaseDC(pDC); // 釋放設備上下文

                   }
                   CView::OnLButtonUp(nFlags, point);

            }

            posted @ 2011-03-01 14:03 wrh 閱讀(2434) | 評論 (0)編輯 收藏
            char是C語言標準數據類型,字符型,至于由幾個字節組成通常由編譯器決定,一般一個字節。

            Windows為了消除各編譯器的差別,重新定義了一些數據類型,你提到了另外幾個類型都是這樣。CHAR為

            單字節字符。還有個WCHAR為Unicode字符,即不論中英文,每個字有兩個字節組成。如果當前編譯方式為

            ANSI(默認)方式,TCHAR等價于CHAR,如果為Unicode方式,TCHAR等價于WCHAR。在當前版本LPCSTR和

            LPSTR沒區別,即以零結尾的字符串指針,相當于CHAR *。 LPSTR、LPCSTR相當于char *,所以這種類型

            變量的賦值等同于char *的賦值
            下面給出兩個例子,一個是直接賦值,另一個是間接的。
                Ex1: LPSTR lpstrMsg = "I'm tired.";
                Ex2: char strMsg[]="I'm tired.";
                LPSTR lpstrMsg = (LPSTR) strMsg

            posted @ 2011-02-17 09:14 wrh 閱讀(583) | 評論 (0)編輯 收藏

            [原創]在VC中徹底玩轉Excel
                如今Excel是越來越重要了,在我們自己開發的程序中不免要和Excel打交道了。利用Automation技術,我們可以在不去了解
            數據庫的情況下玩轉Excel,而且你會發現一切竟如此輕松!
                好了,咱們開始吧,我不喜歡用長篇累牘的代碼來故弄玄虛,所以下面的代碼都是切中要害的片段,總體上是個連貫的過程,
            包括啟動Excel,讀取數據,寫入數據,以及最后的關閉Excel,其中還包括了很多人感興趣的合并單元格的處理。
                特別說明以下代碼需要MFC的支持,而且工程中還要包含EXCEL2000的定義文件:EXCEL9.H,EXCEL9.CPP

            *****************************************************************************************************************

             //*****
             //變量定義
             _Application app;   
             Workbooks books;
             _Workbook book;
             Worksheets sheets;
             _Worksheet sheet;
             Range range;
             Range iCell;
             LPDISPATCH lpDisp;   
             COleVariant vResult;
             COleVariant
                    covTrue((short)TRUE),
                    covFalse((short)FALSE),
                    covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);   
             
             
             //*****
             //初始化COM的動態連接庫
             if(!AfxOleInit()) 
             {
                    AfxMessageBox("無法初始化COM的動態連接庫!");
                    return ;
                 }  
             
             
             //*****
             //創建Excel 2000服務器(啟動Excel)
             if(!app.CreateDispatch("Excel.Application"))
             {
              AfxMessageBox("無法啟動Excel服務器!");
                return;
             }
             
             app.SetVisible(TRUE);          //使Excel可見
             app.SetUserControl(TRUE);      //允許其它用戶控制Excel
             

             //*****  
             //打開c:\\1.xls
             books.AttachDispatch(app.GetWorkbooks());
             lpDisp = books.Open("C:\\\\1.xls",     
               covOptional, covOptional, covOptional, covOptional, covOptional,
               covOptional, covOptional, covOptional, covOptional, covOptional,
               covOptional, covOptional );   
             
                
             //*****
             //得到Workbook
             book.AttachDispatch(lpDisp);
             
             
             //*****
             //得到Worksheets
             sheets.AttachDispatch(book.GetWorksheets());
             
             
             //*****
             //得到當前活躍sheet
             //如果有單元格正處于編輯狀態中,此操作不能返回,會一直等待
             lpDisp=book.GetActiveSheet();
             sheet.AttachDispatch(lpDisp);
             

             //*****
             //讀取已經使用區域的信息,包括已經使用的行數、列數、起始行、起始列
             Range usedRange;
             usedRange.AttachDispatch(sheet.GetUsedRange());
             range.AttachDispatch(usedRange.GetRows());
             long iRowNum=range.GetCount();                   //已經使用的行數
             
             range.AttachDispatch(usedRange.GetColumns());
             long iColNum=range.GetCount();                   //已經使用的列數
             
             long iStartRow=usedRange.GetRow();               //已使用區域的起始行,從1開始
             long iStartCol=usedRange.GetColumn();            //已使用區域的起始列,從1開始
             
             
             //*****
             //讀取第一個單元格的值
             range.AttachDispatch(sheet.GetCells());
             range.AttachDispatch(range.GetItem (COleVariant((long)1),COleVariant((long)1)).pdispVal );
             COleVariant vResult =range.GetValue();
             CString str;
             if(vResult.vt == VT_BSTR)       //字符串
             {
              str=vResult.bstrVal;
             }
             else if (vResult.vt==VT_R8)     //8字節的數字
             {
              str.Format("%f",vResult.dblVal);
             }
             else if(vResult.vt==VT_DATE)    //時間格式
             {
              SYSTEMTIME st;
                 VariantTimeToSystemTime(&vResult.date, &st);
             }
             else if(vResult.vt==VT_EMPTY)   //單元格空的
             {
              str="";
             } 
             
             
             //*****
             //讀取第一個單元格的對齊方式,數據類型:VT_I4
             //讀取水平對齊方式
             range.AttachDispatch(sheet.GetCells());
             iCell.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal);
             vResult.lVal=0;
             vResult=iCell.GetHorizontalAlignment();
             if(vResult.lVal!=0)
             {
              switch (vResult.lVal)
              {
              case 1:      //默認
               break;
              case -4108:  //居中
               break;
              case -4131 : //靠左
               break;
              case -4152 : //靠右
               break;
              }
             
             }
             
             //垂直對齊方式
             iCell.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal);
             vResult.lVal=0;
             vResult=iCell.GetVerticalAlignment();
             if(vResult.lVal!=0)
             {
              switch (vResult.lVal)
              {
              case -4160 :  //靠上
               break;
              case -4108 :  //居中
               break;
              case -4107 :  //靠下
               break;
              }
             
             }
             
             
             //*****
             //設置第一個單元格的值"HI,EXCEL!"
             range.SetItem(COleVariant(1),COleVariant(1),COleVariant("HI,EXCEL!"));
             

             //*****
             //設置第一個單元格字體顏色:紅色
             Font font;
             range.AttachDispatch(sheet.GetCells());
             range.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal);
             font.SetColor(COleVariant((long)0xFF0000)); 
             
             
             //*****
             //合并單元格的處理
             //包括判斷第一個單元格是否為合并單元格,以及將第一個單元格進行合并
             Range unionRange;
             range.AttachDispatch(sheet.GetCells());
             unionRange.AttachDispatch(range.GetItem (COleVariant((long)1),COleVariant((long)1)).pdispVal );
             
             vResult=unionRange.GetMergeCells();   
             if(vResult.boolVal==-1)             //是合并的單元格   
             {
              //合并單元格的行數
              range.AttachDispatch (unionRange.GetRows ());
              long iUnionRowNum=range.GetCount ();
              
              //合并單元格的列數
              range.AttachDispatch (unionRange.GetColumns ());
              long iUnionColumnNum=range.GetCount ();  
             
              //合并區域的起始行,列
              long iUnionStartRow=unionRange.GetRow();       //起始行,從1開始
              long iUnionStartCol=unionRange.GetColumn();    //起始列,從1開始
             
             }
             else if(vResult.boolVal==0)  
             {//不是合并的單元格}
             
             //將第一個單元格合并成2行,3列
             range.AttachDispatch(sheet.GetCells());
             unionRange.AttachDispatch(range.GetItem (COleVariant((long)1),COleVariant((long)1)).pdispVal );
             unionRange.AttachDispatch(unionRange.GetResize(COleVariant((long)2),COleVariant((long)3)));
             unionRange.Merge(COleVariant((long)0));   //合并單元格
             
             
             //*****
             //將文件保存為2.xls
             book.SaveAs(COleVariant("C:\\\\2.xls"),covOptional,covOptional, \\
              covOptional,covOptional,covOptional,0,\\
              covOptional,covOptional,covOptional,covOptional); 
             
             
             //*****
             //關閉所有的book,退出Excel
             book.Close (covOptional,COleVariant(OutFilename),covOptional);
             books.Close();     
             app.Quit();    

            關于excel.h和excel.cpp,要注意版本問題.
            比如對excel xp, 類庫是直接包含在excel.exe中. 因此你只要用加入類(add class)的方法,直接選中excel.exe,并選擇對話框中的常用的幾個類(如Rang)就可以編程了. 千萬不要選所有的類,否則太大了.

            作者:unionsoft 2003-11-29 11:00:34)


            修改字體顏色的那段漏了一句,應為:
              //*****
              //設置第一個單元格字體顏色:紅色
              Font font;
              range.AttachDispatch(sheet.GetCells());
              range.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal);
              font.AttachDispatch (range.GetFont ());
              font.SetColor(COleVariant((long)0xFF0000));

            作者:zhengkuo 2003-12-2 10:50:00)


            如果,程序既要安裝在2000的計算機上,也可能安裝在XP的機子上,有的用戶還用97,(指的都是office),可能會出現版本問題------其中比較麻煩的是--在app.quit()后,仍舊存在excel進程,如果這樣?怎么解決?
            作者:zhengkuo 2003-12-2 10:51:50)


            請教高手,能否用vb控制excel做成dll,在arx中進行調用,因為畢竟vb與excel親切
            作者:unionsoft 2004-1-30 11:06:58)

             

            以下是引用zhengkuo在2003-12-2 10:50:00的發言:
            如果,程序既要安裝在2000的計算機上,也可能安裝在XP的機子上,有的用戶還用97,(指的都是office),可能會出現版本問題------其中比較麻煩的是--在app.quit()后,仍舊存在excel進程,如果這樣?怎么解決?
            兼容性問題:

                    office2002-office97是向下兼容的,只要你不使用office2002中的新特性,程序在這些office版本中都好用

            Excel程序不能退出的問題:
                  1 . 不要使用#import導入類型庫,如:#import "c:\\excel\\excel.olb"
                  2 . 程序結束時,確保所有IDispatch都釋放了,如:app.ReleaseDispatch (); 

            作者:easypower 2004-5-14 10:00:39)


            還是不明白如何得到excel.cpp和excel.h這兩個文件,請指教
            作者:jack1975 2004-6-24 16:43:03)


            有版本問題時,可以加一個判斷:1、首先通過  exlApp得到版本,比如9.0,10.0,11.0,10.0以后的版本注意open函數的參數為15個,即最后在增加兩個covOptional,即可,另外,補充一下,判斷當前是否有excel應用程序在運行,使之更舒服一些:
            ::CLSIDFromProgID(L"Excel.Application",&clsid); // from registry
             if(::GetActiveObject(clsid, NULL,&pUnk) == S_OK)

            {
              VERIFY(pUnk->QueryInterface(IID_IDispatch,(void**) &pDisp) == S_OK);
              ExcelApp.AttachDispatch(pDisp);
              pUnk->Release();
              }
            else

             {
              if(!ExcelApp.CreateDispatch("Excel.Application")) {
               AfxMessageBox("Excel program not found");
               return 0;
              }

             }

             

            作者:unionsoft 2004-12-13 12:36:09)

             

            以下是引用zhmary在2004-12-10 11:30:10的發言:
            請問各位高手,從哪里得onclick=Cswf() height=22 alt=Flash圖片 src="skins/default/ubb/swf.gif" width=23 border=0>到Excel.cp...


            Excel.cpp和Excel.h是從Excel的類型庫中獲取的,類型庫類似C++中的頭文件,包括接口,方法,屬性的定義;類型庫在Excel的安裝目錄可以找到,Excel的版本不同,這個類型庫也不一樣,如下所示:
            Excel 95 and prior   :   xl5en32.olb
             Excel 97             :   excel8.olb
             Excel 2000           :   excel9.olb
             Excel 2002           :   excel.exe

            具體的獲取方法:

            1 . 使用VC++新建立一個基于MFC的EXE工程

            2 . 點擊菜單"查看"-->"建立類向導",此時會彈全"MFC ClassWizard"對話框

            3 . 點擊"Add Class"-->"From a type libray",指定Excel的type libray,在Excel的安裝目錄下可以找到,如:"D:\\Microsoft Office\\Office\\EXCEL9.OLB"

            4 . 在彈出的對話框中選擇所需的類,按"確定",Excel.cpp和Excel.h就產生了。

            作者:yfy2003 2004-12-23 17:41:57)


            lpDisp = books.Open("C:\\\\1.xls",     
               covOptional, covOptional, covOptional, covOptional, covOptional,
               covOptional, covOptional, covOptional, covOptional, covOptional,
               covOptional, covOptional );   

            編譯顯示錯誤:

            error C2660: 'Open' : function does not take 13 parameters

            作者:xux4618 2005-4-6 8:48:51)


            請問怎樣才能增加一個工作表?
            作者:夢幻神話 2005-4-6 15:50:40)


             Workbooks.AttachDispatch(ExcelApp.GetWorkbooks());
             Workbook.AttachDispatch(Workbooks.Open(FileName,covOptional, covOptional,covOptional, covOptional,covOptional, covOptional,covOptional, covOptional,covOptional, covOptional,covOptional, covOptional));
             Worksheets.AttachDispatch(Workbook.GetWorksheets());
             Worksheet.AttachDispatch(Worksheets.GetItem((COleVariant((long)1))));
             Range.AttachDispatch(Worksheet.GetCells());
             iCell.AttachDispatch(Range.GetItem(COleVariant((long)2),COleVariant((long)2)).pdispVal);

             vResult = iCell.GetMergeCells();

             if(vResult.boolVal == -1)
             {
              AfxMessageBox("Yes");
             
              Range.AttachDispatch(iCell.GetRows());
              long row_num = Range.GetCount();

              Range.AttachDispatch(iCell.GetColumns());
              long col_num = Range.GetCount();

              CString str;
              str.Format("%d×%d",row_num,col_num);
              AfxMessageBox(str);
             }

            請教:為什么str得到的結果都是1×1?(求合并單元格的原始行數和列數)。

            謝謝。。。。。。。。。。

            作者:unionsoft 2005-4-9 10:13:25)


            首先你的Cells(2,2)是否處于合并單元格中
            其次,你缺少了個關鍵語句:iCell.GetMergeArea()),你可以參考下面的語句

            Range UnionRange;

            UnionRange.AttachDispatch(iCell.GetMergeArea());  //先要獲取合并區域

            range.AttachDispatch (UnionRange.GetRows ());

            long iRowNum = range.GetCount();             //合并單元格行數

            range.AttachDispatch (UnionRange.GetColumns ());

            long iColNum = Range.GetCount();            //合并單元格列數

               

            我就想在excel里 實現,第一行為標題(居中)
            第二行為時間(左對齊),下面為9列數據.最后一行為簽名(左對齊)
            怎么辦?  回復  更多評論
             
            # re: [轉]在VC中徹底玩轉Excel
            2006-11-26 17:24 | 好學者

            修改字體顏色的那段漏了一句,應為:
            //*****
            //設置第一個單元格字體顏色:紅色
            Font font;
            range.AttachDispatch(sheet.GetCells());
            range.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal);
            font.AttachDispatch (range.GetFont ());
            font.SetColor(COleVariant((long)0xFF0000));

            這樣改了還是不能用,Font是哪兒來的哦!  回復  更多評論
             
            # re: [轉]在VC中徹底玩轉Excel
            2007-10-19 15:11 | 唐特

            Font 和 _Application,Workbooks等等這些東西一樣, 是打開excel.exe(excel9.olb) 的時候添加的class  回復  更多評論
             
            # re: [轉]在VC中徹底玩轉Excel
            2008-01-16 11:19 | HU

            請教一個問題,現在出現了OFFICE 2007,在2000中做的程序,在2007下無法啟動EXCEL服務,就是CreateDispatch失敗。
            但是,運行的環境既有2007,也會有老版本的EXCEL,這種情況下,怎么辦?怎么讓程序更有通用性?謝謝!!!!  回復  更多評論
             
            # re: [轉]在VC中徹底玩轉Excel
            2008-01-25 10:55 | 想飛的星期

            請問怎么知道我createdispatch出來的excel已經關閉了??我還想每次重用同一個excel進程,怎么辦?  回復  更多評論
             
            # re: [轉]在VC中徹底玩轉Excel
            2008-03-28 14:56 | lamorak

            你好,請教一下,我在做數據導入到excel中的程序,將3個文件的數據導入沒有問題,我為了做測試,將這3個文件復制了44次,就是145個文件的數據,總共有6702314行,200M的數據量,轉換到75M數據的時候,Excel就不給轉了,就彈出Excel中“value,range,GetIDsOfNames”函數出錯,Excel大小有限制嗎?我這個差不多就是做9×3文件循環數據插入,第10個循環就錯了。我每次轉一個文件后都加了Sleep(2000),能幫忙解決一下嗎?  回復  更多評論


            本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/vicozo/archive/2009/04/12/4067804.aspx
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            _Application   ExcelApp;    
              Workbooks   wbsMyBooks;    
              _Workbook   wbMyBook;    
              Worksheets   wssMysheets;    
              _Worksheet   wsMysheet;    
              Range   rgMyRge;    
              //創建Excel   2000服務器(啟動Excel)    
               
              if   (!ExcelApp.CreateDispatch("Excel.Application",NULL))    
              {    
              AfxMessageBox("創建Excel服務失敗!");    
              return;  
              }    
              //得到路徑  
              char   cCurrentDir[255];  
              ::GetCurrentDirectory(255,   cCurrentDir);  
              CString   str   =   cCurrentDir;  
              int   iPos   =   str.ReverseFind('\\');  
              CString   str1   =   str.Left(iPos);  
              CString   strDirectory;  
              strDirectory   =   _tcsdup(str1   +   "\\MyTemplate.xlt");    
              //利用模板文件建立新文檔    
              wbsMyBooks.AttachDispatch(ExcelApp.GetWorkbooks(),true);    
              wbMyBook.AttachDispatch(wbsMyBooks.Add(_variant_t(strDirectory)));    
              //得到Worksheets    
              wssMysheets.AttachDispatch(wbMyBook.GetWorksheets(),true);    
              //得到sheet1    
              wsMysheet.AttachDispatch(wssMysheets.GetItem(_variant_t("sheet1")),true);    
              //得到全部Cells,此時,rgMyRge是cells的集合    
              rgMyRge.AttachDispatch(wsMysheet.GetCells(),true);    
              //設置1行1列的單元的值                     行                         列  
               
              rgMyRge.SetItem(_variant_t((long)1),_variant_t((long)1),_variant_t("名稱"));    
              rgMyRge.SetItem(_variant_t((long)1),_variant_t((long)2),_variant_t("時間"));  
              rgMyRge.SetItem(_variant_t((long)1),_variant_t((long)3),_variant_t("信息"));  
              rgMyRge.SetItem(_variant_t((long)1),_variant_t((long)4),_variant_t("級別"));  
              rgMyRge.SetItem(_variant_t((long)1),_variant_t((long)5),_variant_t("確認時間"));  
              rgMyRge.SetItem(_variant_t((long)1),_variant_t((long)6),_variant_t("人"));  
              rgMyRge.SetItem(_variant_t((long)1),_variant_t((long)7),_variant_t("啊啊"));  
              rgMyRge.SetItem(_variant_t((long)1),_variant_t((long)8),_variant_t("cc"));  
              rgMyRge.SetItem(_variant_t((long)1),_variant_t((long)9),_variant_t("gh元"));  
              rgMyRge.SetItem(_variant_t((long)1),_variant_t((long)10),_variant_t("h"));  
              rgMyRge.SetItem(_variant_t((long)1),_variant_t((long)11),_variant_t("dsf"));  
               
               
               
              //int   j=m_theListCtrl.GetItemCount();  
              //CString   str;  
              //str=m_theListCtrl.GetItemText(0,1);  
              //MessageBox(str);  
               
               
              for(int   i   =   2;   i   <   m_theListCtrl.GetItemCount()+2;   i++)  
              {  
              rgMyRge.SetItem(_variant_t((long)i),_variant_t((long)1),_variant_t(m_theListCtrl.GetItemText(i-2,0)));  
              rgMyRge.SetItem(_variant_t((long)i),_variant_t((long)2),_variant_t(m_theListCtrl.GetItemText(i-2,1)));  
              rgMyRge.SetItem(_variant_t((long)i),_variant_t((long)3),_variant_t(m_theListCtrl.GetItemText(i-2,2)));  
              rgMyRge.SetItem(_variant_t((long)i),_variant_t((long)4),_variant_t(m_theListCtrl.GetItemText(i-2,3)));  
              rgMyRge.SetItem(_variant_t((long)i),_variant_t((long)5),_variant_t(m_theListCtrl.GetItemText(i-2,4)));  
              rgMyRge.SetItem(_variant_t((long)i),_variant_t((long)6),_variant_t(m_theListCtrl.GetItemText(i-2,5)));  
              rgMyRge.SetItem(_variant_t((long)i),_variant_t((long)7),_variant_t(m_theListCtrl.GetItemText(i-2,6)));  
              rgMyRge.SetItem(_variant_t((long)i),_variant_t((long)8),_variant_t(m_theListCtrl.GetItemText(i-2,7)));  
              rgMyRge.SetItem(_variant_t((long)i),_variant_t((long)9),_variant_t(m_theListCtrl.GetItemText(i-2,8)));  
              rgMyRge.SetItem(_variant_t((long)i),_variant_t((long)10),_variant_t(m_theListCtrl.GetItemText(i-2,9)));  
              rgMyRge.SetItem(_variant_t((long)i),_variant_t((long)11),_variant_t(m_theListCtrl.GetItemText(i-2,10)));  
               
              }  
               
              //得到所有的列    
              rgMyRge.AttachDispatch(wsMysheet.GetColumns(),true);    
               
               
              //得到第一列   //設置列寬    
              rgMyRge.AttachDispatch(rgMyRge.GetItem(_variant_t((long)1),vtMissing).pdispVal,true);    
              rgMyRge.SetColumnWidth(_variant_t((long)15));    
               
              rgMyRge.AttachDispatch(rgMyRge.GetItem(_variant_t((long)2),vtMissing).pdispVal,true);    
              rgMyRge.SetColumnWidth(_variant_t((long)15));    
               
              rgMyRge.AttachDispatch(rgMyRge.GetItem(_variant_t((long)3),vtMissing).pdispVal,true);    
              rgMyRge.SetColumnWidth(_variant_t((long)16));    
               
              rgMyRge.AttachDispatch(rgMyRge.GetItem(_variant_t((long)4),vtMissing).pdispVal,true);    
              rgMyRge.SetColumnWidth(_variant_t((long)15));    
               
              rgMyRge.AttachDispatch(rgMyRge.GetItem(_variant_t((long)5),vtMissing).pdispVal,true);    
              rgMyRge.SetColumnWidth(_variant_t((long)15));    
               
              //顯示excel表  
              wbMyBook.SetSaved(true);    
              ExcelApp.SetVisible(true);    
              //wbMyBook.PrintPreview(_variant_t(false));    
               
              //釋放對象    
              rgMyRge.ReleaseDispatch();    
              wsMysheet.ReleaseDispatch();    
              wssMysheets.ReleaseDispatch();    
              wbMyBook.ReleaseDispatch();    
              wbsMyBooks.ReleaseDispatch();    
              ExcelApp.ReleaseDispatch();   

            本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/vicozo/archive/2009/04/12/4067835.aspx
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            SDK程序,沒有用MFC。  
              用的是excel2003  
              //   StatisticsGen.cpp   :   Defines   the   entry   point   for   the   console   application.  
              //  
               
              #include   "stdafx.h"  
               
              int   _tmain(int   argc,   _TCHAR*   argv[])  
              {  
              // Dispatch   interface  
              IDispatch *pDispExcel;  
              // Temporary   variable   to   hold   names.  
              unsigned   short *ucPtr;  
              // ClSID   of   excel  
              CLSID clsidExcel;  
              // Return   value  
              HRESULT hr;  
               
               
              // Initialize   OLE   Libraries.  
              OleInitialize(NULL);  
               
               
              // Get   CLSID   for   Excel.Application   from   registry.  
              hr   =   CLSIDFromProgID(L"Excel.Application",   &clsidExcel);  
              if   (   FAILED(hr)   )  
              {  
              MessageBox(NULL,   "Excel   not   registered.",   "Error",   MB_OK);  
              goto   __exit;  
              }  
               
              ///////////////////////////////////////////////////////////////////////////////////////////////////  
              // Start   excel   and   get   its   IDispatch   pointer.  
              hr   =   CoCreateInstance(clsidExcel,   NULL,   CLSCTX_LOCAL_SERVER,   IID_IDispatch,   (void**)&pDispExcel);  
              if   (   FAILED(hr)   )  
              {  
              MessageBox(NULL,   "Couldn't   start   Excel.",   "Error",   MB_OK);  
              goto   __exit;  
              }  
               
              ///////////////////////////////////////////////////////////////////////////////////////////////////  
              // Get   the   'visible'   property's   DISPID.  
              DISPPARAMS dispParamsVisible   =   {   NULL,   NULL,   0,   0};  
              VARIANT parmVisible;  
              DISPID dispidNamed   =   DISPID_PROPERTYPUT;  
              DISPID dispVisible;  
               
              ucPtr   =   L"Visible";  
              pDispExcel->GetIDsOfNames(IID_NULL,   &ucPtr,   1,   LOCALE_USER_DEFAULT,   &dispVisible);  
               
              // Initialize   parameters   to   set   visible   property   to   true.  
              VariantInit(&parmVisible);  
              parmVisible.vt   =   VT_I4;  
              parmVisible.llVal   =   1;  
               
              //   One   argument.  
              dispParamsVisible.cArgs   =   1;  
              dispParamsVisible.rgvarg   =   &parmVisible;  
               
              // Handle   special-case   for   property-puts!  
              dispParamsVisible.cNamedArgs =   1;  
              dispParamsVisible.rgdispidNamedArgs =   &dispidNamed;  
               
              // Set   'visible'   property   to   true.  
              hr   =   pDispExcel->Invoke(dispVisible,   IID_NULL,   LOCALE_SYSTEM_DEFAULT,     DISPATCH_PROPERTYPUT   |   DISPATCH_METHOD,  
              &dispParamsVisible,   NULL,   NULL,   NULL);  
              VariantClear(&parmVisible);  
               
              if(FAILED(hr))    
              {  
              MessageBox(NULL,   "Set   visible!",   "Failed!",   MB_OK);  
              goto   __exit;  
              }  
               
               
              /////////////////////////////////////////////////////////////////////////////////////////////////////  
              OLECHAR*   szGetBooks   =   L"Workbooks";    
              DISPID dispGetWorkbooks;  
              VARIANT   varBooks;  
               
              hr   =   pDispExcel->GetIDsOfNames(IID_NULL,   &szGetBooks,   1,   LOCALE_USER_DEFAULT,   &dispGetWorkbooks);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
              DISPPARAMS   dispParamsForGetBooks   =   {   NULL,   NULL,   0,   0};  
              hr   =   pDispExcel->Invoke(dispGetWorkbooks,   IID_NULL,   LOCALE_SYSTEM_DEFAULT,     DISPATCH_PROPERTYGET   |   DISPATCH_METHOD,  
              &dispParamsForGetBooks,   &varBooks,   NULL,   NULL);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
               
              ///////////////////////////////////////////////////////////////////////////////////////////////////  
              // Open  
              IDispatch*   pDispBooks;  
              IDispatch*   pDispBook;  
               
              if   (   varBooks.vt   !=   VT_DISPATCH)  
              goto   __exit;  
              else  
              {  
              // Get   workbooks   dispatch   interface  
              pDispBooks   =   varBooks.pdispVal;  
               
              // Open  
              VARIANT   varRetBook;  
              VARIANTARG   varg;  
              varg.vt   =   VT_BSTR;  
              varg.bstrVal   =   _bstr_t("c:\\bool.xls");  
               
              DISPPARAMS   dpOpen=   {   &varg,   NULL,   1,   0   };  
               
              LPOLESTR   lpOpen   =   L"Open";  
              DISPID   dispOpen;  
               
              hr   =   pDispBooks->GetIDsOfNames(IID_NULL,   &lpOpen,   1,   LOCALE_USER_DEFAULT,   &dispOpen);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
              hr   =   pDispBooks->Invoke(dispOpen,   IID_NULL,   LOCALE_SYSTEM_DEFAULT,   DISPATCH_PROPERTYGET   |   DISPATCH_METHOD,  
              &dpOpen,   &varRetBook,   NULL,   NULL);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
               
              if   (   varRetBook.vt   !=   VT_DISPATCH   )  
              goto   __exit;  
              else  
              pDispBook   =   varRetBook.pdispVal;  
              }  
             

            //   worksheets  
              IDispatch*   pDispSheets;  
              if   (   pDispBook   !=   NULL   )  
              {  
              DISPPARAMS   dpSheets   =   {NULL,   NULL,   0,   0};  
              DISPID dispSheets;  
              LPOLESTR   lpSheets   =   L"Worksheets";  
              VARIANT   varRetSheets;  
               
              hr   =   pDispBook->GetIDsOfNames(IID_NULL,   &lpSheets,   1,   LOCALE_USER_DEFAULT,   &dispSheets);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
              hr   =   pDispBook->Invoke(dispSheets,   IID_NULL,   LOCALE_SYSTEM_DEFAULT,   DISPATCH_PROPERTYGET   |   DISPATCH_METHOD,  
              &dpSheets,   &varRetSheets,   NULL,   NULL);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
               
              if   (   varRetSheets.vt   !=   VT_DISPATCH   )  
              goto   __exit;  
              else  
              pDispSheets   =   varRetSheets.pdispVal;  
              }  
               
              ///////////////////////////////////////////////////////////////////////////////////////////////////  
              // worksheet  
              IDispatch*   pDispSheet;  
              if   (   pDispSheets   !=   NULL   )  
              {  
              VARIANT     varRetSheet;  
               
              VARIANTARG   vargSheet;  
              vargSheet.vt   =   VT_I4;  
              vargSheet.intVal   =   1;  
               
              DISPPARAMS dpSheet   =   {   &vargSheet,   NULL,   1,   0   };  
               
              LPOLESTR   lpSheet   =   L"Item";  
              DISPID dispSheet;  
               
              hr   =   pDispSheets->GetIDsOfNames(IID_NULL,   &lpSheet,   1,   LOCALE_USER_DEFAULT,   &dispSheet);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
              hr   =   pDispSheets->Invoke(dispSheet,   IID_NULL,   LOCALE_USER_DEFAULT,   DISPATCH_PROPERTYGET   |   DISPATCH_METHOD,    
              &dpSheet,   &varRetSheet,   NULL,   NULL);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
               
              if   (   varRetSheet.vt   !=   VT_DISPATCH   )  
              goto   __exit;  
              else  
              pDispSheet   =   varRetSheet.pdispVal;  
              }  
               
              ///////////////////////////////////////////////////////////////////////////////////////////////////  
              IDispatch*   pDispRange;  
              if   (   pDispSheet   !=   NULL   )  
              {  
              LPOLESTR   lpCells   =   L"Cells";  
              DISPPARAMS   dpCells   =   {   NULL,   NULL,   0,   0   };  
              DISPID   dispCells;  
              VARIANT   varRetRange;  
               
              hr   =   pDispSheet->GetIDsOfNames(IID_NULL,   &lpCells,   1,   LOCALE_USER_DEFAULT,   &dispCells);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
              hr   =   pDispSheet->Invoke(dispCells,   IID_NULL,   LOCALE_USER_DEFAULT,     DISPATCH_PROPERTYGET   |   DISPATCH_METHOD,  
              &dpCells,   &varRetRange,   NULL,   NULL);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
               
              if   (   varRetRange.vt   !=   VT_DISPATCH   )  
              goto   __exit;  
              else  
              pDispRange   =   varRetRange.pdispVal;  
              }  
               
              ///////////////////////////////////////////////////////////////////////////////////////////////////  
              // put   value   in   Item   property  
              if   (   pDispRange   !=   NULL   )  
              {  
              LPOLESTR   lpRangeItem   =   L"Item";  
              DISPID   dispRangeItem;  
               
              hr   =   pDispRange->GetIDsOfNames(IID_NULL,   &lpRangeItem,   1,   LOCALE_USER_DEFAULT,   &dispRangeItem);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
               
              VARIANT*   vargRangeItem   =   new   VARIANT[3];  
               
              for   (   int   i   =   0;   i   <   3;   i   ++   )  
              VariantInit(&vargRangeItem[i]);  
               
              vargRangeItem[0].vt   =   VT_I4;  
              vargRangeItem[0].intVal   =   1;  
              vargRangeItem[1].vt   =   VT_I4;  
              vargRangeItem[1].intVal   =   1;  
              vargRangeItem[2].vt   =   VT_I4;  
              vargRangeItem[2].intVal   =   1;  
               
              DISPPARAMS   dpRangeItem   =   {NULL,   NULL,   0,   0};  
              dpRangeItem.cArgs   =   3;  
              dpRangeItem.rgvarg   =   vargRangeItem;  
              dpRangeItem.cNamedArgs   =   1;  
              DISPID   dispIDRangeItem   =   DISPID_PROPERTYPUT;  
              dpRangeItem.rgdispidNamedArgs   =   &dispIDRangeItem;  
               
              EXCEPINFO   except;  
               
              hr   =   pDispRange->Invoke(dispRangeItem,   IID_NULL,   LOCALE_USER_DEFAULT,   DISPATCH_PROPERTYPUT   |   DISPATCH_METHOD,  
              &dpRangeItem,   NULL,   &except,   NULL);  
               
              delete   []vargRangeItem;  
               
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
              }  
               
              ///////////////////////////////////////////////////////////////////////////////////////////////////  
              // Save  
              if   (   pDispBook   )  
              {  
              LPOLESTR   lpBookSave   =   L"Save";  
              DISPID   dispIDBookSave;  
               
              hr   =   pDispBook->GetIDsOfNames(IID_NULL,   &lpBookSave,   1,   LOCALE_USER_DEFAULT,   &dispIDBookSave);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
              DISPPARAMS   dispBookSave   =   {   NULL,   NULL,   0,   0   };  
               
              hr   =   pDispBook->Invoke(dispIDBookSave,   IID_NULL,   LOCALE_USER_DEFAULT,   DISPATCH_METHOD,   &dispBookSave,   NULL,   NULL,   NULL);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
              }  
               
              ///////////////////////////////////////////////////////////////////////////////////////////////  
              // quit  
              if   (   pDispExcel   )  
              {  
              LPOLESTR   lpExcelQuit   =   L"Quit";  
              DISPID   dispIDExcelQuit;  
               
              hr   =   pDispExcel->GetIDsOfNames(IID_NULL,   &lpExcelQuit,   1,   LOCALE_USER_DEFAULT,   &dispIDExcelQuit);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
               
              DISPPARAMS   dispExcelQuit   =   {   NULL,   NULL,   0,   0   };  
               
              hr   =   pDispExcel->Invoke(dispIDExcelQuit,   IID_NULL,   LOCALE_USER_DEFAULT,   DISPATCH_METHOD,   &dispExcelQuit,  
              NULL,   NULL,   NULL);  
              if   (   FAILED(hr)   )  
              goto   __exit;  
               
              }  
               
              __exit:  
              if   (   pDispRange   )  
              pDispRange->Release();  
               
              if   (   pDispSheet   )  
              pDispSheet->Release();  
               
              if   (   pDispSheets   )  
              pDispSheets->Release();  
               
              if   (   pDispBook   )  
              pDispBook->Release();  
               
              if   (   pDispBooks   )  
              pDispBooks->Release();  
               
              if   (   pDispExcel   )  
              pDispExcel->Release();  
               
              OleUninitialize();  
               
              return   0;  
              } 


            本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/vicozo/archive/2009/04/12/4067838.aspx

            posted @ 2011-02-15 08:58 wrh 閱讀(2451) | 評論 (0)編輯 收藏
            僅列出標題
            共25頁: 1 2 3 4 5 6 7 8 9 Last 

            導航

            <2009年11月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345

            統計

            • 隨筆 - 268
            • 文章 - 11
            • 評論 - 52
            • 引用 - 0

            常用鏈接

            留言簿(19)

            隨筆檔案

            文章檔案

            收藏夾

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            久久综合狠狠综合久久97色| 久久人人爽人人爽人人片AV不| 久久精品国产亚洲av瑜伽| 久久精品亚洲福利| 97久久婷婷五月综合色d啪蜜芽 | 久久久久国产一级毛片高清版| 成人国内精品久久久久影院VR| 亚洲欧洲精品成人久久曰影片| 99久久99久久久精品齐齐 | 亚洲精品无码久久一线| 久久免费国产精品一区二区| 怡红院日本一道日本久久| 国产精品中文久久久久久久| 四虎国产精品免费久久5151| 亚洲AV无码1区2区久久| 久久婷婷五月综合色99啪ak| 国产精品欧美久久久天天影视| 久久九九久精品国产免费直播| 狠狠人妻久久久久久综合| 久久精品无码专区免费东京热| 久久久久久久波多野结衣高潮| 国内精品久久久久久久影视麻豆| 久久99精品国产自在现线小黄鸭| 久久天天躁狠狠躁夜夜不卡 | 一本色综合网久久| 久久午夜福利电影| 久久婷婷久久一区二区三区| 国产高潮国产高潮久久久| 伊人久久久AV老熟妇色| 中文精品久久久久人妻| 久久免费99精品国产自在现线| 国产免费久久精品丫丫| 久久久久四虎国产精品| 精品久久久久久综合日本| 久久国产欧美日韩精品| 久久国产精品99精品国产| 久久男人Av资源网站无码软件 | 久久免费线看线看| 久久国产精品99久久久久久老狼 | 精品999久久久久久中文字幕| 国产精品无码久久综合|