【高分请教】Windows下如何自动安装驱动程序

时间:2022-05-28 05:54:32
Hi,
小弟目前做的项目需要在Windows下安装一个简单的USB驱动,驱动程序由第三方提供(没有经过MS认证),包含DLL、INF、SYS等等文件。
一般情况下,当即插即用设备连上PC后,如果PC中没有该设备的驱动,会弹出安装驱动的提示,用户根据提示来一步步安装就可以了。
现在这个项目需要事先就把驱动安装到PC中去,也就是把安装驱动这件事放在安装软件(项目最终的发布软件)的过程中完成。那么应该怎么去安装驱动呢?
并且由于软件最终会运行在XP、VISTA和Windows7下面,那么这三个系统下的自动安装的过程有多大的区别呢?


PS:请教过一个高手,写个精简DOS程序即可,但还是没有弄清楚。正在看《Windows驱动开发技术详解》,由于不是写驱动,只是安装驱动,这本书中也没有找到可行的办法。

32 个解决方案

#1


楼主关键是要实现你的设备的HID,我们采用一个带USB的单片机,开始也没实现免驱,后来市场需求,我们采用挂接在HID上,实现了免驱设计。即可以利用电脑的自带的USB的等驱动文件,自动识别我的设备。
oogle与百度下“免驱设计 HID”

一下几篇文章很不错,
http://www.dzsc.com/data/html/2009-7-21/77757.html
http://www.abc188.com/info/html/wangzhanyunying/jianzhanjingyan/20080417/67834.html
http://linux.chinaunix.net/techdoc/install/2008/03/14/983179.shtml

#2


感谢楼上解答。
只是楼上提供的是关于libUSB的相关资料。
而且驱动程序已经有提供了,我需要安装这个驱动。

#3


这个感觉向是把你的驱动 要加载到操作系统中,做到即插即用的,就跟我们使用U盘是一样的

楼主可以写个啥程序,把驱动加载到PC上,只要插上你的设备 就可以识别

这只是我的想法 具体这软件咋写 我也不会

#4


我也想知道,好像没有见过类似的做法。

#5


回cfanlwn: 是的。因为用到了一个USB转串口的芯片,所以要安装下驱动,当然就像平常那样的,当硬件接上PC后,按照提示一步一步安装也可以。但是这样子一来是使得用户的使用变得麻烦,而且增加了安装过程的风险(比如说MS的数字认证问题)。所以现在要将驱动在安装程序的时候就安装上去。

就是不晓得应该怎么做啊。。。



#6


你说让他自动获取,然后我们一步步安装,最后安装上也就是把一些信息放在WINDOWS下,然后在注册表中加写信息,楼主可以查查这些资料,看能不能写个批处理程序

#7


回cfanlwn:

是不是大家都是通过批处理来做这件事的?因为我问了其他版块的高手,有人也这么说的。

有个高手提供了如下的批处理脚本:

echo 安装驱动
rundll32.exe setupapi.dll,InstallHinfSection DefaultInstall 128 %inf%
echo 安装完成

我没有写过批处理脚本,刚刚找了一篇批处理的文章正在屁颠屁颠的看。

能帮忙分析一下这个脚本么?


#8


请教cfanlwn:

我刚刚试了一下。
批处理代码如下:
@echo off
echo 判断系统版本
set inf=D:\XP\DRIVER\CH341WDM.INF
echo 安装驱动
rundll32.exe setupapi.dll,InstallHinfSection DefaultInstall 128 %inf%
echo 安装完成

发现没有安装上去,请问是怎么一回事呢? 问题出在哪里了呢?

#9


用DeviceTree查看了一下,确实没有安装上去。。。

#10


引用 5 楼 kisery008 的回复:
回cfanlwn: 是的。因为用到了一个USB转串口的芯片,所以要安装下驱动,当然就像平常那样的,当硬件接上PC后,按照提示一步一步安装也可以。但是这样子一来是使得用户的使用变得麻烦,而且增加了安装过程的风险(比如说MS的数字认证问题)。所以现在要将驱动在安装程序的时候就安装上去。

就是不晓得应该怎么做啊。。。


一般的USB转串口的芯片,都会由这个芯片厂家提供PC端的驱动,一般只要实现在PC上安装驱动,之后你随时插拔,系统就会自动识别你的设备。

我们用到很多USB转串口的转接线都是这样的,我们用CP2102做的一款产品也是这样,先人为安装驱动,之后就不用管了、

#11


既然第三方已经提供了“包含DLL、INF、SYS等等文件。”

楼主是否可以百度或者google下,“如何生成exe可执行文件”。


我们当时做项目,就把这个DLL和一些系统文件,用专用的软件人为生成了一个exe,之后一点就自动运行。

#12


回kyzf:
谢谢提示啊~~
因为这个驱动没有取得MS的认证,所以如果人工安装的话可能对那些警告提示感到头疼。

关于生成exe可执行文件,是个不错的方法,我现在看到有人用批处理程序就搞定了,所以就先按照那个方法先试了一下。。

没找到专业软件生成EXE文件,能提供一个下载的链接或者方法么?谢谢咯~~

另外,“把这个DLL和一些系统文件,用专用的软件人为生成了一个exe”,请问还需要哪些系统文件呢?最后生成的EXE可执行文件会不会很大啊??

#13


为什么我按照系统提示来安装的时候  那个进度条显示的安装内容是DLL文件   而用批处理倒的时候 显示安装的内容是SYS文件    

一般驱动程序不都是INF+VXD+SYS么?  我知道那个DLL文件里提供了一些操作数据流的接口。

不明白的是,安装驱动到底是要copy哪些内容到系统文件夹呢?

#14


重新测试过了,DLL文件和SYS文件都已经COPY到了正确的系统文件夹下面。但是插上硬件的时候,系统还是会弹出安装驱动的提示。

是不是和注册表有关系呢?

我按照系统提示安装的驱动 和 通过批处理程序安装的驱动 所调用的INF文件时同一个文件啊。
按理说应该不会出现注册表的修改内容不一致的情况。

请教各位老大 ,  这到底是什么情况呢?


#15


Windows DDK中有一个例子叫做BindView可以实现你的目的,不过如果没有数字证书,是一定会弹出提示“驱动可能不安全”的窗口的。前几天我刚把BindView中自动安装的代码分离了出来,有需要的话可以跟我联系。

#16


回hzy_76:
BindView的实现原理是什么呢? 也是通过WDM加载的么?还是通过NT方式加载的(这个方法在《Windows驱动开发技术详解》第三章有附带的源代码)。

另外怎么联系你呢?

#17


应该是WDM吧,我是用来安装我自己写的NDIS驱动的,已经调试通过。如果需要的话,留言给我,我可以把代码发给你。
驱动开发我也是初学者,有问题一起探讨!

#18


回楼上: 给你留言了,指点我一下吧。

#19


回头看了一下,那段代码好像是安装网络驱动的,你这种驱动可能不适合。
我把代码贴出来吧,你自己研究看看是否可以借鉴:


//这两个是对应网络服务和网卡的定义,安装其他驱动时需要修改
const GUID *pguidClassService = &GUID_DEVCLASS_NETSERVICE;
const GUID *pguidClassNet = &GUID_DEVCLASS_NET;

//
// Function:  ReleaseRef
//
// Purpose:   Release reference.
//
// Arguments:
//    punk     [in]  IUnknown reference to release.
//
// Returns:   Reference count.
//
// Notes:
//
VOID CTryCodeDlg::ReleaseRef (IN IUnknown* punk)
{
if (punk)
{
punk->Release();
}

return;
}

//
// Function:  HrGetINetCfg
//
// Purpose:   Get a reference to INetCfg.
//
// Arguments:
//    fGetWriteLock  [in]  If TRUE, Write lock.requested.
//    lpszAppName    [in]  Application name requesting the reference.
//    ppnc           [out] Reference to INetCfg.
//    lpszLockedBy   [in]  Optional. Application who holds the write lock.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetINetCfg (IN BOOL fGetWriteLock, IN LPCWSTR lpszAppName, OUT INetCfg** ppnc, OUT LPWSTR *lpszLockedBy)
{
INetCfg      *pnc = NULL;
INetCfgLock  *pncLock = NULL;
HRESULT      hr = S_OK;

//
// Initialize the output parameters.
//

*ppnc = NULL;

if (lpszLockedBy)
{
*lpszLockedBy = NULL;
}

//
// Create the object implementing INetCfg.
//

hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (void**)&pnc);
if (hr == S_OK)
{
if (fGetWriteLock)
{
//
// Get the locking reference
//
hr = pnc->QueryInterface(IID_INetCfgLock, (LPVOID *)&pncLock);
if (hr == S_OK)
{
//
// Attempt to lock the INetCfg for read/write
//
hr = pncLock->AcquireWriteLock(LOCK_TIME_OUT, lpszAppName, lpszLockedBy);
if (hr == S_FALSE)
{
hr = NETCFG_E_NO_WRITE_LOCK;
}
}
}

if (hr == S_OK)
{
//
// Initialize the INetCfg object.
//

hr = pnc->Initialize(NULL);

if (hr == S_OK)
{
*ppnc = pnc;
pnc->AddRef();
}
else
{
//
// Initialize failed, if obtained lock, release it
//

if (pncLock)
{
pncLock->ReleaseWriteLock();
}
}
}

ReleaseRef(pncLock);
ReleaseRef(pnc);
}

