(******************************************************************************
 *                                                                            *
 *  Придумал и написал Кода Виктор                                            *
 *                                                                            *
 *  Файл:       main.pas                                                      *
 *  Содержание: Пример перечисления различных аппратных устройств в DirectX   *
 *                                                                            *
 ******************************************************************************)
unit main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, StdCtrls,
  ExtCtrls;

type
  TForm1 = class(TForm)
    gb1: TGroupBox;
    gb2: TGroupBox;
    gb3: TGroupBox;
    cbAdapter: TComboBox;
    cbSndCard: TComboBox;
    btnClose: TButton;
    cbInput: TComboBox;
    Image1: TImage;
    Image2: TImage;
    Image3: TImage;
    procedure btnCloseClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses
  DirectDraw,
  DirectSound,
  DirectInput8;




//------------------------------------------------------------------------------
// Имя:      DDEnumCallback()
// Описание: Вызывается при перечислении драйверов видеокарт
//------------------------------------------------------------------------------
function DDEnumCallback( lpGuid: PGUID; lpstrDescription: PAnsiChar;
                         lpstrModule: PAnsiChar; lpContext: Pointer ): BOOL; stdcall;
var
  lpDD7: IDirectDraw7;
  dddi2: TDDDEVICEIDENTIFIER2;
begin
  // К сожалению, из функции DDEnumCallback() можно получить только описание
  // драйвера видеоадаптера - оно хранится в переменной lpstrDescription
  // (например "Первичный видеодрайвер"). Чтобы получить описание видеоадаптера,
  // нужно вызвать метод IDirectDraw7.GetDeviceIdentifier(). При создании объекта
  // DirectDraw необходимо передать GUID адаптера, который предоставляет пере-
  // менная lpGUID
  Result := FALSE;

  lpDD7 := nil;

  // Создаём объект DirectDraw7, указав полученный при перечислении GUID
  if FAILED( DirectDrawCreateEx( lpGUID, lpDD7, IID_IDirectDraw7,
                                 nil ) ) then
     Exit;
  lpDD7._AddRef();

  // Получаем информацию о видеоадаптере, данные записываются в структуру dddi2
  lpDD7.GetDeviceIdentifier( dddi2, 0 );
  // Наполняем список названием видеоадаптера и описанием драйвера
  Form1.cbAdapter.Items.Add( dddi2.szDescription +
                             Format( ' (Драйвер %s)', [ dddi2.szDriver ] ) );
  // Удаляем объект DirectDraw7
  lpDD7._Release;
  lpDD7 := nil;

  Result := TRUE;
end;




//------------------------------------------------------------------------------
// Имя:      DSEnumCallback()
// Описание: Вызывается при перечислении звуковых карт
//------------------------------------------------------------------------------
function DSEnumCallback( lpGuid: PGUID; lpstrDescription: PAnsiChar;
                         lpstrModule: PAnsiChar; lpContext: Pointer): BOOL; stdcall;
begin
  // Функция DSEnumCallback() позволяет узнать описание звуковой карты и её
  // драйвера
  Form1.cbSndCard.Items.Add( lpstrDescription +
                             Format( ' (%s)', [ lpstrModule ] ) );
  Result := TRUE;
end;




//------------------------------------------------------------------------------
// Имя:      DIEnumCallback()
// Описание: Вызывается при перечислении устройств ввода
//------------------------------------------------------------------------------
function DIEnumCallback( var lpddi: TDIDeviceInstanceA; pvRef: Pointer ):
  Integer; stdcall;
var
  desc: string;
begin
  // Получаем тип перечисленного устройства ввода.
  // Предупреждение: здесь у DirectInput могут возникнуть проблемы с правильным
  // определением типа, т. к. вся информация получается от драйвера. Если он
  // "сырой" или написан неверно, то определение будет некорректным. Например,
  // мой геймпад определяется как DI8DEVTYPE_FLIGHT, а не как DI8DEVTYPE_GAMEPAD
  // Мышь и клавиатура определяются правильно
  desc := 'Неизвестный тип';
  case GET_DIDEVICE_TYPE( lpddi.dwDevType ) of
    DI8DEVTYPE_DEVICE:        desc := 'Общее устройство';
    DI8DEVTYPE_MOUSE:         desc := 'Мышь';
    DI8DEVTYPE_KEYBOARD:      desc := 'Клавиатура';
    DI8DEVTYPE_JOYSTICK:      desc := 'Джойстик';
    DI8DEVTYPE_GAMEPAD:       desc := 'Геймпад';
    DI8DEVTYPE_DRIVING:       desc := 'Устройство для вождения';          //?
    DI8DEVTYPE_FLIGHT:        desc := 'Штурвал';
    DI8DEVTYPE_1STPERSON:     desc := 'First-person action game device';  //?
    DI8DEVTYPE_DEVICECTRL:    desc := 'Управляемое устройство';           //?
    DI8DEVTYPE_SCREENPointer: desc := 'Световой карандаш';
    DI8DEVTYPE_REMOTE:        desc := 'Пульт дистанционного управления';
    DI8DEVTYPE_SUPPLEMENTAL:  desc := 'Дополнительный элемент ввода';
  end;   

  // Выводим описание устройства ввода и его тип
  Form1.cbInput.Items.Add( lpddi.tszProductName + Format( ' (%s)', [ desc ] ) );

  Result := DIENUM_CONTINUE;
end;




//------------------------------------------------------------------------------
// Имя:      TForm1.FormCreate()
// Описание: Получает управление при старте программмы
//------------------------------------------------------------------------------
procedure TForm1.FormCreate(Sender: TObject);
var
  lpDI8: IDirectInput8;
begin
  // Перечисляем все видеоадаптеры
  if FAILED( DirectDrawEnumerate( DDEnumCallback, nil) ) then
     Halt;

  // Перечисляем все звуковые карты
  if FAILED( DirectSoundEnumerate( DSEnumCallback, nil ) ) then
     Halt;

  // Функция DirectInputEnumerate() отсутствует как таковая, все устройства
  // ввода можо перечислить методом DirectInput8.EnumDevices()
  lpDI8 := nil;
  if FAILED( DirectInput8Create( GetModuleHandle( 0 ), DIRECTINPUT_VERSION,
                                 IID_IDirectInput8, lpDI8,  nil ) ) then
     Halt;
  lpDI8._AddRef;

  // Методом объекта перечисляем все устройства, в том числе отключенные.
  if FAILED( lpDI8.EnumDevices( DI8DEVCLASS_ALL, DIEnumCallback, nil,
                                DIEDFL_ALLDEVICES ) ) then
     Exit;

  // Удаляем объект
  lpDI8._Release();
  lpDI8 := nil;

  // GUI
  cbAdapter.ItemIndex := 0;
  cbSndCard.ItemIndex := 0;
  cbInput.ItemIndex   := 0;
end;




//------------------------------------------------------------------------------
// Имя:      TForm1.Button1Click()
// Описание: Закрывает программу
//------------------------------------------------------------------------------
procedure TForm1.btnCloseClick(Sender: TObject);
begin
  Form1.Close();
end;

end.
