返回首页

{A}{S0}简介
在实验室自动化控制软件的开发和使用领域的工作经常需要建立的沟通渠道,交谈的各种设备,如机器人手臂或自动化细胞培养箱。硬件的连接可以通过USB,火线,CAN总线,I2C和串行端口,并可以使用,例如一个USB串行端口框或4路串行到I2C转换器转换器。相反,大多数设备制造商的指示,设置应用程序错误与错误的设置通道的试剂盒通过一块交谈是很容易的,因为是堵在设备进入了错误的端口。各种法律似乎也需要这种情况下,在面积有限的空间定位连接器之间布线,具有较强的意大利面条一样的倾向。
最初的实验室自动化的开发,因为他们读设备涉及的各个位,通常工作在其特定的发展笔记本连接。这些开发商通常集中在一块试剂盒和运行。忽略文件,通信信道的设置也许是硬编码,或在一些晦涩难懂的设置文件记录,已被证明是一个普遍的现象。为了解决这个问题,两个C类已被写入由第一个开发使用,为后来的开发者和最终用户的利益。这些类允许的通信信道选项中显示的方式有利于把事情和快速运行,不会出现混乱。类通常用于快速而简单地显示在列表控件(和设备图标)过滤设备的信息。他们周围的一些Windows安装程序API函数的瘦包装有优势,因为他们是比较薄的包装类,不过这些方法比原来的API文档,需要使用。
作为一个例子,下面通过两个C类获得的数据显示在屏幕截图显示的是用户,如果这个特定的PC上选择COM13的,相关的设备一块应插入到标有"3口"的连接器4路USB到串口转换盒。这听起来像一个简单的锻炼,但正在使用某些设备时,只是坐在那里,也许是因为一定的电脑最初使用的一些通信通道,或不正确的有线非标准通信导致不同的默认值,能够来证明一切正确连接在几分钟而不是几小时或几天内(或不)是一个很大的优势。例如使用串行端口,但也同样适用于其他类型的设备和沟通渠道。背景
研究如何列表,最初只是对串行端口可用,但扩大到所有(软件)设备的信息,首先导致代码使用的registry.nbsp;一种实用工具附带的4路USB转串口框显示,还可以得到其他有用的信息。寻找一种手段,做一些类似导致setupapi.h使用,如的功能,它提供了由邓川良公用事业,也着眼于这方面。类
两类:CDevInfo CDeviceImageList,书面包装各种结构和API调用。 CDeviceImageList用于获取设备的图标和CDevInfo是用于访问和枚举设备信息的图像列表。
CDevInfo包装一个HDEVINFO,处理设备接口集和结构,它定义了该设备的接口设置设备。 SETUPAPI调用CDevInfo包裹是:{A4}{A5}{A6}{A7}{A8}{A9}
CDeviceImageList包装{A10},从而产生设备类,如在设备管理器显示的图标。
这两个类与一个ATL CListViewCtrl允许使用安装设备的注册表属性(SPDRP)代码被选中的设备和相关信息的列表。每个条目旁边显示相应的设备类的图标。显示这些信息是使用以下形式的代码:

// m_wndListView is a CListViewCtrl in report mode...



m_wndListView.Attach(GetDlgItem(IDC_LIST1));

m_wndListView.InsertColumn(0, _T("Name"), LVCFMT_LEFT, 200, 0);

m_wndListView.InsertColumn(1, _T("Friendly-Name"), LVCFMT_LEFT, 200, 0);

m_wndListView.InsertColumn(2, _T("Driver"), LVCFMT_LEFT, 200, 0);

m_wndListView.InsertColumn(3, _T("Mfg"), LVCFMT_LEFT, 200, 0);

m_wndListView.InsertColumn(4, _T("Physical Device"), LVCFMT_LEFT, 200, 0);

m_wndListView.SetImageList(m_DevImageList, 1);



CDevInfo cDevInfo(m_hWnd);

int a = 0;

while(cDevInfo.EnumDeviceInfo())