return hr;
}

//
// Function:  HrReleaseINetCfg
//
// Purpose:   Get a reference to INetCfg.
//
// Arguments:
//    pnc           [in] Reference to INetCfg to release.
//    fHasWriteLock [in] If TRUE, reference was held with write lock.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrReleaseINetCfg (IN INetCfg* pnc, IN BOOL fHasWriteLock)
{
INetCfgLock    *pncLock = NULL;
HRESULT        hr = S_OK;

//
// If write lock is present, unlock it
//
if (hr == S_OK && fHasWriteLock)
{
//
// Get the locking reference
//

hr = pnc->QueryInterface(IID_INetCfgLock, (LPVOID *)&pncLock);
if (hr == S_OK)
{
hr = pncLock->ReleaseWriteLock();
ReleaseRef(pncLock);
}
}

ReleaseRef(pnc);

return hr;
}

//
// Function:  HrInstallComponent
//
// Purpose:   Install a network component(protocols, clients and services)
//            given its INF file.
// Arguments:
//    pnc              [in] Reference to INetCfg.
//    lpszComponentId  [in] PnpID of the network component.
//    pguidClass       [in] Class GUID of the network component.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrInstallComponent(IN INetCfg* pnc, IN LPCWSTR szComponentId, IN const GUID* pguidClass)
{
INetCfgClassSetup   *pncClassSetup = NULL;
INetCfgComponent    *pncc = NULL;
OBO_TOKEN           OboToken;
HRESULT             hr = S_OK;

//
// OBO_TOKEN specifies on whose behalf this
// component is being installed.
// Set it to OBO_USER so that szComponentId will be installed
// on behalf of the user.
//
ZeroMemory(&OboToken, sizeof(OboToken));
OboToken.Type = OBO_USER;

//
// Get component's setup class reference.
//
hr = pnc->QueryNetCfgClass (pguidClass, IID_INetCfgClassSetup, (void**)&pncClassSetup);
if (hr == S_OK)
{
hr = pncClassSetup->Install(szComponentId,
&OboToken,
0,
0,       // Upgrade from build number.
NULL,    // Answerfile name
NULL,    // Answerfile section name
&pncc); // Reference after the component
if (S_OK == hr) 
{
// is installed.
//
// we don't need to use pncc (INetCfgComponent), release it
//
ReleaseRef(pncc);
}

ReleaseRef(pncClassSetup);
}

return hr;
}

//
// Function:  HrInstallNetComponent
//
// Purpose:   Install a network component(protocols, clients and services)
//            given its INF file.
//
// Arguments:
//    pnc              [in] Reference to INetCfg.
//    lpszComponentId  [in] PnpID of the network component.
//    pguidClass       [in] Class GUID of the network component.
//    lpszInfFullPath  [in] INF file to install from.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrInstallNetComponent (IN INetCfg *pnc, IN LPCWSTR lpszComponentId, IN const GUID    *pguidClass, IN LPCWSTR lpszInfFullPath)
{
DWORD     dwError;
HRESULT   hr = S_OK;
WCHAR     Drive[_MAX_DRIVE];
WCHAR     Dir[_MAX_DIR];
WCHAR     DirWithDrive[_MAX_DRIVE+_MAX_DIR];

//
// If full path to INF has been specified, the INF
// needs to be copied using Setup API to ensure that any other files
// that the primary INF copies will be correctly found by Setup API
//
if (lpszInfFullPath)
{
//
// Get the path where the INF file is.
//
_wsplitpath(lpszInfFullPath, Drive, Dir, NULL, NULL);

wcscpy(DirWithDrive, Drive);
wcscat(DirWithDrive, Dir);

//
// Copy the INF file and other files referenced in the INF file.
//
if (!SetupCopyOEMInfW(lpszInfFullPath,
DirWithDrive, // Other files are in the
// same dir. as primary INF
SPOST_PATH, // First param is path to INF
0, // Default copy style
NULL, // Name of the INF after
// it's copied to %windir%\inf
0, // Max buf. size for the above
NULL, // Required size if non-null
NULL))
{
// Optionally get the filename
// part of Inf name after it is copied.
dwError = GetLastError();

hr = HRESULT_FROM_WIN32(dwError);
}
}

if (S_OK == hr)
{
//
// Install the network component.
//
hr = HrInstallComponent(pnc, lpszComponentId, pguidClass);
if (hr == S_OK)
{
//
// On success, apply the changes
//
hr = pnc->Apply();
}
}

return hr;
}

//
// Function:  HrUninstallNetComponent
//
// Purpose:   Uninstall a network component(protocols, clients and services).
//
// Arguments:
//    pnc           [in] Reference to INetCfg.
//    szComponentId [in] PnpID of the network component to uninstall.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrUninstallNetComponent(IN INetCfg* pnc, IN LPCWSTR szComponentId)
{
INetCfgComponent    *pncc = NULL;
INetCfgClass        *pncClass = NULL;
INetCfgClassSetup   *pncClassSetup = NULL;
OBO_TOKEN           OboToken;
GUID                guidClass;
HRESULT             hr = S_OK;

//
// OBO_TOKEN specifies on whose behalf this
// component is being installed.
// Set it to OBO_USER so that szComponentId will be installed
// on behalf of the user.
//
ZeroMemory(&OboToken, sizeof(OboToken));
OboToken.Type = OBO_USER;

//
// Get the component's reference.
//
hr = pnc->FindComponent(szComponentId, &pncc);

if (S_OK == hr)
{
//
// Get the component's class GUID.
//
hr = pncc->GetClassGuid(&guidClass);

if (hr == S_OK)
{
//
// Get component's class reference.
//
hr = pnc->QueryNetCfgClass(&guidClass, IID_INetCfgClass, (void**)&pncClass);
if (hr == S_OK)
{
//
// Get Setup reference.
//
hr = pncClass->QueryInterface(IID_INetCfgClassSetup, (void**)&pncClassSetup);
if (hr == S_OK)
{
hr = pncClassSetup->DeInstall(pncc, &OboToken, NULL);
if (hr == S_OK)
{
//
// Apply the changes
//
hr = pnc->Apply();
}

ReleaseRef(pncClassSetup);
}

ReleaseRef(pncClass);
}
}

ReleaseRef(pncc);
}

return hr;
}

#20



//
// Function:  HrGetComponentEnum
//
// Purpose:   Get network component enumerator reference.
//
// Arguments:
//    pnc         [in]  Reference to INetCfg.
//    pguidClass  [in]  Class GUID of the network component.
//    ppencc      [out] Enumerator reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetComponentEnum (INetCfg* pnc, IN const GUID* pguidClass, OUT IEnumNetCfgComponent **ppencc)
{
INetCfgClass  *pncclass;
HRESULT       hr;

*ppencc = NULL;

//
// Get the class reference.
//
hr = pnc->QueryNetCfgClass(pguidClass, IID_INetCfgClass, (PVOID *)&pncclass);

if (hr == S_OK)
{
//
// Get the enumerator reference.
//
hr = pncclass->EnumComponents(ppencc);

//
// We don't need the class reference any more.
//
ReleaseRef(pncclass);
}

return hr;
}

//
// Function:  HrGetFirstComponent
//
// Purpose:   Enumerates the first network component.
//
// Arguments:
//    pencc      [in]  Component enumerator reference.
//    ppncc      [out] Network component reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetFirstComponent (IN IEnumNetCfgComponent* pencc, OUT INetCfgComponent **ppncc)
{
HRESULT  hr;
ULONG    ulCount;

*ppncc = NULL;

pencc->Reset();

hr = pencc->Next(1, ppncc, &ulCount);
return hr;
}

