在 Windows CE 下自带有无线网卡的配置和连接程序,可是我的系统剪裁掉了资源管理器和任务栏,导致自带的无线网卡配置程序不能再使用了,只好自力更生。

我的环境是 S3C2440 + WinCE 5.0 + VNUWCL5(威盛无线网卡)及驱动程序。使用 Automatic Configuration Functions API

一、枚举系统中可用的无线网络设备

      下面的函数可以枚举出系统中所有可用的无线网卡设备的GUID,为了简化,我选择第一块可用的无线网卡来操作      

BOOL GetFirstWirelessCard(PTCHAR pCard)
{
if (!pCard)
{
return FALSE;
}
INTFS_KEY_TABLE IntfsTable;
IntfsTable.dwNumIntfs = 0;
IntfsTable.pIntfs = NULL;
_tcscpy(pCard, TEXT(""));
// 枚举系统中可用的无线网卡
DWORD dwStatus = WZCEnumInterfaces(NULL, &IntfsTable);
if (dwStatus != ERROR_SUCCESS)
{
RETAILMSG(DBG_MSG, (TEXT("WZCEnumInterfaces() error 0x%08X\n"),dwStatus));
return FALSE;
}
// 判断无线网卡的数量,可以根据无线网卡数量来枚举出所有可用的无线网卡
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;
}

 二、获取无线网络信息

        获取到了系统可用的无线网卡后,我们就可以利用它的 GUID 号来进行进一步的操作了,首先要做的事情就是得到该无线网卡的信息以及该无线网卡扫描到的 WIFI 网关信息。

        以下函数可以获取到该无线网卡及扫描的到的无线 AP 信息

//////////////////////////////////////////////////////////////////////////
// pCard: 无线网卡GUID
// pIntf: 无线网卡配置信息结果体
// pOutFlags: 网卡配置信息掩码标志
//////////////////////////////////////////////////////////////////////////
BOOL GetWirelessCardInfo(PTCHAR pCard, PINTF_ENTRY_EX pIntf, PDWORD pOutFlags)
{
TCHAR *szWiFiCard = NULL;
// 参数校验
if (!pCard || !pIntf || !pOutFlags)
{
RETAILMSG(DBG_MSG, (TEXT("Param Error.\n")));
return FALSE;
}
szWiFiCard = pCard;
*pOutFlags = 0;
// 初始化无线网卡信息
ZeroMemory(pIntf, sizeof(INTF_ENTRY_EX));
// 设置GUID 号
pIntf->wszGuid = szWiFiCard;
// 查询无线网卡信息
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;
}

三、判断连接状态

        我们可以通过无线网卡的状态来判断当前无线网卡是否已经和无线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信息

        获取了无线网卡的信息后,可以通过无线网卡枚举出当前所有可用的无线AP的SSID名称以及加密模式等等所有可用信息,一下函数可以实现该功能

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 码转化成字符串
PrintSSID(&rdBuffer, tSsid);
if (hListCtlWnd)
{
if (ListBox_FindString(hListCtlWnd, 0, tSsid) == LB_ERR)
{
ListBox_AddString(hListCtlWnd, tSsid);
}
}
//RETAILMSG(DBG_MSG, (TEXT("\n")));
}
}
}

五、连接到指定的无线AP

//////////////////////////////////////////////////////////////////////////
// pCard: 无线网卡GUID
// pSSID: 无线AP SSID号
// bAdhoc: 是否点对点的WIFI 连接
// ulPrivacy: 加密模式(WEP/WPA....)
// ndisMode: 认证模式(Open/Share)
// iKeyIndex: 密钥索引(1-4)
// pKey: 密码
// iEapType: 802.11 认证模式
//////////////////////////////////////////////////////////////////////////
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)
{
// 对密钥进行转换
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;
}

六、密钥转换

        输入的密钥需要通过加密方式进行一定的转化,以下函数可以完成改功能

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了,再加上些适当的UI程序,完全可以用来替代 Windows CE 自带的无线配置程序了,我再连接中放置了一个简单的而完整的测试程序,相信大家看了以后都知道怎么操作无线网卡了

http://download.csdn.net/source/927575

posted @ 2010-12-16 09:31 wrh 阅读(1620) | 评论 (0)编辑 收藏
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 );

三、获取设备名称

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 );
}

 

四、检测连接状态

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 );
}

五、获取信号强度

