unit MySetupApi;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, CommCtrl;


// Restore point information

const

  // Type of Event
  BEGIN_SYSTEM_CHANGE = 100;
  END_SYSTEM_CHANGE = 101;
  // Type of Restore Points
  APPLICATION_INSTALL = 0;
  DEVICE_DRIVER_INSTAL = 10;
  CANCELLED_OPERATION = 13;
  MAX_DESC = 64;
  MIN_EVENT = 100;

  DIGCF_ALLCLASSES = $00000004;
  DIGCF_PRESENT = $00000002;
  DIGCF_PROFILE = $00000008;
  DIGCF_DEVICEINTERFACE = $00000010;

  SPDRP_DEVICEDESC = $00000000;
  SPDRP_HARDWAREID = $00000001; // HardwareID (R/W)
  SPDRP_COMPATIBLEIDS = $00000002; // CompatibleIDs (R/W)
  SPDRP_SERVICE = $00000004;
  SPDRP_CLASSGUID = $00000008; // ClassGUID (R/W)
  SPDRP_FRIENDLYNAME = $0000000C; // FriendlyName (R/W)

  SPDRP_DRIVER = $00000009; // Driver (R/W)

  // Производитель или класс устройства
  SPDRP_MFG = $0000000B; // Mfg (R/W)

  INF_STYLE_WIN4 = $00000002; // Win95

  MAX_CLASS_NAME_LEN = 128;
  DICD_GENERATE_ID = 1;
  HARDID_BUF_SIZE = 1024;
  DIF_REGISTERDEVICE = $00000019;
  INSTALLFLAG_FORCE = 1;

  DRIVER_PACKAGE_ONLY_IF_DEVICE_PRESENT = $00000008;
  DRIVER_PACKAGE_LEGACY_MODE = $00000010;
  DRIVER_PACKAGE_FORCE = $00000004;
  DRIVER_PACKAGE_SILENT = $00000002;

  CM_LOCATE_DEVNODE_NORMAL = $00000000;
  CR_SUCCESS = $00000000;

type

  TGradientDirection = (gdLeftRight, gdTopBottom);


  COLOR16 = Word; { is declared as Shortint in Delphi 7 }

  PTriVertex = ^TTriVertex;

  _TRIVERTEX = packed record
    x: Longint;
    y: Longint;
    Red: COLOR16;
    Green: COLOR16;
    Blue: COLOR16;
    Alpha: COLOR16;
  end;

  TTriVertex = _TRIVERTEX;
  TRIVERTEX = _TRIVERTEX;



  PRESTOREPTINFOA = ^_RESTOREPTINFOA;

  _RESTOREPTINFOA = packed record
    dwEventType: DWORD; // Type of Event - Begin or End
    dwRestorePtType: DWORD; // Type of Restore Point - App install/uninstall
    llSequenceNumber: INT64; // Sequence Number - 0 for begin
    szDescription: array [0 .. MAX_DESC] of CHAR;
    // Description - Name of Application / Operation
  end;

  RESTOREPOINTINFO = _RESTOREPTINFOA;
  PRESTOREPOINTINFOA = ^_RESTOREPTINFOA;

  // Status returned by System Restore

  PSMGRSTATUS = ^_SMGRSTATUS;

  _SMGRSTATUS = packed record
    nStatus: DWORD; // Status returned by State Manager Process
    llSequenceNumber: INT64; // Sequence Number for the restore point
  end;

  STATEMGRSTATUS = _SMGRSTATUS;
  PSTATEMGRSTATUS = ^_SMGRSTATUS;

  ULONG_PTR = DWORD;
{$EXTERNALSYM ULONG_PTR}
  PGuid = ^TGuid;

  { SP_DEVINFO_DATA=record
    cbSize:DWord;
    ClassGuid:TGuid;
    DevInst:DWord;    // DEVINST handle
    Reserved:LongInt;
    end;

    PSP_DEVINFO_DATA=^SP_DEVINFO_DATA; }

  PSPDevInfoData = ^TSPDevInfoData;

  SP_DEVINFO_DATA = packed record
    cbSize: DWORD;
    ClassGuid: TGuid;
    DevInst: DWORD; // DEVINST handle
    Reserved: ULONG_PTR;
  end;
{$EXTERNALSYM SP_DEVINFO_DATA}

  TSPDevInfoData = SP_DEVINFO_DATA;

  PInfContext = ^TInfContext;

  INFCONTEXT = packed record
    Inf: Pointer;
    CurrentInf: Pointer;
    Section: UINT;
    Line: UINT;
  end;

  TInfContext = INFCONTEXT;

  INSTALLERINFO_A = record
    pApplicationId, pDisplayName, pProductName, pMfgName: PChar;
  end;

  PINSTALLERINFO_A = ^INSTALLERINFO_A;
  PCINSTALLERINFO_A = PINSTALLERINFO_A;

  PSPClassImageListData = ^TSPClassImageListData;

  SP_CLASSIMAGELIST_DATA = packed record
    cbSize: DWORD;
    ImageList: HIMAGELIST;
    Reserved: ULONG_PTR;
  end;
{$EXTERNALSYM SP_CLASSIMAGELIST_DATA}

  TSPClassImageListData = SP_CLASSIMAGELIST_DATA;

  HDEVINFO = Pointer;
{$EXTERNALSYM HDEVINFO}
  RETURN_TYPE = DWORD;
{$EXTERNALSYM RETURN_TYPE}
  CONFIGRET = RETURN_TYPE;
{$EXTERNALSYM CONFIGRET}
  DevInst = DWORD;
{$EXTERNALSYM DEVINST}
function WindowsGradientFill(DC: THandle; Vertex: PTriVertex; NumVertex: ULONG;
  Mesh: Pointer; NumMesh, Mode: ULONG): BOOL; stdcall;
  external 'msimg32.dll' name 'GradientFill';