//
// Function:  HrGetNextComponent
//
// Purpose:   Enumerate the next network component.
//
// Arguments:
//    pencc      [in]  Component enumerator reference.
//    ppncc      [out] Network component reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:     The function behaves just like HrGetFirstComponent if
//            it is called right after HrGetComponentEnum.
//
//
HRESULT CTryCodeDlg::HrGetNextComponent (IN IEnumNetCfgComponent* pencc, OUT INetCfgComponent **ppncc)
{
HRESULT  hr;
ULONG    ulCount;

*ppncc = NULL;

hr = pencc->Next(1, ppncc, &ulCount);
return hr;
}

//
// Function:  HrGetBindingPathEnum
//
// Purpose:   Get network component's binding path enumerator reference.
//
// Arguments:
//    pncc           [in]  Network component reference.
//    dwBindingType  [in]  EBP_ABOVE or EBP_BELOW.
//    ppencbp        [out] Enumerator reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetBindingPathEnum (IN INetCfgComponent *pncc, IN DWORD dwBindingType, OUT IEnumNetCfgBindingPath **ppencbp)
{
INetCfgComponentBindings *pnccb = NULL;
HRESULT                  hr;

*ppencbp = NULL;

//
// Get component's binding.
//

hr = pncc->QueryInterface(IID_INetCfgComponentBindings, (PVOID *)&pnccb);

if (hr == S_OK)
{
//
// Get binding path enumerator reference.
//
hr = pnccb->EnumBindingPaths(dwBindingType, ppencbp);

ReleaseRef(pnccb);
}

return hr;
}

//
// Function:  HrGetFirstBindingPath
//
// Purpose:   Enumerates the first binding path.
//
// Arguments:
//    pencc      [in]  Binding path enumerator reference.
//    ppncc      [out] Binding path reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetFirstBindingPath (IN IEnumNetCfgBindingPath *pencbp, OUT INetCfgBindingPath **ppncbp)
{
ULONG   ulCount;
HRESULT hr;

*ppncbp = NULL;

pencbp->Reset();

hr = pencbp->Next(1, ppncbp, &ulCount);

return hr;
}

//
// Function:  HrGetNextBindingPath
//
// Purpose:   Enumerate the next binding path.
//
// Arguments:
//    pencbp      [in]  Binding path enumerator reference.
//    ppncbp      [out] Binding path reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:     The function behaves just like HrGetFirstBindingPath if
//            it is called right after HrGetBindingPathEnum.
//
//
HRESULT CTryCodeDlg::HrGetNextBindingPath (IN IEnumNetCfgBindingPath *pencbp, OUT INetCfgBindingPath **ppncbp)
{
ULONG   ulCount;
HRESULT hr;

*ppncbp = NULL;

hr = pencbp->Next(1, ppncbp, &ulCount);

return hr;
}

//
// Function:  HrGetBindingInterfaceEnum
//
// Purpose:   Get binding interface enumerator reference.
//
// Arguments:
//    pncbp          [in]  Binding path reference.
//    ppencbp        [out] Enumerator reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetBindingInterfaceEnum (IN INetCfgBindingPath *pncbp, OUT IEnumNetCfgBindingInterface **ppencbi)
{
HRESULT hr;

*ppencbi = NULL;

hr = pncbp->EnumBindingInterfaces(ppencbi);

return hr;
}

//
// Function:  HrGetFirstBindingInterface
//
// Purpose:   Enumerates the first binding interface.
//
// Arguments:
//    pencbi      [in]  Binding interface enumerator reference.
//    ppncbi      [out] Binding interface reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetFirstBindingInterface (IN IEnumNetCfgBindingInterface *pencbi, OUT INetCfgBindingInterface **ppncbi)
{
ULONG   ulCount;
HRESULT hr;

*ppncbi = NULL;

pencbi->Reset();

hr = pencbi->Next(1, ppncbi, &ulCount);

return hr;
}

#21



//
// Function:  HrGetNextBindingInterface
//
// Purpose:   Enumerate the next binding interface.
//
// Arguments:
//    pencbi      [in]  Binding interface enumerator reference.
//    ppncbi      [out] Binding interface reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:     The function behaves just like HrGetFirstBindingInterface if
//            it is called right after HrGetBindingInterfaceEnum.
//
//
HRESULT CTryCodeDlg::HrGetNextBindingInterface (IN IEnumNetCfgBindingInterface *pencbi, OUT INetCfgBindingInterface **ppncbi)
{
ULONG   ulCount;
HRESULT hr;

*ppncbi = NULL;

hr = pencbi->Next(1, ppncbi, &ulCount);

return hr;
}

BOOL CTryCodeDlg::GetFileName (HWND hwndDlg, LPWSTR lpszFilter, LPWSTR lpszTitle, DWORD dwFlags, LPWSTR lpszFile, LPWSTR lpszDefExt)
{
OPENFILENAMEW ofn;
   
lpszFile[0] = NULL;

ZeroMemory(&ofn, sizeof(OPENFILENAMEW));
ofn.lStructSize = sizeof(OPENFILENAMEW);
ofn.hwndOwner = hwndDlg;
ofn.lpstrFilter = lpszFilter;
ofn.lpstrFile = lpszFile;
ofn.lpstrDefExt  = lpszDefExt;
ofn.nMaxFile = MAX_PATH+1;
ofn.lpstrTitle = lpszTitle;
ofn.Flags = dwFlags;

return GetOpenFileNameW(&ofn);
}

HRESULT CTryCodeDlg::InstallSpecifiedComponent (LPWSTR lpszInfFile, LPWSTR lpszPnpID, const GUID *pguidClass)
{
INetCfg    *pnc;
LPWSTR     lpszApp;
HRESULT    hr;

hr = HrGetINetCfg(TRUE, APP_NAME, &pnc, &lpszApp);

if (hr == S_OK)
{
//
// Install the network component.
//

hr = HrInstallNetComponent(pnc, lpszPnpID, pguidClass, lpszInfFile);
if ((hr == S_OK) || (hr == NETCFG_S_REBOOT))
{
hr = pnc->Apply();
}
else
{
if (hr != HRESULT_FROM_WIN32(ERROR_CANCELLED))
{
AfxMessageBox("Couldn't install the network component.");
}
}

HrReleaseINetCfg(pnc, TRUE);
}
else
{
if ((hr == NETCFG_E_NO_WRITE_LOCK) && lpszApp)
{
AfxMessageBox("%s currently holds the lock, try later.");
CoTaskMemFree(lpszApp);
}
else
{
AfxMessageBox("Couldn't the get notify object interface.");
}
}

return hr;
}

HRESULT CTryCodeDlg::GetKeyValue (HINF hInf, LPCWSTR lpszSection, LPCWSTR lpszKey, DWORD  dwIndex, LPWSTR *lppszValue)
{
INFCONTEXT  infCtx;
DWORD       dwSizeNeeded;
HRESULT     hr;

*lppszValue = NULL;

if (SetupFindFirstLineW(hInf, lpszSection, lpszKey, &infCtx) == FALSE)
{
return HRESULT_FROM_WIN32(GetLastError());
}

SetupGetStringFieldW(&infCtx, dwIndex, NULL, 0, &dwSizeNeeded);

*lppszValue = (LPWSTR) CoTaskMemAlloc(sizeof(WCHAR) * dwSizeNeeded);

if (!*lppszValue)
{
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}

if (SetupGetStringFieldW(&infCtx, dwIndex, *lppszValue, dwSizeNeeded, NULL) == FALSE)
{
hr = HRESULT_FROM_WIN32(GetLastError());

CoTaskMemFree(*lppszValue);
*lppszValue = NULL;
}
else
{
hr = S_OK;
}

return hr;
}

HRESULT CTryCodeDlg::GetPnpID (LPWSTR lpszInfFile, LPWSTR *lppszPnpID)
{
HINF    hInf;
LPWSTR  lpszModelSection;
HRESULT hr;

*lppszPnpID = NULL;

hInf = SetupOpenInfFileW(lpszInfFile, NULL, INF_STYLE_WIN4, NULL);

if (hInf == INVALID_HANDLE_VALUE)
{
return HRESULT_FROM_WIN32(GetLastError());
}

//
// Read the Model section name from Manufacturer section.
//

hr = GetKeyValue(hInf, L"Manufacturer", NULL, 1, &lpszModelSection);

if (hr == S_OK)
{
//
// Read PnpID from the Model section.
//

hr = GetKeyValue(hInf, lpszModelSection, NULL, 2, lppszPnpID);

CoTaskMemFree(lpszModelSection);
}

SetupCloseInfFile(hInf);

return hr;
}