// 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) );
}
posted @ 2010-12-16 09:12 wrh 阅读(1683) | 评论 (1)编辑 收藏


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
posted @ 2010-12-16 09:01 wrh 阅读(2615) | 评论 (0)编辑 收藏
用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到一个WLAN_INTERFACE_INFO_LIST结构。如下:
WlanEnumInterfaces(phClientHandle,NULL,&wiiList);
然后wiiList->dwNumberOfItems的值就是无线网卡的数量。
VC6的时候没有Wlanapi.h头文件。可以直接LoadLibrary("wlanapi.dll"),然后GetProcAddress取得以上两个函数指针。














#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( "普通网卡\n " );
if ( dwBuf == 2 )
printf( "无线网卡\n " );
return 0;
}
posted @ 2010-12-16 08:45 wrh 阅读(2034) | 评论 (0)编辑 收藏

转载文章一:http://www.cnblogs.com/shanhaobo/articles/1065380.html

[3D基础]理解计算机3D图形学中的坐标系变换

     要谈坐标系变换,那么坐标系有哪些呢?依次有:物体坐标系,世界坐标系,相机坐标系,投影坐标系以及屏幕坐标系.我要讨论的就是这些坐标系间的转换。
     这些坐标系不是凭空而来,他们都是为了完成计算机3D图形学最最最基本的目标而出现.
      计算机3D图形学最最最基本的目标就是:将构建好的3D物体显示在2D屏幕坐标上.
      初看好像就是将最初的物体坐标系转换到屏幕坐标系就可以了呀,为什么多出了世界坐标系,相机坐标系,投影坐标 系。这是因为:在一个大世界里有多个物体,而每个物体都有自己的坐标系,如何表述这些物体间相对的关系,这个多出了世界坐标系;如果只需要看到这个世界其 中一部分,这里就多出了相机坐标系;至于投影坐标系那是因为直接将3D坐标转换为屏幕坐标是非常复杂的(因为它们不仅维度不同,度量不同(屏幕坐标一般都 是像素为单位,3D空间中我们可以现实世界的米,厘米为单位),XY的方向也不同,在2D空间时还要进行坐标系变换),所以先将3D坐标降维到2D坐标, 然后2D坐标转换到屏幕坐标。
