DEVCON.EXE(驱动程序工具)和OpenVPN

时间:2009-07-22 19:15:50

标签: c# driver openvpn

我们已经编写了一个应用程序,可以从托盘中管理OpenVPN,作为更大软件包的附件。

OpenVPN包含一个名为tapinstall.exe的文件,用于安装OpenVPN适配器(或任何驱动程序)。做一些研究,这个文件与Microsoft在Windows DDK中包含的名为devcon的命令行工具完全相同。 OpenVPN的人刚刚将其重命名为使用它。

因此我们在安装程序(msi)安装程序中使用它来自定义操作来安装驱动程序,这在大多数情况下都可以正常工作。

每隔一段时间,devcon就会失败并挂起 - 永不退出。在那之后,你可以重新运行devcon,它将安装驱动程序两次......这基本上打破了OpenVPN。

有没有人与devcon见过这个问题,知道它在做什么,或者知道修复它的方法?

作为替代解决方案,有谁知道如何从C#安装驱动程序? (我们有.inf和.sys文件)

更新:我们发现这个问题非常罕见。它最常发生在我们应用更新时,我们卸载OpenVPN适配器的V8版本,然后安装OpenVPN适配器的新版本(V9)。如果你在两次安装之间重新启动电脑,似乎也不会发生这种情况,所以我们最好在卸载时强行重启电脑....

SIDE注意:我听说有人使用WiX和DifxAPI(我认为这就是所谓的)从MSI安装程序安装驱动程序。如果可以通过自定义操作中的纯C#来完成任何想法?我们真的不想重新开始使用WiX的设置项目(这可能非常耗时)。

2 个答案:

答案 0 :(得分:4)

我没有针对您的问题的解决方案,但这里有一些想法:

  • DevCon的源代码作为 DDK root \ Src \ Setup \ Devcon Windows DDK的一部分提供。如果您的问题是可重现的,您可以构建自己的版本并在IDE中进行调试。

  • 可以在OpenVPN SVN repository中找到OpenVPN安装程序的来源。您可以比较调用DevCon的方式,并查看OpenVPN是否以防止问题的方式执行此操作。

  • 可以使用

    之类的命令从命令行安装INF文件

    rundll32 syssetup,SetupInfObjectInstallAction DefaultInstall 128 .\<file>.inf

    但我猜DevCon的功能不止于此,所以我不知道这是不是一种可行的方法。显然,为什么OpenVPN安装程序使用DevCon,对吧?


@Update:

OpenVPN安装程序似乎set a "Reboot Flag"取决于DevCon的返回值。

;------------------------------------------
;Set reboot flag based on tapinstall return

Function CheckReboot
  IntCmp $R0 1 "" noreboot noreboot
  IntOp $R0 0 & 0
  SetRebootFlag true
  DetailPrint "REBOOT flag set"
 noreboot:
FunctionEnd

@side note:

我猜你应该能够使用P / Invokes将DevCon移植到C#。 DevCon显然只是SetupAPI和DIFxAPI的包装。


<强> DIFxAPI

文档:

P /调用:

测试程序:

SetDifxLogCallback(DIFLogCallbackFunc, IntPtr.Zero);

bool needReboot;

var error =
    DriverPackageInstall(driverPackageInfPath, 0, IntPtr.Zero, out needReboot);

if (error != 0)
    throw new Win32Exception(error);

输出:

INFO: ENTER:  DriverPackageInstallW. Error code: 0
INFO: Installing INF file 'C:\Program Files (x86)\OpenVPN\driver\OemWin2k.inf' (Plug and Play).. Error code: 0
INFO: Looking for Model Section [tap0901.NTamd64].... Error code: 0
INFO: Installing devices with Id "tap0901" using INF "C:\Windows\system32\DriverStore\FileRepository\oemwin2k.inf_128556d6\OemWin2k.inf".. Error code: 0
INFO: ENTER UpdateDriverForPlugAndPlayDevices.... Error code: 0
SUCCESS: RETURN UpdateDriverForPlugAndPlayDevices.. Error code: 0
INFO: Installation was successful.. Error code: 0
SUCCESS: Install completed. Error code: 0
INFO: RETURN: DriverPackageInstallW  (0x0). Error code: 0

该程序必须以管理员身份运行,否则您将获得ERROR_ACCESS_DENIED

如果已安装驱动程序,则会获得ERROR_NO_MORE_ITEMS

答案 1 :(得分:0)

