在 Windows CE 下自帶有無線網(wǎng)卡的配置和連接程序,可是我的系統(tǒng)剪裁掉了資源管理器和任務(wù)欄,導(dǎo)致自帶的無線網(wǎng)卡配置程序不能再使用了,只好自力更生。
我的環(huán)境是 S3C2440 + WinCE 5.0 + VNUWCL5(威盛無線網(wǎng)卡)及驅(qū)動(dòng)程序。使用 Automatic Configuration Functions API
一、枚舉系統(tǒng)中可用的無線網(wǎng)絡(luò)設(shè)備
下面的函數(shù)可以枚舉出系統(tǒng)中所有可用的無線網(wǎng)卡設(shè)備的GUID,為了簡(jiǎn)化,我選擇第一塊可用的無線網(wǎng)卡來操作
BOOL GetFirstWirelessCard(PTCHAR pCard)
{
if (!pCard)
{
return FALSE;
}
INTFS_KEY_TABLE IntfsTable;
IntfsTable.dwNumIntfs = 0;
IntfsTable.pIntfs = NULL;
_tcscpy(pCard, TEXT(""));
// 枚舉系統(tǒng)中可用的無線網(wǎng)卡
DWORD dwStatus = WZCEnumInterfaces(NULL, &IntfsTable);
if (dwStatus != ERROR_SUCCESS)
{
RETAILMSG(DBG_MSG, (TEXT("WZCEnumInterfaces() error 0x%08X\n"),dwStatus));
return FALSE;
}
// 判斷無線網(wǎng)卡的數(shù)量,可以根據(jù)無線網(wǎng)卡數(shù)量來枚舉出所有可用的無線網(wǎng)卡
if (!IntfsTable.dwNumIntfs)
{
RETAILMSG(DBG_MSG, (TEXT("System has no wireless card.\n")));
return FALSE;
}
_tcscpy(pCard, IntfsTable.pIntfs[0].wszGuid);
LocalFree(IntfsTable.pIntfs);
return TRUE;
}
二、獲取無線網(wǎng)絡(luò)信息
獲取到了系統(tǒng)可用的無線網(wǎng)卡后,我們就可以利用它的 GUID 號(hào)來進(jìn)行進(jìn)一步的操作了,首先要做的事情就是得到該無線網(wǎng)卡的信息以及該無線網(wǎng)卡掃描到的 WIFI 網(wǎng)關(guān)信息。
以下函數(shù)可以獲取到該無線網(wǎng)卡及掃描的到的無線 AP 信息
//////////////////////////////////////////////////////////////////////////
// pCard: 無線網(wǎng)卡GUID
// pIntf: 無線網(wǎng)卡配置信息結(jié)果體
// pOutFlags: 網(wǎng)卡配置信息掩碼標(biāo)志
//////////////////////////////////////////////////////////////////////////
BOOL GetWirelessCardInfo(PTCHAR pCard, PINTF_ENTRY_EX pIntf, PDWORD pOutFlags)
{
TCHAR *szWiFiCard = NULL;
// 參數(shù)校驗(yàn)
if (!pCard || !pIntf || !pOutFlags)
{
RETAILMSG(DBG_MSG, (TEXT("Param Error.\n")));
return FALSE;
}
szWiFiCard = pCard;
*pOutFlags = 0;
// 初始化無線網(wǎng)卡信息
ZeroMemory(pIntf, sizeof(INTF_ENTRY_EX));
// 設(shè)置GUID 號(hào)
pIntf->wszGuid = szWiFiCard;
// 查詢無線網(wǎng)卡信息
DWORD dwStatus = WZCQueryInterfaceEx(NULL, INTF_ALL, pIntf, pOutFlags);
if (dwStatus != ERROR_SUCCESS)
{
RETAILMSG(DBG_MSG, (TEXT("WZCQueryInterfaceEx() error 0x%08X\n"), dwStatus));
return FALSE;
}
return TRUE;
}
三、判斷連接狀態(tài)
我們可以通過無線網(wǎng)卡的狀態(tài)來判斷當(dāng)前無線網(wǎng)卡是否已經(jīng)和無線AP建立了連接
BOOL IsAssociated(const INTF_ENTRY_EX Intf, const DWORD dwOutFlags)
{
if (dwOutFlags & INTF_BSSID)
{
PRAW_DATA prdMAC = (PRAW_DATA)(&Intf.rdBSSID);
// 判斷BSSID 的MAC 地址是否有效來判斷是否和無線AP建立了連接
if (prdMAC == NULL || prdMAC->dwDataLen == 0 ||
(!prdMAC->pData[0] && !prdMAC->pData[1] && !prdMAC->pData[2] &
!prdMAC->pData[3] && !prdMAC->pData[4] && !prdMAC->pData[5]))
{
RETAILMSG(DBG_MSG, (TEXT("(This wifi card is not associated to any)\n")));
return FALSE;
}
else
{
RETAILMSG(DBG_MSG, (TEXT("(This wifi card is associated state)\n")));
return TRUE;
}
}
else
{
return FALSE;
}
}
四、獲取無線AP信息
獲取了無線網(wǎng)卡的信息后,可以通過無線網(wǎng)卡枚舉出當(dāng)前所有可用的無線AP的SSID名稱以及加密模式等等所有可用信息,一下函數(shù)可以實(shí)現(xiàn)該功能
void GetWirelseeListSSID(const PRAW_DATA prdBSSIDList, HWND hListCtlWnd)
{
if (prdBSSIDList == NULL || prdBSSIDList->dwDataLen == 0)
{
RETAILMSG(DBG_MSG, (TEXT("<null> entry.\n")));
}
else
{
PWZC_802_11_CONFIG_LIST pConfigList = (PWZC_802_11_CONFIG_LIST)prdBSSIDList->pData;
//RETAILMSG(DBG_MSG, (TEXT("[%d] entries.\n"), pConfigList->NumberOfItems));
uint i;
// 枚舉所有無線AP
for (i = 0; i < pConfigList->NumberOfItems; i++)
{
PWZC_WLAN_CONFIG pConfig = &(pConfigList->Config[i]);
RAW_DATA rdBuffer;
rdBuffer.dwDataLen = pConfig->Ssid.SsidLength;
rdBuffer.pData = pConfig->Ssid.Ssid;
TCHAR tSsid[MAX_PATH];
// 將SSID 的ASCII 碼轉(zhuǎn)化成字符串
PrintSSID(&rdBuffer, tSsid);
if (hListCtlWnd)
{
if (ListBox_FindString(hListCtlWnd, 0, tSsid) == LB_ERR)
{
ListBox_AddString(hListCtlWnd, tSsid);
}
}
//RETAILMSG(DBG_MSG, (TEXT("\n")));
}
}
}
五、連接到指定的無線AP
//////////////////////////////////////////////////////////////////////////
// pCard: 無線網(wǎng)卡GUID
// pSSID: 無線AP SSID號(hào)
// bAdhoc: 是否點(diǎn)對(duì)點(diǎn)的WIFI 連接
// ulPrivacy: 加密模式(WEP/WPA....)
// ndisMode: 認(rèn)證模式(Open/Share)
// iKeyIndex: 密鑰索引(1-4)
// pKey: 密碼
// iEapType: 802.11 認(rèn)證模式
//////////////////////////////////////////////////////////////////////////
BOOL WirelessConnect(PTCHAR pCard, PTCHAR pSSID, BOOL bAdhoc, ULONG ulPrivacy, NDIS_802_11_AUTHENTICATION_MODE ndisMode, int iKeyIndex, PTCHAR pKey, int iEapType)
{
BOOL bRet = FALSE;
if (!pSSID)
{
RETAILMSG(DBG_MSG, (TEXT("Param Error.\n")));
return FALSE;
}
else
{
WZC_WLAN_CONFIG wzcConfig;
ZeroMemory(&wzcConfig, sizeof(WZC_WLAN_CONFIG));
wzcConfig.Length = sizeof(WZC_WLAN_CONFIG);
wzcConfig.dwCtlFlags = 0;
wzcConfig.Ssid.SsidLength = _tcslen(pSSID);
for (UINT i = 0; i < wzcConfig.Ssid.SsidLength; i++)
{
wzcConfig.Ssid.Ssid[i] = (CHAR)pSSID[i];
}
if (bAdhoc)
{
wzcConfig.InfrastructureMode = Ndis802_11IBSS;
}
else
{
wzcConfig.InfrastructureMode = Ndis802_11Infrastructure;
}
wzcConfig.AuthenticationMode = ndisMode;
wzcConfig.Privacy = ulPrivacy;
if (pKey == NULL || _tcslen(pKey) == 0)
{
// 對(duì)密鑰進(jìn)行轉(zhuǎn)換
bRet = InterpretEncryptionKeyValue(wzcConfig, 0, NULL, TRUE);
wzcConfig.EapolParams.dwEapType = iEapType;
wzcConfig.EapolParams.dwEapFlags = EAPOL_ENABLED;
wzcConfig.EapolParams.bEnable8021x = TRUE;
wzcConfig.EapolParams.dwAuthDataLen = 0;
wzcConfig.EapolParams.pbAuthData = 0;
}
else
{
RETAILMSG(DBG_MSG, (TEXT("WirelessConnect iKeyIndex = %d.\n"), iKeyIndex));
bRet = InterpretEncryptionKeyValue(wzcConfig, iKeyIndex, pKey, FALSE);
}
// 連接到指定的無線AP,并將該AP添加到首先無線AP中
AddToPreferredNetworkList(pCard, wzcConfig, pSSID);
}
return bRet;
}
六、密鑰轉(zhuǎn)換
輸入的密鑰需要通過加密方式進(jìn)行一定的轉(zhuǎn)化,以下函數(shù)可以完成改功能
static void EncryptWepKMaterial(IN OUT WZC_WLAN_CONFIG* pwzcConfig)
{
BYTE chFakeKeyMaterial[] = { 0x56, 0x09, 0x08, 0x98, 0x4D, 0x08, 0x11, 0x66, 0x42, 0x03, 0x01, 0x67, 0x66 };
for (int i = 0; i < WZCCTL_MAX_WEPK_MATERIAL; i++)
pwzcConfig->KeyMaterial[i] ^= chFakeKeyMaterial[(7*i)%13];
}
BOOL InterpretEncryptionKeyValue(IN OUT WZC_WLAN_CONFIG& wzcConfig, IN int iKeyIndex, IN PTCHAR pKey, IN BOOL bNeed8021X)
{
if(wzcConfig.Privacy == Ndis802_11WEPEnabled)
{
if(!bNeed8021X && pKey)
{
wzcConfig.KeyIndex = iKeyIndex;
wzcConfig.KeyLength = _tcslen(pKey);
if((wzcConfig.KeyLength == 5) || (wzcConfig.KeyLength == 13))
{
for(UINT i=0; i<wzcConfig.KeyLength; i++)
wzcConfig.KeyMaterial[i] = (UCHAR)pKey[i];
}
else
{
if((pKey[0] != TEXT('0')) || (pKey[1] != TEXT('x')))
{
RETAILMSG(DBG_MSG, (TEXT("Invalid key value.\n")));
return FALSE;
}
pKey += 2;
wzcConfig.KeyLength = wcslen(pKey);
if((wzcConfig.KeyLength != 10) && (wzcConfig.KeyLength != 26))
{
RETAILMSG(DBG_MSG, (TEXT("Invalid key value.\n")));
return FALSE;
}
wzcConfig.KeyLength >>= 1;
for(UINT i=0; i<wzcConfig.KeyLength; i++)
{
wzcConfig.KeyMaterial[i] = (HEX(pKey[2 * i]) << 4) | HEX(pKey[2 * i + 1]);
}
}
EncryptWepKMaterial(&wzcConfig);
wzcConfig.dwCtlFlags |= WZCCTL_WEPK_PRESENT;
}
}
else if(wzcConfig.Privacy == Ndis802_11Encryption2Enabled
|| wzcConfig.Privacy == Ndis802_11Encryption3Enabled)
{
if(!bNeed8021X)
{
wzcConfig.KeyLength = wcslen(pKey);
if((wzcConfig.KeyLength < 8) || (wzcConfig.KeyLength > 63))
{
RETAILMSG(DBG_MSG, (TEXT("WPA-PSK/TKIP key should be 8-63 char long string.\n")));
return FALSE;
}
char szEncryptionKeyValue8[64]; // longest key is 63
memset(szEncryptionKeyValue8, 0, sizeof(szEncryptionKeyValue8));
WideCharToMultiByte(CP_ACP,
0,
pKey,
wzcConfig.KeyLength + 1,
szEncryptionKeyValue8,
wzcConfig.KeyLength + 1,
NULL,
NULL);
WZCPassword2Key(&wzcConfig, szEncryptionKeyValue8);
EncryptWepKMaterial(&wzcConfig);
wzcConfig.dwCtlFlags |= WZCCTL_WEPK_XFORMAT
| WZCCTL_WEPK_PRESENT
| WZCCTL_ONEX_ENABLED;
}
wzcConfig.EapolParams.dwEapFlags = EAPOL_ENABLED;
wzcConfig.EapolParams.dwEapType = DEFAULT_EAP_TYPE;
wzcConfig.EapolParams.bEnable8021x = TRUE;
wzcConfig.WPAMCastCipher = Ndis802_11Encryption2Enabled;
}
return TRUE;
}
通過以上操作,完全可以連接到可用的無線AP了,再加上些適當(dāng)?shù)腢I程序,完全可以用來替代 Windows CE 自帶的無線配置程序了,我再連接中放置了一個(gè)簡(jiǎn)單的而完整的測(cè)試程序,相信大家看了以后都知道怎么操作無線網(wǎng)卡了
http://download.csdn.net/source/927575
Note:需CE4.0或更高版本(兼容NDIS5.1)支持
一、加入頭文件
#include <winioctl.h>
#include <ntddndis.h>
#include <nuiouser.h>
二、Attach to NDISUIO
HANDLE hNdis = ::CreateFile( NDISUIO_DEVICE_NAME, GENERIC_ALL, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
(HANDLE)INVALID_HANDLE_VALUE );
三、獲取設(shè)備名稱
UCHAR cbQueryBuffer[ 1024 ];
PNDISUIO_QUERY_BINDING pQueryBinding;
DWORD dwBytesReturned = 0;
pQueryBinding = (PNDISUIO_QUERY_BINDING)&cbQueryBuffer[ 0 ];
pQueryBinding->BindingIndex = 0;
if ( ::DeviceIoControl( hNdis,
IOCTL_NDISUIO_QUERY_BINDING,
(LPVOID)&cbQueryBuffer[ 0 ],
sizeof(NDISUIO_QUERY_BINDING),
(LPVOID)&cbQueryBuffer[ 0 ],
sizeof(cbQueryBuffer),
&dwBytesReturned,
NULL ) == TRUE )
{
TCHAR* pDeviceName = (TCHAR*)( cbQueryBuffer + pQueryBinding->DeviceNameOffset );
}
四、檢測(cè)連接狀態(tài)
NIC_STATISTICS nicStatistics = { 0 };
DWORD dwBytesReturned = 0;
BOOL bConnected = FALSE;
nicStatistics.ptcDeviceName = pDeviceName;
if ( ::DeviceIoControl( hNdis,
IOCTL_NDISUIO_NIC_STATISTICS,
NULL,
0,
&nicStatistics,
sizeof(NIC_STATISTICS),
&dwBytesReturned,
NULL ) == TRUE )
{
bConnected = ( nicStatistics.MediaState == MEDIA_STATE_CONNECTED );
}
五、獲取信號(hào)強(qiáng)度
// example.
// < -90 : No Signal
// < -81 : Very Low
// < -71 : Low
// < -67 : Good
// < -57 : Very Good
// ... : Excellent
NDISUIO_QUERY_OID ndisQueryOid = { 0 };
DWORD dwBytesReturned = 0;
int nDb = 0;
ndisQueryOid.Oid = OID_802_11_RSSI;
ndisQueryOid.ptcDeviceName = pDeviceName;
if ( ::DeviceIoControl( hNdis,
IOCTL_NDISUIO_QUERY_OID_VALUE,
(LPVOID)&ndisQueryOid,
sizeof(ndisQueryOid),
(LPVOID)&ndisQueryOid,
sizeof(ndisQueryOid),
&dwBytesReturned,
NULL ) == TRUE )
{
::CopyMemory( &nDb, &ndisQueryOid.Data[ 0 ], sizeof(ULONG) );
}
http://msdn.microsoft.com/en-us/library/ms706716(VS.85).aspx
The WlanEnumInterfaces function enumerates all of the wireless LAN interfaces currently enabled on the local computer.
Syntax
DWORD WINAPI WlanEnumInterfaces(
__in HANDLE hClientHandle,
__reserved PVOID pReserved,
__out PWLAN_INTERFACE_INFO_LIST *ppInterfaceList
);
Parameters
- hClientHandle [in]
-
The client's session handle, obtained by a previous call to the WlanOpenHandle function.
- pReserved [in]
-
Reserved for future use. This parameter must be set to NULL.
- ppInterfaceList [out]
-
A pointer to storage for a pointer to receive the returned list of wireless LAN interfaces in a WLAN_INTERFACE_INFO_LIST structure.
The buffer for the WLAN_INTERFACE_INFO_LIST returned is allocated by the WlanEnumInterfaces function if the call succeeds.
Return Value
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value may be one of the following return codes.
Return code |
Description |
- ERROR_INVALID_PARAMETER
|
A parameter is incorrect. This error is returned if the hClientHandle or ppInterfaceList parameter is NULL. This error is returned if the pReserved is not NULL. This error is also returned if the hClientHandle parameter is not valid.
|
- ERROR_INVALID_HANDLE
|
The handle hClientHandle was not found in the handle table.
|
- RPC_STATUS
|
Various error codes.
|
- ERROR_NOT_ENOUGH_MEMORY
|
Not enough memory is available to process this request and allocate memory for the query results.
|
Remarks
The WlanEnumInterfaces function allocates memory for the list of returned interfaces that is returned in the buffer pointed to by the ppInterfaceList parameter when the function succeeds. The memory used for the buffer pointed to by ppInterfaceList parameter should be released by calling the WlanFreeMemory function after the buffer is no longer needed.
Examples
The following example enumerates the wireless LAN interfaces on the local computer and prints values from the retrieved WLAN_INTERFACE_INFO_LIST structure and the enumerated WLAN_INTERFACE_INFO structures.
Note This example will fail to load on Windows Server 2008 and Windows Server 2008 R2 if the Wireless LAN Service is not installed and started.
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <wlanapi.h>
#include <objbase.h>
#include <wtypes.h>
#include <stdio.h>
#include <stdlib.h>
// Need to link with Wlanapi.lib and Ole32.lib
#pragma comment(lib, "wlanapi.lib")
#pragma comment(lib, "ole32.lib")
int wmain()
{
// Declare and initialize variables.
HANDLE hClient = NULL;
DWORD dwMaxClient = 2; //
DWORD dwCurVersion = 0;
DWORD dwResult = 0;
int iRet = 0;
WCHAR GuidString[40] = {0};
int i;
/* variables used for WlanEnumInterfaces */
PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
PWLAN_INTERFACE_INFO pIfInfo = NULL;
dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient);
if (dwResult != ERROR_SUCCESS) {
wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);
// FormatMessage can be used to find out why the function failed
return 1;
}
dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList);
if (dwResult != ERROR_SUCCESS) {
wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult);
// FormatMessage can be used to find out why the function failed
return 1;
}
else {
wprintf(L"Num Entries: %lu\n", pIfList->dwNumberOfItems);
wprintf(L"Current Index: %lu\n", pIfList->dwIndex);
for (i = 0; i < (int) pIfList->dwNumberOfItems; i++) {
pIfInfo = (WLAN_INTERFACE_INFO *) &pIfList->InterfaceInfo[i];
wprintf(L" Interface Index[%d]:\t %lu\n", i, i);
iRet = StringFromGUID2(pIfInfo->InterfaceGuid, (LPOLESTR) &GuidString, 39);
// For c rather than C++ source code, the above line needs to be
// iRet = StringFromGUID2(&pIfInfo->InterfaceGuid, (LPOLESTR) &GuidString, 39);
if (iRet == 0)
wprintf(L"StringFromGUID2 failed\n");
else {
wprintf(L" InterfaceGUID[%d]: %ws\n",i, GuidString);
}
wprintf(L" Interface Description[%d]: %ws", i,
pIfInfo->strInterfaceDescription);
wprintf(L"\n");
wprintf(L" Interface State[%d]:\t ", i);
switch (pIfInfo->isState) {
case wlan_interface_state_not_ready:
wprintf(L"Not ready\n");
break;
case wlan_interface_state_connected:
wprintf(L"Connected\n");
break;
case wlan_interface_state_ad_hoc_network_formed:
wprintf(L"First node in a ad hoc network\n");
break;
case wlan_interface_state_disconnecting:
wprintf(L"Disconnecting\n");
break;
case wlan_interface_state_disconnected:
wprintf(L"Not connected\n");
break;
case wlan_interface_state_associating:
wprintf(L"Attempting to associate with a network\n");
break;
case wlan_interface_state_discovering:
wprintf(L"Auto configuration is discovering settings for the network\n");
break;
case wlan_interface_state_authenticating:
wprintf(L"In process of authenticating\n");
break;
default:
wprintf(L"Unknown state %ld\n", pIfInfo->isState);
break;
}
wprintf(L"\n");
}
}
if (pIfList != NULL) {
WlanFreeMemory(pIfList);
pIfList = NULL;
}
return 0;
}
Requirements
Minimum supported client
|
Windows Vista, Windows XP with SP3 |
Minimum supported server
|
Windows Server 2008 |
Redistributable
|
Wireless LAN API for Windows XP with SP2 |
Header
|
Wlanapi.h (include Wlanapi.h) |
Library
|
Wlanapi.lib |
DLL
|
Wlanapi.dll |
用native wifi api吧。
VS2008下:
加入:
#include "Wlanapi.h"
#pragma comment(lib, "Wlanapi.lib")
變量:
DWORD pdwNegotiatedVersion;
HANDLE phClientHandle;
PWLAN_INTERFACE_INFO_LIST wiiList;
然后用下面語句打開handle.
WlanOpenHandle (1,NULL,&pdwNegotiatedVersion,&phClientHandle);
用WlanEnumInterfaces來枚舉interfaces到一個(gè)WLAN_INTERFACE_INFO_LIST結(jié)構(gòu)。如下:
WlanEnumInterfaces(phClientHandle,NULL,&wiiList);
然后wiiList->dwNumberOfItems的值就是無線網(wǎng)卡的數(shù)量。
VC6的時(shí)候沒有Wlanapi.h頭文件。可以直接LoadLibrary("wlanapi.dll"),然后GetProcAddress取得以上兩個(gè)函數(shù)指針。
#include <windows.h>
#include <stdio.h>
int main()
{
HKEY bKey,hKey;
LONG retVal;
DWORD dwBuf = 1;
DWORD dwLen;
char SubKey[] = "System\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}";
char SubKeyValueName[] = "MediaSubType";
bKey = HKEY_LOCAL_MACHINE;
retVal = RegOpenKeyEx(bKey,SubKey,0,KEY_ALL_ACCESS,&hKey);
if(retVal!=ERROR_SUCCESS)
{
return -1;
}
RegQueryValueEx( bKey, SubKeyValueName, 0, 0, (LPBYTE)&dwBuf, &dwLen );
if ( dwBuf == 1 )
printf( "普通網(wǎng)卡\n " );
if ( dwBuf == 2 )
printf( "無線網(wǎng)卡\n " );
return 0;
}
轉(zhuǎn)載文章一:http://www.cnblogs.com/shanhaobo/articles/1065380.html
[3D基礎(chǔ)]理解計(jì)算機(jī)3D圖形學(xué)中的坐標(biāo)系變換
要談坐標(biāo)系變換,那么坐標(biāo)系有哪些呢?依次有:物體坐標(biāo)系,世界坐標(biāo)系,相機(jī)坐標(biāo)系,投影坐標(biāo)系以及屏幕坐標(biāo)系.我要討論的就是這些坐標(biāo)系間的轉(zhuǎn)換。
這些坐標(biāo)系不是憑空而來,他們都是為了完成計(jì)算機(jī)3D圖形學(xué)最最最基本的目標(biāo)而出現(xiàn).
計(jì)算機(jī)3D圖形學(xué)最最最基本的目標(biāo)就是:將構(gòu)建好的3D物體顯示在2D屏幕坐標(biāo)上.
初看好像就是將最初的物體坐標(biāo)系轉(zhuǎn)換到屏幕坐標(biāo)系就可以了呀,為什么多出了世界坐標(biāo)系,相機(jī)坐標(biāo)系,投影坐標(biāo) 系。這是因?yàn)?在一個(gè)大世界里有多個(gè)物體,而每個(gè)物體都有自己的坐標(biāo)系,如何表述這些物體間相對(duì)的關(guān)系,這個(gè)多出了世界坐標(biāo)系;如果只需要看到這個(gè)世界其 中一部分,這里就多出了相機(jī)坐標(biāo)系;至于投影坐標(biāo)系那是因?yàn)橹苯訉?D坐標(biāo)轉(zhuǎn)換為屏幕坐標(biāo)是非常復(fù)雜的(因?yàn)樗鼈儾粌H維度不同,度量不同(屏幕坐標(biāo)一般都 是像素為單位,3D空間中我們可以現(xiàn)實(shí)世界的米,厘米為單位),XY的方向也不同,在2D空間時(shí)還要進(jìn)行坐標(biāo)系變換),所以先將3D坐標(biāo)降維到2D坐標(biāo), 然后2D坐標(biāo)轉(zhuǎn)換到屏幕坐標(biāo)。
理解3D圖形學(xué)的第一步:理解左手坐標(biāo)系與右手坐標(biāo)系
為什么會(huì)有左手坐標(biāo)系與右手坐標(biāo)系之分?
在3D空間(沒錯(cuò)!就是3D)中,所有2D坐標(biāo)系是等價(jià)的(就是通過一系列的仿射變換,可以互相轉(zhuǎn)換)
而3D坐標(biāo)系不是等價(jià)的,通過仿射變換,是無法將左手坐標(biāo)系轉(zhuǎn)換到右手坐標(biāo)系;也就是說,物體坐標(biāo)系用的就是左手坐標(biāo)系,世界坐標(biāo)系用的是右手 坐標(biāo)系,那么物體可能就是不會(huì)是我們所希望的樣子了,可能是倒立的,也可能是背對(duì)著我們的,所以我們要區(qū)分左手坐標(biāo)系與右手坐標(biāo)系。也許在4D空間,左右 手坐標(biāo)系就可以互相變換了吧。
進(jìn)入正題吧:
首先討論的是物體坐標(biāo)系->世界坐標(biāo)系
前面說了為了描述多個(gè)物體間相對(duì)的關(guān)系,這里引進(jìn)了世界坐標(biāo)系,所以世界坐標(biāo)系是個(gè)參考坐標(biāo)系。
這一步的目的將所有的物體的點(diǎn)都轉(zhuǎn)移到世界坐標(biāo)系,這里主要涉及的是旋轉(zhuǎn),縮放,平移等。
不過我將詳細(xì)說明為何及如何用矩陣來描述這些變換。
例:如果有兩個(gè)坐標(biāo)系C與C`, C`是C繞Z軸旋轉(zhuǎn)θ得到的。下面是各坐標(biāo)軸的變換:
如果是C坐標(biāo)系的點(diǎn)P(x, y, z),而在C`的表示就是

這時(shí)該如何建立矩陣呢? 答案就是區(qū)分你用的是行向量還是列向量.也許有人會(huì)問為什么不區(qū)分是左手坐標(biāo)系還是右手坐標(biāo)系呢?因?yàn)镃可以變換到C`,那么他們一定是同在左手坐標(biāo)系或右手坐標(biāo)系,變換只能在可以互相轉(zhuǎn)換的坐標(biāo)系之間進(jìn)行。
如果你用的是行向量:由于行向量只能左乘矩陣(注意乘與乘以的區(qū)別)
所以矩陣形式應(yīng)該是這樣