VOID CTryCodeDlg::InstallSelectedComponentType (HWND hwndDlg, LPWSTR lpszInfFile)
{
HRESULT   hr;

if (lpszInfFile)
{
LPWSTR  lpszPnpID;

//
// Inf file name specified, install the network component
// from this file.
//

hr = GetPnpID(lpszInfFile, &lpszPnpID);

if (hr == S_OK)
{
hr = InstallSpecifiedComponent(lpszInfFile, lpszPnpID, pguidClassService);
CoTaskMemFree(lpszPnpID);
}
else
{
AfxMessageBox("Error read inf file.");
}
}
else
{
AfxMessageBox("No inf file.");
}

switch(hr)
{
case S_OK:
MessageBoxW(hwndDlg,
L"Component installed successfully.",
L"Network Component Installation",
MB_OK | MB_ICONINFORMATION);
break;

case NETCFG_S_REBOOT:
MessageBoxW(hwndDlg,
L"Component installed successfully: "
L"Reboot required.",
L"Network Component Installation",
MB_OK | MB_ICONINFORMATION);
}

return;
}

//这里使用“文件”对话框选择inf文件,可以更改为其他方式
void CTryCodeDlg::OnInstallDriver() 
{
// TODO: Add your control notification handler code here
WCHAR lpszInfFile[MAX_PATH + 1];
if (GetFileName(this->m_hWnd,
L"INF files (*.inf)\0*.inf\0",
L"Select the INF file of the network component to install",
OFN_DONTADDTORECENT | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST,
lpszInfFile,
NULL))
{
InstallSelectedComponentType(this->m_hWnd, lpszInfFile);
}
}

#22


最近在给客户做一个类似于三星的DNW的工具,用到的驱动文件也是和DNW同样的,也需要考虑和楼主同样的问题,还不清楚怎么实现呢

#23


回hzy_76:
非常感谢你提供源代码,我正在研究呢。
我看到你的安装驱动的核心步骤就是调用setupCopyOEMInf函数。
关于这个函数我还不是很了解其内部机制是什么?MSDN上说,这个函数就是将INF文件以及其相关的文件COPY到系统文件夹中去。
那么这个函数和InstallHinfSection有什么区别呢?我想用DOS批处理脚本来安装驱动,论坛上许多人建议过这样的方法。InstallHinfSection也是将INF文件及其相关文件COPY到系统文件夹下面,并修改注册表。(这一点我在系统文件夹和注册表都有监视过)。结果还是没有安装成功(硬件插上后还是会弹出提示)。


另外,我现在同时还在试验用InstallShield来做个exe的安装包。不知道哪位老大有InstallShield 12 的电子版教材啊?  能分享一下吗?  谢谢咯!

#24


是的,复制安装文件是必要的步骤。修改注册表部分,BindView里边是用INetCfgClassSetup来做的,看起来是针对网络的,估计你用不着了。不过你可以沿这个思路看是否有类似的解决方案。

我原来也想过用InstallShield来做,它的帮助里边也提到过可以制作驱动安装程序,但没有进展,后来就去研究BindView代码了。

#25


引用楼主 kisery008 的回复:
Hi,
 小弟目前做的项目需要在Windows下安装一个简单的USB驱动,驱动程序由第三方提供(没有经过MS认证),包含DLL、INF、SYS等等文件。
 一般情况下,当即插即用设备连上PC后,如果PC中没有该设备的驱动,会弹出安装驱动的提示,用户根据提示来一步步安装就可以了。
 现在这个项目需要事先就把驱动安装到PC中去,也就是把安装驱动这件事放在安装软件(项目最终的发布软件)的过程中完成。那么应该怎么去安装驱动呢?
 并且由于软件最终会运行在XP、VISTA和Windows7下面,那么这三个系统下的自动安装的过程有多大的区别呢?


 PS:请教过一个高手,写个精简DOS程序即可,但还是没有弄清楚。正在看《Windows驱动开发技术详解》,由于不是写驱动,只是安装驱动,这本书中也没有找到可行的办法。

嘿嘿,不好意思,刚看到你的留言。
 1.现在这个项目需要事先就把驱动安装到PC中去,也就是把安装驱动这件事放在安装软件(项目最终的发布软件)的过程中完成。那么应该怎么去安装驱动呢?
我看了你的那个脚本,你把设备插在上边然后安装一下,试试看能不能成功,不过安装过程中肯定要提示的。装好之后换个口插入肯定也会提示。(因为你没有经过ms认证。)
一般安装驱动的程序都是使用setupapi或者difx这两套库通过自己的程序实现的。
2. 并且由于软件最终会运行在XP、VISTA和Windows7下面,那么这三个系统下的自动安装的过程有多大的区别呢?
如果没有经过ms认证的驱动的话,在64位操作系统和32位操作系统下是有区别的。区别就是64位下不能使用。^_^.32位下,都一样,使用正规的操作装上之后,第一次插入设备时,还是会提示安装,只是这时选择自动搜索可以自动装上去。而且在安装过程中会有未经过认证的提示。

#26


如果使用InstallShield 12的话,这个工具里自带了安装驱动的接口,你只需要在里边点击几下,配置一下你驱动的路径就可以了。

#27


引用 23 楼 kisery008 的回复:
 那么这个函数和InstallHinfSection有什么区别呢?我想用DOS批处理脚本来安装驱动,论坛上许多人建议过这样的方法。InstallHinfSection也是将INF文件及其相关文件COPY到系统文件夹下面,并修改注册表。(这一点我在系统文件夹和注册表都有监视过)。结果还是没有安装成功(硬件插上后还是会弹出提示)。

硬件插上后还是会弹出提示,这个情况是因为你的驱动程序没有经过签名,你可以找一台裸机,或者把你的机器上的驱动删干净试。和你的脚本程序是一样的,如果没有运行过程序或者脚本,在插入设备后提示安装驱动,这时你选择自动搜索,不能将驱动更新。如果运行过了,那就可以更新驱动了。

#28


我现在也是这个问题,用InstallShield 做的包太大了, 换成Setup Factory在搞,可是研究了几天都还没搞定,用SetupCopyOEMInfA拷贝文件到INF文件夹,可是好像没有成功!不知道怎么回事?拷贝文件后还需要做些什么操作吗?
    在网上找了下,说要再去写注册表,可是不知道写啥?郁闷,
    关注中!!!

#29


驱动的安装方式大至有二种: 
1,在插上设备的时候进行安装,即使用函数UpdateDriverForPlugAndPlayDevice()。 
2,在没有物理设备的时候安装,即通常所说的驱动预安装(SetupCopyOEMInf)。 

需要注意的是: 
1,SetupCopyOEMInf()只是生成一个oem*.inf文件和oem*.pnf文件到Windows\inf\文件夹中, 
  即没有修改任何注册表,也没有复制文件。生成的pnf文件包含源文件路径信息,以便在真正 
 插上设备的时候能够找到相应的sys等文件。 
2,UpdateDriverForPlugAndPlayDevice()在没有插上设备的时候是会执行失败的。 

Windows插上设备到找到合适的驱动的大致步骤是: 
1,插上设备后Windows设备信息到硬件键[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\下去寻找相应的项。 

2,如果在Enum键下没有相应的信息,则Windows到预安装目录中去寻找相应的oem*.inf和oem*.pnf文件(oem*.inf和oem*.pnf只要前面的文件名相同就可以,故如果对二个同时改成相同的名字不会有什么影响). 
如果进行了预安装,则可以在这里找到相应的inf和pnf文件。于是弹出发现新硬件对话框,点自动安装就可成功(这个对话框可以通过协助安装程序搞掉它)。安装时会弹出徽标论证的对话框(XP下可以通过改注册表的方式搞掉,Vista下暂没发现办法) 

3,注册CoInstall的方法即修改以下键值: 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CoDeviceInstallers],子键名为要注册CoInstall的GUID,值为dll的名字和函数名。 

#30


你的驱动目前打包完成没?

#31


我的方法:

DPInst.exe是WDK中的一个实用工具,它可以自动搜索指定目录的inf文件,并安装相应设备的驱动程序。

MSDN中有关于DPInst.exe的详细资料:
http://msdn.microsoft.com/en-us/library/ms790308.aspx
http://www.microsoft.com/china/whdc/driver/install/difxtools.mspx

下载地址:
http://www.microsoft.com/china/whdc/driver/install/DIFxtls.mspx
http://www.microsoft.com/downloads/details.aspx?FamilyID=2105564e-1a9a-4bf4-8d74-ec5b52da3d00&displaylang=en

DPInst.exe支持命令行,它支持的参数可以使用DPInst.exe /?查看。

