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

C# DEVCON.EXE(驱动程序工具)和OpenVPN,c#,driver,openvpn,C#,Driver,Openvpn,我们已经编写了一个应用程序,作为一个更大软件包的附加组件,从托盘中管理OpenVPN OpenVPN包含一个名为tapinstall.exe的文件,用于安装OpenVPN适配器(或任何驱动程序)。进行一些研究后,该文件与Microsoft在WindowsDDK中包含的名为devcon的命令行工具完全相同。OpenVPN的人只是为了使用而重命名了它 因此,我们在安装程序(msi)的过程中,通过自定义操作使用它来安装驱动程序,在大多数情况下,它工作正常 devcon时不时地会失败并挂起——永远不会退

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

OpenVPN包含一个名为tapinstall.exe的文件,用于安装OpenVPN适配器(或任何驱动程序)。进行一些研究后,该文件与Microsoft在WindowsDDK中包含的名为devcon的命令行工具完全相同。OpenVPN的人只是为了使用而重命名了它

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

devcon时不时地会失败并挂起——永远不会退出。之后,您可以重新运行devcon,它将安装驱动程序两次。。。这基本上破坏了OpenVPN

有没有人见过devcon的这个问题,知道它在做什么,或者知道解决它的方法

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

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


旁注:我听说有人使用WiX和DifxAPI(我想这就是它的名字)从MSI安装程序安装驱动程序。如果这可以在自定义操作中从普通C#实现,有什么想法吗?我们真的不想使用WiX重新开始安装项目(这可能很耗时)。

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

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

  • 可以在中找到OpenVPN安装程序的源代码。您可以比较DevCon是如何被调用的,并查看OpenVPN是否以防止问题发生的方式进行调用

  • 可以使用以下命令行安装INF文件

    rundll32 syssetup,SetupInfObjectInstallAction DefaultInstall 128.\.inf

    但我猜DevCon做的不止这些,所以我不知道这是否是一种可行的方法。OpenVPN安装程序使用DevCon显然是有原因的,对吧


@更新:

OpenVPN安装程序似乎取决于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

@旁注:

我想您应该能够使用p/Invokes将DevCon移植到C。DevCon显然只是一个包装器和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
该程序必须以管理员身份运行,否则会出现
错误\u访问被拒绝


如果驱动程序已经安装,您将得到一个
错误\u NO\u MORE\u ITEMS

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

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

一个简单的代码示例,仅用于测试,使用在win 7 32位上运行的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;
}
#包括
#包括
#包括“difxapi.h”
内部主(空)
{
DWORD dwRet=0;
PCTSTR DriverPackageInfPath=TEXT(“D:\\MYDRIVER.INF”);
DWORD标志=0;
INSTALLERINFO INSTALLERINFO;
BOOL-bNeedReboot;
char chName[]=“事物名称”;
char chGUID[]=“{4D36E979-E325-11CE-BFC1-08002BE10318}”;//打印机GUID
InstallerInfo.pDisplayName=&chName;
InstallerInfo.pProductName=&chName;
InstallerInfo.pMfgName=&chName;
InstallerInfo.pApplicationId=&chGUID;
dwRet=DriverPackageInstall(DriverPackageInfPath、Flags、&installernfo、&bNeedReboot);
交换机(dwRet)
{
案例错误\u成功:
printf(“\n\n错误\u成功-Ret:%d,%xh”,dwRet,dwRet);
打破
案例证书已过期:
printf(“\n\n证书已过期-Ret:%d,%xh”,dwRet,dwRet);
打破
案例证书不可信:
printf(“\n\n证书不可信-Ret:%d,%xh”,dwRet,dwRet);
打破
案例证书错误使用:
printf(“\n\n证书使用错误-Ret:%d,%xh”,dwRet,dwRet);
打破
案例加密文件错误:
printf(“\n\n加密文件错误-Ret:%d,%xh”,dwRet,dwRet);
打破
案例错误\u访问\u被拒绝:
printf(“\n\n错误\u访问被拒绝-Ret:%d,%xh”,dwRet,dwRet);
打破
案例错误\u坏\u环境:
printf(“\n\n错误\u坏\u环境-Ret:%d,%xh”,dwRet,dwRet);
打破
案例错误\u无法\u访问\u文件:
printf(“\n\n错误\u无法\u访问\u文件-Ret:%d,%xh”,dwRet,dwRet);
打破
案例错误\u未找到文件\u:
printf(“\n\n找不到错误文件-Ret:%d,%xh”,dwRet,dwRet);
打破
案例错误\u文件名\u超出\u范围:
printf(“\n\n错误\u文件名\u超出\u范围-Ret:%d,%xh”,dwRet,dwRet);
打破
/*案例错误\u在\u WOW64中:
printf(“\n\n错误\u在\u WOW64-Ret:%d,%xh”,dwRet,dwRet);
中断*/
案例错误\u安装\u失败:
printf(“\n\n错误\u安装\u失败-Ret:%d,%xh”,dwRet,dwRet);
打破
案例错误\u无效\u目录\u数据:
printf(“\n\n错误\u无效\u目录\u数据-Ret:%d,%xh”,dwRet,dwRet);
打破
案例错误\u无效\u名称:
printf(“\n\n错误\u无效\u名称-Ret:%d,%xh”,dwRet,dwRet);
打破
案例错误\u无效\u参数:
printf(“\n\n错误\u无效\u参数-Ret:%d,%xh”,dwRet,dwRet);
布雷亚