5

デバイスマネージャと同じように、特定のデバイスのすべてのドライバファイルを取得する方法を知りたいですか?

私は次のコードを持っています:

procedure TdlgMain.Test(const DeviceIndex: Integer);
var
  PnPHandle: HDEVINFO;
  DevData: TSPDevInfoData;
  DeviceInterfaceData: TSPDeviceInterfaceData;
  FunctionClassDeviceData: PSPDeviceInterfaceDetailData;
  Success: LongBool;
  Devn: Integer;
  BytesReturned: DWORD;
  SerialGUID: TGUID;
begin
  ZeroMemory(@DevData, SizeOf(SP_DEVINFO_DATA));
  DevData.cbSize := SizeOf(SP_DEVINFO_DATA);

  ZeroMemory(@DeviceInterfaceData, SizeOf(TSPDeviceInterfaceData));
  DeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData);

  if not SetupDiEnumDeviceInfo(hAllDevices,
    DeviceIndex, DevData) then Exit;

  SerialGUID := DevData.ClassGuid;

  PnPHandle := SetupDiGetClassDevs(@SerialGUID, nil, 0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE);
  if PnPHandle = Pointer(INVALID_HANDLE_VALUE) then
    Exit;

  Devn := 0;
  repeat
    DeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData);
    Success := SetupDiEnumDeviceInterfaces(PnPHandle, nil, SerialGUID, Devn, DeviceInterfaceData);
    if Success then
    begin
      DevData.cbSize := SizeOf(DevData);
      BytesReturned := 0;
      // get size required for call
      SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData, nil, 0, BytesReturned, @DevData);
      if (BytesReturned <> 0) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
      begin
        // allocate buffer and initialize it for call
        FunctionClassDeviceData := AllocMem(BytesReturned);
        FunctionClassDeviceData.cbSize := SizeOf(TSPDeviceInterfaceDetailData);
        //FunctionClassDeviceData.cbSize := BytesReturned;
        if SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData,
          FunctionClassDeviceData, BytesReturned, BytesReturned, @DevData) then
        begin
          ShowMessage(FunctionClassDeviceData.DevicePath);
        end else
          RaiseLastOSError();
        FreeMem(FunctionClassDeviceData);
      end;
    end;
    Inc(Devn);
  until not Success;
  SetupDiDestroyDeviceInfoList(PnPHandle);

ただし、ShowMessage()はまったく呼び出されないか、を返します\。ファイルを正しく取得するにはどうすればよいですか?

WinDDKから確認しましdevconたが、ファイルも返されません。

ありがとうございました。

4

1 に答える 1

5

私はそれを考え出した。それを行うためのAPIはありません。結果を得るには、INFファイルを解析する必要があります。これは、興味のあるすべての人のための簡単な解決策です。