{

	wchar_t  szBuf[MAX_PATH] = {0};

	if(cDevInfo.GetDeviceRegistryProperty(SPDRP_CLASS, (PBYTE)szBuf))

	{

		wchar_t  szFriendlyName[MAX_PATH] = {0};

		cDevInfo.GetDeviceRegistryProperty(SPDRP_FRIENDLYNAME, 

				(PBYTE)szFriendlyName);



		wchar_t  szDriver[MAX_PATH] = {0};

		cDevInfo.GetDeviceRegistryProperty(SPDRP_DRIVER, (PBYTE)szDriver);



		wchar_t  szMfg[MAX_PATH] = {0};

		cDevInfo.GetDeviceRegistryProperty(SPDRP_MFG, (PBYTE)szMfg);



		wchar_t  szPhysical[MAX_PATH] = {0};

		cDevInfo.GetDeviceRegistryProperty

			(SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, (PBYTE)szPhysical);



		int ImageIndex = 0;

		if(cDevInfo.GetClassImageIndex(m_DevImageList, &ImageIndex))

		{

			wchar_t  szDesc[MAX_PATH] = {0};

			if(cDevInfo.GetClassDescription(szDesc))

			{

				ATLTRACE(szDesc);

				ATLTRACE(_T("\n"));

			}

			m_wndListView.InsertItem(a,szDesc,ImageIndex);

			m_wndListView.SetItemText(a,1,szFriendlyName);

			m_wndListView.SetItemText(a,2,szDriver);

			m_wndListView.SetItemText(a,3,szMfg);

			m_wndListView.SetItemText(a,4,szPhysical);

		}

	}

}	

为了能够过滤显示的设备,添加备用的CDevInfo构造,公开的GUID的API来指定感兴趣的设备。现在可以创建一个对象可以传递所需的任何标志的设备类型和GUID的GUID。在下面的情况下,标志,确保只,实际上是连接到PC的串口设备和USB串行设备显示:{C}
没有DIGCF_PRESENT标志,任何已安装的的设备,使用了一个COM端口将显示,无论是物理连接到PC或的,但时使用的标志DIGCF_PRESENT是,只有USB串行设备实际上是插入到PC的显示。 ,由于所使用的转换盒制造商包括的"信息"栏框上的连接器数量,现在可以显示用户的选择,说,COM11一些串行设备,从该串行铅设备需要将标记转换盒上的端口1连接器插入。兴趣点
传递图像列表CDeviceImageList缠CListViewCtrl方法之一时,产生的图像列表的所有权问题。为了解决这个问题,一个非标准的拷贝构造函数和CDeviceImageList放大器;运算符=(CDeviceImageList放大器; pSource)写在自动PTR方式通过列表的所有权,而不是把它复制。 CDevInfo类也被以同样的方式,使包裹HDEVINFO,而不是通过复制。 Visual Studio项目DevInfoTester行使此功能通过创建几个CDevInfo对象,并将其分配给周围如下所示:
CDevInfo foo(CDevInfo & _DevInfo)

{

	return _DevInfo;

}

int _tmain(int /*argc*/, _TCHAR* /*argv[]*/)