示例:
1.自动搜索C:\VGA目录下的INF文件并安装驱动程序:
DPInst.exe /PATH "C:\VGA" /F /Q /LM /A

2.自动搜索C:\目录下的INF文件并安装驱动程序:
DPInst.exe /PATH C:\ /LM

http://qingfengju.com/article.asp?id=183

#32


HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CoDeviceInstallers 下面注册coinstaller,不过coinstaller 里面SetupDiEnumDriverInfo会失败,没找到好的办法

#1


楼主关键是要实现你的设备的HID,我们采用一个带USB的单片机,开始也没实现免驱,后来市场需求,我们采用挂接在HID上,实现了免驱设计。即可以利用电脑的自带的USB的等驱动文件,自动识别我的设备。
oogle与百度下“免驱设计 HID”

一下几篇文章很不错,
http://www.dzsc.com/data/html/2009-7-21/77757.html
http://www.abc188.com/info/html/wangzhanyunying/jianzhanjingyan/20080417/67834.html
http://linux.chinaunix.net/techdoc/install/2008/03/14/983179.shtml

#2


感谢楼上解答。
只是楼上提供的是关于libUSB的相关资料。
而且驱动程序已经有提供了,我需要安装这个驱动。

#3


这个感觉向是把你的驱动 要加载到操作系统中,做到即插即用的,就跟我们使用U盘是一样的

楼主可以写个啥程序,把驱动加载到PC上,只要插上你的设备 就可以识别

这只是我的想法 具体这软件咋写 我也不会

#4


我也想知道,好像没有见过类似的做法。

#5


回cfanlwn: 是的。因为用到了一个USB转串口的芯片,所以要安装下驱动,当然就像平常那样的,当硬件接上PC后,按照提示一步一步安装也可以。但是这样子一来是使得用户的使用变得麻烦,而且增加了安装过程的风险(比如说MS的数字认证问题)。所以现在要将驱动在安装程序的时候就安装上去。

就是不晓得应该怎么做啊。。。



#6


你说让他自动获取,然后我们一步步安装,最后安装上也就是把一些信息放在WINDOWS下,然后在注册表中加写信息,楼主可以查查这些资料,看能不能写个批处理程序

#7


回cfanlwn:

是不是大家都是通过批处理来做这件事的?因为我问了其他版块的高手,有人也这么说的。

有个高手提供了如下的批处理脚本:

echo 安装驱动
rundll32.exe setupapi.dll,InstallHinfSection DefaultInstall 128 %inf%
echo 安装完成

我没有写过批处理脚本,刚刚找了一篇批处理的文章正在屁颠屁颠的看。

能帮忙分析一下这个脚本么?


#8


请教cfanlwn:

我刚刚试了一下。
批处理代码如下:
@echo off
echo 判断系统版本
set inf=D:\XP\DRIVER\CH341WDM.INF
echo 安装驱动
rundll32.exe setupapi.dll,InstallHinfSection DefaultInstall 128 %inf%
echo 安装完成

发现没有安装上去,请问是怎么一回事呢? 问题出在哪里了呢?

#9


用DeviceTree查看了一下,确实没有安装上去。。。

#10


引用 5 楼 kisery008 的回复:
回cfanlwn: 是的。因为用到了一个USB转串口的芯片,所以要安装下驱动,当然就像平常那样的,当硬件接上PC后,按照提示一步一步安装也可以。但是这样子一来是使得用户的使用变得麻烦,而且增加了安装过程的风险(比如说MS的数字认证问题)。所以现在要将驱动在安装程序的时候就安装上去。

就是不晓得应该怎么做啊。。。


一般的USB转串口的芯片,都会由这个芯片厂家提供PC端的驱动,一般只要实现在PC上安装驱动,之后你随时插拔,系统就会自动识别你的设备。

我们用到很多USB转串口的转接线都是这样的,我们用CP2102做的一款产品也是这样,先人为安装驱动,之后就不用管了、

#11


既然第三方已经提供了“包含DLL、INF、SYS等等文件。”

楼主是否可以百度或者google下,“如何生成exe可执行文件”。


我们当时做项目,就把这个DLL和一些系统文件,用专用的软件人为生成了一个exe,之后一点就自动运行。

#12


回kyzf:
谢谢提示啊~~
因为这个驱动没有取得MS的认证,所以如果人工安装的话可能对那些警告提示感到头疼。

关于生成exe可执行文件,是个不错的方法,我现在看到有人用批处理程序就搞定了,所以就先按照那个方法先试了一下。。

没找到专业软件生成EXE文件,能提供一个下载的链接或者方法么?谢谢咯~~

另外,“把这个DLL和一些系统文件,用专用的软件人为生成了一个exe”,请问还需要哪些系统文件呢?最后生成的EXE可执行文件会不会很大啊??

#13


为什么我按照系统提示来安装的时候  那个进度条显示的安装内容是DLL文件   而用批处理倒的时候 显示安装的内容是SYS文件    

一般驱动程序不都是INF+VXD+SYS么?  我知道那个DLL文件里提供了一些操作数据流的接口。

不明白的是,安装驱动到底是要copy哪些内容到系统文件夹呢?

#14


重新测试过了,DLL文件和SYS文件都已经COPY到了正确的系统文件夹下面。但是插上硬件的时候,系统还是会弹出安装驱动的提示。

是不是和注册表有关系呢?

我按照系统提示安装的驱动 和 通过批处理程序安装的驱动 所调用的INF文件时同一个文件啊。
按理说应该不会出现注册表的修改内容不一致的情况。

请教各位老大 ,  这到底是什么情况呢?


#15


Windows DDK中有一个例子叫做BindView可以实现你的目的,不过如果没有数字证书,是一定会弹出提示“驱动可能不安全”的窗口的。前几天我刚把BindView中自动安装的代码分离了出来,有需要的话可以跟我联系。

#16


回hzy_76:
BindView的实现原理是什么呢? 也是通过WDM加载的么?还是通过NT方式加载的(这个方法在《Windows驱动开发技术详解》第三章有附带的源代码)。

另外怎么联系你呢?

#17


应该是WDM吧,我是用来安装我自己写的NDIS驱动的,已经调试通过。如果需要的话,留言给我,我可以把代码发给你。
驱动开发我也是初学者,有问题一起探讨!

#18


回楼上: 给你留言了,指点我一下吧。

#19


回头看了一下,那段代码好像是安装网络驱动的,你这种驱动可能不适合。
我把代码贴出来吧,你自己研究看看是否可以借鉴:


//这两个是对应网络服务和网卡的定义,安装其他驱动时需要修改
const GUID *pguidClassService = &GUID_DEVCLASS_NETSERVICE;
const GUID *pguidClassNet = &GUID_DEVCLASS_NET;

//
// Function:  ReleaseRef
//
// Purpose:   Release reference.
//
// Arguments:
//    punk     [in]  IUnknown reference to release.
//
// Returns:   Reference count.
//
// Notes:
//
VOID CTryCodeDlg::ReleaseRef (IN IUnknown* punk)
{
if (punk)
{
punk->Release();
}

return;
}

//
// Function:  HrGetINetCfg
//
// Purpose:   Get a reference to INetCfg.
//
// Arguments:
//    fGetWriteLock  [in]  If TRUE, Write lock.requested.
//    lpszAppName    [in]  Application name requesting the reference.
//    ppnc           [out] Reference to INetCfg.
//    lpszLockedBy   [in]  Optional. Application who holds the write lock.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetINetCfg (IN BOOL fGetWriteLock, IN LPCWSTR lpszAppName, OUT INetCfg** ppnc, OUT LPWSTR *lpszLockedBy)
{
INetCfg      *pnc = NULL;
INetCfgLock  *pncLock = NULL;
HRESULT      hr = S_OK;

//
// Initialize the output parameters.
//

*ppnc = NULL;

if (lpszLockedBy)
{
*lpszLockedBy = NULL;
}

//
// Create the object implementing INetCfg.
//

hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (void**)&pnc);
if (hr == S_OK)
{
if (fGetWriteLock)
{
//
// Get the locking reference
//
hr = pnc->QueryInterface(IID_INetCfgLock, (LPVOID *)&pncLock);
if (hr == S_OK)
{
//
// Attempt to lock the INetCfg for read/write
//
hr = pncLock->AcquireWriteLock(LOCK_TIME_OUT, lpszAppName, lpszLockedBy);
if (hr == S_FALSE)
{
hr = NETCFG_E_NO_WRITE_LOCK;
}
}
}

if (hr == S_OK)
{
//
// Initialize the INetCfg object.
//

hr = pnc->Initialize(NULL);

if (hr == S_OK)
{
*ppnc = pnc;
pnc->AddRef();
}
else
{
//
// Initialize failed, if obtained lock, release it
//

if (pncLock)
{
pncLock->ReleaseWriteLock();
}
}
}

ReleaseRef(pncLock);
ReleaseRef(pnc);
}

