简体   繁体   English

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

[英]DEVCON.EXE (driver tool) and OpenVPN

We have written an application that manages OpenVPN from the tray as an add-on for a bigger software package. 我们编写了一个应用程序,从托盘中管理OpenVPN作为更大软件包的附件。

OpenVPN includes a file called tapinstall.exe that installs the OpenVPN adapter (or any driver for that matter). OpenVPN包含一个名为tapinstall.exe的文件,用于安装OpenVPN适配器(或任何驱动程序)。 Doing some research, this file is the exact same as a command-line tool called devcon that Microsoft includes in the Windows DDK. 做一些研究,这个文件与Microsoft在Windows DDK中包含的名为devcon的命令行工具完全相同。 The OpenVPN guys just renamed it for their use. OpenVPN的人刚刚将它重命名为使用它。

So we use it during our setup (msi) installer in a custom action to install the driver, which for the most part, works just fine. 所以我们在安装程序(msi)安装程序中使用它来自定义操作来安装驱动程序,这在大多数情况下都可以正常工作。

Every now and again, devcon fails and hangs--never exiting. devcon一次又一次地失败并且挂起 - 永不退出。 After that point, you can re-run devcon and it will install the driver twice... which basically breaks OpenVPN. 在那之后,你可以重新运行devcon,它将安装驱动程序两次......这基本上打破了OpenVPN。

Has anyone seen this issue with devcon, know what it's doing, or know a way to fix it? 有没有人与devcon一起看过这个问题,知道它在做什么,或者知道修复它的方法?

As an alternate solution, does anyone know how to install a driver from C#? 作为替代解决方案,有谁知道如何从C#安装驱动程序? (we have a .inf and a .sys file) (我们有.inf和.sys文件)

UPDATE: We've found this issues to be pretty rare. 更新:我们发现这个问题非常罕见。 It occurs most often when we've applied an update where we uninstall the V8 version of the OpenVPN adapter and then install the new version (V9) of the OpenVPN adapter. 它最常发生在我们应用更新时,我们卸载OpenVPN适配器的V8版本,然后安装OpenVPN适配器的新版本(V9)。 It also seems to not happen if you restart your PC in between installs, so we might be better off forcing a PC restart on uninstall.... 如果你在安装之间重新启动你的电脑似乎也没有发生,所以我们可能最好在卸载时强制重启电脑....

SIDE NOTE: I've heard of people using WiX and the DifxAPI (I think that is what it's called) to install drivers from an MSI installer. 侧面注意:我听说有人使用WiX和DifxAPI(我认为这就是所谓的)从MSI安装程序安装驱动程序。 Any ideas if this can be done from plain C# in a custom action? 如果可以通过自定义操作中的纯C#来完成任何想法? We don't really want to start over with our setup project using WiX (it could be time consuming). 我们真的不想重新开始使用WiX的设置项目(这可能非常耗时)。

I don't have a solution for your problem, but here are some ideas: 我没有针对您的问题的解决方案,但这里有一些想法:

  • The source code for DevCon is available as part of the Windows DDK under DDK root\\Src\\Setup\\Devcon . DevCon的源代码作为DDK root \\ Src \\ Setup \\ Devcon下的Windows DDK的一部分提供。 If your problem is reproducable, you could build your own version and debug it in your IDE. 如果您的问题是可重现的,您可以构建自己的版本并在IDE中进行调试。

  • The sources of the OpenVPN installer can be found in the OpenVPN SVN repository . 可以在OpenVPN SVN存储库中找到OpenVPN安装程序的源代码。 You could compare how DevCon is invoked and see if the OpenVPN is doing it in a way that prevents the problem. 您可以比较调用DevCon的方式,并查看OpenVPN是否以防止问题的方式执行此操作。

  • INF files can be installed from the command line using something like 可以使用类似命令从命令行安装INF文件

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

    but I'd guess that DevCon is doing more than that, so I don't know if this is a viable way. 但我猜DevCon的功能不止于此,所以我不知道这是否可行。 There has to be some reason obviously why the OpenVPN installer is using DevCon, right? 显然有一些原因显然OpenVPN安装程序使用DevCon,对吧?


@update: @Update:

The OpenVPN installer seems to set a "Reboot Flag" depending of the return value of 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

@side note: @边注:

I'd guess you should be able to port DevCon to C# using P/Invokes. 我猜你应该能够使用P / Invokes将DevCon移植到C#。 DevCon apparently is just a wrapper around SetupAPI and DIFxAPI. DevCon显然只是SetupAPI和DIFxAPI的包装器。


DIFxAPI DIFxAPI

Documentation: 文档:

P/Invokes: P /调用:

Test program: 测试程序:

SetDifxLogCallback(DIFLogCallbackFunc, IntPtr.Zero);

bool needReboot;

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

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

Output: 输出:

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

The program must be run as administrator, otherwise you get an ERROR_ACCESS_DENIED . 该程序必须以管理员身份运行,否则您将获得ERROR_ACCESS_DENIED

If the driver is already installed you get an ERROR_NO_MORE_ITEMS . 如果已安装驱动程序,则会收到ERROR_NO_MORE_ITEMS

Just a complement, if someone cannot run difxapi functions, you need by someway link your project to difxapi.h and difxapi.lib that came with WDK. 只是一个补充,如果有人不能运行difxapi函数,你需要通过某种方式将你的项目链接到与WDK一起提供的difxapi.hdifxapi.lib

Fast way, just copy difxapi.h and difxapi.lib to your folder project and add to your project. 快速方法,只需将difxapi.hdifxapi.lib复制到您的文件夹项目并添加到您的项目中。 Beware to chose this files that are compatilhe to x86 in wdk folder. 请注意选择与wdk文件夹中的x86兼容的文件。

A simple code example, just for test, using C that run on win 7 32bit: 一个简单的代码示例,仅用于测试,使用在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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM