一、軟件準(zhǔn)備:Apache(2.0.52): PHP(4.3.9): MySQL(4.1.7): Zend Optimizer(2.5.5): phpMyAdmin(2.6.0): 二、安裝 PHP :(1)、下載后得到 php-4.3.9-Win32.zip ,解壓至 C:\PHP(這個(gè)路徑可以隨意,不過(guò)下面要是用到這個(gè)路徑,請(qǐng)相應(yīng)修改);(2)、進(jìn)入 C:\PHP ,將 php.ini-dist 復(fù)制一份放到 C:\WINNT( Windows 2003 下為 C:\Windows )內(nèi),改名為 php.ini ,然后用記事本打開(kāi),利用記事本的查找功能搜索 extension_dir = "./" ,并將其路徑指到你的 PHP 目錄下的 extensions 目錄,比如:extension_dir = "C:\PHP\extensions" ;再搜索 register_globals = Off ,將 Off 改成 On ;如果你想讓 PHP 支持更多功能模塊,請(qǐng)按照下面的步驟去做,如果不想的話,直接保存關(guān)閉 php.ini 即可.PHP 支持的模塊很多,搜索:;Windows Extensions;Note that MySQL and ODBC support is now built in, so no dll is needed for it.;下面所列的就是 PHP 預(yù)支持的擴(kuò)展模塊,默認(rèn)情況下都用分號(hào)在前面注釋掉了,如果你想 PHP 支持某個(gè)模塊,請(qǐng)將前面的“;”廳巧去掉即可。如果安裝完畢后測(cè)試時(shí),彈出不支持 xxx.dll 模塊的話,直接將前面分號(hào)再加上去,保存后重啟 Web 服務(wù)器就可以了。(3)、把 C:\PHP\php4ts.dll 和 C:\PHP\dlls 目錄下的所有文件復(fù)制粘貼到 C:\WINNT\system32\( Windows 2003 下為 C:\Windows\system32 )內(nèi);(4)、配置 IIS 使其支持 PHP :首先必須確定系統(tǒng)中已經(jīng)正確安裝 IIS ,如果沒(méi)有安裝,需要先安裝 IIS ,安裝步驟如下:a Windows 2000 下的 IIS 安裝:用 Administrator 帳號(hào)登陸系統(tǒng),將 Windows 2000 安裝光盤(pán)插入光盤(pán)驅(qū)動(dòng)器,進(jìn)入“控制面板”點(diǎn)擊“添加/刪除程序”,再點(diǎn)擊左側(cè)的“添加/刪除 Windows 組件”,在彈出的窗口中選擇“Internet 信息服務(wù)(IIS)”,點(diǎn)下面的“詳細(xì)信息”按鈕,選擇組件,以下組件是必須的:“Internet 服務(wù)管理器”、“World Wide Web 服務(wù)器”和“公用文件”,確定安裝。安裝完畢后,在“控制面板”的“管理工具”里打開(kāi)“服務(wù)”,檢查“IIS Admin Service”和“World Wide Web Publishing Service”兩項(xiàng)服務(wù),如果沒(méi)有啟動(dòng),將其啟動(dòng)即可。b Windows 2003 下的 IIS 安裝:由于 Windows 2003 的 IIS 6.0 集成在應(yīng)用程序服務(wù)器中,因此安裝應(yīng)用程序服務(wù)器就會(huì)默認(rèn)安裝 IIS 6.0 ,在“開(kāi)始”菜單中點(diǎn)擊“配置您的服務(wù)器”,在打開(kāi)的“配置您的服務(wù)器向?qū)А崩镒髠?cè)選擇“應(yīng)用程序服務(wù)器(IIS,ASP.NET)”,單擊“下一步”手伏灶出現(xiàn)“應(yīng)用程序服務(wù)器選項(xiàng)”,你可以選擇和應(yīng)用程序服務(wù)器一起安裝的組件,默認(rèn)全選即可,單擊“下一步”,出現(xiàn)“選擇總結(jié)界面”,提示了本次安裝中的選項(xiàng),配置程序?qū)⒆詣?dòng)按照“選擇總結(jié)”中的選項(xiàng)進(jìn)行安裝和配置。打開(kāi)瀏覽器,輸入:,看到成功頁(yè)面后進(jìn)行下面的操作:PHP 支持 CGI 和 ISAPI 兩種安裝模式,推薦使用 ISAPI 模式。a、CGI 模式安裝步驟:在畢扮“控制面板”的“管理工具”中選擇“Internet 服務(wù)管理器”,打開(kāi) IIS 后停止服務(wù),然后在左側(cè)“默認(rèn)Web站點(diǎn)”上單擊右鍵選擇“屬性”,在打開(kāi)的“默認(rèn) Web 站點(diǎn)屬性”窗口的“主目錄”標(biāo)簽里找到并點(diǎn)擊“配置”按鈕,在彈出的“應(yīng)用程序配置”窗口中找到并點(diǎn)擊“添加”按鈕,在彈出的窗口中新增一個(gè)擴(kuò)展名映射,擴(kuò)展名為 .php ,單擊“瀏
網(wǎng)站建設(shè)公司,為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì)及定制網(wǎng)站建設(shè)服務(wù),專注于成都定制網(wǎng)頁(yè)設(shè)計(jì),高端網(wǎng)頁(yè)制作,對(duì)成都自上料攪拌車等多個(gè)行業(yè)擁有豐富的網(wǎng)站建設(shè)經(jīng)驗(yàn)的網(wǎng)站建設(shè)公司。專業(yè)網(wǎng)站設(shè)計(jì),網(wǎng)站優(yōu)化推廣哪家好,專業(yè)seo優(yōu)化優(yōu)化,H5建站,響應(yīng)式網(wǎng)站。
串口API通信函數(shù)編程
16位串口應(yīng)用程序中,使用的16位的Windows API通信函數(shù):
①OpenComm()打開(kāi)串口資源,并指定輸入、輸出緩沖區(qū)的大小(以字節(jié)計(jì))
CloseComm() 關(guān)閉串口;
例:int idComDev;
idComDev = OpenComm("COM1", 1024, 128);
CloseComm(idComDev);
②BuildCommDCB() 、setCommState()填寫(xiě)設(shè)備控制塊DCB,然后對(duì)已打開(kāi)的串口進(jìn)行參數(shù)配置; 例:DCB dcb;
BuildCommDCB("COM1:2400,n,8,1", dcb);
SetCommState(dcb);
③ ReadComm 、WriteComm()對(duì)串口進(jìn)行讀寫(xiě)操作,即數(shù)據(jù)的接收和發(fā)送.
例:char *m_pRecieve; int count;
ReadComm(idComDev,m_pRecieve,count);
Char wr[30]; int count2;
WriteComm(idComDev,wr,count2);
16位下的串口通信程序最大的特點(diǎn)就在于:串口等外部設(shè)備的操作有自己特有的API函數(shù);而32位程序則把串口操作(以及并口等)和文件操作統(tǒng)一起來(lái)了,使用類似的操作。
在MFC下的32位串口應(yīng)用程序
32位下串口通信程序可以用兩種方法實(shí)現(xiàn):利用ActiveX控件;使用API 通信函數(shù)。
使用ActiveX控件,程序?qū)崿F(xiàn)非常簡(jiǎn)單,結(jié)構(gòu)清晰,缺點(diǎn)是欠靈活;使用API 通信函數(shù)的優(yōu)缺點(diǎn)則基本上相反。
使用ActiveX控件:
VC++ 6.0提供的MSComm控件通過(guò)串行端口發(fā)送和接收數(shù)據(jù),為應(yīng)用程序提供串行通信功能。使用非常方便,但可惜的是,很少有介紹MSComm控件槐鉛和的資料。
⑴.在當(dāng)前的Workspace中插入MSComm控件。
Project菜單------Add to Project----Components and Controls-----Registered
ActiveX Controls---選擇Components: Microsoft Communications Control,
version 6.0 插入到當(dāng)前的Workspace中。
結(jié)果添加了類CMSComm(及相應(yīng)文件:mscomm.h和mscomm.cpp )。
⑵.在MainFrm.h中加入MSComm控件。
protected:
CMSComm m_ComPort;
在Mainfrm.cpp::OnCreare()中:
DWORD style=WS_VISIBLE|WS_CHILD;
if (!m_ComPort.Create(NULL,style,CRect(0,0,0,0),this,ID_COMMCTRL)){
TRACE0("Failed to create OLE Communications Control\n");
return -1; // fail to create
}
⑶.初始化串口
m_ComPort.SetCommPort(1); //選擇COM?
m_ComPort. SetInBufferSize(1024); //設(shè)置輸入緩沖區(qū)的大小,Bytes
m_ComPort. SetOutBufferSize(512); //設(shè)置輸入緩沖區(qū)的大小,Bytes//
if(!m_ComPort.GetPortOpen()) //打開(kāi)串口
m_ComPort.SetPortOpen(TRUE);
m_ComPort.SetInputMode(1); //設(shè)置輸入方式為二進(jìn)制方式
m_ComPort.SetSettings("9600,n,8,1"); //設(shè)置波特率等參數(shù)
m_ComPort.SetRThreshold(1); //為1表示有一個(gè)字符引發(fā)一個(gè)事件
m_ComPort.SetInputLen(0);
⑷.捕捉串口事項(xiàng)。MSComm控件可以采用輪詢或事件驅(qū)動(dòng)的方法從端口獲取數(shù)據(jù)。我們介紹比較使用的事件驅(qū)動(dòng)方法:鉛盯有事件(如接收到數(shù)據(jù))時(shí)通知程激虧序。在程序中需要捕獲并處理這些通訊事件。
在MainFrm.h中:
protected:
afx_msg void OnCommMscomm();
DECLARE_EVENTSINK_MAP()
在MainFrm.cpp中:
BEGIN_EVENTSINK_MAP(CMainFrame,CFrameWnd )
ON_EVENT(CMainFrame,ID_COMMCTRL,1,OnCommMscomm,VTS_NONE) //映射ActiveX控件事件
END_EVENTSINK_MAP()
⑸.串口讀寫(xiě). 完成讀寫(xiě)的函數(shù)的確很簡(jiǎn)單,GetInput()和SetOutput()就可。兩個(gè)函數(shù)的原型是:
VARIANT GetInput();及 void SetOutput(const VARIANT newValue);都要使用VARIANT類型(所有Idispatch::Invoke的參數(shù)和返回值在內(nèi)部都是作為VARIANT對(duì)象處理的)。
無(wú)論是在PC機(jī)讀取上傳數(shù)據(jù)時(shí)還是在PC機(jī)發(fā)送下行命令時(shí),我們都習(xí)慣于使用字符串的形式(也可以說(shuō)是數(shù)組形式)。查閱VARIANT文檔知道,可以用BSTR表示字符串,但遺憾的是所有的BSTR都是包含寬字符,即使我們沒(méi)有定義_UNICODE_UNICODE也是這樣! WinNT支持寬字符, 而Win95并不支持。為解決上述問(wèn)題,我們?cè)趯?shí)際工作中使用CbyteArray,給出相應(yīng)的部分程序如下:
void CMainFrame::OnCommMscomm(){
VARIANT vResponse; int k;
if(m_commCtrl.GetCommEvent()==2) {
k=m_commCtrl.GetInBufferCount(); //接收到的字符數(shù)目
if(k0) {
vResponse=m_commCtrl.GetInput(); //read
SaveData(k,(unsigned char*) vResponse.parray-pvData);
} // 接收到字符,MSComm控件發(fā)送事件 }
。。。。。 // 處理其他MSComm控件
}
void CMainFrame::OnCommSend() {
。。。。。。。。 // 準(zhǔn)備需要發(fā)送的命令,放在TxData[]中
CByteArray array;
array.RemoveAll();
array.SetSize(Count);
for(i=0;iCount;i++)
array.SetAt(i, TxData[i]);
m_ComPort.SetOutput(COleVariant(array)); // 發(fā)送數(shù)據(jù) }
二 使用32位的API 通信函數(shù):
⑴.在中MainFrm.cpp定義全局變量
HANDLE hCom; // 準(zhǔn)備打開(kāi)的串口的句柄
HANDLE hCommWatchThread ;//輔助線程的全局函數(shù)
⑵.打開(kāi)串口,設(shè)置串口
hCom =CreateFile( "COM2", GENERIC_READ | GENERIC_WRITE, // 允許讀寫(xiě)
0, // 此項(xiàng)必須為0
NULL, // no security attrs
OPEN_EXISTING, //設(shè)置產(chǎn)生方式
FILE_FLAG_OVERLAPPED, // 我們準(zhǔn)備使用異步通信
NULL );
我使用了FILE_FLAG_OVERLAPPED結(jié)構(gòu)。這正是使用API實(shí)現(xiàn)非阻塞通信的關(guān)鍵所在。
ASSERT(hCom!=INVALID_HANDLE_VALUE); //檢測(cè)打開(kāi)串口操作是否成功
SetCommMask(hCom, EV_RXCHAR|EV_TXEMPTY );//設(shè)置事件驅(qū)動(dòng)的類型
SetupComm( hCom, 1024,512) ; //設(shè)置輸入、輸出緩沖區(qū)的大小
PurgeComm( hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR
| PURGE_RXCLEAR ); //清干凈輸入、輸出緩沖區(qū)
COMMTIMEOUTS CommTimeOuts ; //定義超時(shí)結(jié)構(gòu),并填寫(xiě)該結(jié)構(gòu)
…………
SetCommTimeouts( hCom, CommTimeOuts ) ;//設(shè)置讀寫(xiě)操作所允許的超時(shí)
DCB dcb ; // 定義數(shù)據(jù)控制塊結(jié)構(gòu)
GetCommState(hCom, dcb ) ; //讀串口原來(lái)的參數(shù)設(shè)置
dcb.BaudRate =9600; dcb.ByteSize =8; dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT ;dcb.fBinary = TRUE ;dcb.fParity = FALSE;
SetCommState(hCom, dcb ) ; //串口參數(shù)配置
上述的COMMTIMEOUTS結(jié)構(gòu)和DCB都很重要,實(shí)際工作中需要仔細(xì)選擇參數(shù)。
⑶啟動(dòng)一個(gè)輔助線程,用于串口事件的處理。
Windows提供了兩種線程,輔助線程和用戶界面線程。輔助線程沒(méi)有窗口,所以它沒(méi)有自己的消息循環(huán)。但是輔助線程很容易編程,通常也很有用。
在次,我們使用輔助線程。主要用它來(lái)監(jiān)視串口狀態(tài),看有無(wú)數(shù)據(jù)到達(dá)、通信有無(wú)錯(cuò)誤;而主線程則可專心進(jìn)行數(shù)據(jù)處理、提供友好的用戶界面等重要的工作。
hCommWatchThread=
CreateThread( (LPSECURITY_ATTRIBUTES) NULL, //安全屬性
0,//初始化線程棧的大小,缺省為與主線程大小相同
(LPTHREAD_START_ROUTINE)CommWatchProc, //線程的全局函數(shù)
GetSafeHwnd(), //此處傳入了主框架的句柄
0, dwThreadID );
ASSERT(hCommWatchThread!=NULL);
⑷為輔助線程寫(xiě)一個(gè)全局函數(shù),主要完成數(shù)據(jù)接收的工作。請(qǐng)注意OVERLAPPED結(jié)構(gòu)的使用,以及怎樣實(shí)現(xiàn)了非阻塞通信。
UINT CommWatchProc(HWND hSendWnd){
DWORD dwEvtMask=0 ;
SetCommMask( hCom, EV_RXCHAR|EV_TXEMPTY );//有哪些串口事件需要監(jiān)視?
WaitCommEvent( hCom, dwEvtMask, os );// 等待串口通信事件的發(fā)生
檢測(cè)返回的dwEvtMask,知道發(fā)生了什么串口事件:
if ((dwEvtMask EV_RXCHAR) == EV_RXCHAR){ // 緩沖區(qū)中有數(shù)據(jù)到達(dá)
COMSTAT ComStat ; DWORD dwLength;
ClearCommError(hCom, dwErrorFlags, ComStat ) ;
dwLength = ComStat.cbInQue ; //輸入緩沖區(qū)有多少數(shù)據(jù)?
if (dwLength 0) { BOOL fReadStat ;
fReadStat = ReadFile( hCom, lpBuffer,dwLength, dwBytesRead,READ_OS( npTTYInfo ) ); //讀數(shù)據(jù)
注:我們?cè)贑reareFile()時(shí)使用了FILE_FLAG_OVERLAPPED,現(xiàn)在ReadFile()也必須使用
LPOVERLAPPED結(jié)構(gòu).否則,函數(shù)會(huì)不正確地報(bào)告讀操作已完成了.
使用LPOVERLAPPED結(jié)構(gòu), ReadFile()立即返回,不必等待讀操作完成,實(shí)現(xiàn)非阻塞
通信.此時(shí), ReadFile()返回FALSE, GetLastError()返回ERROR_IO_PENDING.
if (!fReadStat){
if (GetLastError() == ERROR_IO_PENDING){
while(!GetOverlappedResult(hCom,READ_OS( npTTYInfo ), dwBytesRead, TRUE )){
dwError = GetLastError();
if(dwError == ERROR_IO_INCOMPLETE) continue;//緩沖區(qū)數(shù)據(jù)沒(méi)有讀完,繼續(xù)
…… ……
::PostMessage((HWND)hSendWnd,WM_NOTIFYPROCESS,0,0);//通知主線程,串口收到數(shù)據(jù)}
所謂的非阻塞通信,也即異步通信。是指在進(jìn)行需要花費(fèi)大量時(shí)間的數(shù)據(jù)讀寫(xiě)操作(不僅僅是指串行通信操作)時(shí),一旦調(diào)用ReadFile()、WriteFile(), 就能立即返回,而讓實(shí)際的讀寫(xiě)操作在后臺(tái)運(yùn)行;相反,如使用阻塞通信,則必須在讀或?qū)懖僮魅客瓿珊蟛拍芊祷?。由于操作可能需要任意長(zhǎng)的時(shí)間才能完成,于是問(wèn)題就出現(xiàn)了。
非常阻塞操作還允許讀、寫(xiě)操作能同時(shí)進(jìn)行(即重疊操作?),在實(shí)際工作中非常有用。
要使用非阻塞通信,首先在CreateFile()時(shí)必須使用FILE_FLAG_OVERLAPPED;然后在 ReadFile()時(shí)lpOverlapped參數(shù)一定不能為NULL,接著檢查函數(shù)調(diào)用的返回值,調(diào)用GetLastError(),看是否返回ERROR_IO_PENDING。如是,最后調(diào)用GetOverlappedResult()返回重疊操作(overlapped operation)的結(jié)果;WriteFile()的使用類似。
⑸.在主線程中發(fā)送下行命令。
BOOL fWriteStat ; char szBuffer[count];
…………//準(zhǔn)備好發(fā)送的數(shù)據(jù),放在szBuffer[]中
fWriteStat = WriteFile(hCom, szBuffer, dwBytesToWrite,
dwBytesWritten, WRITE_OS( npTTYInfo ) ); //寫(xiě)數(shù)據(jù)
//我在CreareFile()時(shí)使用了FILE_FLAG_OVERLAPPED,現(xiàn)在WriteFile()也必須使用LPOVERLAPPED結(jié)構(gòu).否則,函數(shù)會(huì)不正確地報(bào)告寫(xiě)操作已完成了.
使用LPOVERLAPPED結(jié)構(gòu),WriteFile()立即返回,不必等待寫(xiě)操作完成,實(shí)現(xiàn)非阻塞 通信.此時(shí), WriteFile()返回FALSE, GetLastError()返回ERROR_IO_PENDING.
int err=GetLastError();
if (!fWriteStat) {
if(GetLastError() == ERROR_IO_PENDING){
while(!GetOverlappedResult(hCom, WRITE_OS( npTTYInfo ),
dwBytesWritten, TRUE )) {
dwError = GetLastError();
if(dwError == ERROR_IO_INCOMPLETE){// normal result if not finished
dwBytesSent += dwBytesWritten; continue; }
......................
//我使用了多線程技術(shù),在輔助線程中監(jiān)視串口,有數(shù)據(jù)到達(dá)時(shí)依靠事件驅(qū)動(dòng),讀入數(shù)據(jù)并向主線程報(bào)告(發(fā)送數(shù)據(jù)在主線程中,相對(duì)說(shuō)來(lái),下行命令的數(shù)據(jù)總是少得多);并且,WaitCommEvent()、ReadFile()、WriteFile()都使用了非阻塞通信技術(shù),依靠重疊(overlapped)讀寫(xiě)操作,讓串口讀寫(xiě)操作在后臺(tái)運(yùn)行。
現(xiàn)在我用我所知道的為樓主介紹VB.NET的API調(diào)用,請(qǐng)樓主瀏覽一下,看看行不行。
Windows API就是Windows系統(tǒng)的API函數(shù)簡(jiǎn)稱(Application Program Interface,即:應(yīng)用程序接口函數(shù)),它是Windows操作系統(tǒng)提供給各種開(kāi)發(fā)基于Windows平臺(tái)應(yīng)用軟件的開(kāi)發(fā)語(yǔ)言的一些公用的函數(shù),這些函數(shù)一般都比較底層,所以當(dāng)各種開(kāi)發(fā)語(yǔ)言使用自帶的函數(shù)或類庫(kù)已無(wú)法解決問(wèn)題時(shí),調(diào)用Windows API函數(shù)往往是一種非常直接、有效的解決方法。但由于在程序中調(diào)用Windows API函數(shù)一般都很復(fù)雜,所以對(duì)于程序員來(lái)說(shuō)穗肆鏈,是否能夠靈活的使用Windows API函數(shù),往往也是其水平高低的一個(gè)重要標(biāo)志。但自從微軟推出.Net框架以后雹廳,各種開(kāi)發(fā)基于.Net平臺(tái)下的程序語(yǔ)言,如Visual Basic .Net、Visual C#等卻很少使用Windows API函數(shù),并且微軟公司也不像以前那樣,提倡在這些.Net開(kāi)發(fā)語(yǔ)言中使用Windows API函數(shù),其主要的原因如下:
1. .Net框架所附帶的類庫(kù).Net FrameWork SDK是一個(gè)內(nèi)容豐富、功能強(qiáng)大的軟件開(kāi)發(fā)包,各種Windows API函數(shù)所實(shí)現(xiàn)的各種功能幾乎都可以在這個(gè)軟件開(kāi)發(fā)包中找到與之對(duì)應(yīng)的部分。
2. 微軟Visual Basic .Net、Visual C#等目的是編寫(xiě)跨平臺(tái)的應(yīng)用程序,如果在Visual Basic .Net、Visual C#等中使用Windows API函數(shù),這也就注定了編寫(xiě)出的程序只能運(yùn)行于Windows平臺(tái)之下,而弱化了.NET的跨平臺(tái)能力。這也就是為什么微軟不提倡在.Net平臺(tái)調(diào)用Windows API函數(shù)的原因。
雖然微軟并不提倡在Visual Basic .Net、Visual C#中調(diào)用Windows API函數(shù),但由于目前.Net 框架推出時(shí)間較短,.Net FrameWork SDK中提供的類庫(kù)還并不足以完全替換Windows API函數(shù)的所有功能,所以在某些時(shí)候,.Net開(kāi)發(fā)語(yǔ)言還是必須要調(diào)用Windows API函數(shù)。
一.平臺(tái)調(diào)用、托管DLL、非托管DLL簡(jiǎn)介:
托管DLL就是能夠在公共語(yǔ)言運(yùn)行庫(kù)(Common Language Runtime,簡(jiǎn)稱CLR)中能夠直接引用的,并且擴(kuò)展名為“DLL”的文件。具體所指就是封裝各種命名空間所在的DLL文件,如System.dll等。非托管DLL就是平常所的動(dòng)態(tài)鏈接庫(kù)等,其中就包括了封裝所有Windows API函數(shù)的DLL文件。各種非托管DLL中的函數(shù)在公共語(yǔ)言運(yùn)行庫(kù)中不能直接被調(diào)用,而需要經(jīng)過(guò).Net框架提供的“平臺(tái)調(diào)用”服務(wù)后才可以。
“平臺(tái)調(diào)用”是.Net框架為Visual Basic .Net、Visual C#等.Net開(kāi)發(fā)語(yǔ)言提供的一種服務(wù),用以在托管代碼中引入各種非托管DLL中封裝的函數(shù)(其中包括Windows API函數(shù))?!捌脚_(tái)調(diào)用”依賴于元數(shù)據(jù)在運(yùn)行時(shí)查找導(dǎo)出函數(shù)并封裝其參數(shù)。圖01公共語(yǔ)言運(yùn)行庫(kù)利用“平臺(tái)服務(wù)”調(diào)用非托管DLL中的函數(shù)的流程圖:
圖01:“平臺(tái)服務(wù)”的調(diào)用非托管函數(shù)的流程圖
在托管代碼中使用“平臺(tái)調(diào)用”服務(wù)調(diào)用非托管DLL中封裝的函數(shù)時(shí),“平臺(tái)服務(wù)”將依次執(zhí)行以下操作:
1. 查找包含該函數(shù)所在的DLL文件。
2. 如果找到,則將該DLL文件 加載到內(nèi)存中。
3. 查找函數(shù)在內(nèi)存中的地址并將其參數(shù)推到堆棧上,并封送所需的猜孫數(shù)據(jù)。
4. 將控制權(quán)轉(zhuǎn)移給非托管函數(shù)。 這樣整個(gè)函數(shù)調(diào)用完成。
在Visual Basic .Net中使用“平臺(tái)調(diào)用”服務(wù),申明Windows API函數(shù)主要有二種具體的實(shí)現(xiàn)方法:
1. 使用DllImport特征類來(lái)申明Windows API函數(shù)。
2. 使用“Declare”語(yǔ)句來(lái)申明Windows API函數(shù)。
這二種方法雖有異曲同工之效,但在繁簡(jiǎn)上卻有很大差異,第一種方法申明過(guò)程比較復(fù)雜,很容易在申明Windows API函數(shù)時(shí)出錯(cuò),所以并不提倡。而第二種方法相對(duì)簡(jiǎn)單,并且又保存了以前Visual Basic中的很多語(yǔ)法,所以在平常時(shí)大都使用這種方法來(lái)申明Windows API函數(shù)。
二.VB.Net查看文件中圖標(biāo)的函數(shù)及申明Windows API的方法:
Visual Basic .Net要實(shí)現(xiàn)查看文件中的圖標(biāo),目前只使用.Net FrameWork SDK是無(wú)法實(shí)現(xiàn)這種功能的,正如前面所說(shuō),主要是由于.Net FrameWork SDK推出的時(shí)間較短,其功能還不可能面面俱到。解決問(wèn)題的關(guān)鍵是正確使用Windows API函數(shù),其中所涉及到的Windows API函數(shù)主要有二個(gè):其一是獲得指定文件中的圖標(biāo)數(shù)目;其二是從指定文件的指定位置導(dǎo)出圖標(biāo)的Windows句柄。這二個(gè)函數(shù)都位于“Shell32.dll”文件中,并且函數(shù)的入口點(diǎn)都為“ExtractIcon”。下面是在Visual Basic .Net中分別使用DllImport特征類和“Declare”語(yǔ)句申明這二個(gè)Windows API函數(shù)的具體方法。
(1).使用DllImport特征類來(lái)申明Windows API函數(shù):
下面是在Visual Basic .Net中使用DllImport特征類申明二個(gè)Windows API函數(shù)的具體示例:
'函數(shù)ExtractIcon,其功能是是從指定文件的指定位置導(dǎo)出圖標(biāo)的Windows句柄。
< System.Runtime.InteropServices.DllImport ( "Shell32.dll" , EntryPoint := "ExtractIcon" ) > _
Public Function _
ExtractIcon ( ByVal src As System.IntPtr , ByVal strFileName As string , ByVal uiIconIndex As UInt32 ) As System.IntPtr
End Function
'函數(shù)Icon_Num,其功能是獲得指定文件中的圖標(biāo)數(shù)目
< System.Runtime.InteropServices.DllImport ( "Shell32.dll" , EntryPoint := "ExtractIcon" ) > _
Public Function _
Icon_Num ( ByVal src As System.IntPtr , ByVal strFileName As string , ByVal uiIconIndex As Integer ) As Integer
End Function
在使用DllImport特征類申明Windows API函數(shù)時(shí),如果申明的函數(shù)名稱和函數(shù)的入口點(diǎn)相同,則可以在申明Windows API函數(shù)時(shí),省略定義函數(shù)入口點(diǎn)對(duì)應(yīng)的代碼,即EntryPoint對(duì)象字段對(duì)應(yīng)的代碼,這樣聲明ExtractIcon函數(shù)的代碼也可以簡(jiǎn)化為如下所示:
< System.Runtime.InteropServices.DllImport ( "Shell32.dll" ) > _
Public Function _
ExtractIcon ( ByVal src As System.IntPtr , ByVal strFileName As string , ByVal uiIconIndex As UInt32 ) As System.IntPtr
End Function
(2).使用“Declare”語(yǔ)句來(lái)申明Windows API函數(shù):
使用“Declare”語(yǔ)句的確比使用DllImport特征類要簡(jiǎn)單了許多,下面是在Visual Basic .Net中使用“Declare”語(yǔ)句來(lái)聲明上述二個(gè)Windows API函數(shù)的具體方法:
Declare Auto Function ExtractIcon Lib "Shell32.dll" Alias "ExtractIcon" ( ByVal src As System.IntPtr , ByVal strFileName As string , ByVal uiIconIndex As UInt32 ) As System.IntPtr
'聲明ExtractIcon函數(shù)
Declare Auto Function Icon_Num Lib "Shell32.dll" Alias "ExtractIcon" ( ByVal src As System.IntPtr , ByVal strFileName As string , ByVal uiIconIndex As Integer ) As Integer
'聲明Icon_Num函數(shù)
在Visual Basic .Net中聲明Windows API函數(shù)時(shí),“Declare”語(yǔ)句中Alias關(guān)鍵字的作用相當(dāng)于使用DllImport特征類中的EntryPoint對(duì)象字段。同樣在使用“Declare”語(yǔ)句聲明Windows API函數(shù)時(shí),如果聲明的函數(shù)和函數(shù)的入口點(diǎn)相同,也可以省略Alias關(guān)鍵字對(duì)應(yīng)的代碼,所以ExtractIcon函數(shù)也可以簡(jiǎn)化為如下:
Declare Auto Function ExtractIcon Lib "Shell32.dll" ( ByVal src As System.IntPtr , ByVal strFileName As string , ByVal uiIconIndex As UInt32 ) As System.IntPtr
下面就結(jié)合一個(gè)示例的編寫(xiě)過(guò)程來(lái)掌握的這二個(gè)Windows API函數(shù)的具體使用方法,這個(gè)示例的作用就是讀取指定文件中的圖標(biāo)數(shù)目,并顯示文件中的圖標(biāo)。
三.本文中程序的編寫(xiě)、調(diào)試和運(yùn)行環(huán)境:
(1).視窗2000高級(jí)服務(wù)器版。
(2).Visual Studio .Net 2003企業(yè)結(jié)構(gòu)設(shè)計(jì)版,.Net FrameWork SDK版本號(hào)4322。
四.Visual Basic .Net讀取文件中的圖標(biāo)的實(shí)現(xiàn)步驟:
下面介紹的示例,其功能讀取指定文件中包含的圖標(biāo)數(shù)目,并把這些圖標(biāo)全部顯示出來(lái)。下面是這個(gè)示例的實(shí)現(xiàn)步驟:
1. 啟動(dòng)Visual Studio .Net。
2. 選擇菜單【文件】|【新建】|【項(xiàng)目】后,彈出【新建項(xiàng)目】對(duì)話框。
3. 將【項(xiàng)目類型】設(shè)置為【Visual Basic項(xiàng)目】。
4. 將【模板】設(shè)置為【W(wǎng)indows應(yīng)用程序】。
5. 在【名稱】文本框中輸入【Visual Basic .Net查看文件中的圖標(biāo)】。
6. 在【位置】的文本框中輸入【E:\VS.NET項(xiàng)目】,然后單擊【確定】按鈕,這樣在【E:\VS.NET項(xiàng)目】目錄中就產(chǎn)生了名稱為【Visual Basic .Net查看文件中的圖標(biāo)】文件夾,里面存放著【Visual Basic .Net查看文件中的圖標(biāo)】項(xiàng)目的所有文件。具體如圖02所示:
圖02:【Visual Basic .Net查看文件中的圖標(biāo)】項(xiàng)目的【新建項(xiàng)目】對(duì)話框
7. 選擇菜單【項(xiàng)目】|【添加新項(xiàng)】,在彈出的對(duì)話框中的【模板】設(shè)置為【模塊】,【名稱】文本框設(shè)置為【Module1.vb】后。單擊【打開(kāi)】按鈕,則在項(xiàng)目中增加了一個(gè)模板文件,名稱為【Module1.vb】。
8. 把Visual Stuido .Net的當(dāng)前窗口切換到Module1.vb的代碼編輯窗口,并在其Module1的代碼區(qū)中添加下列代碼,下列代碼是用二種方式聲明二個(gè)Windows API函數(shù):
< System.Runtime.InteropServices.DllImport ( "Shell32.dll" ) > _
Public Function _
ExtractIcon ( ByVal src As System.IntPtr , ByVal strFileName As String , ByVal uiIconIndex As UInt32 ) As System.IntPtr
End Function
'聲明ExtractIcon函數(shù)
Declare Auto Function Icon_Num Lib "Shell32.dll" Alias "ExtractIcon" ( ByVal src As System.IntPtr , ByVal strFileName As String , ByVal uiIconIndex As Integer ) As Integer
9. 把Visual Studio .Net的當(dāng)前窗口切換到Form1窗體的設(shè)計(jì)查看,并從【工具箱】中的【W(wǎng)indows窗體】選項(xiàng)卡中拖入下列組件到Form1窗體:
四個(gè)Label組件,其中二個(gè)用以顯示提示信息,另外二個(gè)分別用以顯示選擇的文件名稱和這個(gè)文件中包含的圖標(biāo)數(shù)目。
一個(gè)ListView組件,利用其顯示大圖標(biāo)的屬性用以顯示選定文件中的圖標(biāo)。
一個(gè)OpenFileDialog組件,用以選擇要查看圖標(biāo)的文件名稱。
一個(gè)ImageList組件,它起的是橋梁的作用,首先把從文件中導(dǎo)出的圖標(biāo)存放到這里,然后再提供ListView組件顯示出來(lái)。
一個(gè)Button組件。
10. 按照表01中數(shù)值來(lái)設(shè)定設(shè)定組件的主要屬性:
組件類型 組件名稱 屬性 設(shè)置結(jié)果
Form Form1 Text VB.NET查看文件中的圖標(biāo)
Form1 MaximizeBox False
Form1 MinimizeBox False
Form1 FormBorderStyle FixedSingle
ListView ListView1 ImageList1 LargeImageList
ListView1 MultiSelect False
ListView1 Size Size ( 380 , 208 )
Button Button1 Text 選擇文件
Button1 FlatStyle Flat
ImageList ImageList1 Size Size ( 32 , 32 )
ImageList1 TransparentColor Color.Transparent
Label Label1 Text 文件名稱:
Label2 Text 圖標(biāo)數(shù)目:
Label3 Text ""
Label4 Text "0"
表01:【Visual Basic .Net查看文件中的圖標(biāo)】項(xiàng)目窗體中各組件的主要屬性設(shè)定數(shù)值表
并按照?qǐng)D02中各組件的位置、大小和排列方式來(lái)調(diào)整窗體中各個(gè)組件:
圖02:【Visual Basic .Net查看文件中的圖標(biāo)】項(xiàng)目的設(shè)計(jì)界面
11. 把Visual Studio .Net當(dāng)前窗口切換到Form.vb的代碼編輯窗口,并用下列代碼替換Form1.vb中的Button1組件的Click事件的處理代碼,下列代碼是在Button1組件的Click事件中處理查看文件中圖標(biāo)的功能,具體如下:
Private Sub Button1_Click ( ByVal sender As System.Object , ByVal e As System.EventArgs ) Handles Button1.Click
If OpenFileDialog1.ShowDialog ( ) = DialogResult.OK Then
'清除組件中的所有項(xiàng)目
ListView1.Items.Clear ( )
ImageList1.Images.Clear ( )
Dim sfName As String = OpenFileDialog1.FileName
Label3.Text = sfName
Dim iIcon_Num As Integer = Icon_Num ( IntPtr.Zero , sfName , -1 )
'顯示文件中的圖標(biāo)數(shù)目
Label4.Text = iIcon_Num.ToString ( )
Dim i As Integer
For i = 0 To iIcon_Num - 1 Step 1
'強(qiáng)制實(shí)現(xiàn)int到uint類型轉(zhuǎn)換
Dim j As UInt32
j = System.Convert.ToUInt32 ( i )
Dim hIcon As System.IntPtr = ExtractIcon ( IntPtr.Zero , sfName , j )
'在imageList1組件中加入當(dāng)然提取的圖標(biāo)
ImageList1.Images.Add ( Icon.FromHandle ( hIcon ).ToBitmap ( ) )
'在ListView組件中加入一個(gè)項(xiàng)目
ListView1.Items.Add ( "第" + ( i + 1 ).ToString ( ) + "個(gè)圖標(biāo)" )
'把加入項(xiàng)目的圖象索引指向剛才加入圖標(biāo)在imagList1組件中的索引,從而顯示圖標(biāo)
ListView1.Items ( i ).ImageIndex = i
Next i
End If
End Sub
12. 至此,在上述步驟都正確執(zhí)行后,【Visual Basic .Net查看文件中的圖標(biāo)】項(xiàng)目的全部工作就完成了。單擊快捷鍵F5就可以運(yùn)行程序,此時(shí)單擊【選擇文件】按鈕選擇文件后,程序就能夠讀取這個(gè)文件中的圖標(biāo)及其數(shù)目,并顯示出來(lái)了。具體如圖03所示:
圖03:【Visual Basic .Net查看文件中的圖標(biāo)】項(xiàng)目的運(yùn)行界面
五.總結(jié):
解決Visual Basic .Net查看文件中的圖標(biāo)的關(guān)鍵并非是使用.Net框架中提供的類庫(kù),而是使用Windows的API函數(shù)。雖然這與利用Visual Basic .Net開(kāi)發(fā)跨平臺(tái)程序的初衷相違背,但的確不失為一種解決問(wèn)題的方法。有些時(shí)候通過(guò)Windows API函數(shù)能夠快捷、方便的解決實(shí)際問(wèn)題,而這往往是只使用.Net FrameWork SDK所望塵莫及的,但隨著.Net FrameWork SDK內(nèi)容的不斷豐富,各種新的組成部分和新的功能不斷加入,可以預(yù)見(jiàn)的是,在未來(lái)的.Net FrameWork SDK中必將擁有可以替換本文中介紹的二個(gè)Windows API函數(shù)的組成部分。
success = WritePrivateProfileStringA改遲蘆成巖旦尺success = WritePrivateProfileString 另外vc6里的long在vc點(diǎn)虐 里要換成integer,你這樣調(diào)粗高用會(huì)出錯(cuò)的