return hr;
}

//
// Function:  HrReleaseINetCfg
//
// Purpose:   Get a reference to INetCfg.
//
// Arguments:
//    pnc           [in] Reference to INetCfg to release.
//    fHasWriteLock [in] If TRUE, reference was held with write lock.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrReleaseINetCfg (IN INetCfg* pnc, IN BOOL fHasWriteLock)
{
INetCfgLock    *pncLock = NULL;
HRESULT        hr = S_OK;

//
// If write lock is present, unlock it
//
if (hr == S_OK && fHasWriteLock)
{
//
// Get the locking reference
//

hr = pnc->QueryInterface(IID_INetCfgLock, (LPVOID *)&pncLock);
if (hr == S_OK)
{
hr = pncLock->ReleaseWriteLock();
ReleaseRef(pncLock);
}
}

ReleaseRef(pnc);

return hr;
}

//
// Function:  HrInstallComponent
//
// Purpose:   Install a network component(protocols, clients and services)
//            given its INF file.
// Arguments:
//    pnc              [in] Reference to INetCfg.
//    lpszComponentId  [in] PnpID of the network component.
//    pguidClass       [in] Class GUID of the network component.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrInstallComponent(IN INetCfg* pnc, IN LPCWSTR szComponentId, IN const GUID* pguidClass)
{
INetCfgClassSetup   *pncClassSetup = NULL;
INetCfgComponent    *pncc = NULL;
OBO_TOKEN           OboToken;
HRESULT             hr = S_OK;

//
// OBO_TOKEN specifies on whose behalf this
// component is being installed.
// Set it to OBO_USER so that szComponentId will be installed
// on behalf of the user.
//
ZeroMemory(&OboToken, sizeof(OboToken));
OboToken.Type = OBO_USER;

//
// Get component's setup class reference.
//
hr = pnc->QueryNetCfgClass (pguidClass, IID_INetCfgClassSetup, (void**)&pncClassSetup);
if (hr == S_OK)
{
hr = pncClassSetup->Install(szComponentId,
&OboToken,
0,
0,       // Upgrade from build number.
NULL,    // Answerfile name
NULL,    // Answerfile section name
&pncc); // Reference after the component
if (S_OK == hr) 
{
// is installed.
//
// we don't need to use pncc (INetCfgComponent), release it
//
ReleaseRef(pncc);
}

ReleaseRef(pncClassSetup);
}

return hr;
}

//
// Function:  HrInstallNetComponent
//
// Purpose:   Install a network component(protocols, clients and services)
//            given its INF file.
//
// Arguments:
//    pnc              [in] Reference to INetCfg.
//    lpszComponentId  [in] PnpID of the network component.
//    pguidClass       [in] Class GUID of the network component.
//    lpszInfFullPath  [in] INF file to install from.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrInstallNetComponent (IN INetCfg *pnc, IN LPCWSTR lpszComponentId, IN const GUID    *pguidClass, IN LPCWSTR lpszInfFullPath)
{
DWORD     dwError;
HRESULT   hr = S_OK;
WCHAR     Drive[_MAX_DRIVE];
WCHAR     Dir[_MAX_DIR];
WCHAR     DirWithDrive[_MAX_DRIVE+_MAX_DIR];

//
// If full path to INF has been specified, the INF
// needs to be copied using Setup API to ensure that any other files
// that the primary INF copies will be correctly found by Setup API
//
if (lpszInfFullPath)
{
//
// Get the path where the INF file is.
//
_wsplitpath(lpszInfFullPath, Drive, Dir, NULL, NULL);

wcscpy(DirWithDrive, Drive);
wcscat(DirWithDrive, Dir);

//
// Copy the INF file and other files referenced in the INF file.
//
if (!SetupCopyOEMInfW(lpszInfFullPath,
DirWithDrive, // Other files are in the
// same dir. as primary INF
SPOST_PATH, // First param is path to INF
0, // Default copy style
NULL, // Name of the INF after
// it's copied to %windir%\inf
0, // Max buf. size for the above
NULL, // Required size if non-null
NULL))
{
// Optionally get the filename
// part of Inf name after it is copied.
dwError = GetLastError();

hr = HRESULT_FROM_WIN32(dwError);
}
}

if (S_OK == hr)
{
//
// Install the network component.
//
hr = HrInstallComponent(pnc, lpszComponentId, pguidClass);
if (hr == S_OK)
{
//
// On success, apply the changes
//
hr = pnc->Apply();
}
}

return hr;
}

//
// Function:  HrUninstallNetComponent
//
// Purpose:   Uninstall a network component(protocols, clients and services).
//
// Arguments:
//    pnc           [in] Reference to INetCfg.
//    szComponentId [in] PnpID of the network component to uninstall.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrUninstallNetComponent(IN INetCfg* pnc, IN LPCWSTR szComponentId)
{
INetCfgComponent    *pncc = NULL;
INetCfgClass        *pncClass = NULL;
INetCfgClassSetup   *pncClassSetup = NULL;
OBO_TOKEN           OboToken;
GUID                guidClass;
HRESULT             hr = S_OK;

//
// OBO_TOKEN specifies on whose behalf this
// component is being installed.
// Set it to OBO_USER so that szComponentId will be installed
// on behalf of the user.
//
ZeroMemory(&OboToken, sizeof(OboToken));
OboToken.Type = OBO_USER;

//
// Get the component's reference.
//
hr = pnc->FindComponent(szComponentId, &pncc);

if (S_OK == hr)
{
//
// Get the component's class GUID.
//
hr = pncc->GetClassGuid(&guidClass);

if (hr == S_OK)
{
//
// Get component's class reference.
//
hr = pnc->QueryNetCfgClass(&guidClass, IID_INetCfgClass, (void**)&pncClass);
if (hr == S_OK)
{
//
// Get Setup reference.
//
hr = pncClass->QueryInterface(IID_INetCfgClassSetup, (void**)&pncClassSetup);
if (hr == S_OK)
{
hr = pncClassSetup->DeInstall(pncc, &OboToken, NULL);
if (hr == S_OK)
{
//
// Apply the changes
//
hr = pnc->Apply();
}

ReleaseRef(pncClassSetup);
}

ReleaseRef(pncClass);
}
}

ReleaseRef(pncc);
}

return hr;
}

#20



//
// Function:  HrGetComponentEnum
//
// Purpose:   Get network component enumerator reference.
//
// Arguments:
//    pnc         [in]  Reference to INetCfg.
//    pguidClass  [in]  Class GUID of the network component.
//    ppencc      [out] Enumerator reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetComponentEnum (INetCfg* pnc, IN const GUID* pguidClass, OUT IEnumNetCfgComponent **ppencc)
{
INetCfgClass  *pncclass;
HRESULT       hr;

*ppencc = NULL;

//
// Get the class reference.
//
hr = pnc->QueryNetCfgClass(pguidClass, IID_INetCfgClass, (PVOID *)&pncclass);

if (hr == S_OK)
{
//
// Get the enumerator reference.
//
hr = pncclass->EnumComponents(ppencc);

//
// We don't need the class reference any more.
//
ReleaseRef(pncclass);
}

return hr;
}

//
// Function:  HrGetFirstComponent
//
// Purpose:   Enumerates the first network component.
//
// Arguments:
//    pencc      [in]  Component enumerator reference.
//    ppncc      [out] Network component reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetFirstComponent (IN IEnumNetCfgComponent* pencc, OUT INetCfgComponent **ppncc)
{
HRESULT  hr;
ULONG    ulCount;

*ppncc = NULL;

pencc->Reset();

hr = pencc->Next(1, ppncc, &ulCount);
return hr;
}

//
// Function:  HrGetNextComponent
//
// Purpose:   Enumerate the next network component.
//
// Arguments:
//    pencc      [in]  Component enumerator reference.
//    ppncc      [out] Network component reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:     The function behaves just like HrGetFirstComponent if
//            it is called right after HrGetComponentEnum.
//
//
HRESULT CTryCodeDlg::HrGetNextComponent (IN IEnumNetCfgComponent* pencc, OUT INetCfgComponent **ppncc)
{
HRESULT  hr;
ULONG    ulCount;

*ppncc = NULL;

hr = pencc->Next(1, ppncc, &ulCount);
return hr;
}

