windows 网路驱动安装

最近在开发网路协议及小端口驱动,在http://www.ndis.com/下载了协议驱动安装的例子ProtInstall(http://www.ndis.com/ndis-general/ndisinstall/programinstall.htm),研究了一下,特记录一下。

网络方面的驱动可以使用INetCfg接口安装,其安装步骤大致如下

1. 使用CoCreateInstance创建Com对象

hr = CoCreateInstance( CLSID_CNetCfg,
            NULL, CLSCTX_INPROC_SERVER,
            IID_INetCfg,
            (void**)&pnc );

2. 获取接口IID_INetCfgLock并请求写锁

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;
                    }
                }
3. 初始化接口IID_INetCfg

                hr = pnc->Initialize( NULL );

                if ( hr == S_OK ) {
                    *ppnc = pnc;
                    pnc->AddRef();
                }
                else {

                    //
                    // Initialize failed, if obtained lock, release it
                    //

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

4. 调用SetupCopyOEMInf执行预安装(preinstall)

if ( !SetupCopyOEMInfW(
            lpszInfFullPath,
            szDirWithDrive, // 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 );
        }

执行完这个函数后,inf文件会被拷贝到%SystemRoot%\Inf文件夹下,并生成预编译文件(*.pnf),其中第二个参数 OEMSourceMediaLocation将会被编译进这个文件,当真正执行安装函数时,源文件地址信息会被从这个文件里解析出来。这个函数可以设置拷贝模式,具体不写了。


5. 查询安装类的接口并安装

hr = pnc->QueryNetCfgClass ( pguidClass,
        IID_INetCfgClassSetup,
        (void**)&pncClassSetup );

    if ( hr == S_OK )
    {
		MessageBox(NULL,_T("Before Install"),_T("Tip"), MB_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 );
    }
其中szComponentID指的是inf文件中的deviceID。

6. 很重要最后一步,应用。

pnc->Apply();

至此,安装代码完毕。


我测试以上代码是,发现协议驱动若是没有签名或者没有签名的cat文件,windows会有警告提示,体验不好。于是我首先对驱动签名,并使用了inf2cat文件生成了cat文件并签名。再安装发现windows弹出另外一个对话框


于是我启用ProcMon工具,发现勾选始终信任CheckBox框后其向注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\TrustedPublisher\Certificates

写入了一些值,根据注册表路径名称的暗示,这个位置存储了那些信任的发布者列表,于是我把其写入的注册表键值拷贝出来,合并进一台干净的虚拟机后再安装驱动,这是这个对话框消失了,用户体验更好了。

再来说说卸载,其步骤如下

1. 找到Component对象

2. 找到compoentID的class guid。

3. 找到安装类

4. 执行卸载

HRESULT HrUninstallNetComponent(
    IN INetCfg* pnc,
    IN LPCTSTR 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;
}


编译:

因为需要包含wdk安装目录inc\api目录 文件netcfgx.h,需要向工程属性添加$(WDKPATH)\inc\api目录,但是当向Configuration Properties -> C/C++ -> Additional Include Directories添加目录后,编译错误.

1>ClCompile:
1>  stdafx.cpp
1>c:\program files\microsoft visual studio 10.0\vc\include\crtdefs.h(520): error C2065: '_In_opt_z_' : undeclared identifier
1>c:\program files\microsoft visual studio 10.0\vc\include\crtdefs.h(520): error C2143: syntax error : missing ')' before 'const........

 百度得知原因C:\WinDDK\7600.16385.1\inc\api\目录下存在一个文件sal.h,而VC环境sdk同样包含一个较新的sal.h。而编译环境首先找到wdk中的sal.h,造成了编译错误。
处理这种错误有如下方案:
1. 删掉C:\WinDDK\7600.16385.1\inc\api\sal.h文件,或将其换成别的名字。
这个方案可能会影响到其它驱动程序的编译,所以这里不推荐这种极端恐怖的做法。
2. 将crtdefs.h文件中引用sal.h的方式改为 #include "sal.h"
include中使用双引号时,编译器会先从调用include的文件所在目录开始找起,这样,被引用的文件将是C:\Program Files\Microsoft Visual Studio 9.0\VC\include\sal.h。
这个改动使VS2008的工程每次都引用C:\Program Files\Microsoft Visual Studio 9.0\VC\include\sal.h,但目前看来,问题不会很大。或许会对一些驱动工程造成影响,所以这样修改时还是要小心为上。
3. Just use '$(IncludePath);C:\WinDDK\6001.18001\inc\api' as include directories. (好的方案)


代码开发完毕后,觉得直接使用WDK提供的ndisprot.inf文件不够专业,于是对其改造了一番,最主要的就是更改了注册的服务名称及与服务名称相关的其它项。但是安装后,发现绑定回调函数并未被调用,经排查发现,仅仅修改inf文件中的服务名是不行的,还要修改注册协议时NDIS_PROTOCOL_DRIVER_CHARACTERISTICS结构体的名称,使其和服务名称一致,才能使协议驱动正常工作。



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值