3

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

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

因此,我们在设置 (msi) 安装程序中以自定义操作使用它来安装驱动程序,在大多数情况下,它工作得很好。

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

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

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

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

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

4

2 回答 2

4

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

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

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

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

    rundll32 syssetup,SetupInfObjectInstallAction DefaultInstall 128 .\<file>.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 显然只是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.

于 2009-07-22T19:53:02.203 回答
0

只是一个补充,如果有人不能运行 difxapi 函数,你需要通过某种方式将你的项目链接到difxapi.hWDKdifxapi.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;
}
于 2015-01-22T14:15:28.840 回答