DEVCON.EXE(驱动工具)和OpenVPN

发布于 2024-07-27 13:02:44 字数 763 浏览 7 评论 0原文

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

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

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

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

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

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

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

旁注:我听说有人使用 WiX 和 DifxAPI(我认为这是它的名称)从 MSI 安装程序安装驱动程序。 如果可以在自定义操作中通过纯 C# 来完成此操作,有什么想法吗? 我们真的不想使用 WiX 重新开始我们的设置项目(这可能很耗时)。

We have written an application that manages OpenVPN from the tray as an add-on for a bigger software package.

OpenVPN includes a file called tapinstall.exe that installs the OpenVPN adapter (or any driver for that matter). Doing some research, this file is the exact same as a command-line tool called devcon that Microsoft includes in the Windows DDK. The OpenVPN guys just renamed it for their use.

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.

Every now and again, devcon fails and hangs--never exiting. After that point, you can re-run devcon and it will install the driver twice... which basically breaks OpenVPN.

Has anyone seen this issue with devcon, know what it's doing, or know a way to fix it?

As an alternate solution, does anyone know how to install a driver from C#? (we have a .inf and a .sys file)

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. 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. Any ideas if this can be done from plain C# in a custom action? We don't really want to start over with our setup project using WiX (it could be time consuming).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

蝶…霜飞 2024-08-03 13:02:44

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

  • DevCon 的源代码作为 Windows DDK 位于 DDK root\Src\Setup\Devcon 下。 如果您的问题可以重现,您可以构建自己的版本并在 IDE 中对其进行调试。

  • OpenVPN 安装程序的源代码可以在 OpenVPN SVN 存储库。 您可以比较 DevCon 的调用方式,并查看 OpenVPN 是否以防止出现问题的方式执行此操作。

  • 可以使用类似的命令从命令行安装 INF 文件

    rundll32 syssetup,SetupInfObjectInstallAction DefaultInstall 128 .\<文件>.inf

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


@update:

OpenVPN安装程序似乎设置了一个“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

@旁注:

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


DIFxAPI

文档:

P/Invokes:

测试程序:

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

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. If your problem is reproducable, you could build your own version and debug it in your IDE.

  • The sources of the OpenVPN installer can be found in the OpenVPN SVN repository. You could compare how DevCon is invoked and see if the OpenVPN is doing it in a way that prevents the problem.

  • INF files can be installed from the command line using something like

    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. There has to be some reason obviously why the OpenVPN installer is using DevCon, right?


@update:

The OpenVPN installer seems to set a "Reboot Flag" depending of the return value of 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. DevCon apparently is just a wrapper around SetupAPI and DIFxAPI.


DIFxAPI

Documentation:

P/Invokes:

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.

If the driver is already installed you get an ERROR_NO_MORE_ITEMS.

寂寞清仓 2024-08-03 13:02:44

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

快速的方法,只需将 difxapi.hdifxapi.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;
}

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.

Fast way, just copy difxapi.h and difxapi.lib to your folder project and add to your project. Beware to chose this files that are compatilhe to x86 in wdk folder.

A simple code example, just for test, using C that run on win 7 32bit:

#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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文