買(mǎi)到蘋(píng)果新款MacBook Air后大家最想干的事是什么?體驗(yàn)一下Mac OS X?事實(shí)告訴我們有幾乎一半的人第一件想要做的事是裝一個(gè)微軟的Windows系統(tǒng),但問(wèn)題是新版的MBA已經(jīng)沒(méi)有光驅(qū)了,這可如何是好?其實(shí)只需一個(gè)4GB的U盤(pán)便能搞定了。
首先你要準(zhǔn)備的是一臺(tái)攜帶光驅(qū)的Windows 7電腦,另外需要準(zhǔn)備一張Windows 7系統(tǒng)光盤(pán),還需要一個(gè)至少4GB的U盤(pán)(閃存+讀卡器不可),再準(zhǔn)備大概1個(gè)小時(shí),恩,差不多就行了。
一,在U盤(pán)上安裝Windows 7的詳細(xì)步驟
1.先將U盤(pán)插到Windows 7電腦上,接著用管理員身份啟動(dòng)CMD命令提示符。
(單擊開(kāi)始-搜索區(qū)域鍵入“CMD”-對(duì)著CMD右鍵選擇以管理員身份運(yùn)行)
2.打開(kāi)Diskpart,這是因?yàn)槠綍r(shí)我們看到的系統(tǒng)都是字母盤(pán)符,我們需要讓其變?yōu)樽钤嫉臄?shù)字。
(在CMD中輸入“diskpart”,然后按回車(chē),切換為DISKPART>之后輸入“list disk”按回車(chē))
3.現(xiàn)在屏幕上應(yīng)該會(huì)顯示出所有電腦上正在使用的儲(chǔ)存設(shè)備,根據(jù)容量就能看出哪一個(gè)是我們插入的U盤(pán),3856 MB那個(gè)當(dāng)然就是4GB的U盤(pán),讓我們選中它吧。
(在CMD中輸入“select disk 3”,U盤(pán)所在的位置)
接下來(lái)運(yùn)行的每一個(gè)步驟都不能有錯(cuò),另外你還需要確保一件事,那就是在第3步中你已經(jīng)成功選擇了U盤(pán)所在位置,不然其他硬盤(pán)數(shù)據(jù)可就清空了哦。
(在CMD中輸入“clean”清空U盤(pán),輸入“create partition primary”創(chuàng)建主分區(qū),輸入“select partition 1”選擇分區(qū)1,輸入“active”將選中分區(qū)標(biāo)記為活動(dòng)分區(qū),輸入“format fs=ntfs”格式化U盤(pán)的分區(qū)1,輸入“assign”給所選分區(qū)分配一個(gè)驅(qū)動(dòng)器號(hào),輸入“exit”退出Diskpart)(輸入“assign”時(shí)U盤(pán)有可能斷開(kāi)重新連接,這很正常,請(qǐng)不要驚慌)
4.我們需要將Windows 7的安裝內(nèi)容裝進(jìn)U盤(pán)內(nèi),請(qǐng)將你的Windows 7光盤(pán)插入到光驅(qū)內(nèi)(本次案例光驅(qū)所在位置為E盤(pán),U盤(pán)所在位置為H盤(pán),諸君請(qǐng)自動(dòng)替換適用盤(pán)符)
(插入光盤(pán)后在CMD中輸入“e: cd boot”改為光盤(pán)啟動(dòng),輸入“bootsect.exe /nt60 h:”使其安裝至U盤(pán))
5.接下來(lái)電腦會(huì)將Windows 7的安裝內(nèi)容全部?jī)?chǔ)存到U盤(pán)內(nèi),這需要等待10分鐘左右,在那之后U盤(pán)就可以在任何電腦上安裝Windows 7了,不過(guò)首選當(dāng)然需要在BIOS中設(shè)置為U盤(pán)啟動(dòng)。好了,U盤(pán)安裝完畢,接著讓我們拿出U盤(pán),拿出等候已久的新款MacBook Air。
二,接著使用MacBook Air支持U盤(pán)啟動(dòng)
雖然新款的MacBook Air支持用U盤(pán)安裝軟件,但這并不代表其可以直接在Mac中安裝Windows 7,畢竟你可不能直接在Mac中運(yùn)行Setup.exe對(duì)吧。所以我們還需要一個(gè)軟件,那就是rEFIt引導(dǎo)工具,下載地址在這。下載完之后在Mac雙擊運(yùn)行rEFIt.mpkg即可安裝。
安裝完畢后,下次你重新啟動(dòng)MacBook Air的時(shí)候應(yīng)該就會(huì)出現(xiàn)如下畫(huà)面了,這樣就能選擇是使用Mac OS X啟動(dòng)還是其他系統(tǒng)啟動(dòng)了(當(dāng)然是Windows啦)。不過(guò)首先需要按住Option鍵在設(shè)置中將路徑改為U盤(pán)所在位置。
三,在MacBook Air上安裝Windows 7
要想在MacBook Air安裝Windows 7,我們還需要一個(gè)軟件,那就是Boot Camp Assistant,該軟件已經(jīng)在Mac OS X中自帶了,請(qǐng)各位同學(xué)自己尋找。運(yùn)行它之后,會(huì)提示你需要一個(gè)光盤(pán)驅(qū)動(dòng)器,忽略這條消息,點(diǎn)擊繼續(xù)。
下一步,你需要下載Windows支持的軟件,包括Boot Camp中的各種驅(qū)動(dòng)以及遠(yuǎn)程CD/DVD支持,都保存在一個(gè)文件夾中吧,接下來(lái)你會(huì)用到它的。
接下來(lái)Boot Camp Assistant會(huì)要求你縮小現(xiàn)在的Mac OS X上的分區(qū)大小以騰出空間安裝Windows,請(qǐng)謹(jǐn)慎選擇分區(qū)大小,畢竟兩個(gè)分區(qū)的文件格式將會(huì)改變。
現(xiàn)在你可以在MacBook Air上插入剛才制作好的Windows 7啟動(dòng)U盤(pán),然后重新啟動(dòng)MBA,按住Option鍵,確保路徑選擇是U盤(pán)啟動(dòng)。USB圖標(biāo)應(yīng)該很容易辨認(rèn)。
接下來(lái)就會(huì)進(jìn)入Windows 7的安裝過(guò)程,這一步相信大家都是熟門(mén)熟路了,只有一點(diǎn)需要注意的是,剛才通過(guò) Boot Camp Assistant劃分的分區(qū)是FAT32格式的,而Windows 7不能使用FAT32的分區(qū),所以選擇的時(shí)候需要重新格式化改為NTFS格式。
這是目前為止安裝Windows最快的電腦,新款MacBook Air一共花了才7分鐘就能將Windows 7安裝完畢,是不是覺(jué)得有點(diǎn)不可思議?進(jìn)入Windows 7后還有一件事需要干,那就是將剛才下載的Boot Camp中的Windows的驅(qū)動(dòng)程序安裝一遍,接著你就能使用Windows 7了!
Sun號(hào)稱開(kāi)源方面的領(lǐng)路人之一,其實(shí)Google擁有的開(kāi)源項(xiàng)目也是十分豐富的。除了開(kāi)發(fā)方面的項(xiàng)目外,也有MySQL等方面的內(nèi)容。在這其中還包括新出的Google Go!
Google是支持開(kāi)源運(yùn)動(dòng)的最大公司之一,它們現(xiàn)在總共發(fā)布有超過(guò)500個(gè)的開(kāi)源項(xiàng)目(大部分都是利用它們的API來(lái)完成),本文將列舉一些有趣的開(kāi)源項(xiàng)目,其中很可能有不少你不知道的哦。
Google開(kāi)源助Web2.0開(kāi)發(fā) 不排斥專有深入了解Google開(kāi)源框架GWT Google開(kāi)源新舉動(dòng):Linux桌面1.1版上線(.. Mozilla、Google開(kāi)源合作遭美國(guó)稅局質(zhì)疑微軟擔(dān)心Google和蘋(píng)果超越Windows 8 文本文件處理:
◆Google CRUSH (Custom Reporting Utilities for SHell)
CRUSH是為命令行或shell scripts處理特定文字?jǐn)?shù)據(jù)而制作的一系列工具,這里有指南。
C++庫(kù)和源代碼:
◆Google Breakpad
一個(gè)開(kāi)源的多平臺(tái)崩潰報(bào)告系統(tǒng)。
◆Google GFlags
Gflags是一個(gè)命令行標(biāo)記的處理庫(kù),它可以替代“getopt()”,其內(nèi)置對(duì)C++的支持比如string。指南在此。
◆Google Glog
Glog庫(kù)可執(zhí)行應(yīng)用級(jí)的登陸,提供基于C++式的登陸API,可用于Linux、BSD和Windows。指南見(jiàn)此。
◆Google PerfTools
這個(gè)工具可讓開(kāi)發(fā)創(chuàng)建更強(qiáng)大的應(yīng)用程序,特別是那些用C++模版開(kāi)發(fā)的多線程應(yīng)用程序,包括TCMalloc, heap-checker, heap-profiler 和cpu-profiler。指南見(jiàn)此還有這里。
◆Google Sparse Hash
非常節(jié)省內(nèi)存的hash-map。指南見(jiàn)此。
◆Omaha – Google Update
Omaha,也就是Google Update,它可以保證你的軟件隨時(shí)升級(jí)到最新版本,目前很多Windows下的Google軟件都是用Omaha升級(jí)的,包括Google Chrome和Google Earth,當(dāng)然你也可以用于自己的應(yīng)用程序。指南看這里還有這里。
◆Protocol Buffers
Protocol Buffers是一種可擴(kuò)展編碼序列數(shù)據(jù)的方式,Google在幾乎所有內(nèi)部RPC協(xié)議和文件格式都使用了Protocol Buffers。指南見(jiàn)此。它可以用于很多語(yǔ)言而且被一些IDE所支持,比如NetBeans。
互聯(lián)網(wǎng):
◆Google Code Pretiffy
這是一個(gè)Javascript模塊和CSS文件,它可以讓HTML頁(yè)面里的部分源碼高亮顯示,支持C/C++, Java, Python, Ruby, PHP, VisualBasic, AWK, Bash, SQL, HTML, XML, CSS, JavaScript, Makefiles和部分Perl,不支持Smalltalk和所有的CAML。例子見(jiàn)此。
◆SpriteMe – easy “CSS spirtes”
SpriteMe使你可以更輕松的創(chuàng)造CSS Sprites(俗稱雪碧……)就是把網(wǎng)站要用到的圖片都堆在一張圖片里,用CSS控制調(diào)用哪個(gè)區(qū)域。它有一個(gè)自己的官網(wǎng)在這里。
◆Redacisaurus
Reducisaurus是一個(gè)壓縮CSS和JS文件的網(wǎng)絡(luò)服務(wù),基于YUI壓縮算法,運(yùn)行于App Engine。
◆JaikuEngine
JaikuEngine是一個(gè)運(yùn)行于App Engine的微博系統(tǒng),由jaiku.com運(yùn)營(yíng)。要查看移動(dòng)客戶端的源碼可以看這里,這里還有介紹。
◆Selector Shell
Selector Shell是一個(gè)基于瀏覽器的測(cè)試工具,它可以讓你看到CSS在不同瀏覽器里的樣式,用Javascript寫(xiě)的,你可以在這里測(cè)試。
◆Google Feed Server
Google Feed Server是一個(gè)開(kāi)源Atom發(fā)布協(xié)議服務(wù),基于Apache Abdera框架,允許開(kāi)發(fā)者快速為當(dāng)前數(shù)據(jù)源(比如數(shù)據(jù)庫(kù))配置feed。指南見(jiàn)這里和這里。
◆Melange, the Spice of Creation
這個(gè)項(xiàng)目的目標(biāo)是創(chuàng)建出一個(gè)適合開(kāi)源貢獻(xiàn)流程的框架,比如Google Summer of Code TM (GSoC)項(xiàng)目。使用這個(gè)框架你就可以用Google App Engine來(lái)運(yùn)行Google Summer of Code項(xiàng)目,和其它類(lèi)似項(xiàng)目比如Google Highly Open Participation TM Contest和GHOP。指南見(jiàn)此。
◆NameBench
它可以查找最快的DNS服務(wù)器給你的電腦用,在Mac OS X、Windows和UNIX系統(tǒng)下都有命令行也有用戶界面可以幫你測(cè)試,這是Google工程師用20%自由時(shí)間寫(xiě)出來(lái)的。
◆Rat Proxy
一個(gè)半自動(dòng)化的大型被動(dòng)網(wǎng)絡(luò)應(yīng)用安全審查工具,專為精確的探測(cè)而優(yōu)化,文檔在此。
◆TopDraw
Top Draw是一個(gè)圖形生成程序,使用簡(jiǎn)單的文字腳本,基于JavaScript編程語(yǔ)言,Top Draw可以創(chuàng)造出非常復(fù)雜和有趣的圖形。支持Mac OS 10.5以上系統(tǒng),使用XCode開(kāi)發(fā)。
◆etherpad
開(kāi)源的EtherPad,這是一個(gè)基于網(wǎng)絡(luò)的實(shí)時(shí)合作文檔編輯器,這個(gè)項(xiàng)目主要是為了演示代碼而開(kāi)發(fā),幫助那些想在自己服務(wù)器部署Etherpad的人使用,這里有如何安裝的指南。EtherPad使用JavaScript、Java和Comet服務(wù)器來(lái)建造實(shí)時(shí)協(xié)作服務(wù)。
◆Chromium
Chromium是開(kāi)源版的Chrome瀏覽器,Chromium的目標(biāo)是建立一個(gè)新一代的強(qiáng)大網(wǎng)絡(luò)應(yīng)用程序,它與Chrome有很多不同之處。這里有指導(dǎo)如何在Linux上編譯Chromium。
◆V8 Google’s open source JavaScript engine
V8是Google的開(kāi)源JavaScript引擎,用C++寫(xiě)成,用于Chrome瀏覽器之上。V8使用ECMAScript的ECMA-262第三版可運(yùn)行于Windows XP、vista、Mac OS 10.5和使用IA-32或ARM處理器的Linux。V8可獨(dú)立運(yùn)行也可嵌入到任何C++程序里使用,這里有指南。
◆Chromium OS
Chromium OS是開(kāi)源版的Chrome OS操作系統(tǒng),提供快速、簡(jiǎn)單而安全的網(wǎng)絡(luò)體驗(yàn),源碼在此。
◆Android
Android是第一個(gè)免費(fèi)、開(kāi)源而且可完全自定義的移動(dòng)平臺(tái),提供完整的堆棧:一個(gè)操作系統(tǒng)、中間件和重要的一用應(yīng)用,它包含豐富的API可以讓第三方開(kāi)發(fā)者開(kāi)發(fā)出強(qiáng)大的應(yīng)用程序。
MySQL工具:
◆Google MySQL Tools
各種管理、維護(hù)和改進(jìn)MySQL數(shù)據(jù)庫(kù)性能的工具,由Google編寫(xiě),包括:
◆mypgrep.py:一個(gè)類(lèi)似pgrep的工具來(lái)管理MySQL連接
compact_innodb.py:可導(dǎo)出和重載所有表格的密集型innodb數(shù)據(jù)文件
◆Google mMAIM
mMAIM的目標(biāo)是對(duì)MySQL的監(jiān)控和分析更簡(jiǎn)單,且可以和任何環(huán)境整合使用。它可顯示主/從同步狀態(tài),一些性能狀態(tài),可以返回大量“show”命令的狀態(tài)等等。
其它:
◆Stressful Application Test (stressapptest)
Stressful Application Test試圖讓來(lái)自處理器和I/O到內(nèi)存的數(shù)據(jù)盡量隨機(jī)化,以創(chuàng)造出模擬現(xiàn)實(shí)的環(huán)境來(lái)測(cè)試現(xiàn)在的硬件設(shè)備是否穩(wěn)定,Google就在使用它,現(xiàn)在是Apache 2.0許可,這里有介紹、安裝向?qū)Ш椭改稀?/p>
◆Pop and IMAP Troubleshooter
它用于診斷并解決客戶端到郵件服務(wù)器的連接問(wèn)題。
◆OpenDuckBill
Openduckbill是一個(gè)Linux下簡(jiǎn)單的命令行備份工具,可用于監(jiān)視文件/目錄在有變化后是否標(biāo)記為備份,并傳輸這些變化到本地備份目錄、遠(yuǎn)程N(yùn)FS導(dǎo)出分卷或是用rsync命令導(dǎo)出到遠(yuǎn)程SSH服務(wù)器。見(jiàn)安裝向?qū)А?/p>
◆ZXing
ZXing(發(fā)音類(lèi)似Zebra crossing)是Java的開(kāi)源多格式1D/2D條碼圖像處理庫(kù),目的是使用內(nèi)置在手機(jī)上的攝像頭拍照并對(duì)條碼進(jìn)行解碼,而不必與服務(wù)器通訊,它被用于Android系統(tǒng)。這里有向?qū)Ш椭С值脑O(shè)備列表。
◆Tesseract OCR Engine
Tesseract OCR引擎是1995年UNLV Accuracy測(cè)試的前三名之一,在1995和2006年之間它的進(jìn)展不大,但依然是當(dāng)前精度最高的OCR引擎。這個(gè)源碼可讀取二進(jìn)制、灰階或彩色圖片并輸出文字,內(nèi)置一個(gè)TIFF閱讀器可讀取非壓縮的TIFF文件,增加libtiff后也可讀取壓縮圖片。指南和問(wèn)答。
◆Neatx – Open Source NX server
Neatx是一個(gè)開(kāi)源NX服務(wù),類(lèi)似NoMachine公司商業(yè)的NX服務(wù)。NX協(xié)議比VNX更強(qiáng)大,它們的區(qū)別主要在:
NX是X11客戶端所以不會(huì)發(fā)送位圖
NX可兼容X、VNC和Windows版的Remote Desktop
NX可緩存數(shù)據(jù)
NX安裝簡(jiǎn)單
另外一個(gè)可選的項(xiàng)目可以看看Google的FreeNx。
◆PSVM
它是這個(gè)文件的代碼,這是一個(gè)SVM的“支持所有核心”的版本,可多機(jī)并行運(yùn)行,實(shí)例見(jiàn)此。
◆Google GO
Google開(kāi)發(fā)的新編程語(yǔ)言。
◆The Google Collections Library for Java
這是一系列與Java 5以及更高版本有關(guān)的庫(kù),Google花錢(qián)給買(mǎi)過(guò)來(lái)了。
◆Google styleguIDE
每個(gè)主流的開(kāi)源項(xiàng)目都有它自己的向?qū)问剑热缫幌盗械难菔敬a。如果這些代碼都按照“Style”的形式來(lái)演示,會(huì)更友好。
http://www.oulan.com/w/2009/12/29/google-opensource-project/
HTML5 canvas has changed the way javascript used to be. We're now able to achieve complex animation however we do need a powerful browser to interpret it. The following is 8 new HTML5 + Javascript animation effect you probably have not seen before! Play with each of them, you'll be blown away by the creativity and robustness of HTML5 canvas!
I like Tunnelers and Bomomo the most! You've to try Bomomo, it's fun!
http://blog.csdn.net/lights_joy/
lights@hb165.com
本文適用于
SDL-1.2.13
vs2008
Windows XP
歡迎轉(zhuǎn)載,但請(qǐng)保留作者信息
SDL的設(shè)計(jì)并沒(méi)有考慮到要和MFC相結(jié)合,但是既然它要在windows的系統(tǒng)上運(yùn)行,必然需要使用Windows提供的API。為了在MFC SDI中使用SDL,首先想到的就是替換SDL創(chuàng)建的窗口,改為使用MFC提供的窗口。
想想在Windows下要?jiǎng)?chuàng)建窗口需要使用的API必然是CreateWindow,在SDL代碼中搜,很容易發(fā)現(xiàn)了這樣一段代碼:
int DIB_CreateWindow(_THIS)
{
char *windowid = SDL_getenv("SDL_WINDOWID");
SDL_RegisterApp(NULL, 0, 0);
SDL_windowid = (windowid != NULL);
if ( SDL_windowid ) {
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
/* wince 2.1 does not have strtol */
wchar_t *windowid_t = SDL_malloc((SDL_strlen(windowid) + 1) * sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, windowid, -1, windowid_t, SDL_strlen(windowid) + 1);
SDL_Window = (HWND)wcstol(windowid_t, NULL, 0);
SDL_free(windowid_t);
#else
SDL_Window = (HWND)SDL_strtoull(windowid, NULL, 0);
#endif
if ( SDL_Window == NULL ) {
SDL_SetError("Couldn't get user specified window");
return(-1);
}
/* DJM: we want all event's for the user specified
window to be handled by SDL.
*/
userWindowProc = (WNDPROCTYPE)GetWindowLongPtr(SDL_Window, GWLP_WNDPROC);
SetWindowLongPtr(SDL_Window, GWLP_WNDPROC, (LONG_PTR)WinMessage);
} else {
SDL_Window = CreateWindow(SDL_Appname, SDL_Appname,
(WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX),
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, SDL_Instance, NULL);
if ( SDL_Window == NULL ) {
SDL_SetError("Couldn't create window");
return(-1);
}
ShowWindow(SDL_Window, SW_HIDE);
}
/* JC 14 Mar 2006
Flush the message loop or this can cause big problems later
Especially if the user decides to use dialog boxes or assert()!
*/
WIN_FlushMessageQueue();
return(0);
}
注意到前面的if條件判斷使用了SDL_windowid,如果這個(gè)變量不為0,那么SDL是不會(huì)創(chuàng)建新窗口的!而這個(gè)值直接來(lái)自于SDL_WINDOWID這個(gè)環(huán)境變量!以此推斷,只要在調(diào)用SDL_Init之前設(shè)置好SDL_WINDOWID這個(gè)環(huán)境變量,那么SDL將可以使用我們提供的窗口。
下面修改SDL提供的testwin示例,使之在MFC SDI環(huán)境下運(yùn)行。
1.1 工程創(chuàng)建
直接使用VS2008的向?qū)梢粋€(gè)叫sdi_sdl的MFC工程,選擇SDI類(lèi)型。
1.2 拋棄SDLmain.lib
在SDL提供的測(cè)試用例中,都要使用SDLmain.lib,這個(gè)lib文件實(shí)現(xiàn)了Winmain和main這兩個(gè)入口函數(shù),在這兩個(gè)函數(shù)中進(jìn)行了一些SDL的初始化工作。而在MFC下,我們不需要自己寫(xiě)WinMain,因此直接拋棄SDLmain.lib,將相關(guān)的代碼轉(zhuǎn)移到Csdi_sdlView的OnCreate函數(shù)中。之所以選擇Csdi_sdlView::OnCreate是因?yàn)榇藭r(shí)窗口已經(jīng)創(chuàng)建,可以取到這個(gè)窗口的Handle,從而可以在SDL初始化之前設(shè)置好Window id。
int Csdi_sdlView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
char variable[256];
sprintf(variable, "SDL_WINDOWID=0x%lx", this->GetSafeHwnd());
SDL_putenv(variable);
SDL_WinMain(AfxGetApp()->m_hInstance, NULL, AfxGetApp()->m_lpCmdLine, SW_MAXIMIZE);
return 0;
}
1.3 SDL_WinMain
這個(gè)函數(shù)來(lái)源于SDLmain中的WinMain函數(shù),只是刪除了一些不必要的代碼:
/* This is where execution begins [windowed apps] */
int Csdi_sdlView::SDL_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
{
HINSTANCE handle;
char **argv;
int argc;
char *cmdline;
char *bufp;
size_t nLen;
/* Start up DDHELP.EXE before opening any files, so DDHELP doesn't
keep them open. This is a hack.. hopefully it will be fixed
someday. DDHELP.EXE starts up the first time DDRAW.DLL is loaded.
*/
handle = LoadLibrary(TEXT("DDRAW.DLL"));
if ( handle != NULL ) {
FreeLibrary(handle);
}
/* Grab the command line */
bufp = GetCommandLine();
nLen = SDL_strlen(bufp)+1;
cmdline = SDL_stack_alloc(char, nLen);
SDL_strlcpy(cmdline, bufp, nLen);
/* Parse it into argv and argc */
argc = ParseCommandLine(cmdline, NULL);
argv = SDL_stack_alloc(char*, argc+1);
ParseCommandLine(cmdline, argv);
/* Run the main program (after a little SDL initialization) */
SDL_PreMain(argc, argv);
/* Hush little compiler, don't you cry... */
return 0;
}
1.4 SDL_PreMain
這個(gè)函數(shù)來(lái)源于sdlmain.lib中的main函數(shù):
/* This is where execution begins [console apps] */
int Csdi_sdlView::SDL_PreMain(int argc, char *argv[])
{
size_t n;
char *bufp, *appname;
int status;
/* Get the class name from argv[0] */
appname = argv[0];
if ( (bufp=SDL_strrchr(argv[0], '\\')) != NULL ) {
appname = bufp+1;
} else
if ( (bufp=SDL_strrchr(argv[0], '/')) != NULL ) {
appname = bufp+1;
}
if ( (bufp=SDL_strrchr(appname, '.')) == NULL )
n = SDL_strlen(appname);
else
n = (bufp-appname);
bufp = SDL_stack_alloc(char, n+1);
SDL_strlcpy(bufp, appname, n+1);
appname = bufp;
///* Load SDL dynamic link library */
//if ( SDL_Init(SDL_INIT_NOPARACHUTE) < 0 ) {
// ShowError("WinMain() error", SDL_GetError());
// return(FALSE);
//}
/* Sam:
We still need to pass in the application handle so that
DirectInput will initialize properly when SDL_RegisterApp()
is called later in the video initialization.
*/
SDL_SetModuleHandle(GetModuleHandle(NULL));
/* Run the application main() code */
status = SDL_main(argc, argv);
/* Hush little compiler, don't you cry... */
return 0;
}
1.5 SDL_main
這個(gè)函數(shù)來(lái)自于testwin示例中的main函數(shù),只是在末尾刪除了SDL_Quit這樣的退出語(yǔ)句。
int Csdi_sdlView::SDL_main(int argc, char *argv[])
{
SDL_Surface *screen;
/* Options */
int speedy, flip, nofade;
int delay;
int w, h;
int desired_bpp;
Uint32 video_flags;
/* Set default options and check command-line */
speedy = 0;
flip = 0;
nofade = 0;
delay = 1;
RECT rc;
this->GetWindowRect(&rc);
w = rc.right;
h = rc.bottom;
desired_bpp = 0;
video_flags = 0;
if ( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0 ) {
ShowError("Couldn't initialize SDL", SDL_GetError());
return(1);
}
/* Initialize the display */
screen = SDL_SetVideoMode(w, h, desired_bpp, video_flags);
if ( screen == NULL ) {
ShowError("Couldn't set %dx%dx%d video mode: %s\n", "");
return (1);
}
DrawPict(screen, argv[1], speedy, flip, nofade);
// SDL_Delay(delay*1000);
// SDL_Quit();
return(0);
}
至此,這個(gè)程序就可以正常運(yùn)行了,但是它的大小還不能隨主窗口的變化而變化。為此還需要響應(yīng)WM_SIZE:
void Csdi_sdlView::OnSize(UINT nType, int cx, int cy)
{
SDL_Surface *screen;
screen = SDL_SetVideoMode(cx, cy, 0, 0);
DrawPict(screen, NULL, 0, 0, 0);
}
1.6 SDL_Quit
在程序退出的時(shí)候,需要調(diào)用SDL_Quit進(jìn)行一些清理的工作,原來(lái)想將這個(gè)工作放在Cview::OnDestroy中完成,但是發(fā)現(xiàn)這樣有很多的內(nèi)存泄漏。最后將其放在Csdi_sdlApp:ExitInstance中完成:
BOOL Csdi_sdlApp::ExitInstance()
{
SDL_Quit();
return TRUE;
}
即便是這樣,仍然有一處內(nèi)存泄漏,原因不明:
Detected memory leaks!
Dumping objects ->
{98} normal block at 0x003D37C0, 21 bytes long.
Data: <0x40784 OWID 0x4> 30 78 34 30 37 38 34 00 4F 57 49 44 00 30 78 34
Object dump complete.
本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/lights_joy/archive/2009/04/04/4049123.aspx
出處:http://www.zixundao.com/thread-1672-1-4.html
SDL是一種既是開(kāi)源的,也是跨平臺(tái)的多媒體開(kāi)發(fā)包,在各種平臺(tái)上應(yīng)用很廣,經(jīng)常和FFMPEG等解碼器同時(shí)使用。對(duì)于在windows mobile等缺乏通用播放器的平臺(tái)來(lái)說(shuō),是一種很好的選擇。
網(wǎng)上很多代碼,介紹SDL的用法,主要需要注意的情況有3種:
第一: 綁定播放窗口問(wèn)題:
char sdl_var[128];
sprintf(sdl_var, "SDL_WINDOWID=0x%lx", m_hWnd );//主窗口句柄
SDL_putenv(sdl_var); char *myvalue = SDL_getenv("SDL_WINDOWID");
這端代碼,需要放在播放窗口初始化之前,否則,容易造成全屏。
第二:SDL本身響應(yīng)窗口菜單的問(wèn)題
SDL官方提供以下代碼響應(yīng)窗口菜單:
while(1) {
SDL_WaitEvent(&event);
{
case
}
}
但也可以我們?cè)诔绦蚶锩嬷匦鲁跏蓟@示新菜單,就可以不用這種辦法,直接用我們自己的程序響應(yīng)菜單。
第三:關(guān)于縮放:
網(wǎng)上很多代碼容易誤導(dǎo)人。
把SDL_SetVideoMode和SDL_CreateYUVOverlay的參數(shù)都設(shè)置成一樣的,這種辦法導(dǎo)致屏幕圖象縮放顯示不正常,正確的方法應(yīng)該是:SDL_SetVideoMode的參數(shù)顯示新的顯示大小,而SDL_CreateYUVOverlay(只需建立一次,SDL_SetVideoMode更換時(shí),不需要跟著更換)的參數(shù)則是圖片的原始大小 。
而在SDL_DisplayYUVOverlay中用到的SDL_Rect,大小則和SDL_SetVideoMode一樣,也就是新的顯示大小。
本文原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處和作者,謝謝。
作者:藍(lán)梅居士
出處:http://www.zixundao.com/thread-1672-1-4.html
本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/baishuren/archive/2009/10/13/4665153.aspx
sdl是開(kāi)源的跨平臺(tái)多媒體開(kāi)發(fā)包, 主要用在快速的視頻格式轉(zhuǎn)換和顯示,以及封裝了鍵盤(pán)/鼠標(biāo)/手機(jī)按鍵/觸屏等各個(gè)平臺(tái)的用戶交互響應(yīng),廣泛應(yīng)用在游戲,多媒體播放器等應(yīng)用中。目前支持windows,linux, wince,mac os,非正式地支持symbian os。
一般視頻解碼器輸出圖像的是yuv420格式,而屏幕顯示大都是rgb42規(guī)格。 mobile上畫(huà)面顯示一般經(jīng)由decode>>yuv2rgb>>scale>>directDraw直接寫(xiě)屏。 采用SDL可以加速這一過(guò)程,且更方便響應(yīng)全屏縮放等用戶操作。
下面介紹mobile上用sdl來(lái)加速顯示視頻的全過(guò)程。
1. 把主對(duì)話框的窗口句柄傳給顯示類(lèi)。
2. 初始化sdl,設(shè)置顯示視頻模式
SDL_Surface *screen;
SDL_Rect sdl_rect;
SDL_Overlay *bmp;
bool InitSdl()
{
char sdl_var[64];
sprintf(sdl_var, "SDL_WINDOWID=0x%lx", m_hWnd);//主窗口句柄
SDL_putenv(sdl_var);
char *myvalue = SDL_getenv("SDL_WINDOWID");
atexit(SDL_Quit);
//根據(jù)解碼后的視頻尺寸來(lái)初始化sdl
screen = SDL_SetVideoMode(ImageWidth, ImageHeight, 0,SDL_ANYFORMAT|SDL_RESIZABLE|SDL_DOUBLEBUF|SDL_HWSURFACE);//注意用到的參數(shù)flags
if(!screen)
{
TRACE(L"error SDL SetVideoMode!");
return false;
}
bmp = SDL_CreateYUVOverlay(ImageWidth, ImageHeight, ,SDL_YV12_OVERLAY,screen);
if(!bmp)
{
TRACE(L"error SDL CreateYUVOverlay!");
return false;
}
return TRUE;
}
3. 在屏幕上繪制像素
void SdlDisplayFrame()
{
AVPicture pict;
pict.data[0] = bmp->pixels[0];
pict.data[1] = bmp->pixels[2];
pict.data[2] = bmp->pixels[1];
pict.linesize[0] = bmp->pitches[0];
pict.linesize[1] = bmp->pitches[2];
pict.linesize[2] = bmp->pitches[1];
//pFrame是ffmpeg存放解碼后yuv數(shù)據(jù)的struct
img_convert(&pict, PIX_FMT_YUV420P, (AVPicture *)pFrame, pContext->pix_fmt, iImage_Width, iImage_Height);
SDL_LockSurface(screen);
SDL_LockYUVOverlay(bmp);
{
sdl_rect.x = 0;
sdl_rect.y = 0;
sdl_rect.w = m_width; //pContext->width;
sdl_rect.h = m_height; //pContext->height;
}
SDL_UnlockYUVOverlay(bmp);
SDL_UnlockSurface(screen);
SDL_DisplayYUVOverlay(bmp, &sdl_rect);//顯示圖片到屏幕
}
4. 事件輪詢和按鍵響應(yīng)
void SdlEvent()
{
SDL_Event event;
while ( SDL_PollEvent(&event))
{
TRACE(L"========SDL VIDEORESIZE EVENT START");
switch (event.type)
{
case SDL_VIDEORESIZE:
// 響應(yīng)圖像縮放事件
if (m_iImage_Width == Image_Primary_Width && m_iImage_Height == Image_Primary_Height)
{
TRACE(L"event.resize.w = %d",event.resize.w);
TRACE(L"event.resize.h = %d",event.resize.h);
m_width = event.resize.w;
m_height = event.resize.h;
SDL_FreeYUVOverlay(bmp);
bmp = NULL;
SDL_FreeSurface(screen);
screen = NULL;
if (!IsQcif)
{
m_height = m_height * 2;
m_width = m_width * 2;
screen = SDL_SetVideoMode(MobileFullScreenWidth,MobileFullScreenHeight,
0,SDL_ANYFORMAT|SDL_RESIZABLE|SDL_DOUBLEBUF|SDL_HWSURFACE);
if (screen == NULL)
{
TRACE(L"screen= NULL");
return;
}
bmp = SDL_CreateYUVOverlay(MobileFullScreenWidth,MobileFullScreenHeight,
SDL_YV12_OVERLAY,screen);
if (bmp == NULL)
{
TRACE(L"bm1 = NULL");
return;
}
IsQcif = true;
}
else
{
screen = SDL_SetVideoMode(Image_Primary_Width,Image_Primary_Height,
0,SDL_ANYFORMAT|SDL_RESIZABLE|SDL_DOUBLEBUF|SDL_HWSURFACE);
if (screen == NULL)
{
TRACE(L"screen1= NULL");
return;
}
bmp = SDL_CreateYUVOverlay(Image_Primary_Width,Image_Primary_Height,
SDL_YV12_OVERLAY,screen);
if (bmp == NULL)
{
TRACE(L"bm1 = NULL");
return;
}
IsQcif = false;
}
break;
}
case SDL_MOUSEBUTTONDOWN:
//響應(yīng)觸屏筆點(diǎn)擊事件
break;
}
case SDL_QUIT:
//響應(yīng)退出事件
break;
default:
break;
}
}
}
本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/lius1984/archive/2009/08/07/4420786.aspx
讓游戲開(kāi)發(fā)者不必為每一品牌的硬件來(lái)寫(xiě)不同的驅(qū)動(dòng)程序,也降低用戶安裝及設(shè)置硬件的復(fù)雜度。這樣說(shuō)是不是有點(diǎn)不太明白,其實(shí)從字面意義上說(shuō),Direct就是直接
的意思,而后邊的X則代表了很多的意思,從這一點(diǎn)上我們就可以看出 DirectX的出現(xiàn)就是為了為眾多軟件提供直接服務(wù)的。
DirectX是由很多API組成的,按照性質(zhì)分類(lèi),可以分為四大部分,顯示部分、聲音部分、輸入部分和網(wǎng)絡(luò)部分。
顯示部分擔(dān)任圖形處理的關(guān)鍵,分為Direct Draw(DDraw)和Direct 3D(D3D),前者主要負(fù)責(zé)2D圖像加速。它包括很多方面:我們播放mpg、DVD電影、看圖、玩小游戲等等都是用的DDraw,你可以把它理解成所有劃線的部分都是用的DDraw。后者則主要負(fù)責(zé)3D效果的顯示,比如CS中的場(chǎng)景和人物、FIFA中的人物等等,都是使用了DirectX的Direct 3D。
聲音部分中最主要的API是DirectSound,除了播放聲音和處理混音之外,還加強(qiáng)了3d音效,并提供了錄音功能。我們前面所舉的聲卡兼容的例子,就是利用了DirectSound來(lái)解決的。
輸入部分Direct Input可以支持很多的游戲輸入設(shè)備,它能夠讓這些設(shè)備充分發(fā)揮最佳狀態(tài)和全部功能。除了鍵盤(pán)和鼠標(biāo)之外還可以連接手柄、搖桿、模擬器等。
網(wǎng)絡(luò)部分DirectPlay主要就是為了具有網(wǎng)絡(luò)功能游戲而開(kāi)發(fā)的,提供了多種連接方式,TPC/IP,IPX,Modem,串口等等,讓玩家可以用各種連網(wǎng)方式來(lái)進(jìn)行對(duì)戰(zhàn),此外也提供網(wǎng)絡(luò)對(duì)話功能及保密措施。
DirectX并不是一個(gè)單純的圖形API,它是由微軟公司開(kāi)發(fā)的用途廣泛的API,它包含有Direct Graphics(Direct 3D+Direct Draw)、Direct Input、Direct Play、Direct Sound、Direct Show、Direct Setup、Direct Media Objects等多個(gè)組件,它提供了一整套的多媒體接口方案。只是其在3D圖形方面的優(yōu)秀表現(xiàn),讓它的其它方面顯得暗淡無(wú)光。DirectX開(kāi)發(fā)之初是為了彌補(bǔ)Windows 3.1系統(tǒng)對(duì)圖形、聲音處理能力的不足,而今已發(fā)展成為對(duì)整個(gè)多媒體系統(tǒng)的各個(gè)方面都有決定性影響的接口。 DirectX 是一組低級(jí)“應(yīng)用程序編程接口 (API)”,可為 Windows 程序提供高性能的硬件加速多媒體支持。Windows 支持 DirectX 8.0,它能增強(qiáng)計(jì)算機(jī)的多媒體功能。使用 DirectX 可訪問(wèn)顯卡與聲卡的功能,從而使程序可提供逼真的三維 (3D) 圖形與令人如醉如癡的音樂(lè)與聲音效果。 DirectX 使程序能夠輕松確定計(jì)算機(jī)的硬件性能,然后設(shè)置與之匹配的程序參數(shù)。該程序使得多媒體軟件程序能夠在基于 Windows 的具有 DirectX 兼容硬件與驅(qū)動(dòng)程序的計(jì)算機(jī)上運(yùn)行,同時(shí)可確保多媒體程序能夠充分利用高性能硬件。 DirectX 包含一組 API,通過(guò)它能訪問(wèn)高性能硬件的高級(jí)功能,如三維圖形加速芯片和聲卡。這些 API 控制低級(jí)功能(其中包括二維 (2D) 圖形加速)、支持輸入設(shè)備(如游戲桿、鍵盤(pán)和鼠標(biāo))并控制著混音及聲音輸出。構(gòu)成 DirectX 的下列組件支持低級(jí)功能: Microsoft DirectDraw Microsoft DirectDraw API 支持快速訪問(wèn)計(jì)算機(jī)視頻適配器的加速硬件功能。它支持在所有視頻適配器上顯示圖形的標(biāo)準(zhǔn)方法,并且使用加速驅(qū)動(dòng)程序時(shí)可以更快更直接地訪問(wèn)。DirectDraw 為程序(如游戲和二維圖形程序包)以及 Windows 系統(tǒng)組件(如數(shù)字視頻編解碼器)提供了一種獨(dú)立于設(shè)備之外的方法來(lái)訪問(wèn)特定顯示設(shè)備的功能,而不要求用戶提供設(shè)備功能的其它信息。
Microsoft Direct3D Microsoft Direct3D API (Direct3D) :為大多數(shù)新視頻適配器內(nèi)置的 3-D 調(diào)色功能提供界面。Direct3D 是一種低級(jí)的 3-D API,它為軟件程序提供一種獨(dú)立于設(shè)備之外的方法以便與加速器硬件進(jìn)行有效而強(qiáng)大的通信。Direct3D 包含專用 CPU 指令集支持,從而可為新型計(jì)算機(jī)提供進(jìn)一步加速支持。
Microsoft DirectSound Microsoft DirectSound API :為程序和音頻適配器的混音、聲音播放和聲音捕獲功能之間提供了鏈接。DirectSound 為多媒體軟件程序提供低延遲混合、硬件加速以及直接訪問(wèn)聲音設(shè)備等功能。維護(hù)與現(xiàn)有設(shè)備驅(qū)動(dòng)程序的兼容性時(shí)提供該功能。
Microsoft DirectMusic Microsoft DirectMusic API :是 DirectX 的交互式音頻組件。與捕獲和播放數(shù)字聲音樣本的 DirectSound API 不同,DirectMusic 處理數(shù)字音頻以及基于消息的音樂(lè)數(shù)據(jù),這些數(shù)據(jù)是通過(guò)聲卡或其內(nèi)置的軟件合成器轉(zhuǎn)換成數(shù)字音頻的。DirectMusic API 支持以“樂(lè)器數(shù)字界面 (MIDI)”格式進(jìn)行輸入,也支持壓縮與未壓縮的數(shù)字音頻格式。DirectMusic 為軟件開(kāi)發(fā)人員提供了創(chuàng)建令人陶醉的動(dòng)態(tài)音軌的能力,以響應(yīng)軟件環(huán)境中的各種更改,而不只是用戶直接輸入更改。
Microsoft DirectInput Microsoft DirectInput API :為游戲提供高級(jí)輸入功能并能處理游戲桿以及包括鼠標(biāo)、鍵盤(pán)和強(qiáng)力反饋游戲控制器在內(nèi)的其它相關(guān)設(shè)備的輸入。
Microsoft DirectPlay Microsoft DirectPlay API: 支持通過(guò)調(diào)制解調(diào)器、Internet 或局域網(wǎng)連接游戲。DirectPlay 簡(jiǎn)化了對(duì)通信服務(wù)的訪問(wèn),并提供了一種能夠使游戲彼此通信的方法而不受協(xié)議或聯(lián)機(jī)服務(wù)的限制。DirectPlay 提供了多種游說(shuō)服務(wù),可簡(jiǎn)化多媒體播放器游戲的初始化,同時(shí)還支持可靠的通信協(xié)議以確保重要游戲數(shù)據(jù)在網(wǎng)絡(luò)上不會(huì)丟失。DirectPlay 8.0 的新功能即支持通過(guò)網(wǎng)絡(luò)進(jìn)行語(yǔ)音通信,從而可大大提高基于多媒體播放器小組的游戲的娛樂(lè)性,同時(shí)該組件還通過(guò)提供與玩游戲的其他人對(duì)話的功能而使團(tuán)體游戲更具魅力。
Microsoft DirectShow Microsoft DirectShow API: 提供了可在您的計(jì)算機(jī)與 Internet 服務(wù)器上進(jìn)行高品質(zhì)捕獲與回放多媒體文件的功能。DirectShow 支持各種音頻與視頻格式,包括“高級(jí)流式格式 (ASF)”、“音頻-視頻交錯(cuò) (AVI)”、“數(shù)字視頻 (DV)”、“動(dòng)畫(huà)專家組 (MPEG)”、“MPEG 音頻層 3 (MP3)”、 “Windows 媒體音頻/視頻 (WMA/WMV)”以及 WAV 文件。DirectShow 還具有視頻捕獲、DVD 回放、視頻編輯與混合、硬件加速視頻解碼以及調(diào)諧廣播模擬與數(shù)字電視信號(hào)等功能。
歐幾里德算法是計(jì)算兩個(gè)數(shù)最大公約數(shù)的傳統(tǒng)算法,他無(wú)論從理論還是從效率上都是很好的。但是他有一個(gè)致命的缺陷,這個(gè)缺陷只有在大素?cái)?shù)時(shí)才會(huì)顯現(xiàn)出來(lái)。
考慮現(xiàn)在的硬件平臺(tái),一般整數(shù)最多也就是64位,對(duì)于這樣的整數(shù),計(jì)算兩個(gè)數(shù)之間的模是很簡(jiǎn)單的。對(duì)于字長(zhǎng)為32位的平臺(tái),計(jì)算兩個(gè)不超過(guò)32位的整數(shù)的模,只需要一個(gè)指令周期,而計(jì)算64位以下的整數(shù)模,也不過(guò)幾個(gè)周期而已。但是對(duì)于更大的素?cái)?shù),這樣的計(jì)算過(guò)程就不得不由用戶來(lái)設(shè)計(jì),為了計(jì)算兩個(gè)超過(guò)64位的整數(shù)的模,用戶也許不得不采用類(lèi)似于多位數(shù)除法手算過(guò)程中的試商法,這個(gè)過(guò)程不但復(fù)雜,而且消耗了很多CPU時(shí)間。對(duì)于現(xiàn)代密碼算法,要求計(jì)算128位以上的素?cái)?shù)的情況比比皆是,設(shè)計(jì)這樣的程序迫切希望能夠拋棄除法和取模。
Stein算法由J. Stein 1961年提出,這個(gè)方法也是計(jì)算兩個(gè)數(shù)的最大公約數(shù)。和歐幾里德算法 算法不同的是,Stein算法只有整數(shù)的移位和加減法,這對(duì)于程序設(shè)計(jì)者是一個(gè)福音。
為了說(shuō)明Stein算法的正確性,首先必須注意到以下結(jié)論:
有了上述規(guī)律就可以給出Stein算法如下:
這個(gè)算法的原理很顯然,所以就不再證明了。現(xiàn)在考察一下該算法和歐幾里德方法效率上的差別。
考慮歐幾里德算法,最?lèi)毫拥那闆r是,每次迭代a = 2b -1,這樣,迭代后,r= b-1。如果a小于2N,這樣大約需要 4N次迭代。而考慮Stein算法,每次迭代后,顯然AN+1BN+1≤ ANBN/2,最大迭代次數(shù)也不超過(guò)4N次。也就是說(shuō),迭代次數(shù)幾乎是相等的。但是,需要注意的是,對(duì)于大素?cái)?shù),試商法將使每次迭代都更復(fù)雜,因此對(duì)于大素?cái)?shù)Stein將更有優(yōu)勢(shì)。
外聯(lián)接可以是左向外聯(lián)接、右向外聯(lián)接或完整外部聯(lián)接。在 FROM 子句中指定外聯(lián)接時(shí),可以由下列幾組關(guān)鍵字中的一組指定:LEFT JOIN 或 LEFT OUTER JOIN。
左向外聯(lián)接的結(jié)果集包括 LEFT OUTER 子句中指定的左表的所有行,而不僅僅是聯(lián)接列所匹配的行。如果左表的某行在右表中沒(méi)有匹配行,則在相關(guān)聯(lián)的結(jié)果集行中右表的所有選擇列表列均為空值。
RIGHT JOIN 或 RIGHT OUTER JOIN。
右向外聯(lián)接是左向外聯(lián)接的反向聯(lián)接。將返回右表的所有行。如果右表的某行在左表中沒(méi)有匹配行,則將為左表返回空值。
FULL JOIN 或 FULL OUTER JOIN。
完整外部聯(lián)接返回左表和右表中的所有行。當(dāng)某行在另一個(gè)表中沒(méi)有匹配行時(shí),則另一個(gè)表的選擇列表列包含空值。如果表之間有匹配行,則整個(gè)結(jié)果集行包含基表的數(shù)據(jù)值。
僅當(dāng)至少有一個(gè)同屬于兩表的行符合聯(lián)接條件時(shí),內(nèi)聯(lián)接才返回行。內(nèi)聯(lián)接消除與另一個(gè)表中的任何行不匹配的行。而外聯(lián)接會(huì)返回 FROM 子句中提到的至少一個(gè)表或視圖的所有行,只要這些行符合任何 WHERE 或 HAVING 搜索條件。將檢索通過(guò)左向外聯(lián)接引用的左表的所有行,以及通過(guò)右向外聯(lián)接引用的右表的所有行。完整外部聯(lián)接中兩個(gè)表的所有行都將返回。
Microsoft® SQL Server™ 2000 對(duì)在 FROM 子句中指定的外聯(lián)接使用以下 SQL-92 關(guān)鍵字:
LEFT OUTER JOIN 或 LEFT JOIN
RIGHT OUTER JOIN 或 RIGHT JOIN
FULL OUTER JOIN 或 FULL JOIN
SQL Server 支持 SQL-92 外聯(lián)接語(yǔ)法,以及在 WHERE 子句中使用 *= 和 =* 運(yùn)算符指定外聯(lián)接的舊式語(yǔ)法。由于 SQL-92 語(yǔ)法不容易產(chǎn)生歧義,而舊式 Transact-SQL 外聯(lián)接有時(shí)會(huì)產(chǎn)生歧義,因此建議使用 SQL-92 語(yǔ)法。
使用左向外聯(lián)接
假設(shè)在 city 列上聯(lián)接 authors 表和 publishers 表。結(jié)果只顯示在出版商所在城市居住的作者(本例中為 Abraham Bennet 和 Cheryl Carson)。
若要在結(jié)果中包括所有的作者,而不管出版商是否住在同一個(gè)城市,請(qǐng)使用 SQL-92 左向外聯(lián)接。下面是 Transact-SQL 左向外聯(lián)接的查詢和結(jié)果:
USE pubs
SELECT a.au_fname, a.au_lname, p.pub_name
FROM authors a LEFT OUTER JOIN publishers p
ON a.city = p.city
ORDER BY p.pub_name ASC, a.au_lname ASC, a.au_fname ASC
下面是結(jié)果集:
au_fname au_lname pub_name |
不管是否與 publishers 表中的 city 列匹配,LEFT OUTER JOIN 均會(huì)在結(jié)果中包含 authors 表的所有行。注意:結(jié)果中所列的大多數(shù)作者都沒(méi)有相匹配的數(shù)據(jù),因此,這些行的 pub_name 列包含空值。
使用右向外聯(lián)接
假設(shè)在 city 列上聯(lián)接 authors 表和 publishers 表。結(jié)果只顯示在出版商所在城市居住的作者(本例中為 Abraham Bennet 和 Cheryl Carson)。SQL-92 右向外聯(lián)接運(yùn)算符 RIGHT OUTER JOIN 指明:不管第一個(gè)表中是否有匹配的數(shù)據(jù),結(jié)果將包含第二個(gè)表中的所有行。
若要在結(jié)果中包括所有的出版商,而不管城市中是否還有出版商居住,請(qǐng)使用 SQL-92 右向外聯(lián)接。下面是 Transact-SQL 右向外聯(lián)接的查詢和結(jié)果:
USE pubs |
下面是結(jié)果集:
au_fname au_lname pub_name |
使用謂詞(如將聯(lián)接與常量比較)可以進(jìn)一步限制外聯(lián)接。下例包含相同的右向外聯(lián)接,但消除銷(xiāo)售量低于 50 本的書(shū)籍的書(shū)名:
USE pubs
SELECT s.stor_id, s.qty, t.title
FROM sales s RIGHT OUTER JOIN titles t
ON s.title_id = t.title_id
AND s.qty > 50
ORDER BY s.stor_id ASC
下面是結(jié)果集:
stor_id qty title |
有關(guān)謂詞的更多信息,請(qǐng)參見(jiàn) WHERE。
使用完整外部聯(lián)接
若要通過(guò)在聯(lián)接結(jié)果中包括不匹配的行保留不匹配信息,請(qǐng)使用完整外部聯(lián)接。Microsoft® SQL Server™ 2000 提供完整外部聯(lián)接運(yùn)算符 FULL OUTER JOIN,不管另一個(gè)表是否有匹配的值,此運(yùn)算符都包括兩個(gè)表中的所有行。
假設(shè)在 city 列上聯(lián)接 authors 表和 publishers 表。結(jié)果只顯示在出版商所在城市居住的作者(本例中為 Abraham Bennet 和 Cheryl Carson)。SQL-92 FULL OUTER JOIN 運(yùn)算符指明:不管表中是否有匹配的數(shù)據(jù),結(jié)果將包括兩個(gè)表中的所有行。
若要在結(jié)果中包括所有作者和出版商,而不管城市中是否有出版商或者出版商是否住在同一個(gè)城市,請(qǐng)使用完整外部聯(lián)接。下面是 Transact-SQL 完整外部聯(lián)接的查詢和結(jié)果:
USE pubs |
下面是結(jié)果集:
|
設(shè)想網(wǎng)上購(gòu)物的一次交易,其付款過(guò)程至少包括以下幾步數(shù)據(jù)庫(kù)操作:
· 更新客戶所購(gòu)商品的庫(kù)存信息
· 保存客戶付款信息--可能包括與銀行系統(tǒng)的交互
· 生成訂單并且保存到數(shù)據(jù)庫(kù)中
· 更新用戶相關(guān)信息,例如購(gòu)物數(shù)量等等
正常的情況下,這些操作將順利進(jìn)行,最終交易成功,與交易相關(guān)的所有數(shù)據(jù)庫(kù)信息也成功地更新。但是,如果在這一系列過(guò)程中任何一個(gè)環(huán)節(jié)出了差錯(cuò),例如在更新商品庫(kù)存信息時(shí)發(fā)生異常、該顧客銀行帳戶存款不足等,都將導(dǎo)致交易失敗。一旦交易失敗,數(shù)據(jù)庫(kù)中所有信息都必須保持交易前的狀態(tài)不變,比如最后一步更新用戶信息時(shí)失敗而導(dǎo)致交易失敗,那么必須保證這筆失敗的交易不影響數(shù)據(jù)庫(kù)的狀態(tài)--庫(kù)存信息沒(méi)有被更新、用戶也沒(méi)有付款,訂單也沒(méi)有生成。否則,數(shù)據(jù)庫(kù)的信息將會(huì)一片混亂而不可預(yù)測(cè)。
數(shù)據(jù)庫(kù)事務(wù)正是用來(lái)保證這種情況下交易的平穩(wěn)性和可預(yù)測(cè)性的技術(shù)。
數(shù)據(jù)庫(kù)事務(wù)的ACID屬性
事務(wù)處理可以確保除非事務(wù)性單元內(nèi)的所有操作都成功完成,否則不會(huì)永久更新面向數(shù)據(jù)的資源。通過(guò)將一組相關(guān)操作組合為一個(gè)要么全部成功要么全部失敗的單元,可以簡(jiǎn)化錯(cuò)誤恢復(fù)并使應(yīng)用程序更加可靠。一個(gè)邏輯工作單元要成為事務(wù),必須滿足所謂的ACID(原子性、一致性、隔離性和持久性)屬性:
· 原子性
事務(wù)必須是原子工作單元;對(duì)于其數(shù)據(jù)修改,要么全都執(zhí)行,要么全都不執(zhí)行。通常,與某個(gè)事務(wù)關(guān)聯(lián)的操作具有共同的目標(biāo),并且是相互依賴的。如果系統(tǒng)只執(zhí)行這些操作的一個(gè)子集,則可能會(huì)破壞事務(wù)的總體目標(biāo)。原子性消除了系統(tǒng)處理操作子集的可能性。
· 一致性
事務(wù)在完成時(shí),必須使所有的數(shù)據(jù)都保持一致?tīng)顟B(tài)。在相關(guān)數(shù)據(jù)庫(kù)中,所有規(guī)則都必須應(yīng)用于事務(wù)的修改,以保持所有數(shù)據(jù)的完整性。事務(wù)結(jié)束時(shí),所有的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(如 B 樹(shù)索引或雙向鏈表)都必須是正確的。某些維護(hù)一致性的責(zé)任由應(yīng)用程序開(kāi)發(fā)人員承擔(dān),他們必須確保應(yīng)用程序已強(qiáng)制所有已知的完整性約束。例如,當(dāng)開(kāi)發(fā)用于轉(zhuǎn)帳的應(yīng)用程序時(shí),應(yīng)避免在轉(zhuǎn)帳過(guò)程中任意移動(dòng)小數(shù)點(diǎn)。
· 隔離性
由并發(fā)事務(wù)所作的修改必須與任何其它并發(fā)事務(wù)所作的修改隔離。事務(wù)查看數(shù)據(jù)時(shí)數(shù)據(jù)所處的狀態(tài),要么是另一并發(fā)事務(wù)修改它之前的狀態(tài),要么是另一事務(wù)修改它之后的狀態(tài),事務(wù)不會(huì)查看中間狀態(tài)的數(shù)據(jù)。這稱為可串行性,因?yàn)樗軌蛑匦卵b載起始數(shù)據(jù),并且重播一系列事務(wù),以使數(shù)據(jù)結(jié)束時(shí)的狀態(tài)與原始事務(wù)執(zhí)行的狀態(tài)相同。當(dāng)事務(wù)可序列化時(shí)將獲得最高的隔離級(jí)別。在此級(jí)別上,從一組可并行執(zhí)行的事務(wù)獲得的結(jié)果與通過(guò)連續(xù)運(yùn)行每個(gè)事務(wù)所獲得的結(jié)果相同。由于高度隔離會(huì)限制可并行執(zhí)行的事務(wù)數(shù),所以一些應(yīng)用程序降低隔離級(jí)別以換取更大的吞吐量。
· 持久性
事務(wù)完成之后,它對(duì)于系統(tǒng)的影響是永久性的。該修改即使出現(xiàn)致命的系統(tǒng)故障也將一直保持。
DBMS的責(zé)任和我們的任務(wù)
企業(yè)級(jí)的數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS)都有責(zé)任提供一種保證事務(wù)的物理完整性的機(jī)制。就常用的SQL Server2000系統(tǒng)而言,它具備鎖定設(shè)備隔離事務(wù)、記錄設(shè)備保證事務(wù)持久性等機(jī)制。因此,我們不必關(guān)心數(shù)據(jù)庫(kù)事務(wù)的物理完整性,而應(yīng)該關(guān)注在什么情況下使用數(shù)據(jù)庫(kù)事務(wù)、事務(wù)對(duì)性能的影響,如何使用事務(wù)等等。
本文將涉及到在.net框架下使用C#語(yǔ)言操縱數(shù)據(jù)庫(kù)事務(wù)的各個(gè)方面。
+++@@@+++
體驗(yàn)SQL語(yǔ)言的事務(wù)機(jī)制
作為大型的企業(yè)級(jí)數(shù)據(jù)庫(kù),SQL Server2000對(duì)事務(wù)提供了很好的支持。我們可以使用SQL語(yǔ)句來(lái)定義、提交以及回滾一個(gè)事務(wù)。
如下所示的SQL代碼定義了一個(gè)事務(wù),并且命名為"MyTransaction"(限于篇幅,本文并不討論如何編寫(xiě)SQL語(yǔ)言程序,請(qǐng)讀者自行參考相關(guān)書(shū)籍):
DECLARE @TranName VARCHAR(20)
Select @TranName = ''''MyTransaction''''
BEGIN TRANSACTION @TranNameGOUSE pubs
GO
Update roysched
SET royalty = royalty * 1.10
Where title_id LIKE ''''Pc%''''
GO
COMMIT TRANSACTION MyTransaction
GO
這里用到了SQL Server2000自帶的示例數(shù)據(jù)庫(kù)pubs,提交事務(wù)后,將為所有暢銷(xiāo)計(jì)算機(jī)書(shū)籍支付的版稅增加 10%。
打開(kāi)SQL Server2000的查詢分析器,選擇pubs數(shù)據(jù)庫(kù),然后運(yùn)行這段程序,結(jié)果顯而易見(jiàn)。
可是如何在C#程序中運(yùn)行呢?我們記得在普通的SQL查詢中,一般需要把查詢語(yǔ)句賦值給SalCommand.CommandText屬性,這里也就像普通的SQL查詢語(yǔ)句一樣,將這些語(yǔ)句賦給SqlCommand.CommandText屬性即可。要注意的一點(diǎn)是,其中的"GO"語(yǔ)句標(biāo)志著SQL批處理的結(jié)束,編寫(xiě)SQL腳本是需要的,但是在這里是不必要的。我們可以編寫(xiě)如下的程序來(lái)驗(yàn)證這個(gè)想法:
//TranSql.csusing System;
using System.Data;
using System.Data.SqlClient;
namespace Aspcn
{
public class DbTranSql
{
file://將事務(wù)放到SQL Server中執(zhí)行
public void DoTran()
{
file://建立連接并打開(kāi)
SqlConnection myConn=GetConn();myConn.Open();
SqlCommand myComm=new SqlCommand();
try
{
myComm.Connection=myConn;
myComm.CommandText="DECLARE @TranName VARCHAR(20) ";
myComm.CommandText+="Select @TranName = ''''MyTransaction'''' ";
myComm.CommandText+="BEGIN TRANSACTION @TranName ";
myComm.CommandText+="USE pubs ";
myComm.CommandText+="Update roysched SET royalty = royalty * 1.10 Where title_id LIKE ''''Pc%'''' ";
myComm.CommandText+="COMMIT TRANSACTION MyTransaction ";
myComm.ExecuteNonQuery();
}
catch(Exception err)
{
throw new ApplicationException("事務(wù)操作出錯(cuò),系統(tǒng)信息:"+err.Message);
}
finally
{
myConn.Close();
}
}
file://獲取數(shù)據(jù)連接
private SqlConnection GetConn()
{
string strSql="Data Source=localhost;Integrated Security=SSPI;user id=sa;password=";
SqlConnection myConn=new SqlConnection(strSql);
return myConn;
}
}
public class Test
{
public static void Main()
{
DbTranSql tranTest=new DbTranSql();
tranTest.DoTran();
Console.WriteLine("事務(wù)處理已經(jīng)成功完成。");
Console.ReadLine();
}
}
}
注意到其中的SqlCommand對(duì)象myComm,它的CommandText屬性僅僅是前面SQL代碼字符串連接起來(lái)即可,當(dāng)然,其中的"GO"語(yǔ)句已經(jīng)全部去掉了。這個(gè)語(yǔ)句就像普通的查詢一樣,程序?qū)QL文本事實(shí)上提交給DBMS去處理了,然后接收返回的結(jié)果(如果有結(jié)果返回的話)。
很自然,我們最后看到了輸出"事務(wù)處理已經(jīng)成功完成",再用企業(yè)管理器查看pubs數(shù)據(jù)庫(kù)的roysched表,所有title_id字段以"PC"開(kāi)頭的書(shū)籍的royalty字段的值都增加了0.1倍。
這里,我們并沒(méi)有使用ADO.net的事務(wù)處理機(jī)制,而是簡(jiǎn)單地將執(zhí)行事務(wù)的SQL語(yǔ)句當(dāng)作普通的查詢來(lái)執(zhí)行,因此,事實(shí)上該事務(wù)完全沒(méi)有用到.net的相關(guān)特性。
了解.net中的事務(wù)機(jī)制
如你所知,在.net框架中主要有兩個(gè)命名空間(namespace)用于應(yīng)用程序同數(shù)據(jù)庫(kù)系統(tǒng)的交互:System.Data.SqlClient和System.Data.OleDb。前者專門(mén)用于連接Microsoft公司自己的SQL Server數(shù)據(jù)庫(kù),而后者可以適應(yīng)多種不同的數(shù)據(jù)庫(kù)。這兩個(gè)命名空間中都包含有專門(mén)用于管理數(shù)據(jù)庫(kù)事務(wù)的類(lèi),分別是System.Data.SqlClient.SqlTranscation類(lèi)和System.Data.OleDb.OleDbTranscation類(lèi)。
就像它們的名字一樣,這兩個(gè)類(lèi)大部分功能是一樣的,二者之間的主要差別在于它們的連接機(jī)制,前者提供一組直接調(diào)用 SQL Server 的對(duì)象,而后者使用本機(jī) OLE DB 啟用數(shù)據(jù)訪問(wèn)。 事實(shí)上,ADO.net 事務(wù)完全在數(shù)據(jù)庫(kù)的內(nèi)部處理,且不受 Microsoft 分布式事務(wù)處理協(xié)調(diào)器 (DTC) 或任何其他事務(wù)性機(jī)制的支持。本文將主要介紹System.Data.SqlClient.SqlTranscation類(lèi),下面的段落中,除了特別注明,都將使用System.Data.SqlClient.SqlTranscation類(lèi)。
+++@@@+++
事務(wù)的開(kāi)啟和提交
現(xiàn)在我們對(duì)事務(wù)的概念和原理都了然于心了,并且作為已經(jīng)有一些基礎(chǔ)的C#開(kāi)發(fā)者,我們已經(jīng)熟知編寫(xiě)數(shù)據(jù)庫(kù)交互程序的一些要點(diǎn),即使用SqlConnection類(lèi)的對(duì)象的Open()方法建立與數(shù)據(jù)庫(kù)服務(wù)器的連接,然后將該連接賦給SqlCommand對(duì)象的Connection屬性,將欲執(zhí)行的SQL語(yǔ)句賦給它的CommandText屬性,于是就可以通過(guò)SqlCommand對(duì)象進(jìn)行數(shù)據(jù)庫(kù)操作了。對(duì)于我們將要編寫(xiě)的事務(wù)處理程序,當(dāng)然還需要定義一個(gè)SqlTransaction類(lèi)型的對(duì)象。并且看到SqlCommand對(duì)象的Transcation屬性,我們很容易想到新建的SqlTransaction對(duì)象應(yīng)該與它關(guān)聯(lián)起來(lái)。
基于以上認(rèn)識(shí),下面我們就開(kāi)始動(dòng)手寫(xiě)我們的第一個(gè)事務(wù)處理程序。我們可以很熟練地寫(xiě)出下面這一段程序:
//DoTran.csusing System;
using System.Data;
using System.Data.SqlClient;
namespace Aspcn
{
public class DbTran
{
file://執(zhí)行事務(wù)處理
public void DoTran()
{
file://建立連接并打開(kāi)
SqlConnection myConn=GetConn();
myConn.Open();
SqlCommand myComm=new SqlCommand();
SqlTransaction myTran=new SqlTransaction();
try
{
myComm.Connection=myConn;
myComm.Transaction=myTran;
file://定位到pubs數(shù)據(jù)庫(kù)
myComm.CommandText="USE pubs";
myComm.ExecuteNonQuery();
file://更新數(shù)據(jù)
file://將所有的計(jì)算機(jī)類(lèi)圖書(shū)
myComm.CommandText="Update roysched SET royalty = royalty * 1.10 Where title_id LIKE ''''Pc%''''";
myComm.ExecuteNonQuery();//提交事務(wù)
myTran.Commit();
}
catch(Exception err)
{
throw new ApplicationException("事務(wù)操作出錯(cuò),系統(tǒng)信息:"+err.Message);
}
finally
{
myConn.Close();
}
}
file://獲取數(shù)據(jù)連接
private SqlConnection GetConn()
{
string strSql="Data Source=localhost;Integrated Security=SSPI;user id=sa;password=";
SqlConnection myConn=new SqlConnection(strSql);
return myConn;
}
}
public class Test{public static void Main()
{
DbTran tranTest=new DbTran();
tranTest.DoTran();
Console.WriteLine("事務(wù)處理已經(jīng)成功完成。");
Console.ReadLine();
}
}
}
顯然,這個(gè)程序非常簡(jiǎn)單,我們非常自信地編譯它,但是,出乎意料的結(jié)果使我們的成就感頓時(shí)煙消云散:
error CS1501: 重載"SqlTransaction"方法未獲取"0"參數(shù)
是什么原因呢?注意到我們初始化的代碼:
SqlTransaction myTran=new SqlTransaction();
顯然,問(wèn)題出在這里,事實(shí)上,SqlTransaction類(lèi)并沒(méi)有公共的構(gòu)造函數(shù),我們不能這樣新建一個(gè)SqlTrancaction類(lèi)型的變量。在事務(wù)處理之前確實(shí)需要有一個(gè)SqlTransaction類(lèi)型的變量,將該變量關(guān)聯(lián)到SqlCommand類(lèi)的Transcation屬性也是必要的,但是初始化方法卻比較特別一點(diǎn)。在初始化SqlTransaction類(lèi)時(shí),你需要使用SqlConnection類(lèi)的BeginTranscation()方法:
SqlTransaction myTran; myTran=myConn.BeginTransaction();
該方法返回一個(gè)SqlTransaction類(lèi)型的變量。在調(diào)用BeginTransaction()方法以后,所有基于該數(shù)據(jù)連接對(duì)象的SQL語(yǔ)句執(zhí)行動(dòng)作都將被認(rèn)為是事務(wù)MyTran的一部分。同時(shí),你也可以在該方法的參數(shù)中指定事務(wù)隔離級(jí)別和事務(wù)名稱,如:
SqlTransaction myTran;
myTran=myConn.BeginTransaction(IsolationLevel.ReadCommitted,"SampleTransaction");
關(guān)于隔離級(jí)別的概念我們將在隨后的內(nèi)容中探討,在這里我們只需牢記一個(gè)事務(wù)是如何被啟動(dòng),并且關(guān)聯(lián)到特定的數(shù)據(jù)鏈接的。
先不要急著去搞懂我們的事務(wù)都干了些什么,看到這一行:
myTran.Commit();
是的,這就是事務(wù)的提交方式。該語(yǔ)句執(zhí)行后,事務(wù)的所有數(shù)據(jù)庫(kù)操作將生效,并且為數(shù)據(jù)庫(kù)事務(wù)的持久性機(jī)制所保持--即使系統(tǒng)在這以后發(fā)生致命錯(cuò)誤,該事務(wù)對(duì)數(shù)據(jù)庫(kù)的影響也不會(huì)消失。
對(duì)上面的程序做了修改之后我們可以得到如下代碼(為了節(jié)約篇幅,重復(fù)之處已省略,請(qǐng)參照前文):
//DoTran.cs……}
file://執(zhí)行事務(wù)處理
public void DoTran()
{
file://建立連接并打開(kāi)
SqlConnection myConn=GetConn();
myConn.Open();
SqlCommand myComm=new SqlCommand();
file://SqlTransaction myTran=new SqlTransaction();
file://注意,SqlTransaction類(lèi)無(wú)公開(kāi)的構(gòu)造函數(shù)
SqlTransaction myTran;
file://創(chuàng)建一個(gè)事務(wù)
myTran=myConn.BeginTransaction();
try
{
file://從此開(kāi)始,基于該連接的數(shù)據(jù)操作都被認(rèn)為是事務(wù)的一部分
file://下面綁定連接和事務(wù)對(duì)象
myComm.Connection=myConn;
myComm.Transaction=myTran; file://定位到pubs數(shù)據(jù)庫(kù)
myComm.CommandText="USE pubs";
myComm.ExecuteNonQuery();//更新數(shù)據(jù)
file://將所有的計(jì)算機(jī)類(lèi)圖書(shū)
myComm.CommandText="Update roysched SET royalty = royalty * 1.10 Where title_id LIKE ''''Pc%''''";
myComm.ExecuteNonQuery();
file://提交事務(wù)
myTran.Commit();
}
catch(Exception err)
{
throw new ApplicationException("事務(wù)操作出錯(cuò),系統(tǒng)信息:"+err.Message);
}
finally
{
myConn.Close();
}
}
……
到此為止,我們僅僅掌握了如何開(kāi)始和提交事務(wù)。下一步我們必須考慮的是在事務(wù)中可以干什么和不可以干什么。
該文章轉(zhuǎn)載自'大智の博客':http://www.csafe.cn/article.asp?id=271