只是补充,如果某人无法运行difxapi函数,您需要通过某种方式将项目链接到WDK附带的difxapi.hdifxapi.lib

快捷方式,只需将difxapi.hdifxapi.lib复制到您的文件夹项目中即可添加到您的项目中。请注意选择与wdk文件夹中的x86兼容的文件。

一个简单的代码示例,仅用于测试,使用在win 7 32bit上运行的C:

#include <windows.h>
#include <stdio.h>
#include "difxapi.h"    

int main(void)
{
    DWORD dwRet = 0;

    PCTSTR DriverPackageInfPath = TEXT("D:\\MYDRIVER.INF");
    DWORD Flags = 0;
    INSTALLERINFO InstallerInfo;
    BOOL bNeedReboot;

    char chName[] = "Thing Name";
    char chGUID[] = "{4D36E979-E325-11CE-BFC1-08002BE10318}"; //printer GUID

    InstallerInfo.pDisplayName = &chName;
    InstallerInfo.pProductName = &chName;
    InstallerInfo.pMfgName = &chName;
    InstallerInfo.pApplicationId = &chGUID;

    dwRet = DriverPackageInstall( DriverPackageInfPath, Flags, &InstallerInfo , &bNeedReboot );

    switch(dwRet)
    {
    case ERROR_SUCCESS:
        printf("\n\n ERROR_SUCCESS - Ret: %d, %xh", dwRet, dwRet);
        break;
    case CERT_E_EXPIRED:
        printf("\n\n CERT_E_EXPIRED - Ret: %d, %xh", dwRet, dwRet);
        break;
    case CERT_E_UNTRUSTEDROOT:
        printf("\n\n CERT_E_UNTRUSTEDROOT - Ret: %d, %xh", dwRet, dwRet);
        break;
    case CERT_E_WRONG_USAGE:
        printf("\n\n CERT_E_WRONG_USAGE - Ret: %d, %xh", dwRet, dwRet);
        break;
    case CRYPT_E_FILE_ERROR:
        printf("\n\n CRYPT_E_FILE_ERROR - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_ACCESS_DENIED:
        printf("\n\n ERROR_ACCESS_DENIED - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_BAD_ENVIRONMENT:
        printf("\n\n ERROR_BAD_ENVIRONMENT - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_CANT_ACCESS_FILE:
        printf("\n\n ERROR_CANT_ACCESS_FILE - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_FILE_NOT_FOUND:
        printf("\n\n ERROR_FILE_NOT_FOUND - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_FILENAME_EXCED_RANGE:
        printf("\n\n ERROR_FILENAME_EXCED_RANGE - Ret: %d, %xh", dwRet, dwRet);
        break;
    /*case ERROR_IN_WOW64:
        printf("\n\n ERROR_IN_WOW64 - Ret: %d, %xh", dwRet, dwRet);
        break;*/
    case ERROR_INSTALL_FAILURE:
        printf("\n\n ERROR_INSTALL_FAILURE - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_INVALID_CATALOG_DATA:
        printf("\n\n ERROR_INVALID_CATALOG_DATA - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_INVALID_NAME:
        printf("\n\n ERROR_INVALID_NAME - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_INVALID_PARAMETER:
        printf("\n\n ERROR_INVALID_PARAMETER - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_NO_DEVICE_ID:
        printf("\n\n ERROR_NO_DEVICE_ID - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_NO_MORE_ITEMS:
        printf("\n\n ERROR_NO_MORE_ITEMS - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_NO_SUCH_DEVINST:
        printf("\n\n ERROR_NO_SUCH_DEVINST - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_OUTOFMEMORY:
        printf("\n\n ERROR_OUTOFMEMORY - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_SHARING_VIOLATION:
        printf("\n\n ERROR_SHARING_VIOLATION - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH:
        printf("\n\n ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH - Ret: %d, %xh", dwRet, dwRet);
        break;
    case ERROR_UNSUPPORTED_TYPE:
        printf("\n\n ERROR_UNSUPPORTED_TYPE - Ret: %d, %xh", dwRet, dwRet);
        break;
    case TRUST_E_NOSIGNATURE:
        printf("\n\n TRUST_E_NOSIGNATURE - Ret: %d, %xh", dwRet, dwRet);
        break;
    default:
        printf("\n\n default - Ret: %d, %xh", dwRet, dwRet);
        break;
    }
    printf("\n\n");
    system("pause");

    return 1;
}