3

より大きなソフトウェア パッケージのアドオンとして、トレイから OpenVPN を管理するアプリケーションを作成しました。

OpenVPN には、OpenVPN アダプター (またはその他のドライバー) をインストールする tapinstall.exe というファイルが含まれています。調査の結果、このファイルは、Microsoft が Windows DDK に含めている devcon と呼ばれるコマンドライン ツールとまったく同じです。OpenVPN の担当者は、使用するために名前を変更しました。

そのため、カスタム アクションでセットアップ (msi) インストーラー中に使用して、ドライバーをインストールします。ほとんどの場合、問題なく動作します。

時々、devcon が失敗してハングし、終了しません。その後、devcon を再実行すると、ドライバーが 2 回インストールされます...これにより、基本的に OpenVPN が壊れます。

devcon でこの問題を見た人、それが何をしているのか知っている人、またはそれを修正する方法を知っている人はいますか?

別の解決策として、C# からドライバーをインストールする方法を知っている人はいますか? (.inf ファイルと .sys ファイルがあります)

更新: この問題は非常にまれであることがわかりました。これは、OpenVPN アダプターの V8 バージョンをアンインストールしてから OpenVPN アダプターの新しいバージョン (V9) をインストールするアップデートを適用した場合に最も頻繁に発生します。また、インストールの合間に PC を再起動しても発生しないようです。そのため、アンインストール時に PC を強制的に再起動した方がよいかもしれません....

補足: MSI インストーラーからドライバーをインストールするために、WiX と DifxAPI (私はそう呼ばれていると思います) を使用している人たちについて聞いたことがあります。これがカスタム アクションでプレーンな C# から実行できる場合のアイデアはありますか? WiX を使用してセットアップ プロジェクトを最初からやり直したくありません (時間がかかる可能性があります)。

4

2 に答える 2

4

あなたの問題の解決策はありませんが、ここにいくつかのアイデアがあります:

  • DevCon のソース コードは、 DDK root\Src\Setup\Devconの下のWindows DDKの一部として入手できます。問題が再現可能な場合は、独自のバージョンをビルドして 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.hdifxapi.libそれは WDK に付属しています。

簡単な方法は、フォルダー プロジェクトにコピー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;
}
于 2015-01-22T14:15:28.840 に答える