function SRSetRestorePointA(pRestorePtSpec: PRESTOREPOINTINFOA;
  PSMGRSTATUS: PSTATEMGRSTATUS): BOOL; stdcall;
  external 'SrClient.dll' Name 'SRSetRestorePointA';

function SetupDiCreateDeviceInfoList(ClassGuid: PGuid; hwndParent: cardinal)
  : Pointer; stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupDiCreateDeviceInfoList}
function SetupDiGetClassDevsA(ClassGuid: PGuid; const Enumerator: PChar;
  hwndParent: cardinal; Flags: DWORD): Pointer; stdcall;
  external 'setupapi.dll';
{$EXTERNALSYM SetupDiGetClassDevsA}
function SetupDiGetClassDevsExA(ClassGuid: PGuid; Enumerator: PChar;
  hwndParent: HWND; Flags: DWORD; DeviceInfoSet: Pointer; MachineName: PChar;
  Reserved: Pointer): HDEVINFO; stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupDiGetClassDevsExA}
{ function SetupDiGetDeviceRegistryPropertyA(DeviceInfoSet:HDEVINFO;
  DeviceInfoData:TSPDevInfoData; Property_:DWord; PropertyRegDataType: DWORD;
  PropertyBuffer:Pointer; PropertyBufferSize:cardinal; RequiredSize:Pointer):longbool;
  stdcall; external 'setupapi.dll'; }
// {$EXTERNALSYM SetupDiGetDeviceRegistryPropertyA}

function SetupDiGetDeviceRegistryPropertyA(DeviceInfoSet: HDEVINFO;
  const DeviceInfoData: TSPDevInfoData; Property_: DWORD;
  var PropertyRegDataType: DWORD; PropertyBuffer: PBYTE;
  PropertyBufferSize: DWORD; var RequiredSize: DWORD): LongBool; stdcall;
  stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupDiGetDeviceRegistryPropertyA}
function SetupDiEnumDeviceInfo(DeviceInfoSet: Pointer; MemberIndex: DWORD;
  var DeviceInfoData: SP_DEVINFO_DATA): LongBool; stdcall;
  external 'setupapi.dll';
{$EXTERNALSYM SetupDiEnumDeviceInfo}
function SetupDiDestroyDeviceInfoList(DeviceInfoSet: Pointer): LongBool;
  stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupDiDestroyDeviceInfoList}
function SetupOpenInfFileA(const FileName: PAnsiChar; const InfClass: PAnsiChar;
  InfStyle: DWORD; ErrorLine: PUINT): Pointer; stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupOpenInfFileA}
function SetupFindFirstLineA(InfHandle: Pointer; Section, Key: PAnsiChar;
  var Context: TInfContext): BOOL; stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupFindFirstLineA}
function SetupGetStringFieldA(var Context: TInfContext; FieldIndex: DWORD;
  ReturnBuffer: PAnsiChar; ReturnBufferSize: DWORD; RequiredSize: PDWORD): BOOL;
  stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupGetStringFieldA}
function SetupFindNextLine(var ContextIn, ContextOut: TInfContext): BOOL;
  stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupFindNextLine}
function SetupGetLineCountA(InfHandle: Pointer; Section: PAnsiChar): Integer;
  stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupGetLineCountA}
procedure SetupCloseInfFile(InfHandle: Pointer); stdcall;
  external 'setupapi.dll';
{$EXTERNALSYM SetupCloseInfFile}
function SetupGetFieldCount(var Context: TInfContext): DWORD; stdcall;
  external 'setupapi.dll';
{$EXTERNALSYM SetupGetFieldCount}
function SetupDiGetClassImageList(var ClassImageListData: TSPClassImageListData)
  : LongBool; stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupDiGetClassImageList}
function SetupDiGetClassDescriptionA(var ClassGuid: TGuid;
  ClassDescription: PAnsiChar; ClassDescriptionSize: DWORD;
  RequiredSize: PDWORD): LongBool; stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupDiGetClassDescriptionA}
function SetupDiGetClassImageIndex(var ClassImageListData
  : TSPClassImageListData; var ClassGuid: TGuid; var ImageIndex: Integer)
  : LongBool; stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupDiGetClassImageIndex}
function SetupDiRemoveDevice(DeviceInfoSet: HDEVINFO;
  var DeviceInfoData: TSPDevInfoData): BOOL; stdcall; external 'setupapi.dll';
{$EXTERNALSYM SetupDiRemoveDevice}
function CM_Get_DevNode_Status(var ulStatus: DWORD; var ulProblemNumber: DWORD;
  dnDevInst: DWORD; ulFlags: DWORD): DWORD; stdcall; external 'cfgmgr32.dll';
{$EXTERNALSYM CM_Get_DevNode_Status}
function CM_Reenumerate_DevNode(dnDevInst: DevInst; ulFlags: ULONG): CONFIGRET;
  stdcall; external 'cfgmgr32.dll';
{$EXTERNALSYM CM_Reenumerate_DevNode}
function CM_Locate_DevNodeA(var dnDevInst: DevInst; pDeviceID: PChar;
  ulFlags: ULONG): CONFIGRET; stdcall; external 'cfgmgr32.dll';
{$EXTERNALSYM CM_Locate_DevNodeA}
function UpdateDriverForPlugAndPlayDevicesA(hwndParent: HWND;
  HardwareId: PAnsiChar; FullInfPath: PAnsiChar; InstallFlags: DWORD;
  bRebootRequired: PBOOL): BOOL; stdcall; external 'NewDev.dll';
{$EXTERNALSYM UpdateDriverForPlugAndPlayDevicesA}
procedure CreateRestorePoint();

procedure DrawGradient(Canvas: TCanvas; R: TRect; StartColor, EndColor: TColor; Direction: TGradientDirection = gdLeftRight);

implementation

procedure CreateRestorePoint();
const
  CR = #13#10;
var
  RestorePtSpec: RESTOREPOINTINFO;
  SMgrStatus: STATEMGRSTATUS;
  msg: string;
  time1: TTime;
begin
  if not(mrYes = MessageDlg('Вы действительно хотите' + #13 +
    'создать точку восстановления?', mtConfirmation, [mbYes, mbNo], 0)) then
    exit;

  // Initialize the RESTOREPOINTINFO structure
  RestorePtSpec.dwEventType := BEGIN_SYSTEM_CHANGE;
  RestorePtSpec.dwRestorePtType := DEVICE_DRIVER_INSTAL;
  RestorePtSpec.llSequenceNumber := 0;
  RestorePtSpec.szDescription := 'DriverX POINT';
  time1 := Time;

  if (SRSetRestorePointA(@RestorePtSpec, @SMgrStatus)) then
  begin
    time1 := Time - time1;
    MessageDlg('Контрольна точка создана' + CR + 'Номер точки: ' +
      IntToStr(SMgrStatus.llSequenceNumber) + CR + 'Время создания точки: ' +
      TimeToStr(time1), mtInformation, [mbOK], 0);
  end
  else if SMgrStatus.nStatus <> ERROR_SUCCESS then
  begin
    case SMgrStatus.nStatus of
      ERROR_DISK_FULL:
        msg := 'Недостаточно места на диске!';
      ERROR_SERVICE_DISABLED:
        msg := 'Служба восстановления отключена!';
      ERROR_BAD_ENVIRONMENT:
        msg := 'Служба восстановления не работает в безопасном режиме!';
    end;
    MessageDlg('Ошибка' + #13 + msg, mtError, [mbOK], 0);
  end;
end;

procedure SetVertex(var Vertex: TTriVertex; X, Y: Integer; Color: TColor);
begin
 Vertex.x      := X;
 Vertex.y      := Y;
 Vertex.Red    := (Color and $000000FF) shl 8;
 Vertex.Green  := (Color and $0000FF00);
 Vertex.Blue   := (Color and $00FF0000) shr 8;
 Vertex.Alpha  := 0;
end;

procedure DrawGradient(Canvas: TCanvas; R: TRect; StartColor, EndColor: TColor;
  Direction: TGradientDirection);
var
  Vertices: array [0 .. 1] of TTriVertex;
  Rects: array [0 .. 0] of TGradientRect;
  Mode: ULONG;
begin
  SetVertex(Vertices[0], R.Left, R.Top, StartColor);
  SetVertex(Vertices[1], R.Right, R.Bottom, EndColor);

  Rects[0].UpperLeft := 0;
  Rects[0].LowerRight := 1;

  if Direction = gdLeftRight then
    Mode := GRADIENT_FILL_RECT_H
  else
    Mode := GRADIENT_FILL_RECT_V;

  WindowsGradientFill(Canvas.Handle, @Vertices, 2, @Rects, 1, Mode);
end;

end.