procedure TdlgMain.Test(const DeviceIndex: Integer);
var
  Paths: TStringList;
  I: Integer;

  function GetWinDir: string; inline;
  var
    dir: array [0 .. MAX_PATH] of Char;
  begin
    GetWindowsDirectory(dir, MAX_PATH);
    Result := IncludeTrailingBackslash(StrPas(dir));
  end;

  function GetSpecialFolderPath(const folder: Integer): string; inline;
  const
    SHGFP_TYPE_CURRENT = 0;
  var
    path: array [0 .. MAX_PATH] of Char;
  begin
    if SUCCEEDED(SHGetFolderPath(0, folder, 0, SHGFP_TYPE_CURRENT, @path[0]))
    then
      Result := IncludeTrailingBackslash(path)
    else
      Result := '';
  end;

  function LocateInfFile(const F: String): String; inline;
  var
    T: String;
  begin
    Result := '';

    if (Pos(SysUtils.PathDelim, F) > 0) then
    begin
      Result := F;
      Exit;
    end;

    T := GetWinDir();
    if (FileExists(T + 'inf\' + F)) then
      Result := T + 'inf\' + F
    else if (FileExists(T + 'system32\' + F)) then
      Result := T + 'system32\' + F;
  end;

  procedure ReadSectionNoKeys(const AFile, ASection: String;
    const SL: TStringList);
  var
    TheFile: TStringList;
    Line: String;
    TrimEnd: Boolean;
    Idx, Tmp: Integer;
  begin
    TrimEnd := False;

    TheFile := TStringList.Create();
    try
      TheFile.LoadFromFile(AFile);
      Idx := TheFile.IndexOf('[' + ASection + ']');
      if (Idx <> -1) then
      begin
        Idx := Idx + 1;
        while True do
        begin
          Line := Trim(TheFile[Idx]);
          Inc(Idx);
          if (Pos(';', Line) = 1) then
            continue;

          if (Pos('[', Line) > 0) then
            Break;

          Tmp := Pos(',', Line);
          if (Tmp > 0) then
            TrimEnd := True
          else
          begin
            Tmp := PosEx(';', Line, 3);
            if (Tmp > 0) then
              TrimEnd := True;
          end;

          if (Line <> '') then
          begin
            if (TrimEnd) then
            begin
              Line := Trim(Copy(Line, 1, Tmp - 1));
              TrimEnd := False;
            end;

            SL.Add(Line);
          end;

          if (Idx = (TheFile.Count - 1)) then
            Break;
        end;
      end;
    finally
      TheFile.Free();
    end;
  end;

  function IniReadStr(const Ini: TIniFile; const S, L, D: String): String;
  var
    T: Integer;
  begin
    Result := Ini.ReadString(S, L, D);

    T := Pos(';', Result);
    if (T > 0) then
      Result := Trim(Copy(Result, 1, T - 1));
  end;

  procedure ParseInfFile(const InfFile, SectionName: String);
  var
    I: TIniFile;
    SL, FilesList: TStringList;
    X, Y, Tmp: Integer;
    Pth, S, S1: String;
  begin
    I := TIniFile.Create(InfFile);
    try
      if (SectionName <> '') and (I.SectionExists(SectionName)) then
      begin
        // Check if the section has a value called "CopyFiles".
        if (I.ValueExists(SectionName, 'CopyFiles')) then
        begin
          // It has. Read it to a string and separate by commas.
          SL := TStringList.Create();
          try
            SL.CommaText := IniReadStr(I, SectionName, 'CopyFiles', '');

            // Now, every line of the string list is a section name. Check
            // the destination directory of each.
            if (I.SectionExists('DestinationDirs')) then
              for X := 0 to SL.Count - 1 do
              begin
                S := IniReadStr(I, 'DestinationDirs', SL[X], '');
                if (S = '') then
                  S := IniReadStr(I, 'DestinationDirs', 'DefaultDestDir', '');

                if (S <> '') then
                begin
                  // Split the path by comma, if any.
                  Tmp := Pos(',', S);
                  S1 := '';
                  if (Tmp > 0) then
                  begin
                    S1 := Trim(Copy(S, Tmp + 1, Length(S)));
                    S := Trim(Copy(S, 1, Tmp - 1));
                  end;

                  // Convert the numeric value of S to a proper directory.
                  Pth := '';
                  if (S = '10') then
                    Pth := GetWinDir();
                  if (S = '11') then
                    Pth := GetWinDir() + 'system32\';
                  if (S = '12') then
                    Pth := GetWinDir() + 'system32\drivers\';
                  if (S = '50') then
                    Pth := GetWinDir() + 'system\';
                  if (S = '30') then
                    Pth := ExtractFileDrive(GetWinDir());
                  if (StrToInt(S) >= 16384) then
                    Pth := GetSpecialFolderPath(StrToInt(S));

                  if (S1 <> '') then
                    Pth := IncludeTrailingBackslash(Pth + S1);

                  // If we got the path, read the files.
                  if (Pth <> '') then
                  begin
                    FilesList := TStringList.Create();
                    try
                      ReadSectionNoKeys(InfFile, SL[X], FilesList);
                      for Y := 0 to FilesList.Count - 1 do
                        if (Paths.IndexOf(Pth + FilesList[Y]) = -1) then
                          Paths.Add(Pth + FilesList[Y]);
                    finally
                      FilesList.Free();
                    end;
                  end;
                end;
              end;
          finally
            SL.Free();
          end;
        end;

        // Check if there're "Include" and "Needs" values.
        if ((I.ValueExists(SectionName, 'Include')) and
          (I.ValueExists(SectionName, 'Needs'))) then
        begin
          // Split both by comma.
          SL := TStringList.Create();
          FilesList := TStringList.Create();
          try
            SL.CommaText := IniReadStr(I, SectionName, 'Include', '');
            FilesList.CommaText := IniReadStr(I, SectionName, 'Needs', '');
            if (SL.Text <> '') and (FilesList.Text <> '') then
              for X := 0 to SL.Count - 1 do
                for Y := 0 to FilesList.Count - 1 do
                  ParseInfFile(LocateInfFile(SL[X]), FilesList[Y]);
          finally
            FilesList.Free();
            SL.Free();
          end;
        end;
      end;
    finally
      I.Free();
    end;
  end;

begin
  Paths := TStringList.Create();
  try
    ParseInfFile(LocateInfFile(DeviceHelper.InfName), DeviceHelper.InfSection);
    Paths.Sort();

    ListView_InsertGroup(lvAdvancedInfo.Handle, 'Driver Files', 2);
    for I := 0 to Paths.Count - 1 do
      ListView_AddItemsInGroup(lvAdvancedInfo, '', Paths[I], 2);
  finally
    Paths.Free();
  end;
end;
于 2012-05-07T16:24:55.700 に答える