2012-05-07 21 views
5

Tôi muốn biết làm cách nào để có thể tải tất cả các tệp trình điều khiển cho một thiết bị cụ thể giống như Trình quản lý Thiết bị?Tải các tập tin trình điều khiển cho một thiết bị cụ thể

Tôi có đoạn mã sau:

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); 

Nhưng ShowMessage() hoặc là không được gọi là ở tất cả hoặc trả \. Làm cách nào để tải tệp đúng cách?

Tôi đã xem devcon từ WinDDK, nhưng cũng không trả lại tệp.

Cảm ơn bạn.

Trả lời

5

Tôi đã tìm ra. Không có API để làm điều đó cho bạn, bạn cần phải phân tích cú pháp các tệp INF để đạt được kết quả. Đây là giải pháp nhanh chóng cho tất cả các bạn, những người quan tâm.

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; 
Các vấn đề liên quan