第1章 Windows位圖和調色闆
1.1 位圖和調色闆的概念
如今Windows(3.x以及95,98,NT)系列已經成為絕大多數使用者使用的作業系統,它比DOS成功的一個重要因素是它可視化的漂亮界面。那麼Windows是如何顯示圖象的呢?這就要談到位圖(bitmap)。
我們知道,普通的顯示器螢幕是由許許多多點構成的,我們稱之為象素。顯示時采用掃描的方法:電子槍每次從左到右掃描一行,為每個象素着色,然後從上到下這樣掃描若幹行,就掃過了一屏。為了防止閃爍,每秒要重複上述過程幾十次。例如我們常說的螢幕分辨率為640×480,重新整理頻率為70Hz,意思是說每行要掃描640個象素,一共有480行,每秒重複掃描螢幕70次。
我們稱這種顯示器為位映象裝置。所謂位映象,就是指一個二維的象素矩陣,而位圖就是采用位映象方法顯示和存儲的圖象。舉個例子,圖1.1是一幅普通的黑白位圖,圖1.2是被放大後的圖,圖中每個方格代表了一個象素。我們可以看到:整個骷髅就是由這樣一些黑點和白點組成的。
圖1.1 骷髅 | 圖1.2 放大後的骷髅位圖 |
那麼,彩色圖是怎麼回事呢?
我們先來說說三元色RGB概念。
我們知道,自然界中的所有顔色都可以由紅、綠、藍(R,G,B)組合而成。有的顔色含有紅色成分多一些,如深紅;有的含有紅色成分少一些,如淺紅。針對含有紅色成分的多少,可以分成0到255共256個等級,0級表示不含紅色成分;255級表示含有100%的紅色成分。同樣,綠色和藍色也被分成256級。這種分級概念稱為量化。
這樣,根據紅、綠、藍各種不同的組合我們就能表示出256×256×256,約1600萬種顔色。這麼多顔色對于我們人眼來說已經足夠豐富了。
表1.1 常見顔色的RGB 組合值顔色 | R | G | B |
紅 | 255 | ||
藍 | 255 | ||
綠 | 255 | ||
黃 | 255 | 255 | |
紫 | 255 | 255 | |
青 | 255 | 255 | |
白 | 255 | 255 | 255 |
黑 | |||
灰 | 128 | 128 | 128 |
你大概已經明白了,當一幅圖中每個象素賦予不同的RGB值時,能呈現出五彩缤紛的顔色了,這樣就形成了彩色圖。的确是這樣的,但實際上的做法還有些差别。
讓我們來看看下面的例子。
有一個長寬各為200個象素,顔色數為16色的彩色圖,每一個象素都用R、G、B三個分量表示。因為每個分量有256個級别,要用8位(bit),即一個位元組(byte)來表示,是以每個象素需要用3個位元組。整個圖象要用200×200×3,約120k位元組,可不是一個小數目呀!如果我們用下面的方法,就能省的多。
因為是一個16色圖,也就是說這幅圖中最多隻有16種顔色,我們可以用一個表:表中的每一行記錄一種顔色的R、G、B值。這樣當我們表示一個象素的顔色時,隻需要指出該顔色是在第幾行,即該顔色在表中的索引值。舉個例子,如果表的第0行為255,0,0(紅色),那麼當某個象素為紅色時,隻需要标明0即可。
讓我們再來計算一下:16種狀态可以用4位(bit)表示,是以一個象素要用半個位元組。整個圖象要用200×200×0.5,約20k位元組,再加上表占用的位元組為3×16=48位元組.整個占用的位元組數約為前面的1/6,省很多吧?
這張R、G、B的表,就是我們常說的調色闆(Palette),另一種叫法是顔色查找表LUT(Look Up Table),似乎更确切一些。Windows位圖中便用到了調色闆技術。其實不光是Windows位圖,許多圖象檔案格式如pcx、tif、gif等都用到了。是以很好地掌握調色闆的概念是十分有用的。
有一種圖,它的顔色數高達256×256×256種,也就是說包含我們上述提到的R、G、B顔色表示方法中所有的顔色,這種圖叫做真彩色圖(true color)。真彩色圖并不是說一幅圖包含了所有的顔色,而是說它具有顯示所有顔色的能力,即最多可以包含所有的顔色。表示真彩色圖時,每個象素直接用R、G、B三個分量位元組表示,而不采用調色闆技術。原因很明顯:如果用調色闆,表示一個象素也要用24位,這是因為每種顔色的索引要用24位(因為總共有224種顔色,即調色闆有224行),和直接用R,G,B三個分量表示用的位元組數一樣,不但沒有任何便宜,還要加上一個256×256×256×3個位元組的大調色闆。是以真彩色圖直接用R、G、B三個分量表示,它又叫做24位色圖。
1.2 bmp檔案格式
介紹完位圖和調色闆的概念,下面就讓我們來看一看Windows的位圖檔案(.bmp檔案)的格式是什麼樣子的。
bmp檔案大體上分成四個部分,如圖1.3所示。
位圖檔案頭BITMAPFILEHEADER |
位圖資訊頭BITMAPINFOHEADER |
調色闆Palette |
實際的位圖資料ImageDate |
第一部分為位圖檔案頭
BITMAPFILEHEADER,是一個結構,其定義如下:
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
這個結構的長度是固定的,為14個位元組(WORD為無符号16位整數,DWORD為無符号32位整數),各個域的說明如下:
bfType指定檔案類型,必須是0x424D,即字元串“BM”,也就是說所有.bmp檔案的頭兩個位元組都是“BM”。
bfSize指定檔案大小,包括這14個位元組。
bfReserved1 ,bfReserved2為保留字,不用考慮
bfOffBits為從檔案頭到實際的位圖資料的偏移位元組數,即圖1.3中前三個部分的長度之和。
第二部分為位圖資訊頭
BITMAPINFOHEADER,也是一個結構,其定義如下:
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
這個結構的長度是固定的,為40個位元組(LONG為32位整數),各個域的說明如下:
biSize指定這個結構的長度,為40。
biWidth指定圖象的寬度,機關是象素。
biHeight指定圖象的高度,機關是象素。
biPlanes必須是1,不用考慮。
biBitCount指定表示顔色時要用到的位數,常用的值為1(黑白二色圖), 4(16色圖), 8(256色), 24(真彩色圖)(新的.bmp格式支援32位色,這裡就不做讨論了)。
biCompression指定位圖是否壓縮,有效的值為BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS(都是一些Windows定義好的常量)。要說明的是,Windows位圖可以采用RLE4,和RLE8的壓縮格式,但用的不多。我們今後所讨論的隻有第一種不壓縮的情況,即biCompression為BI_RGB的情況。
biSizeImage指定實際的位圖資料占用的位元組數,其實也可以從以下的公式中計算出來:
biSizeImage=biWidth’ × biHeight
要注意的是:上述公式中的biWidth’必須是4的整倍數(是以不是biWidth,而是biWidth’,表示大于或等于biWidth的,最接近4的整倍數。舉個例子,如果biWidth=240,則biWidth’=240;如果biWidth=241,biWidth’=244)。
如果biCompression為BI_RGB,則該項可能為零
biXPelsPerMeter指定目标裝置的水準分辨率,機關是每米的象素個數,關于分辨率的概念,我們将在第4章詳細介紹。
biYPelsPerMeter指定目标裝置的垂直分辨率,機關同上。
biClrUsed指定本圖象實際用到的顔色數,如果該值為零,則用到的顔色數為2biBitCount。
biClrImportant指定本圖象中重要的顔色數,如果該值為零,則認為所有的顔色都是重要的。
第三部分為調色闆
Palette,當然,這裡是對那些需要調色闆的位圖檔案而言的。有些位圖,如真彩色圖,前面已經講過,是不需要調色闆的,BITMAPINFOHEADER後直接是位圖資料。
調色闆實際上是一個數組,共有biClrUsed個元素(如果該值為零,則有2biBitCount個元素)。數組中每個元素的類型是一個RGBQUAD結構,占4個位元組,其定義如下:
typedef struct tagRGBQUAD {
BYTE rgbBlue; //該顔色的藍色分量
BYTE rgbGreen; //該顔色的綠色分量
BYTE rgbRed; //該顔色的紅色分量
BYTE rgbReserved; //保留值
} RGBQUAD;
第四部分就是實際的圖象資料了。對于用到調色闆的位圖,圖象資料就是該象素顔在調色闆中的索引值。對于真彩色圖,圖象資料就是實際的R、G、B值。下面針對2色、16色、256色位圖和真彩色位圖分别介紹。
對于2色位圖,用1位就可以表示該象素的顔色(一般0表示黑,1表示白),是以一個位元組可以表示8個象素。
對于16色位圖,用4位可以表示一個象素的顔色,是以一個位元組可以表示2個象素。
對于256色位圖,一個位元組剛好可以表示1個象素。
對于真彩色圖,三個位元組才能表示1個象素,哇,好費空間呀!沒辦法,誰叫你想讓圖的顔色顯得更亮麗呢,有得必有失嘛。
要注意兩點:
(1) 每一行的位元組數必須是4的整倍數,如果不是,則需要補齊。這在前面介紹biSizeImage時已經提到了。
(2) 一般來說,.bMP檔案的資料從下到上,從左到右的。也就是說,從檔案中最先讀到的是圖象最下面一行的左邊第一個象素,然後是左邊第二個象素……接下來是倒數第二行左邊第一個象素,左邊第二個象素……依次類推 ,最後得到的是最上面一行的最右一個象素。
好了,終于介紹完bmp檔案結構了,是不是覺得頭有些大?别着急,對照着下面的程式,你就會很清楚了(我最愛看源程式了,呵呵)。
1.3 顯示一個bmp檔案的C程式
下面的函數LoadBmpFile,其功能是從一個.bmp檔案中讀取資料(包括BITMAPINFOHEADER,調色闆和實際圖象資料),将其存儲在一個全局記憶體句柄hImgData中,這個hImgData将在以後的圖象處理程式中用到。同時填寫一個類型為HBITMAP的全局變量hBitmap和一個類型為HPALETTE的全局變量hPalette。這兩個變量将在處理WM_PAINT消息時用到,用來顯示位圖。該函數的兩個參數分别是用來顯示位圖的視窗句柄,和.bmp檔案名(全路徑)。當函數成功時,傳回TRUE,否則傳回FALSE。
BITMAPFILEHEADER bf;
BITMAPINFOHEADER bi;
BOOL LoadBmpFile (HWND hWnd,char *BmpFileName)
{
HFILE hf; //檔案句柄
//指向BITMAPINFOHEADER結構的指針
LPBITMAPINFOHEADER lpImgData;
LOGPALETTE *pPal; //指向邏輯調色闆結構的指針
LPRGBQUAD lpRGB; //指向RGBQUAD結構的指針
HPALETTE hPrevPalette; //用來儲存裝置中原來的調色闆
HDC hDc; //裝置句柄
HLOCAL hPal; //存儲調色闆的局部記憶體句柄
DWORD LineBytes; //每一行的位元組數
DWORD ImgSize; //實際的圖象資料占用的位元組數
//實際用到的顔色數 ,即調色闆數組中的顔色個數
DWORD NumColors;
DWORD i;
if((hf=_lopen(BmpFileName,OF_READ))==HFILE_ERROR){
MessageBox(hWnd,"File c://test.bmp not found!","Error Message",
MB_OK|MB_ICONEXCLAMATION);
return FALSE; //打開檔案錯誤,傳回
}
//将BITMAPFILEHEADER結構從檔案中讀出,填寫到bf中
_lread(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER));
//将BITMAPINFOHEADER結構從檔案中讀出,填寫到bi中
_lread(hf,(LPSTR)&bi,sizeof(BITMAPINFOHEADER));
//我們定義了一個宏 #define WIDTHBYTES(i) ((i+31)/32*4)上面曾經
//提到過,每一行的位元組數必須是4的整倍數,隻要調用
//WIDTHBYTES(bi.biWidth*bi.biBitCount)就能完成這一換算。舉一個例
//子,對于2色圖,如果圖象寬是31,則每一行需要31位存儲,合3個
//位元組加7位,因為位元組數必須是4的整倍數,是以應該是4,而此時的
//biWidth=31,biBitCount=1,WIDTHBYTES(31*1)=4,和我們設想的一樣。
//再舉一個256色的例子,如果圖象寬是31,則每一行需要31個位元組存
//儲,因為位元組數必須是4的整倍數,是以應該是32,而此時的
//biWidth=31,biBitCount=8,WIDTHBYTES(31*8)=32,我們設想的一樣。你可
//以多舉幾個例子來驗證一下
//LineBytes為每一行的位元組數
LineBytes=(DWORD)WIDTHBYTES(bi.biWidth*bi.biBitCount);
//ImgSize為實際的圖象資料占用的位元組數
ImgSize=(DWORD)LineBytes*bi.biHeight;
//NumColors為實際用到的顔色數 ,即調色闆數組中的顔色個數
if(bi.biClrUsed!=0)
//如果bi.biClrUsed不為零,即為實際用到的顔色數
NumColors=(DWORD)bi.biClrUsed;
else //否則,用到的顔色數為2biBitCount。
switch(bi.biBitCount){
case 1:
NumColors=2;
break;
case 4:
NumColors=16;
break;
case 8:
NumColors=256;
break;
case 24:
NumColors=0; //對于真彩色圖,沒用到調色闆
break;
default: //不處理其它的顔色數,認為出錯。
MessageBox(hWnd,"Invalid color numbers!","Error Message",
MB_OK|MB_ICONEXCLAMATION);
_lclose(hf);
return FALSE; //關閉檔案,傳回FALSE
}
if(bf.bfOffBits!=(DWORD)(NumColors*sizeof(RGBQUAD)+
sizeof(BITMAPFILEHEADER)+
sizeof(BITMAPINFOHEADER)))
{
//計算出的偏移量與實際偏移量不符,一定是顔色數出錯
MessageBox(hWnd,"Invalid color numbers!","Error Message",
MB_OK|MB_ICONEXCLAMATION);
_lclose(hf);
return FALSE; //關閉檔案,傳回FALSE
}
bf.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+
NumColors*sizeof(RGBQUAD)+ImgSize;
//配置設定記憶體,大小為BITMAPINFOHEADER結構長度加調色闆+實際位圖
if((hImgData=GlobalAlloc(GHND,(DWORD)
(sizeof(BITMAPINFOHEADER)+
NumColors*sizeof(RGBQUAD)+
ImgSize)))==NULL)
{
//配置設定記憶體錯誤
MessageBox(hWnd,"Error alloc memory!","ErrorMessage",MB_OK|
MB_ICONEXCLAMATION);
_lclose(hf);
return FALSE; //關閉檔案,傳回FALSE
}
//指針lpImgData指向該記憶體區
lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);
//檔案指針重新定位到BITMAPINFOHEADER開始處
_llseek(hf,sizeof(BITMAPFILEHEADER),SEEK_SET);
//将檔案内容讀入lpImgData
_hread(hf,(char *)lpImgData,(long)sizeof(BITMAPINFOHEADER)
+(long)NumColors*sizeof(RGBQUAD)+ImgSize);
_lclose(hf); //關閉檔案
if(NumColors!=0) //NumColors不為零,說明用到了調色闆
{
//為邏輯調色闆配置設定局部記憶體,大小為邏輯調色闆結構長度加
//NumColors個PALETTENTRY
hPal=LocalAlloc(LHND,sizeof(LOGPALETTE)+
NumColors* sizeof(PALETTEENTRY));
//指針pPal指向該記憶體區
pPal =(LOGPALETTE *)LocalLock(hPal);
//填寫邏輯調色闆結構的頭
pPal->palNumEntries = NumColors;
pPal->palVersion = 0x300;
//lpRGB指向的是調色闆開始的位置
lpRGB = (LPRGBQUAD)((LPSTR)lpImgData +
(DWORD)sizeof(BITMAPINFOHEADER));
//填寫每一項
for (i = 0; i < NumColors; i++)
{
pPal->palPalEntry[i].peRed=lpRGB->rgbRed;
pPal->palPalEntry[i].peGreen=lpRGB->rgbGreen;
pPal->palPalEntry[i].peBlue=lpRGB->rgbBlue;
pPal->palPalEntry[i].peFlags=(BYTE)0;
lpRGB++; //指針移到下一項
}
//産生邏輯調色闆,hPalette是一個全局變量
hPalette=CreatePalette(pPal);
//釋放局部記憶體
LocalUnlock(hPal);
LocalFree(hPal);
}
//獲得裝置上下文句柄
hDc=GetDC(hWnd);
if(hPalette) //如果剛才産生了邏輯調色闆
{
//将新的邏輯調色闆選入DC,将舊的邏輯調色闆句柄儲存在//hPrevPalette
hPrevPalette=SelectPalette(hDc,hPalette,FALSE);
RealizePalette(hDc);
}
//産生位圖句柄
hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpImgData,
(LONG)CBM_INIT,
(LPSTR)lpImgData+sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD),
(LPBITMAPINFO)lpImgData, DIB_RGB_COLORS);
//将原來的調色闆(如果有的話)選入裝置上下文句柄
if(hPalette && hPrevPalette)
{
SelectPalette(hDc,hPrevPalette,FALSE);
RealizePalette(hDc);
}
ReleaseDC(hWnd,hDc); //釋放裝置上下文
GlobalUnlock(hImgData); //解鎖記憶體區
return TRUE; //成功傳回
}
對上面的程式要說明兩點:
(1) 對于需要調色闆的圖,要想正确地顯示,必須根據bmp檔案,産生邏輯調色闆。産生的方法是:①為邏輯調色闆指針配置設定記憶體,大小為邏輯調色闆結構(LOGPALETTE)長度加NumColors個PALETTENTRY大小(調色闆的每一項都是一個PALETTEENTRY結構);②填寫邏輯調色闆結構的頭pPal->palNumEntries = NumColors; pPal->palVersion = 0x300;③從檔案中讀取調色闆的RGB值,填寫到每一項中;④産生邏輯調色闆:hPalette=CreatePalette(pPal)。
(2) 産生位圖(BITMAP)句柄,該項工作由函數CreateDIBitmap來完成。
hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpImgData,
(LONG)CBM_INIT,
(LPSTR)lpImgData+sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD),
(LPBITMAPINFO)lpImgData, DIB_RGB_COLORS);
CreateDIBitmap的作用是産生一個和Windows裝置無關的位圖。該函數的第一項參數為裝置上下文句柄。如果位圖用到了調色闆,要在調用CreateDIBitmap之前将邏輯調色闆選入該裝置上下文中,産生hBitmap後,再把原調色闆選入該裝置上下文中,并釋放該上下文;第二項為指向BITMAPINFOHEADER的指針;第三項就用常量CBM_INI,不用考慮;第四項為指向調色闆的指針;第五項為指向BITMAPINFO(包括BITMAPINFOHEADER,調色闆,及實際的圖象資料)的指針;第六項就用常量DIB_RGB_COLORS,不用考慮。
上面提到了裝置上下文,相信編過Windows程式的讀者對它并不陌生,這裡再簡單介紹一下。Windows作業系統統一管理着諸如顯示,列印等操作,将它們看作是一個個的裝置,每一個裝置都有一個複雜的資料結構來維護。所謂裝置上下文就是指這個資料結構。然而,我們不能直接和這些裝置上下文打交道,隻能通過引用辨別它的句柄(實際上是一個整數),讓Windows去做相應的處理。
産生的邏輯調色闆句柄hPalette和位圖句柄hBitmap要在處理WM_PAINT消息時使用,這樣才能在螢幕上顯示出來,處理過程如下面的程式。
Static HDC hDC,hMemDC;
PAINTSTRUCT ps;
case WM_PAINT:
{
hDC = BeginPaint(hwnd, &ps); //獲得螢幕裝置上下文
if (hBitmap) //hBitmap一開始是NULL,當不為NULL時表示有圖
{
hMemDC = CreateCompatibleDC(hDC); //建立一個記憶體裝置上下文
if (hPalette) //有調色闆
{
//将調色闆選入螢幕裝置上下文
SelectPalette (hDC, hPalette, FALSE);
//将調色闆選入記憶體裝置上下文
SelectPalette (hMemDC, hpalette, FALSE);
RealizePalette (hDC);
}
//将位圖選入記憶體裝置上下文
SelectObject(hMemDC, hBitmap);
//顯示位圖
BitBlt(hDC, 0, 0, bi.biWidth, bi.biHeight, hMemDC, 0, 0, SRCCOPY);
//釋放記憶體裝置上下文
DeleteDC(hMemDC);
}
//釋放螢幕裝置上下文
EndPaint(hwnd, &ps);
break;
}
在上面的程式中,我們調用CreateCompatibleDC建立一個記憶體裝置上下文。SelectObject函數将與裝置無關的位圖選入記憶體裝置上下文中。然後我們調用BitBlt函數在記憶體裝置上下文和螢幕裝置上下文中進行位拷貝。由于所有操作都是在記憶體中進行,是以速度很快。
BitBlt函數的參數分别為:1.目标裝置上下文,在上面的程式裡,為螢幕裝置上下文,如果改成列印裝置上下文,就不是顯示位圖,而是列印;2.目标矩形左上角點x坐标;3. 目标矩形左上角點y坐标,在上面的程式中,2和3為(0,0),表示顯示在視窗的左上角;4.目标矩形的寬度;5. 目标矩形的高度;6. 源裝置上下文,在上面的程式裡,為記憶體裝置上下文;7. 源矩形左上角點x坐标;8. 源矩形左上角點y坐标;9.操作方式,在這裡為SRCCOPY,表示直接将源矩形拷貝到目标矩形。還可以是反色,擦除,做“與”運算等操作,具體細節見VC++幫助。你可以試着改改第2、3、4、5、7、8、9項參數,就能體會到它們的含義了。
哇,終于講完了。是不是覺得有點枯燥?這一章是有點兒枯燥,特别是當你對Windows的程式設計并不清楚時,就更覺得如此。不過,當一幅漂亮的bmp圖顯示在螢幕上時,你還是會興奮地大叫“Yeah!”,至少當年我是這樣。
在本書的附盤中包含所有的源程式,包括頭檔案和資源檔案和例圖。特别要注意的是,退出時,别忘了釋放記憶體和資源,這是每個程式員應該養成的習慣。這些個程式并不是很完善,例如,如果一幅圖很大,螢幕顯示不下怎麼辦?你可以試着自己加上滾動條。另外,為了節省篇幅,.bmp檔案名被固定為c:/test.bmp,可以自己加入打開檔案對話框,任意選擇你要顯示的檔案。圖1.4為程式運作時的畫面。
圖1.4 運作時的畫面最後,再介紹一個指令行編譯的竅門。為什麼要用指令行編譯呢?主要有兩個好處:第一,不用進入IDE(內建開發環境),節省了時間,而且編譯速度也比較快;第二,對于簡單的程式,不用生成項目檔案.mdp或.mak,直接就能生成.exe檔案,這一點,在下面的例子中可以看到。
在安裝完Visual C++時,在bin目錄下會産生一個VCVARS32.BAT檔案,它的作用是在指令行編譯時設定正确的環境變量,如存放頭檔案的INCLUDE目錄,存放庫檔案的LIB目錄等。如果你沒找到這個批處理檔案,可以參考下面的例子,自己做一個批處理。
@echo off
set MSDevDir=d:/MSDEV
set VcOsDir=WIN95
set PATH="%MSDevDir%/BIN";"%MSDevDir%/BIN/%VcOsDir%";"%PATH%"
set INCLUDE=%MSDevDir%/INCLUDE;%MSDevDir%/MFC/INCLUDE;
%INCLUDE%
set LIB=%MSDevDir%/LIB;%MSDevDir%/MFC/LIB;%LIB%
set VcOsDir=
隻要把上面的“d:/MSDEV”改成你自己的VC目錄就可以了。在DOS PROMPT下執行該批處理檔案,執行set指令,你就能看到新設定的環境變量了。如下所示:
PATH=D:/MSDEV/BIN;D:/MSDEV/BIN/WIN95;C:/WIN95;C:/WIN95/COMMAND;C:/WIN95/SYSTEM;
INCLUDE=d:/msdev/INCLUDE;d:/msdev/MFC/INCLUDE;
LIB=d:/msdev/LIB;d:/msdev/MFC/LIB;
現在我們就可以進行指令行編譯了。首先編譯資源檔案,輸入rc bmp.rc,将生成bmp.res檔案,接着輸入cl bmp.c bmp.res user32.lib gdi32.lib,就生成bmp.exe 了。可以看到,我們并沒有用到項目檔案,是以,對于這種簡單的程式來說,使用指令行編譯還是非常友善的。
有時指令行編譯會出現“Out of enviroment space”的錯誤,那是因為command.com預設的初始環境變量記憶體太小,首先執行command /e:2048 (或更大)指令即可解決改問題。
使用ide的方法是:new project,類型是win32 application->empty project,然後把.h,.rc,.c檔案add to project編譯即可。
好了,運作bmp.exe,欣賞一下你今天的勞動成果。
The University of Southern California does not screen or control the content on this website and thus does not guarantee the accuracy, integrity, or quality of such content. All content on this website is provided by and is the sole responsibility of the person from which such content originated, and such content does not necessarily reflect the opinions of the University administration or the Board of Trustees