理解3D图形学的第一步:理解左手坐标系与右手坐标系
      为什么会有左手坐标系与右手坐标系之分?
      在3D空间(没错!就是3D)中,所有2D坐标系是等价的(就是通过一系列的仿射变换,可以互相转换)
      而3D坐标系不是等价的,通过仿射变换,是无法将左手坐标系转换到右手坐标系;也就是说,物体坐标系用的就是左手坐标系,世界坐标系用的是右手 坐标系,那么物体可能就是不会是我们所希望的样子了,可能是倒立的,也可能是背对着我们的,所以我们要区分左手坐标系与右手坐标系。也许在4D空间,左右 手坐标系就可以互相变换了吧。
      进入正题吧:
     首先讨论的是物体坐标系->世界坐标系
      前面说了为了描述多个物体间相对的关系,这里引进了世界坐标系,所以世界坐标系是个参考坐标系。
      这一步的目的将所有的物体的点都转移到世界坐标系,这里主要涉及的是旋转,缩放,平移等。
      不过我将详细说明为何及如何用矩阵来描述这些变换。
      例:如果有两个坐标系C与C`, C`是C绕Z轴旋转θ得到的。下面是各坐标轴的变换:
             
     如果是C坐标系的点P(x, y, z),而在C`的表示就是
   
     这时该如何建立矩阵呢? 答案就是区分你用的是行向量还是列向量.也许有人会问为什么不区分是左手坐标系还是右手坐标系呢?因为C可以变换到C`,那么他们一定是同在左手坐标系或右手坐标系,变换只能在可以互相转换的坐标系之间进行。
      如果你用的是行向量:由于行向量只能左乘矩阵(注意乘与乘以的区别)
      所以矩阵形式应该是这样
    
     只有这样,在左乘矩阵时才能得到上面P`的形式。
    
     如果你用的是列向量: 由于列向量只能右乘矩阵(注意乘与乘以的区别)
     所以矩阵形式应该是这样
    
     只有这样,在右乘矩阵时才能得到上面P`的形式。
  
     至于如何旋转,缩放,平移我不在多说。
     …………………………………觉得自己好像跑题了.还好这两个坐标系变换很简单。
     我们再讨论世界坐标系->相机坐标系
     引进相机的目的就是只需看到世界的一部分,而哪些是可以在相机里看到的,就需要进行筛选。将物体转换到相机坐标系,这样相机坐标系进行筛选时就会简单很多。这里的重点是构建相机坐标系。
     物体坐标系,世界坐标系是美工在绘制时就定义好了的。而相机坐标系是需要程序实时构建的。(当然这是通常情况下,如果你要建立一个世界,这个世界都是围绕 你转,要实时改变所有物体坐标系,固定相机坐标系(其实这时候相机坐标系就是世界坐标系),建立一个地心说的世界,我也没办法,你的思维也太不一样了。)
     如何构建相机坐标系呢?首先我们要明确目标:我们是要构建3D坐标系(好像是废话),三个坐标轴要互相垂直(也好像是废话).
      我们一般用UVN相机。例如:D3D的D3DXMatrixLookAtLH,D3DXMatrixLookAtRH,OGL的gluLookAt(右手坐标系).
      如何建立呢UVN相机呢? 我们就要利用叉积这个工具了:两个不平行,不重叠的向量的叉积可以得到与这两个向量互相垂直的向量。
      如果有了相机的位置与目标的位置那么我们可以确定一个Z轴(有人问为什么是Z轴,因为物体的远与近我们就习惯用Z值来表示的)。求Z轴时要注意 是左手坐标系还是右手坐标系,左右手坐标系XY轴方向相同时,Z轴的方向相反。所以左手坐标系是目标位置减去相机位置,而右手坐标系则是相机位置减去目标 位置。记得normalize
     这是我们要得到X与Y轴了。如何求X,Y轴呢?
     一般方法是:
     1、选择一个临时Y轴,
     2、对临时Y 与Z 轴进行叉积求得一个X轴
     3、X轴再与Z轴进行叉积,得到一个Y轴。
     有了XYZ就可以求出旋转的相机矩阵了。
     如何选择一个Y轴呢?大多数情况下是(0,1,0),但是如果是相机位置E与目标位置T垂直,即(E-T=(0,+/-1,0)时),这时就不能用(0,1,0)了, 因为两个平行向量的叉积是零向量,所以我们就要另选一个Y轴。
     但是我觉得我们可以改变方法。
      如果不能选Y轴,我们就选择一个临时X轴,这个临时X轴就是(1,0,0)。
     然后再对临时X轴与Z轴进行叉积求得一个Y轴。
     最后Y轴再与Z轴进行叉积,得到X轴。
      这样可以得到XYZ轴。
      最后再根据行向量与列向量建立相机矩阵,再进行平移。

     相机坐标系->投影坐标系.
     投影的目的就是:降维.
      两种投影方式:正交投影与透视投影.
      在我们TEAM中易颖已经写了,我就不多说了,大家去看他的文章。

     投影坐标系->屏幕坐标系
      这是最简单的。2D坐标变换。也不多说。

转载文章2:http://www.xingousi.com/computer/computergraphics.htm

计算机图形学笔记(Part 1 ):计算机图形学透视投影变换原理及一点和两点透视

 

一、平行互分法

吴英凡所写的《透视作图的新方法——交点法体系》,其中谈到的平行互分法,还是有道理的。

其实简单点说,就是透视图上的两条“原来空间中的平行线”(在画面上透视投影为相交于灭点),通过其中一条透视投影直线的端点画另一条透视投影直线的平行线,必平行于画面;这第三条线在画面的透视投影的灭点必然在另一条透视投影线上。

 

 

 

二、透视投影变换学习总结

1、用多维数列表示低维空间坐标,加深理解齐次坐标表示法。

    齐次坐标表示法可以方便地运算,同时形状不变。[x,y,z,0]表示一个无穷的点。

   

2、透视投影变换公式可以看成两个矩阵的乘积,其中一个做透视变换,另外一个作正投影

   保留的z'值的确切含义:指的是在完全作完透视投影变换之前,仅作透视投影之后的一条线.

   它的几何意义见李建平《计算机图形学原理教程》第44页。

3、左手和右手坐标系的坐标转换

   “视点坐标系与一般的物体所在的世界坐标系不同,它遵循左手法则,即左手大拇指指向Z正轴,与之垂直的四个手指指向X正轴,四指弯曲90度的方向是Y正轴。而世界坐标系遵循右手法则的。”

4、视点坐标系的透视变换公式很重要!!王飞著计算机图形学书65

5z'值的确切含义:指的是在完全作完透视投影变换之前,仅作透视投影之后的一条线

 

 

 

三、两点透视的变换矩阵:

王飞编著《计算机图形学基础》的道理是:

从平面图形的平移、旋转、错切开始推导,两点透视的变换矩阵可以看成是:

物体本身有一个物体坐标系——xw,yw,zw,视点作为原点又构成一个视点坐标系——xeyeze,物体坐标系z轴朝上,y轴朝向远处;而视点坐标系y轴朝上,z轴朝向远处。

这样,最终的二点透视状态可以这样取得,首先把物体的位置的物体坐标系表示法转化为视点坐标系的表示法(第一个矩阵),然后围绕视点坐标系的y轴旋转(第二个矩阵),然后在xyz方向上平移(第三个矩阵),最后做透视变换(第四个矩阵),它的原文是把平移放在第二步,我在平移之前转动,目的是保证了物体旋转的轴在离它不远的地方:

我使用的矩阵变换如下,原文是是把平移放在第二步:

[xw,yw,zw,1]* ***

 

最后所得结果是一个新的矩阵,

[xe ye ze 1]=[cos*xw-sin*yw+l   zw+m   2sin*xw+2cos*yw+2n-d   (sin*xw+cos*yw+n/d]

把最后一项变成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)

 

实际上我的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));

 

 

四、通过变换过的两点透视的结果xe,yezw*,反求原来的物体坐标xw,yw

即:xe,yezw已知,求出xw,yw

根据:

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

而前面已经得到

Xw=(Xe*(zw+m)+ sin*yw*ye- ye*l)/ (Ye* cos)            (4)

 

实际上相当于opengl里面的逆变换,从鼠标选中的屏幕位置来确定对应的三维空间中位置,opengl使用gluUnProjectgluUnProject4来计算。

posted @ 2010-12-06 14:19 wrh 阅读(1141) | 评论 (0)编辑 收藏
     摘要: 1. API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接 WNetAddConnection2 创建同一个网络资源的连接 WNetAddConnection3 创建同一个网络资源的连接 WNetCancelConnection 结束一个网络连接 WNetCancelConnection2 结束一个网络连接 WNetCloseEnum 结束一次枚举操作 ...  阅读全文
posted @ 2010-12-02 09:20 wrh 阅读(1787) | 评论 (0)编辑 收藏
     摘要: //本机网络连接类型(成功)   #define  NET_TYPE_RAS_DIAL_UP_CONNECT_NET           0x01    //上网类型:采用RAS拨号连接上网 ...  阅读全文
posted @ 2010-12-02 09:07 wrh 阅读(9361) | 评论 (0)编辑 收藏
和所有初学者一样,刚开始接触新的东西,总想把画面做的漂亮些,可是在vc中很难做到,比如对话框中按钮等控件的字体设置,就颇费了我一番功夫。
    一。做成一个函数,改变字体大小,方法如下:
      1。在最开头声明一个全局的字体指针 CFont *my_font=new CFont();//注意初始化,不能为空
      2。在需要改变字体的地方调用函数:
          set_font(60,my_font,"隶书"); //字体大小、指针、名称
          GetDlgItem(IDC_anniu)->SetFont(my_font);//改变字体
      3。对与不同的字体,你需要设置不同的字体指针就可以了。
      4。注意在退出时要删除字体,否则多次调用出现问题
       BOOL CMyDlg::DestroyWindow()
      {
       if (my_font)   my_font->DeleteObject();
       return CDialog::DestroyWindow();
      }
      5。 以下是函设置字体函数的详细内容:
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)//自己使用的提示函数
#define bt(ch)   SetWindowText(ch)//自己使用的提示函数
  
二。改变字体颜色,要加入系统函数
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
//    return hbr;
    switch(nCtlColor)
{
case CTLCOLOR_STATIC://静态文本
   TCHAR lpszClassName[255];
   GetClassName(pWnd->m_hWnd, lpszClassName, 255);
   if(_tcscmp(lpszClassName, TRACKBAR_CLASS) == 0)//类名是拉动条
    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,"测试数据")==0 )//指定的标题
     {
      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); //得到标题内容
     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);//白笔画内矩形
   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;
}
posted @ 2010-12-02 08:54 wrh 阅读(2685) | 评论 (0)编辑 收藏

2008-06-23 星期一 天气  

      很久没有来这里写东西了,感觉真有点对不起这个空间. 
 过年到现在一直都忙于工作.(项目一个接一个.报告一个接一个) 