//
// Function:  HrGetBindingPathEnum
//
// Purpose:   Get network component's binding path enumerator reference.
//
// Arguments:
//    pncc           [in]  Network component reference.
//    dwBindingType  [in]  EBP_ABOVE or EBP_BELOW.
//    ppencbp        [out] Enumerator reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetBindingPathEnum (IN INetCfgComponent *pncc, IN DWORD dwBindingType, OUT IEnumNetCfgBindingPath **ppencbp)
{
INetCfgComponentBindings *pnccb = NULL;
HRESULT                  hr;

*ppencbp = NULL;

//
// Get component's binding.
//

hr = pncc->QueryInterface(IID_INetCfgComponentBindings, (PVOID *)&pnccb);

if (hr == S_OK)
{
//
// Get binding path enumerator reference.
//
hr = pnccb->EnumBindingPaths(dwBindingType, ppencbp);

ReleaseRef(pnccb);
}

return hr;
}

//
// Function:  HrGetFirstBindingPath
//
// Purpose:   Enumerates the first binding path.
//
// Arguments:
//    pencc      [in]  Binding path enumerator reference.
//    ppncc      [out] Binding path reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetFirstBindingPath (IN IEnumNetCfgBindingPath *pencbp, OUT INetCfgBindingPath **ppncbp)
{
ULONG   ulCount;
HRESULT hr;

*ppncbp = NULL;

pencbp->Reset();

hr = pencbp->Next(1, ppncbp, &ulCount);

return hr;
}

//
// Function:  HrGetNextBindingPath
//
// Purpose:   Enumerate the next binding path.
//
// Arguments:
//    pencbp      [in]  Binding path enumerator reference.
//    ppncbp      [out] Binding path reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:     The function behaves just like HrGetFirstBindingPath if
//            it is called right after HrGetBindingPathEnum.
//
//
HRESULT CTryCodeDlg::HrGetNextBindingPath (IN IEnumNetCfgBindingPath *pencbp, OUT INetCfgBindingPath **ppncbp)
{
ULONG   ulCount;
HRESULT hr;

*ppncbp = NULL;

hr = pencbp->Next(1, ppncbp, &ulCount);

return hr;
}

//
// Function:  HrGetBindingInterfaceEnum
//
// Purpose:   Get binding interface enumerator reference.
//
// Arguments:
//    pncbp          [in]  Binding path reference.
//    ppencbp        [out] Enumerator reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetBindingInterfaceEnum (IN INetCfgBindingPath *pncbp, OUT IEnumNetCfgBindingInterface **ppencbi)
{
HRESULT hr;

*ppencbi = NULL;

hr = pncbp->EnumBindingInterfaces(ppencbi);

return hr;
}

//
// Function:  HrGetFirstBindingInterface
//
// Purpose:   Enumerates the first binding interface.
//
// Arguments:
//    pencbi      [in]  Binding interface enumerator reference.
//    ppncbi      [out] Binding interface reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:
//
HRESULT CTryCodeDlg::HrGetFirstBindingInterface (IN IEnumNetCfgBindingInterface *pencbi, OUT INetCfgBindingInterface **ppncbi)
{
ULONG   ulCount;
HRESULT hr;

*ppncbi = NULL;

pencbi->Reset();

hr = pencbi->Next(1, ppncbi, &ulCount);

return hr;
}

#21



//
// Function:  HrGetNextBindingInterface
//
// Purpose:   Enumerate the next binding interface.
//
// Arguments:
//    pencbi      [in]  Binding interface enumerator reference.
//    ppncbi      [out] Binding interface reference.
//
// Returns:   S_OK on sucess, otherwise an error code.
//
// Notes:     The function behaves just like HrGetFirstBindingInterface if
//            it is called right after HrGetBindingInterfaceEnum.
//
//
HRESULT CTryCodeDlg::HrGetNextBindingInterface (IN IEnumNetCfgBindingInterface *pencbi, OUT INetCfgBindingInterface **ppncbi)
{
ULONG   ulCount;
HRESULT hr;

*ppncbi = NULL;

hr = pencbi->Next(1, ppncbi, &ulCount);

return hr;
}

BOOL CTryCodeDlg::GetFileName (HWND hwndDlg, LPWSTR lpszFilter, LPWSTR lpszTitle, DWORD dwFlags, LPWSTR lpszFile, LPWSTR lpszDefExt)
{
OPENFILENAMEW ofn;
   
lpszFile[0] = NULL;

ZeroMemory(&ofn, sizeof(OPENFILENAMEW));
ofn.lStructSize = sizeof(OPENFILENAMEW);
ofn.hwndOwner = hwndDlg;
ofn.lpstrFilter = lpszFilter;
ofn.lpstrFile = lpszFile;
ofn.lpstrDefExt  = lpszDefExt;
ofn.nMaxFile = MAX_PATH+1;
ofn.lpstrTitle = lpszTitle;
ofn.Flags = dwFlags;

return GetOpenFileNameW(&ofn);
}

HRESULT CTryCodeDlg::InstallSpecifiedComponent (LPWSTR lpszInfFile, LPWSTR lpszPnpID, const GUID *pguidClass)
{
INetCfg    *pnc;
LPWSTR     lpszApp;
HRESULT    hr;

hr = HrGetINetCfg(TRUE, APP_NAME, &pnc, &lpszApp);

if (hr == S_OK)
{
//
// Install the network component.
//

hr = HrInstallNetComponent(pnc, lpszPnpID, pguidClass, lpszInfFile);
if ((hr == S_OK) || (hr == NETCFG_S_REBOOT))
{
hr = pnc->Apply();
}
else
{
if (hr != HRESULT_FROM_WIN32(ERROR_CANCELLED))
{
AfxMessageBox("Couldn't install the network component.");
}
}

HrReleaseINetCfg(pnc, TRUE);
}
else
{
if ((hr == NETCFG_E_NO_WRITE_LOCK) && lpszApp)
{
AfxMessageBox("%s currently holds the lock, try later.");
CoTaskMemFree(lpszApp);
}
else
{
AfxMessageBox("Couldn't the get notify object interface.");
}
}

return hr;
}

HRESULT CTryCodeDlg::GetKeyValue (HINF hInf, LPCWSTR lpszSection, LPCWSTR lpszKey, DWORD  dwIndex, LPWSTR *lppszValue)
{
INFCONTEXT  infCtx;
DWORD       dwSizeNeeded;
HRESULT     hr;

*lppszValue = NULL;

if (SetupFindFirstLineW(hInf, lpszSection, lpszKey, &infCtx) == FALSE)
{
return HRESULT_FROM_WIN32(GetLastError());
}

SetupGetStringFieldW(&infCtx, dwIndex, NULL, 0, &dwSizeNeeded);

*lppszValue = (LPWSTR) CoTaskMemAlloc(sizeof(WCHAR) * dwSizeNeeded);

if (!*lppszValue)
{
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}

if (SetupGetStringFieldW(&infCtx, dwIndex, *lppszValue, dwSizeNeeded, NULL) == FALSE)
{
hr = HRESULT_FROM_WIN32(GetLastError());

CoTaskMemFree(*lppszValue);
*lppszValue = NULL;
}
else
{
hr = S_OK;
}

return hr;
}

HRESULT CTryCodeDlg::GetPnpID (LPWSTR lpszInfFile, LPWSTR *lppszPnpID)
{
HINF    hInf;
LPWSTR  lpszModelSection;
HRESULT hr;

*lppszPnpID = NULL;

hInf = SetupOpenInfFileW(lpszInfFile, NULL, INF_STYLE_WIN4, NULL);

if (hInf == INVALID_HANDLE_VALUE)
{
return HRESULT_FROM_WIN32(GetLastError());
}

//
// Read the Model section name from Manufacturer section.
//

hr = GetKeyValue(hInf, L"Manufacturer", NULL, 1, &lpszModelSection);

if (hr == S_OK)
{
//
// Read PnpID from the Model section.
//

hr = GetKeyValue(hInf, lpszModelSection, NULL, 2, lppszPnpID);

CoTaskMemFree(lpszModelSection);
}

SetupCloseInfFile(hInf);

return hr;
}