只有這樣,在左乘矩陣時(shí)才能得到上面P`的形式。

如果你用的是列向量: 由于列向量只能右乘矩陣(注意乘與乘以的區(qū)別)
所以矩陣形式應(yīng)該是這樣

只有這樣,在右乘矩陣時(shí)才能得到上面P`的形式。

至于如何旋轉(zhuǎn),縮放,平移我不在多說。
…………………………………覺得自己好像跑題了
.還好這兩個(gè)坐標(biāo)系變換很簡(jiǎn)單。
我們?cè)儆懻?span>世界坐標(biāo)系->相機(jī)坐標(biāo)系
引進(jìn)相機(jī)的目的就是只需看到世界的一部分,而哪些是可以在相機(jī)里看到的,就需要進(jìn)行篩選。將物體轉(zhuǎn)換到相機(jī)坐標(biāo)系,這樣相機(jī)坐標(biāo)系進(jìn)行篩選時(shí)就會(huì)簡(jiǎn)單很多。這里的重點(diǎn)是構(gòu)建相機(jī)坐標(biāo)系。
物體坐標(biāo)系,世界坐標(biāo)系是美工在繪制時(shí)就定義好了的。而相機(jī)坐標(biāo)系是需要程序?qū)崟r(shí)構(gòu)建的。(當(dāng)然這是通常情況下,如果你要建立一個(gè)世界,這個(gè)世界都是圍繞 你轉(zhuǎn),要實(shí)時(shí)改變所有物體坐標(biāo)系,固定相機(jī)坐標(biāo)系(其實(shí)這時(shí)候相機(jī)坐標(biāo)系就是世界坐標(biāo)系),建立一個(gè)地心說的世界,我也沒辦法,你的思維也太不一樣了。)
如何構(gòu)建相機(jī)坐標(biāo)系呢?首先我們要明確目標(biāo):我們是要構(gòu)建3D坐標(biāo)系(好像是廢話),三個(gè)坐標(biāo)軸要互相垂直(也好像是廢話).
我們一般用UVN相機(jī)。例如:D3D的D3DXMatrixLookAtLH,D3DXMatrixLookAtRH,OGL的gluLookAt(右手坐標(biāo)系).
如何建立呢UVN相機(jī)呢? 我們就要利用叉積這個(gè)工具了:兩個(gè)不平行,不重疊的向量的叉積可以得到與這兩個(gè)向量互相垂直的向量。
如果有了相機(jī)的位置與目標(biāo)的位置那么我們可以確定一個(gè)Z軸(有人問為什么是Z軸,因?yàn)槲矬w的遠(yuǎn)與近我們就習(xí)慣用Z值來表示的)。求Z軸時(shí)要注意 是左手坐標(biāo)系還是右手坐標(biāo)系,左右手坐標(biāo)系XY軸方向相同時(shí),Z軸的方向相反。所以左手坐標(biāo)系是目標(biāo)位置減去相機(jī)位置,而右手坐標(biāo)系則是相機(jī)位置減去目標(biāo) 位置。記得normalize
這是我們要得到X與Y軸了。如何求X,Y軸呢?
一般方法是:
1、選擇一個(gè)臨時(shí)Y軸,
2、對(duì)臨時(shí)Y 與Z 軸進(jìn)行叉積求得一個(gè)X軸
3、X軸再與Z軸進(jìn)行叉積,得到一個(gè)Y軸。
有了XYZ就可以求出旋轉(zhuǎn)的相機(jī)矩陣了。
如何選擇一個(gè)Y軸呢?大多數(shù)情況下是(0,1,0),但是如果是相機(jī)位置E與目標(biāo)位置T垂直,即(E-T=(0,+/-1,0)時(shí)),這時(shí)就不能用(0,1,0)了, 因?yàn)閮蓚€(gè)平行向量的叉積是零向量,所以我們就要另選一個(gè)Y軸。
但是我覺得我們可以改變方法。
如果不能選Y軸,我們就選擇一個(gè)臨時(shí)X軸,這個(gè)臨時(shí)X軸就是(1,0,0)。
然后再對(duì)臨時(shí)X軸與Z軸進(jìn)行叉積求得一個(gè)Y軸。
最后Y軸再與Z軸進(jìn)行叉積,得到X軸。
這樣可以得到XYZ軸。
最后再根據(jù)行向量與列向量建立相機(jī)矩陣,再進(jìn)行平移。
相機(jī)坐標(biāo)系->投影坐標(biāo)系.
投影的目的就是:降維.
兩種投影方式:正交投影與透視投影.
在我們TEAM中易穎已經(jīng)寫了,我就不多說了,大家去看他的文章。
投影坐標(biāo)系->屏幕坐標(biāo)系
這是最簡(jiǎn)單的。2D坐標(biāo)變換。也不多說。
轉(zhuǎn)載文章2:http://www.xingousi.com/computer/computergraphics.htm
計(jì)算機(jī)圖形學(xué)筆記(Part 1 ):計(jì)算機(jī)圖形學(xué)透視投影變換原理及一點(diǎn)和兩點(diǎn)透視
一、平行互分法
吳英凡所寫的《透視作圖的新方法——交點(diǎn)法體系》,其中談到的平行互分法,還是有道理的。
其實(shí)簡(jiǎn)單點(diǎn)說,就是透視圖上的兩條“原來空間中的平行線”(在畫面上透視投影為相交于滅點(diǎn)),通過其中一條透視投影直線的端點(diǎn)畫另一條透視投影直線的平行線,必平行于畫面;這第三條線在畫面的透視投影的滅點(diǎn)必然在另一條透視投影線上。
二、透視投影變換學(xué)習(xí)總結(jié)
1、用多維數(shù)列表示低維空間坐標(biāo),加深理解齊次坐標(biāo)表示法。
齊次坐標(biāo)表示法可以方便地運(yùn)算,同時(shí)形狀不變。[x,y,z,0]表示一個(gè)無窮的點(diǎn)。
2、透視投影變換公式可以看成兩個(gè)矩陣的乘積,其中一個(gè)做透視變換,另外一個(gè)作正投影
保留的z'值的確切含義:指的是在完全作完透視投影變換之前,僅作透視投影之后的一條線.
它的幾何意義見李建平《計(jì)算機(jī)圖形學(xué)原理教程》第44頁(yè)。
3、左手和右手坐標(biāo)系的坐標(biāo)轉(zhuǎn)換
“視點(diǎn)坐標(biāo)系與一般的物體所在的世界坐標(biāo)系不同,它遵循左手法則,即左手大拇指指向Z正軸,與之垂直的四個(gè)手指指向X正軸,四指彎曲90度的方向是Y正軸。而世界坐標(biāo)系遵循右手法則的。”
4、視點(diǎn)坐標(biāo)系的透視變換公式很重要!!王飛著計(jì)算機(jī)圖形學(xué)書65頁(yè)
5、z'值的確切含義:指的是在完全作完透視投影變換之前,僅作透視投影之后的一條線
三、兩點(diǎn)透視的變換矩陣:
王飛編著《計(jì)算機(jī)圖形學(xué)基礎(chǔ)》的道理是:
從平面圖形的平移、旋轉(zhuǎn)、錯(cuò)切開始推導(dǎo),兩點(diǎn)透視的變換矩陣可以看成是:
物體本身有一個(gè)物體坐標(biāo)系——xw,yw,zw,視點(diǎn)作為原點(diǎn)又構(gòu)成一個(gè)視點(diǎn)坐標(biāo)系——xe,ye,ze,物體坐標(biāo)系z軸朝上,y軸朝向遠(yuǎn)處;而視點(diǎn)坐標(biāo)系y軸朝上,z軸朝向遠(yuǎn)處。
這樣,最終的二點(diǎn)透視狀態(tài)可以這樣取得,首先把物體的位置的物體坐標(biāo)系表示法轉(zhuǎn)化為視點(diǎn)坐標(biāo)系的表示法(第一個(gè)矩陣),然后圍繞視點(diǎn)坐標(biāo)系的y軸旋轉(zhuǎn)(第二個(gè)矩陣),然后在x,y,z方向上平移(第三個(gè)矩陣),最后做透視變換(第四個(gè)矩陣),它的原文是把平移放在第二步,我在平移之前轉(zhuǎn)動(dòng),目的是保證了物體旋轉(zhuǎn)的軸在離它不遠(yuǎn)的地方:
我使用的矩陣變換如下,原文是是把平移放在第二步:
[xw,yw,zw,1]*
*
*
*
最后所得結(jié)果是一個(gè)新的矩陣,
[xe ye ze 1]=[cos
*xw-sin
*yw+l zw+m 2sin
*xw+2cos
*yw+2n-d (sin
*xw+cos
*yw+n)/d]
把最后一項(xiàng)變成1,可得
=[(cos
*xw-sin
*yw+l)*d/(sin
*xw+cos
*yw+n (zw+m)*d/(sin
*xw+cos
*yw+n) (2sin
*xw+2cos
*yw+2n-d)*d/(sin
*xw+cos
*yw+n) 1 ]
即:
Xe= (cos
*xw-sin
*yw+l)*d/(sin
*xw+cos
*yw+n)
Ye=(zw+m)*d/(sin
*xw+cos
*yw+n)
Ze=(2sin
*xw+2cos
*yw+2*n-d)*d/(sin
*xw+cos
*yw+n)
實(shí)際上我的delphi程序里面是這樣的:
xe:=trunc((cos(angle)*eee[ii][k].X-sin(angle)*eee[ii][k].Y+l)*d/(sin(angle)*eee[ii][k].X+cos(angle)*eee[ii][k].Y+n));
ye:=trunc((hhh[ii][k]+m)*d/(sin(angle)*eee[ii][k].X+cos(angle)*eee[ii][k].Y+n)); //透視變換
//ze可以考慮使用作為消隱
Ze:=trunc((2*sin(angle)*xw+2*cos(angle)*yw+2*n-d)*d/(sin(angle)*xw+cos(angle)*yw+n));
四、通過變換過的兩點(diǎn)透視的結(jié)果xe,ye,zw和
*,反求原來的物體坐標(biāo)xw,yw
即:xe,ye,zw和
已知,求出xw,yw
根據(jù):
Xe= (cos
*xw-sin
*yw+l)*d/(sin
*xw+cos
*yw+n) (1)
Ye=(zw+m)*d/(sin
*xw+cos
*yw+n) (2)
Ze=(2sin
*xw+2cos
*yw+2n-d)*d/(sin
*xw+cos
*yw+n) (3)
(1)除以(2)得
Xe/Ye= (cos
*xw-sin
*yw+l)/ (zw+m)
(Xe*(zw+m))/Ye=cos
*xw-sin
*yw+l
(Xe*(zw+m))/(Ye* cos
)=xw-tan
*yw+l/cos
Xw=(Xe*(zw+m))/ (Ye* cos
) - (ye*l)/(Ye* cos
)+( sin
*yw*ye)/ (Ye* cos
)
Xw=(Xe*(zw+m)+ sin
*yw*ye- ye*l)/ (Ye* cos
) (4)
由(2)得
Ye*(sin
*xw+cos
*yw+n)= (zw+m)*d
Ye*(sin
*xw)+ye* cos
*yw+n*ye=(zw+m)*d
把(4)代入上式得
Ye* sin
*(Xe*(zw+m)+ sin
*yw*ye- ye*l)/ (Ye* cos
)+ye* cos
*yw+n*ye=(zw+m)*d
約去ye,得
sin
*(Xe*(zw+m)+ sin
*yw*ye- ye*l)/ cos
+ye* cos
*yw+n*ye=(zw+m)*d
tan
*(Xe*zw+xe*m+ sin
*yw*ye- ye*l) +ye* cos
*yw+n*ye=(zw+m)*d
tan
*Xe*zw+xe*m *tan
- ye*l*tan
+ sin
*tan
*yw*ye+ye* cos
*yw+n*ye=(zw+m)*d
(sin
*tan
*ye+ye* cos
)*yw+ tan
*Xe*zw+xe*m *tan
- ye*l*tan
+n*ye=(zw+m)*d
最后得
Yw=[(zw+m)*d- tan
*Xe*zw- xe*m *tan
+ ye*l*tan
- n*ye]/ (sin
*tan
*ye+ye* cos
) (5)
而前面已經(jīng)得到
Xw=(Xe*(zw+m)+ sin
*yw*ye- ye*l)/ (Ye* cos
) (4)
實(shí)際上相當(dāng)于opengl里面的逆變換,從鼠標(biāo)選中的屏幕位置來確定對(duì)應(yīng)的三維空間中位置,opengl使用gluUnProject和gluUnProject4來計(jì)算。
摘要: 1. API之網(wǎng)絡(luò)函數(shù)
WNetAddConnection 創(chuàng)建同一個(gè)網(wǎng)絡(luò)資源的永久性連接
WNetAddConnection2 創(chuàng)建同一個(gè)網(wǎng)絡(luò)資源的連接
WNetAddConnection3 創(chuàng)建同一個(gè)網(wǎng)絡(luò)資源的連接
WNetCancelConnection 結(jié)束一個(gè)網(wǎng)絡(luò)連接
WNetCancelConnection2 結(jié)束一個(gè)網(wǎng)絡(luò)連接
WNetCloseEnum 結(jié)束一次枚舉操作
...
閱讀全文
摘要: //本機(jī)網(wǎng)絡(luò)連接類型(成功)
#define NET_TYPE_RAS_DIAL_UP_CONNECT_NET 0x01 //上網(wǎng)類型:采用RAS撥號(hào)連接上網(wǎng) ...
閱讀全文
和所有初學(xué)者一樣,剛開始接觸新的東西,總想把畫面做的漂亮些,可是在vc中很難做到,比如對(duì)話框中按鈕等控件的字體設(shè)置,就頗費(fèi)了我一番功夫。
一。做成一個(gè)函數(shù),改變字體大小,方法如下:
1。在最開頭聲明一個(gè)全局的字體指針 CFont *my_font=new CFont();//注意初始化,不能為空
2。在需要改變字體的地方調(diào)用函數(shù):
set_font(60,my_font,"隸書"); //字體大小、指針、名稱
GetDlgItem(IDC_anniu)->SetFont(my_font);//改變字體
3。對(duì)與不同的字體,你需要設(shè)置不同的字體指針就可以了。
4。注意在退出時(shí)要?jiǎng)h除字體,否則多次調(diào)用出現(xiàn)問題
BOOL CMyDlg::DestroyWindow()
{
if (my_font) my_font->DeleteObject();
return CDialog::DestroyWindow();
}
5。 以下是函設(shè)置字體函數(shù)的詳細(xì)內(nèi)容:
void set_font(int height,CFont *font,char *name)
{
// font=new CFont();//不在此,要在外部初始化,否則找不到指針
LOGFONT lf;
lf.lfHeight=20; lf.lfWidth= 0;
lf.lfEscapement=0; lf.lfOrientation= 0;
lf.lfWeight= 760; lf.lfItalic= 0;
lf.lfUnderline =0; lf.lfStrikeOut =0;
lf.lfCharSet =134; lf.lfOutPrecision =3;
lf.lfClipPrecision =2; lf.lfQuality= 1;
lf.lfPitchAndFamily =2; lstrcpy(lf.lfFaceName, "宋體");
lf.lfOutPrecision =OUT_TT_ONLY_PRECIS;//OUT_TT_PRECIS;
lf.lfHeight= height; //字體大小
lstrcpy(lf.lfFaceName, name);//名稱
if (font!=NULL)
{
font->DeleteObject();
font->CreateFontIndirect(&lf);
}
}
#define say(ch) AfxMessageBox(ch)//自己使用的提示函數(shù)
#define bt(ch) SetWindowText(ch)//自己使用的提示函數(shù)
二。改變字體顏色,要加入系統(tǒng)函數(shù)
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
// return hbr;
switch(nCtlColor)
{
case CTLCOLOR_STATIC://靜態(tài)文本
TCHAR lpszClassName[255];
GetClassName(pWnd->m_hWnd, lpszClassName, 255);
if(_tcscmp(lpszClassName, TRACKBAR_CLASS) == 0)//類名是拉動(dòng)條
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
else if (IDC_tishi==pWnd->GetDlgCtrlID())//指定的控件ID提示
{
pDC ->SetTextColor(RGB(255,100,100));//RGB(100,255,100)
return hbr;
}
else
{
pWnd->GetWindowText(ch,40);
if ( strcmp(ch,"測(cè)試數(shù)據(jù)")==0 )//指定的標(biāo)題
{
pDC ->SetTextColor(RGB(255,0,200));
return hbr;
}
pDC->SetBkColor(RGB(255,255,255));
return hbr;//(HBRUSH) GetStockObject(HOLLOW_BRUSH);
}
}
break;
case CTLCOLOR_BTN://按鈕,好象不行
// pDC ->SetBkMode(OPAQUE);//背景不透明
// pDC->SetBkMode(TRANSPARENT);//背景透明
// say("button");
CString str;
//owen draw //注意,右擊按鈕屬性改為自繪式
pWnd->GetWindowText(str); //得到標(biāo)題內(nèi)容
RECT rect;
pWnd->GetClientRect(&rect);//得到矩形范圍大小
pDC->SelectStockObject(BLACK_PEN);
pDC->Rectangle(&rect);//黑筆畫外邊矩形
rect.left+=2;rect.top+=2;
rect.right-=2 ;rect.bottom-=2;
pDC->SelectStockObject(WHITE_PEN);
pDC->Rectangle(&rect);//白筆畫內(nèi)矩形
pDC->SelectObject(font);//選擇字體,大小
pDC->SetTextColor(RGB(0,255,0)); //字體得前景顏色
pDC->SetBkColor(RGB(255,0,255)); //字體的背景顏色
pDC->DrawText(str, &rect, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
return (HBRUSH) GetStockObject(HOLLOW_BRUSH);
break;
case CTLCOLOR_EDIT://編輯框
pDC ->SetTextColor(RGB(255,0,0));//文本顏色
pDC ->SetBkColor(RGB(255,255,255));//文本背景
break;
case CTLCOLOR_LISTBOX://列表框
// pDC ->SetTextColor(RGB(255,255,0));
// pDC ->SetBkColor(RGB(160,60,0));
break;
}
// TODO: Return a different brush if the default is not desired
return hbr;
}
2008-06-23 日 星期一 天氣 晴
很久沒有來這里寫東西了,感覺真有點(diǎn)對(duì)不起這個(gè)空間.
過年到現(xiàn)在一直都忙于工作.(項(xiàng)目一個(gè)接一個(gè).報(bào)告一個(gè)接一個(gè))
驅(qū)動(dòng)開發(fā)我關(guān)注很久了.就是沒有實(shí)際行動(dòng).終于有一天不知道怎么了下定了決心搞了.
首先要搞的是編譯和編輯環(huán)境,個(gè)人感覺網(wǎng)上有很多DDK 與Visual Studio6的配置很多都是有問題的,而且都是幾年前寫的.不知道是我理解能力有問題還是作者表達(dá)能力有問題老是弄不好.最后弄雖然弄好也是轉(zhuǎn)了一個(gè)大圈.但是用起來實(shí)在是不敢恭謹(jǐn).也許是我用慣了delphi 和vs2005的緣故.vs2005的代碼編輯和智能排版功能可以說是very Good ! 最后我還是決定把ddk和vs2005給掛上關(guān)系.花了我一個(gè)上午的時(shí)間也弄出來了.用起來比vs6.0爽了很多.效果也達(dá)到了之前設(shè)想的.我寫這些出來是為了減少步我后塵的同志們對(duì)驅(qū)動(dòng)的恐懼.
步驟:
1.首先前期準(zhǔn)備: 安裝xp ddk 和vs2005 (vs2005只要安裝c/c++就可以了) 安裝的步驟我就不在這里說了.
2.準(zhǔn)備一個(gè)驅(qū)動(dòng)源代碼(用ddk內(nèi)的例子也可以)
3.vs2005建立一個(gè)makeFile 工程.
4.把源碼拷貝倒vs2005目錄內(nèi)(包括*.c , *.h,還有source 和makefile)
5.在vs2005工程目錄建立一個(gè)MakeDriver.bat 文件里面內(nèi)容是:
@echo off
if "%1"=="" goto usage1
if "%3"=="" goto usage2
if not exist %1\bin\setenv.bat goto usage3
echo params1: %1
echo params2: %2
echo params3: %3
echo call %1\BIN\setenv %1 %3
call %1\BIN\setenv %1 %3
echo cd /d %2
cd /d %2
build
goto ok
:usage1
echo Error: the first parameter is NULL!
goto exit
:usage2
echo Error: the third parameter is NULL!
goto exit
:usage3
echo Error: %1\bin\setenv.bat not exist!
goto exit
:ok
echo MakeDriver %1 %2 %3
:exit
5. 設(shè)置 vs2005 工程的屬性
編譯分 debug 和 release 兩個(gè)版本
在 NMke 設(shè)置里面設(shè)置 ( 我用的是 vs2005 繁體版 )
releasee 版本.只要將” 建置命令列 ” 內(nèi)容改成 MakeDriver %DDKROOT% $(ProjectDir) fre 就可以了.
我的 ddk 是安裝在 c 盤 .IntelliSense 是為了能在編輯代碼的時(shí)候彈出輸入的列表 . 比如結(jié)構(gòu)體內(nèi)的成員等等
建置命令列 : 是調(diào)用 MakeDriver.bat 文件編譯源代碼 .
如果加上 vss 代碼管理 . 一個(gè)驅(qū)動(dòng)代碼工程管理就算完善了 .
寫到這里了 .
順便提下要了解 MakeDriver.bak 內(nèi)的作用就要了解一些批處理的 dos 命令 . 上網(wǎng)找吧 . 網(wǎng)上什么都有關(guān)鍵是看你怎么找 .
http://harborwan.blog.sohu.com/39762230.html
通常驅(qū)動(dòng)程序的調(diào)試都是用ddk在cmd中完成的。這部分我暫時(shí)略過。下面先介紹如何設(shè)置vc++6.0在Visual Studio 6.0集成環(huán)境中開發(fā)設(shè)備驅(qū)動(dòng)程序的方法。
在Windows上,Windows DDK提供的開發(fā)環(huán)境是基于命令行的,操作起來極為不便,而Visual Studio 6.0給我們提供了非常友好易用的集成環(huán)境,讓我們有如虎添翼之感。
那么,能否利用Visual Studio的集成環(huán)境來開發(fā)驅(qū)動(dòng)程序呢?答案是可以的。通過對(duì)Visual Studio集成環(huán)境的簡(jiǎn)單設(shè)置,創(chuàng)建好自己的驅(qū)動(dòng)開發(fā)集成環(huán)境就可以了。
1,
第一:安裝Vc++6.0,我裝的是英文版,中文版應(yīng)該也可以,不過我沒試。
第二:安裝winXP DDK,注意,安裝目錄中間不能有空格,比如D:\Program Files不行,
我直接裝在了D盤,裝完后設(shè)置環(huán)境變量DDKROOT為安裝目錄D:\WINDDK\2505。
2,創(chuàng)建一個(gè)目錄,作為開發(fā)目錄,我是利用<<PCI設(shè)備開發(fā)寶典>>的光盤中的工程文件PCI9052Demo,直接考到E盤,所以,工作目錄下是E:\PCI9052Demo
3,工作目錄下創(chuàng)建一個(gè)批處理文件MakeDrvr.bat,內(nèi)容如下:
@echo off
if "%1"=="" goto usage
if "%3"=="" goto usage
if not exist %1\bin\setenv.bat goto usage
call %1\bin\setenv %1 %4
%2
cd %3
build -b -w %5 %6 %7 %8 %9
goto exit
:usage
echo usage MakeDrvr DDK_dir Driver_Drive Driver_Dir free/checked [build_options]
echo eg MakeDrvr %%DDKROOT%% F: %%WDMWorkshop%% free -cef
:exit
解釋以下:
1% 是DDK_dir,也就是ddk的安裝目錄
2% 是Driver_Drive,是你工作目錄所在的盤符,這里是E:
3% 是Driver_Dir,是你工作目錄的路徑,這里是E:\PCI9052Demo
4% 是編譯模式,checked表示調(diào)試模式,free表示發(fā)行模式,這里是出問題的地方,后面再說。
該批處理首先對(duì)傳遞的參數(shù)作一些檢查,然后調(diào)用ddk的setenv命令設(shè)置環(huán)境變量,然后改變目錄為源程序所在驅(qū)動(dòng)器和目錄,并最后調(diào)用build,-b保證顯示完全的錯(cuò)誤信息,-w保證在屏幕上輸出警告,在vc ide里的output窗口中可以看到這些錯(cuò)誤和警告。
4,建立一個(gè)空白工程
選File的new菜單項(xiàng),然后選project欄的makefile,然后輸入路徑,一路next下去即可,visual studio提供兩種配置win32 debug和win32 release. 按照cant的《windows wdm 設(shè)備驅(qū)動(dòng)程序開發(fā)指南》方法,可以刪除掉,添加Win32 Checked和 Win32 Free
5,VC的Project->settings里面改變?cè)O(shè)置
修改這兩種配置
=============================================================
Free
=============================================================
build command line:
e:\PCI9052Demo\MakeDrvr %DDKROOT% e: e:\PCI9052Demo free
rebuild all opinions:
-nmake /a
output filename:
PCI9052Demo.sys
browse info file name:
objfre\i386\PCI9052Demo.bsc
=============================================================
Checked
=============================================================
build command line:
e:\PCI9052Demo\MakeDrvr %DDKROOT% e: e:\PCI9052Demo checked
rebuild all opinions:
-nmake /a
output filename:
PCI9052Demo.sys
browse info file name:
objfre\i386\PCI9052Demo.bsc
6.添加源文件到工程
可以新建,也可