驱动开发我关注很久了.就是没有实际行动.终于有一天不知道怎么了下定了决心搞了. 
首先要搞的是编译和编辑环境,个人感觉网上有很多DDK Visual Studio6的配置很多都是有问题的,而且都是几年前写的.不知道是我理解能力有问题还是作者表达能力有问题老是弄不好.最后弄虽然弄好也是转了一个大圈.但是用起来实在是不敢恭谨.也许是我用惯了delphi vs2005的缘故.vs2005的代码编辑和智能排版功能可以说是very Good ! 最后我还是决定把ddkvs2005给挂上关系.花了我一个上午的时间也弄出来了.用起来比vs6.0爽了很多.效果也达到了之前设想的.我写这些出来是为了减少步我后尘的同志们对驱动的恐惧.

步骤:
1.首先前期准备: 安装xp ddk  vs2005 (vs2005只要安装c/c++就可以了) 安装的步骤我就不在这里说了.

2.准备一个驱动源代码(ddk内的例子也可以)

3.vs2005建立一个makeFile 工程.

4.把源码拷贝倒vs2005目录内(包括*.c , *.h,还有source  makefile)

5.vs2005工程目录建立一个MakeDriver.bat 文件里面内容是:

@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. 设置 vs2005 工程的属性
    编译分 debug release 两个版本

NMke 设置里面设置 ( 我用的是 vs2005 繁体版






























releasee 版本.只要將 建置命令列 內容改成 MakeDriver %DDKROOT% $(ProjectDir) fre 就可以了.


我的 ddk 是安装在 c .IntelliSense 是为了能在编辑代码的时候弹出输入的列表 . 比如结构体内的成员等等


建置命令列 : 是调用 MakeDriver.bat 文件编译源代码 .


如果加上 vss 代码管理 . 一个驱动代码工程管理就算完善了 .

写到这里了 .

顺便提下要了解 MakeDriver.bak 内的作用就要了解一些批处理的 dos 命令 . 上网找吧 . 网上什么都有关键是看你怎么找 .

posted @ 2010-12-01 13:12 wrh 阅读(769) | 评论 (0)编辑 收藏

 http://harborwan.blog.sohu.com/39762230.html

通常驱动程序的调试都是用ddk在cmd中完成的。这部分我暂时略过。下面先介绍如何设置vc++6.0在Visual Studio 6.0集成环境中开发设备驱动程序的方法。

在Windows上,Windows DDK提供的开发环境是基于命令行的,操作起来极为不便,而Visual Studio 6.0给我们提供了非常友好易用的集成环境,让我们有如虎添翼之感。 
  那么,能否利用Visual Studio的集成环境来开发驱动程序呢?答案是可以的。通过对Visual Studio集成环境的简单设置,创建好自己的驱动开发集成环境就可以了。

1,

第一:安装Vc++6.0,我装的是英文版,中文版应该也可以,不过我没试。

第二:安装winXP DDK,注意,安装目录中间不能有空格,比如D:\Program Files不行,

我直接装在了D盘,装完后设置环境变量DDKROOT为安装目录D:\WINDDK\2505。

2,创建一个目录,作为开发目录,我是利用<<PCI设备开发宝典>>的光盘中的工程文件PCI9052Demo,直接考到E盘,所以,工作目录下是E:\PCI9052Demo

3,工作目录下创建一个批处理文件MakeDrvr.bat,内容如下:

@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表示调试模式,free表示发行模式,这里是出问题的地方,后面再说。

该批处理首先对传递的参数作一些检查,然后调用ddk的setenv命令设置环境变量,然后改变目录为源程序所在驱动器和目录,并最后调用build,-b保证显示完全的错误信息,-w保证在屏幕上输出警告,在vc ide里的output窗口中可以看到这些错误和警告。

4,建立一个空白工程
 选File的new菜单项,然后选project栏的makefile,然后输入路径,一路next下去即可,visual studio提供两种配置win32 debug和win32 release. 按照cant的《windows wdm 设备驱动程序开发指南》方法,可以删除掉,添加Win32 Checked和 Win32 Free

5,VC的Project->settings里面改变设置

修改这两种配置
 =============================================================
 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.添加源文件到工程
  可以新建,也可

posted @ 2010-12-01 13:11 wrh 阅读(249) | 评论 (0)编辑 收藏
仅列出标题
共25页: 1 2 3 4 5 6 7 8 9 Last 

导航

<2009年10月>
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

统计

常用链接

留言簿(19)

随笔档案

文章档案

收藏夹

搜索

最新评论

阅读排行榜

评论排行榜