2012-05-07 20 views
5

Vorrei sapere come posso ottenere tutti i file del driver per un particolare dispositivo come fa il gestore periferiche?Ottenere file driver per un particolare dispositivo

Ho il codice seguente:

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

Ma la ShowMessage() o non è chiamato affatto o restituisce \. Come ottengo i file correttamente?

Ho dato un'occhiata a devcon da WinDDK, ma non restituisce neanche i file.

Grazie.

risposta

5

L'ho capito. Non ci sono API per farlo, devi analizzare i file INF per ottenere il risultato. Ecco una soluzione rapida e sporca per tutti voi, che sono interessati.

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; 
Problemi correlati