VOID CTryCodeDlg::InstallSelectedComponentType (HWND hwndDlg, LPWSTR lpszInfFile)
{
HRESULT   hr;

if (lpszInfFile)
{
LPWSTR  lpszPnpID;

//
// Inf file name specified, install the network component
// from this file.
//

hr = GetPnpID(lpszInfFile, &lpszPnpID);

if (hr == S_OK)
{
hr = InstallSpecifiedComponent(lpszInfFile, lpszPnpID, pguidClassService);
CoTaskMemFree(lpszPnpID);
}
else
{
AfxMessageBox("Error read inf file.");
}
}
else
{
AfxMessageBox("No inf file.");
}

switch(hr)
{
case S_OK:
MessageBoxW(hwndDlg,
L"Component installed successfully.",
L"Network Component Installation",
MB_OK | MB_ICONINFORMATION);
break;

case NETCFG_S_REBOOT:
MessageBoxW(hwndDlg,
L"Component installed successfully: "
L"Reboot required.",
L"Network Component Installation",
MB_OK | MB_ICONINFORMATION);
}

return;
}

//这里使用“文件”对话框选择inf文件,可以更改为其他方式
void CTryCodeDlg::OnInstallDriver() 
{
// TODO: Add your control notification handler code here
WCHAR lpszInfFile[MAX_PATH + 1];
if (GetFileName(this->m_hWnd,
L"INF files (*.inf)\0*.inf\0",
L"Select the INF file of the network component to install",
OFN_DONTADDTORECENT | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST,
lpszInfFile,
NULL))
{
InstallSelectedComponentType(this->m_hWnd, lpszInfFile);
}
}

#22


最近在给客户做一个类似于三星的DNW的工具,用到的驱动文件也是和DNW同样的,也需要考虑和楼主同样的问题,还不清楚怎么实现呢

#23


回hzy_76:
非常感谢你提供源代码,我正在研究呢。
我看到你的安装驱动的核心步骤就是调用setupCopyOEMInf函数。
关于这个函数我还不是很了解其内部机制是什么?MSDN上说,这个函数就是将INF文件以及其相关的文件COPY到系统文件夹中去。
那么这个函数和InstallHinfSection有什么区别呢?我想用DOS批处理脚本来安装驱动,论坛上许多人建议过这样的方法。InstallHinfSection也是将INF文件及其相关文件COPY到系统文件夹下面,并修改注册表。(这一点我在系统文件夹和注册表都有监视过)。结果还是没有安装成功(硬件插上后还是会弹出提示)。


另外,我现在同时还在试验用InstallShield来做个exe的安装包。不知道哪位老大有InstallShield 12 的电子版教材啊?  能分享一下吗?  谢谢咯!

#24


是的,复制安装文件是必要的步骤。修改注册表部分,BindView里边是用INetCfgClassSetup来做的,看起来是针对网络的,估计你用不着了。不过你可以沿这个思路看是否有类似的解决方案。

我原来也想过用InstallShield来做,它的帮助里边也提到过可以制作驱动安装程序,但没有进展,后来就去研究BindView代码了。

#25


引用楼主 kisery008 的回复:
Hi,
 小弟目前做的项目需要在Windows下安装一个简单的USB驱动,驱动程序由第三方提供(没有经过MS认证),包含DLL、INF、SYS等等文件。
 一般情况下,当即插即用设备连上PC后,如果PC中没有该设备的驱动,会弹出安装驱动的提示,用户根据提示来一步步安装就可以了。
 现在这个项目需要事先就把驱动安装到PC中去,也就是把安装驱动这件事放在安装软件(项目最终的发布软件)的过程中完成。那么应该怎么去安装驱动呢?
 并且由于软件最终会运行在XP、VISTA和Windows7下面,那么这三个系统下的自动安装的过程有多大的区别呢?


 PS:请教过一个高手,写个精简DOS程序即可,但还是没有弄清楚。正在看《Windows驱动开发技术详解》,由于不是写驱动,只是安装驱动,这本书中也没有找到可行的办法。

嘿嘿,不好意思,刚看到你的留言。
 1.现在这个项目需要事先就把驱动安装到PC中去,也就是把安装驱动这件事放在安装软件(项目最终的发布软件)的过程中完成。那么应该怎么去安装驱动呢?
我看了你的那个脚本,你把设备插在上边然后安装一下,试试看能不能成功,不过安装过程中肯定要提示的。装好之后换个口插入肯定也会提示。(因为你没有经过ms认证。)
一般安装驱动的程序都是使用setupapi或者difx这两套库通过自己的程序实现的。
2. 并且由于软件最终会运行在XP、VISTA和Windows7下面,那么这三个系统下的自动安装的过程有多大的区别呢?
如果没有经过ms认证的驱动的话,在64位操作系统和32位操作系统下是有区别的。区别就是64位下不能使用。^_^.32位下,都一样,使用正规的操作装上之后,第一次插入设备时,还是会提示安装,只是这时选择自动搜索可以自动装上去。而且在安装过程中会有未经过认证的提示。

#26


如果使用InstallShield 12的话,这个工具里自带了安装驱动的接口,你只需要在里边点击几下,配置一下你驱动的路径就可以了。

#27


引用 23 楼 kisery008 的回复:
 那么这个函数和InstallHinfSection有什么区别呢?我想用DOS批处理脚本来安装驱动,论坛上许多人建议过这样的方法。InstallHinfSection也是将INF文件及其相关文件COPY到系统文件夹下面,并修改注册表。(这一点我在系统文件夹和注册表都有监视过)。结果还是没有安装成功(硬件插上后还是会弹出提示)。

硬件插上后还是会弹出提示,这个情况是因为你的驱动程序没有经过签名,你可以找一台裸机,或者把你的机器上的驱动删干净试。和你的脚本程序是一样的,如果没有运行过程序或者脚本,在插入设备后提示安装驱动,这时你选择自动搜索,不能将驱动更新。如果运行过了,那就可以更新驱动了。

#28


我现在也是这个问题,用InstallShield 做的包太大了, 换成Setup Factory在搞,可是研究了几天都还没搞定,用SetupCopyOEMInfA拷贝文件到INF文件夹,可是好像没有成功!不知道怎么回事?拷贝文件后还需要做些什么操作吗?
    在网上找了下,说要再去写注册表,可是不知道写啥?郁闷,
    关注中!!!

#29


驱动的安装方式大至有二种: 
1,在插上设备的时候进行安装,即使用函数UpdateDriverForPlugAndPlayDevice()。 
2,在没有物理设备的时候安装,即通常所说的驱动预安装(SetupCopyOEMInf)。 

需要注意的是: 
1,SetupCopyOEMInf()只是生成一个oem*.inf文件和oem*.pnf文件到Windows\inf\文件夹中, 
  即没有修改任何注册表,也没有复制文件。生成的pnf文件包含源文件路径信息,以便在真正 
 插上设备的时候能够找到相应的sys等文件。 
2,UpdateDriverForPlugAndPlayDevice()在没有插上设备的时候是会执行失败的。 

Windows插上设备到找到合适的驱动的大致步骤是: 
1,插上设备后Windows设备信息到硬件键[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\下去寻找相应的项。 

2,如果在Enum键下没有相应的信息,则Windows到预安装目录中去寻找相应的oem*.inf和oem*.pnf文件(oem*.inf和oem*.pnf只要前面的文件名相同就可以,故如果对二个同时改成相同的名字不会有什么影响). 
如果进行了预安装,则可以在这里找到相应的inf和pnf文件。于是弹出发现新硬件对话框,点自动安装就可成功(这个对话框可以通过协助安装程序搞掉它)。安装时会弹出徽标论证的对话框(XP下可以通过改注册表的方式搞掉,Vista下暂没发现办法) 

3,注册CoInstall的方法即修改以下键值: 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CoDeviceInstallers],子键名为要注册CoInstall的GUID,值为dll的名字和函数名。 

#30


你的驱动目前打包完成没?

#31


我的方法:

DPInst.exe是WDK中的一个实用工具,它可以自动搜索指定目录的inf文件,并安装相应设备的驱动程序。

MSDN中有关于DPInst.exe的详细资料:
http://msdn.microsoft.com/en-us/library/ms790308.aspx
http://www.microsoft.com/china/whdc/driver/install/difxtools.mspx

下载地址:
http://www.microsoft.com/china/whdc/driver/install/DIFxtls.mspx
http://www.microsoft.com/downloads/details.aspx?FamilyID=2105564e-1a9a-4bf4-8d74-ec5b52da3d00&displaylang=en

DPInst.exe支持命令行,它支持的参数可以使用DPInst.exe /?查看。

示例:
1.自动搜索C:\VGA目录下的INF文件并安装驱动程序:
DPInst.exe /PATH "C:\VGA" /F /Q /LM /A

2.自动搜索C:\目录下的INF文件并安装驱动程序:
DPInst.exe /PATH C:\ /LM

http://qingfengju.com/article.asp?id=183

#32


HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CoDeviceInstallers 下面注册coinstaller,不过coinstaller 里面SetupDiEnumDriverInfo会失败,没找到好的办法