{

	// Exercise constructor, auto_ptr type copy constructor and assignment operator

	CDevInfo DevInfo1(NULL);

	CDevInfo DevInfo2 = DevInfo1;

	CDevInfo DevInfo3(NULL);

	DevInfo3 = foo(DevInfo2);// Generates C4239 for use of non-standard assignment

	DevInfo1 = DevInfo3;

	...

一些非默认分类CListViewCtrl线被添加到显示在一个合理的秩序,如果没有这个端口显示顺序的COM1,COM11,COM2,而不是COM1,COM2 COM11的COM端口。这表现在Visual Studio项目PortInfo。
使用SetupAPI的通过CDeviceImageList和CListViewCtrl对象允许40线,容易维护的代码,也就是说,在一个对话框来代替不太灵活的代码超过100线,用于直接调用注册表。使用代码
陪同VS2005的解决方案包括三个项目之一,为简单起见,没有WTL的编译和两个WTL的安装需要编译(见下载{A11})。 DevInfoWin32在命令窗口中运行和行使CDevInfo对象后,会显示检测到的端口列表。这个项目是最简单的的。
ListViewTest VS2005的项目使用一个基于对话框的项目,以显示所有发现的设备列表的排序是不是在这个项目的实施,从而说明需要使用的类的代码。
第三VS2005的项目,PortInfo,使用一个对话框访问bynbsp;港口|菜单上的选择,并显示了串行端口的列表。排序是在这个项目的实施。
要更改显示设备类,使用不同的设备的GUID。例如,在目前显示的所有设备,改变的基本CDevInfo构造路线ListViewTest项目... ...
CDevInfo cDevInfo(m_hWnd);

...以...
const GUID Guid = GUID_DEVCLASS_USB;

CDevInfo cDevInfo(m_hWnd, DIGCF_PRESENT , &Guid);

...将限制显示所有的USB设备。参考文献
代码项目文章{A12},当寻找一个提醒对话框大小调整代码。感谢。
自动在资源转移,而不是复制的指针类型的操作,请参见"C行动10.6-10.8,B. Milewski,ISBN 0-201-69948-6,Addison - Wesley的2001年"。历史2008年12月,第12届:初始版本

回答

评论会员:SyamlalS 时间:2011/12/28
,我试图重用在我的应用程序的逻辑。我有一个VC6.0的Win32控制台基于applicaion,在我需要枚举的串行端口。但cDevInfo.EnumDeviceInfo()函数总是返回零填充的GUID。
你有任何想法可能是什么问题。
注: - guiddef.h头文件是不是在我的安装,我评论这头包容性和代码编译。
此外,您的控制台的演示应用程序在我的电脑作品罚款,并列出所有端口完美。

SYAMLAL
评论会员:SyamlalS 时间:2011/12/28
CLSIDFromString(WBUF GUID);函数总是充满了零{S2}
的Guid
SYAMLAL
评论会员:乔纳森戴维斯 时间:2011/12/28
嗨,
我能想到要问的唯一问题是:什么是WBUF时用零填充的Guid
也许如果你能显示的代码,你正在使用它可能有助于
评论会员:?SyamlalS 时间:2011/12/28
喜乔纳森,
我检查的WBUF,它是一些有效的价值。 WBUF初始化为0。 cDevInfo.GetDeviceRegistryProperty(SPDRP_CLASSGUID,(PBYTE)WBUF)在WBUF填充值。
请创建一个示例VC - 6.0项目工作区(Win32控制台应用程序)与下列文件(这些文件是从你的代码复制和修改,在3-4个地方用来消除编译错误类型。

DevInfoWin32.cpp

/ / DevInfoTester.cpp
#包括"stdafx.h中"
/ /#包括LT; guiddef.hgt; / / GUID
#包括LT; objbase.hgt; / / CLSIDFromString
#包括LT; devguid.hgt; / / GUID_DEVCLASS_PORTS
#包括LT; conio.hgt; / / _getch()
#包括"DeviceInfo.h"/ / CDevInfo
CDevInfo美孚(CDevInfo安培; _DevInfo)
{
返回_DevInfo;
}
INT _tmain(INT / * ARGC * /,_TCHAR * / * argv的[]*/){ BR}{
wprintf(L"CDevInfo类的测试,将列表中找到的串行端口:\ N \ N");

CDevInfo cDevInfo(NULL)
INT N = 0;
(cDevInfo.EnumDeviceInfo())
{
的GUID的Guid wchar_t的WBUF [MAX_PATH] = {0}

/ /无符号字符WBUF [1000]; (cDevInfo.GetDeviceRegistryProperty(SPDRP_CLASSGUID,(PBYTE)WBUF))
{:CLSIDFromString(WBUF,放大器; GUID);
INT nEqual = InlineIsEqualGUID(GUID,GUID_DEVCLASS_PORTS)
(0 = nEqual)
{

wchar_t的szFriendlyName [MAX_PATH] = {0} cDevInfo.GetDeviceRegistryProperty(SPDRP_FRIENDLYNAME,(PBYTE)szFriendlyName);
wchar_t的szMfg [MAX_PATH] = {0}
cDevInfo.GetDeviceRegistryProperty(SPDRP_MFG,(PBYTE)szMfg)

wprintf(L"%s的%S \ N",szFriendlyName,szMfg); N;
}
}
} 返回0;}
DeviceInfo.h

/ / DeviceInfo.h
的#pragma一次
#包括LT; setupapi.hgt; / /:SetupDi *********
#包括LT; atlbase.hgt; / / ATLASSERT放大器; ATLTRACE
#包括"CommandError.h"/ / CWin32ErrToWString
的#pragma评论(LIB,"setupapi.lib")

/ **
处理设备通过安装API的包装SetupDiXXXXXXXXXXXX调用驱动程序的信息。创建这个C类代码40行中的应用取代100线后,它是基于。 注意:所有字符串内部已宣布为MAX_PATH长度。被称为第一时间EnumDeviceInfo将访问索引0 SP_DEVINFO_DATA。它被称为下一次将访问
SP_DEVINFO_DATA索引1处,在未来的指数的2和等等。

\ 0.1版
\ TODO
& #160; - 如果这个对象使用相同的复制语义CDeviceImageList发行(ATL中分离)

\错误没有记录。

\警告没有设计被继承。
\警告使用非标准分配产生C4239在调用应用程序(4级警告)
* /
类CDevInfo
{
私人:
HDEVINFO m_hDevInfo;!/ / LT;​​参考设备信息集
SP_DEVINFO_DATA m_spDevInfoData;!/ / LT;​​设备信息结构(引用设备实例,是一个设备信息集的成员)
BOOL m_bDevInfo; / /公升;测试,以确保EnumDeviceInfo被称为
短m_MemberIndex; / /公升;保留EnumDeviceInfo调用之间的状态
市民:
/ **
一个句柄(内CDevInfo举行)获取设备的信息集,其中包含本地计算机的请求的设备信息元素。
参数hWndParent要安装在设备信息设备实例时使用的用户界面的一个顶层窗口的句柄
设置。可以为NULL。 @参数标志设置要枚举的设备信息。@参数ClassGuid设备类或设备接口类的指针的GUID。
参数:统计员一个指针,指向一个NULL结尾的字符串,提供即插即用(PNP)枚举PnP设备实例标识符的名称。

要获得的信息,包括所有设备使用默认的flags参数。为了获得一个唯一的设备目前使用的设置:
\代码
CDevInfo cDevInfo(m_hWnd,DIGCF_ALLCLASSES | DIGCF_PRESENT);
\ endcode
为了获得有特定的设备接口,是目前使用的设备清单:
\代码
常量的GUID GUID = GUID_DEVCLASS_PORTS;
CDevInfo cDevInfo(m_hWnd,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE,放大器; GUID);
\ endcode
* /
CDevInfo(HWND hWndParent,DWORD标志= DIGCF_ALLCLASSES | DIGCF_PROFILE,GUID * ClassGuid = 0,PCWSTR统计员= 0):
m_hDevInfo(0L)
m_bDevInfo(FALSE)
m_MemberIndex(-1)
{
ATLASSERT(::IsWindow(hWndParent)| | 0 == hWndParent)
m_hDevInfo = SetupDiGetClassDevs(ClassGuid,(常量字符*)统计员,hWndParent,旗);
(m_hDevInfo == INVALID_HANDLE_VALUE)
{
DWORD dwErr = GetLastError函数()
的std::wstring的szErr = CWin32ErrToWString()(dwErr);
ATLTRACE(_T("SetupDiGetClassDevs没有因为%s \ N"),szErr.c_str ());{ BR}ATLASSERT(m_hDevInfo = INVALID_HANDLE_VALUE!)
}
}
私人:
/ **
返回当前HDEVINFO和放弃控制。
* /
HDEVINFO发行()
{
HDEVINFO TMP = m_hDevInfo;
m_hDevInfo = 0;
返回TMP;
}
市民:
/ **
创建一个新的CDevInfo这需要从现有对象设置一个HDEVINFO控制所有权
* /
CDevInfo(CDevInfo放大器; _DevInfo):m_hDevInfo(_DevInfo.Release())
{
}

/ **
破坏当前HDEVINFO,rhs的放弃其HDEVINFO和收购所有权所有权。
* /
CDevInfo放大器;运算符=(CDevInfo放大器; pSource)
{
(AMP!pSource =这)
{
(m_hDevInfo!= 0)
{
布尔B =:SetupDiDestroyDeviceInfoList(m_hDevInfo);
(假== B)
{ ATLASSERT(!"无法摧毁设备设置");}
}
}
m_hDevInfo = pSource.Release()

;}
/ **
获取设备的信息结构(引用设备实例,是一个设备信息集的成员)
在构造函数和私有变量m_MemberIndex设定为-1每次EnumDeviceInfo被称为递增。 则返回FALSE如果试图枚举的最后一个设备后。* /
BOOL EnumDeviceInfo(无效)
{ ATLASSERT(m_hDevInfo);m_MemberIndex;
m_spDevInfoData.cbSize = SIZEOF(SP_DEVINFO_DATA);
m_bDevInfo =::SetupDiEnumDeviceInfo(m_hDevInfo,m_MemberIndex,放大器; m_spDevInfoData);
返回m_bDevInfo;
}
/ **
检索指定的即插即用设备的属性。
参数属性的值表示的财产,如SPDRP_CLASSGUID检索或SPDRP_FRIENDLYNAME。参见
完整的细节。http://msdn.microsoft.com/en-us/library/ms792967.aspx
@参数PropertyBuffer正在检索一个指向一个缓冲区,接收的财产。
* /
BOOL GetDeviceRegistryProperty(DWORD物业,PBYTE PropertyBuffer)
{ ATLASSERT(PropertyBuffer);
ATLASSERT(m_bDevInfo);布尔bGotRegProp =:SetupDiGetDeviceRegistryProperty(m_hDevInfo,放大器; m_spDevInfoData,
物业,
0L,
PropertyBuffer,
2048,
0)
返回bGotRegProp;
}
/ **
检索在指定的设备类。
类图像列表索引
参数ClassImageListData一个一个SP_CLASSIMAGELIST_DATA结构,描述了一类图像的名单,其中包括
指针ClassGuid参数指定的设备类的形象。
@参数的ImageIndex一个指针到一个INT类型的变量接收
指定类的形象指数
类的图像列表。* /
BOOL GetClassImageIndex(PSP_CLASSIMAGELIST_DATA ClassImageListData,品脱的ImageIndex)
{ ATLASSERT(ClassImageListData);
ATLASSERT(的ImageIndex);
ATLASSERT(m_bDevInfo);返回:SetupDiGetClassImageIndex(ClassImageListData,放大器; m_spDevInfoData.ClassGuid的ImageIndex);
}
/ ** 检索与指定设备类的GUID相关的设备类的描述。参数ClassDescription接收设备类描述一个字符缓冲区的指针。
例如:wchar_t的szDesc [MAX_PATH] = {0}; cDevInfo.GetClassDescription(szDesc);
* /
BOOL GetClassDescription(PWSTR ClassDescription)
{
ATLASSERT(ClassDescription) ATLASSERT(m_bDevInfo);返回:SetupDiGetClassDescription(安培; m_spDevInfoData.ClassGuid,(char *)的ClassDescription,MAX_PATH,NULL);
}
/ **
删除设备的信息集收购,创建和释放所有关联的内存。
* /
〜CDevInfo()
{
(m_hDevInfo)
{
布尔B =:SetupDiDestroyDeviceInfoList(m_hDevInfo); ATLASSERT(B);m_hDevInfo = 0L;
}
}
}
/ **
\例如DevInfoTester.cpp
这是CDevInfo是如何开发使用。本示例查找使用该端口的GUID的端口:
  ;* /

SYAMLAL
评论会员:乔纳森戴维斯 时间:2011/12/28
嗨,
首先,我有VS2008的不是我的机器上VS6和我原来使用的文件和使用VS2005的测试,修改自己comnpile在VS6和VS2008中运行它们是不necessariliy去解决你的问题是你要申请回VS6任何结果。

我曾尝试pasteing成VS2008的项目,但此代码产生编译错误。而如果我直接从演示下载文件进行编译。

我认为,作为CDevInfo类是只有左右两个或三个设置API调用点之前,您的问题时有一个看看是什么在点的API调用发生,瘦包装。 MSDN文档中的错误条件。

要么启动一个新项目,并没有类类似纯API调用你的代码,以找到问题的根源
评论会员:。Vaibhav盖德 时间:2011/12/28
我enaling在Windows XP中的网络适配器使用SetupDiCallClassInstaller 到SetupDiCallClassInstaller调用立即返回。
后SetupDiCallClassInstaller返回TRUE,一些时间后仍然调用连接在连接状态。
网络适​​配器通过阶段
1。网络电缆unpluged
2。获取网络地址
3。连

由于网络卡是不是在连接状态后调用,我没有得到当时的互联网连接。

我想拨打电话SetupDiCallClassInstaller,同步调用或阻塞调用。
我的要求是,一旦SetupDiCallClassInstaller返回TRUE,这意味着该设备应在连接状态。

同样的情况在Vista上工作,有IM使用WMI。我使用的米调用Win32_NetworkAdapter:启用方法使用IWbemServices:ExecMethod

IWbemServices::ExecMethod设施同步通话功能
。 我的应用程序是一个DLL。
我如何在Windows XP中实现通过设置管理API?

感谢
评论会员:。乔纳森戴维斯 时间:2011/12/28
我从来没有使用SetupDiCallClassInstaller所以我没有真正quaified告知,但在MSDN简要介绍一下它在我看来,预计安装电话提供的"安装"和"连接",而不是只是一个"安装"是从它期待太多
评论会员:会员18691 时间:2011/12/28
缺少文件(S)
评论会员:乔纳森戴维斯 时间:2011/12/28
很抱歉听到你有问题;哪些文件缺少
评论会员:?乔纳森戴维斯 时间:2011/12/28
一个干净的笔记本电脑上安装VS2008和下载和构建解决方案,打造出一个项目的三个。 Win32的一个内置的,但不是两个人,因为他们使用的WTL。错误:无法打开包括文件:"atlapp.h'这两个发生。
从http://sourceforge.net/projects/wtl下载WTL8.0,安装和加入WTL的\ Include目录到VS治愈和所有三个项目的建立和运行。乔纳森
评论会员:乔纳森戴维斯 时间:2011/12/28
虽然你的文章显然是WTL的标记,一些用户可能需要明确给出如何获取和安装WTL的测试或至少有一个链接可以为他们指出正确的方向方向。

约翰
评论会员:罗布郝德杰 时间:2011/12/28
商定。其更新一张纸条和WTL的链接。感谢

乔纳森