powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / SMART SSD в Delphi
8 сообщений из 8, страница 1 из 1
SMART SSD в Delphi
    #39826405
Maxwellion
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Товарищи форумчане, подскажите как в Delphi можно получить SMART диска SSD?
Для не IDE-дисков, вывод информации в Memo1, я использовал такой код:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
unit Unit1;

interface

uses
  Windows, SMART, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IdMultipartFormData, IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient, IdHTTP;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    IdHTTP: TIdHTTP;
    function SMART_DoIDENTIFY(hSMARTIOCTL: THandle;  pSCIP: PSENDCMDINPARAMS;  pSCOP: PSENDCMDOUTPARAMS;  bIDCmd: BYTE;  bDriveNum: BYTE): BOOL;
    function SMART_DoEnableSMART(hSMARTIOCTL: THandle;  pSCIP: PSENDCMDINPARAMS;  pSCOP: PSENDCMDOUTPARAMS;  bDriveNum: BYTE): BOOL;
    function SMART_DoReadAttributesCmd(hSMARTIOCTL: THandle;  pSCIP: PSENDCMDINPARAMS;  pSCOP: PSENDCMDOUTPARAMS;  bDriveNum: BYTE): BOOL;
    function SMART_DoReadThresholdsCmd(hSMARTIOCTL: THandle;  pSCIP: PSENDCMDINPARAMS;  pSCOP: PSENDCMDOUTPARAMS;  bDriveNum: BYTE): BOOL;
    function SMART_OpenSMART(DrvNum:Byte): THandle;
    function SMART_GetVersionSMART(hSMARTIOCTL: THandle):TGetVersionOutParams;

    procedure SMART_DoPrintData(pAttrBuffer: PCHAR;  pThrsBuffer: PCHAR);
    procedure SMART_ChangeByteOrder(szString: PCHAR;  uscStrSize: USHORT);
    procedure GET_INFO_SMART;
    procedure Button1Click(Sender: TObject);
    procedure reporting(txt:String);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1                 : TForm1;
  CurrentHandle         : THandle;
  OSVersionInfo         : TOSVersionInfo;


// Определение глобальных буферов.
  AttrOutCmd            : array [0..(sizeof(SENDCMDOUTPARAMS)-1)+(READ_ATTRIBUTE_BUFFER_SIZE-1)] of BYTE;
  ThreshOutCmd          : array [0..(sizeof(SENDCMDOUTPARAMS)-1)+(READ_THRESHOLD_BUFFER_SIZE-1)] of BYTE;
  IdOutCmd              : array [0..(sizeof(SENDCMDOUTPARAMS)-1)+(IDENTIFY_BUFFER_SIZE-1)] of BYTE;

implementation

{$R *.dfm}

// *****************************************************************************
// ** DoIDENTIFY
// **
// ** Назначение: Посылает диску команду IDENTIFY
// ** bDriveNum = 0-3
// ** bIDCmd = IDE_ID_FUNCTION или IDE_ATAPI_ID
// *****************************************************************************
function TForm1.SMART_DoIDENTIFY(hSMARTIOCTL: THandle;  pSCIP: PSENDCMDINPARAMS;  pSCOP: PSENDCMDOUTPARAMS;  bIDCmd: BYTE;  bDriveNum: BYTE): BOOL;
var
  lpcbBytesReturned     : DWORD;
begin
  pSCIP.cBufferSize := IDENTIFY_BUFFER_SIZE;
  pSCIP.irDriveRegs.bFeaturesReg := 0;
  pSCIP.irDriveRegs.bSectorCountReg := 1;
  pSCIP.irDriveRegs.bSectorNumberReg := 1;
  pSCIP.irDriveRegs.bCylLowReg := 0;
  pSCIP.irDriveRegs.bCylHighReg := 0;
  pSCIP.irDriveRegs.bDriveHeadReg := $A0 OR ((bDriveNum AND 1) SHL 4);// Вычисляем номер накопителя.
  pSCIP.irDriveRegs.bCommandReg := bIDCmd;// Команда может идентифицировать IDE или ATAPI.
  pSCIP.bDriveNumber := bDriveNum;
  result := DeviceIoControl(hSMARTIOCTL,DFP_RECEIVE_DRIVE_DATA,pSCIP,sizeof(SENDCMDINPARAMS)-1,pSCOP,sizeof(SENDCMDOUTPARAMS)+IDENTIFY_BUFFER_SIZE-1,lpcbBytesReturned,nil);
end;

// *****************************************************************************
// ** DoEnableSMART
// ** Назначение: Посылает диску команду SMART_ENABLE_SMART_OPERATIONS
// ** bDriveNum = 0-3
// *****************************************************************************
function TForm1.SMART_DoEnableSMART(hSMARTIOCTL: THandle;  pSCIP: PSENDCMDINPARAMS;  pSCOP: PSENDCMDOUTPARAMS;  bDriveNum: BYTE): BOOL;
var
  lpcbBytesReturned     : DWORD;
begin
  pSCIP.cBufferSize := 0;
  pSCIP.irDriveRegs.bFeaturesReg := SMART_ENABLE_SMART_OPERATIONS;
  pSCIP.irDriveRegs.bSectorCountReg := 1;
  pSCIP.irDriveRegs.bSectorNumberReg := 1;
  pSCIP.irDriveRegs.bCylLowReg := SMART_CYL_LOW;
  pSCIP.irDriveRegs.bCylHighReg := SMART_CYL_HI;
  pSCIP.irDriveRegs.bDriveHeadReg := $A0 OR ((bDriveNum AND 1) SHL 4);// Вычисляем номер накопителя.
  pSCIP.irDriveRegs.bCommandReg := IDE_EXECUTE_SMART_FUNCTION;
  pSCIP.bDriveNumber := bDriveNum;
  result := DeviceIoControl(hSMARTIOCTL,DFP_SEND_DRIVE_COMMAND,pSCIP,sizeof(SENDCMDINPARAMS)-1,pSCOP,sizeof(SENDCMDOUTPARAMS)-1,lpcbBytesReturned,nil);
end;

// *****************************************************************************
// ** DoReadAttributesCmd
// ** Назначение: Посылает диску команду SMART_READ_ATTRIBUTE_VALUES
// ** bDriveNum = 0-3
// *****************************************************************************
function TForm1.SMART_DoReadAttributesCmd(hSMARTIOCTL: THandle;  pSCIP: PSENDCMDINPARAMS;  pSCOP: PSENDCMDOUTPARAMS;  bDriveNum: BYTE): BOOL;
var
  cbBytesReturned       : DWORD;
begin
  pSCIP.cBufferSize := READ_ATTRIBUTE_BUFFER_SIZE;
  pSCIP.irDriveRegs.bFeaturesReg := SMART_READ_ATTRIBUTE_VALUES;
  pSCIP.irDriveRegs.bSectorCountReg := 1;
  pSCIP.irDriveRegs.bSectorNumberReg := 1;
  pSCIP.irDriveRegs.bCylLowReg := SMART_CYL_LOW;
  pSCIP.irDriveRegs.bCylHighReg := SMART_CYL_HI;
  pSCIP.irDriveRegs.bDriveHeadReg := $A0 OR ((bDriveNum AND 1) SHL 4);// Вычисляем номер накопителя.
  pSCIP.irDriveRegs.bCommandReg := IDE_EXECUTE_SMART_FUNCTION;
  pSCIP.bDriveNumber := bDriveNum;
  result := DeviceIoControl(hSMARTIOCTL,DFP_RECEIVE_DRIVE_DATA,pSCIP,sizeof(SENDCMDINPARAMS)-1,pSCOP,sizeof(SENDCMDOUTPARAMS)+READ_ATTRIBUTE_BUFFER_SIZE-1,cbBytesReturned,nil);
end;

// *****************************************************************************
// ** DoReadThresholdsCmd
// ** Назначение: Посылает диску команду SMART_READ_ATTRIBUTE_THRESHOLDS
// ** bDriveNum = 0-3
// *****************************************************************************
function TForm1.SMART_DoReadThresholdsCmd(hSMARTIOCTL: THandle;  pSCIP: PSENDCMDINPARAMS;  pSCOP: PSENDCMDOUTPARAMS;  bDriveNum: BYTE): BOOL;
var
  cbBytesReturned       : DWORD;
begin
  pSCIP.cBufferSize := READ_THRESHOLD_BUFFER_SIZE;
  pSCIP.irDriveRegs.bFeaturesReg := SMART_READ_ATTRIBUTE_THRESHOLDS;
  pSCIP.irDriveRegs.bSectorCountReg := 1;
  pSCIP.irDriveRegs.bSectorNumberReg := 1;
  pSCIP.irDriveRegs.bCylLowReg := SMART_CYL_LOW;
  pSCIP.irDriveRegs.bCylHighReg := SMART_CYL_HI;
  pSCIP.irDriveRegs.bDriveHeadReg := $A0 OR ((bDriveNum AND 1) SHL 4);// Вычисляем номер накопителя.
  pSCIP.irDriveRegs.bCommandReg := IDE_EXECUTE_SMART_FUNCTION;
  pSCIP.bDriveNumber := bDriveNum;
  result := DeviceIoControl(hSMARTIOCTL,DFP_RECEIVE_DRIVE_DATA,pSCIP,sizeof(SENDCMDINPARAMS)-1,pSCOP,sizeof(SENDCMDOUTPARAMS)+READ_THRESHOLD_BUFFER_SIZE-1, cbBytesReturned,nil);
end;

// *****************************************************************************
// ** DoPrintData
// ** FUNCTION: Отображает атрибуты и пороговые значения SMART
// *****************************************************************************
procedure TForm1.SMART_DoPrintData(pAttrBuffer: PCHAR;  pThrsBuffer: PCHAR);
var
  i, z                     : integer;
  pDA                   : PDRIVEATTRIBUTE;
  pAT                   : PATTRTHRESHOLD;
  s : STRING;
begin
  // Выводим информацию: идентификатор и название атрибута, его текущее и пороговое значение
  pDA:= PDRIVEATTRIBUTE(@pAttrBuffer[2]);
  pAT:= PATTRTHRESHOLD(@pThrsBuffer[2]);
  FOR i:=0 TO NUM_ATTRIBUTE_STRUCTS-1 DO BEGIN
    IF(pDA.bAttrID <> 0) THEN BEGIN
	  s := '';
      for z:= 5 downto 0 do s := s + IntToStr(pDA.bRawValue[z]);
      Memo1.Lines.Add('raw'+#$9+inttostr(pDA.bAttrID)+#$9+inttostr(pDA.bAttrValue)+#$9+inttostr(pAT.bWarrantyThreshold)+#$9+inttostr(pDA.bWorstValue)+#$9+'##'+#$9+IntToStr(pDA.bRawValue[5])+#$9+IntToStr(pDA.bRawValue[4])+#$9+IntToStr(pDA.bRawValue[3])+#$9+IntToStr(pDA.bRawValue[2])+#$9+IntToStr(pDA.bRawValue[1])+#$9+IntToStr(pDA.bRawValue[0])+#$9+s);
    END;
    inc(pDA);
    inc(pAT);
  END;
end;

// *****************************************************************************
// ** Меняем WORD-массив на BYTE-массив ****************************************
// *****************************************************************************
procedure TForm1.SMART_ChangeByteOrder(szString: PCHAR;  uscStrSize: USHORT);
var
  i                     : USHORT;
  temp                  : CHAR;
begin
  i := 0;
  WHILE i<uscStrSize DO BEGIN
    temp := szString[i];
    szString[i] := szString[i+1];
    szString[i+1] := temp;
    i:= i + 2;
  END;
end;

// *****************************************************************************
// ** Открываем дескриптор(хэндл) SMART для операций посредством DeviceIoControl.
// *****************************************************************************
function TForm1.SMART_OpenSMART(DrvNum:Byte): THandle;
var
  hSMARTIOCTL           : THandle;
begin
  IF OSVersionInfo.dwPlatformId = VER_PLATFORM_WIN32_NT THEN BEGIN // Windows NT, Windows 2000
    hSMARTIOCTL := CreateFile(PChar('\\.\PhysicalDrive'+inttostr(DrvNum)),GENERIC_READ OR GENERIC_WRITE,FILE_SHARE_READ OR FILE_SHARE_WRITE,nil,OPEN_EXISTING,0,0);
  END
  ELSE BEGIN // Windows 95 OSR2, Windows 98
    hSMARTIOCTL := CreateFile('\\.\SMARTVSD',0,0,nil,CREATE_NEW,0,0);
    IF hSMARTIOCTL = INVALID_HANDLE_VALUE THEN reporting('Невозможно открыть SMARTVSD, код ошибки: '+inttostr(GetLastError)+' - '+SysErrorMessage(GetLastError))
  END;
  result:= hSMARTIOCTL;
end;


// *****************************************************************************
// *****************************************************************************
// *****************************************************************************
function TForm1.SMART_GetVersionSMART(hSMARTIOCTL: THandle):TGetVersionOutParams;
var
  VersionParams         : TGetVersionOutParams;
  cbBytesReturned       : DWORD;
begin
  ZeroMemory(@VersionParams,sizeof(TGetVersionOutParams));
  IF NOT DeviceIoControl(hSMARTIOCTL,DFP_GET_VERSION,nil,0,@VersionParams,sizeof(VersionParams),cbBytesReturned,nil) THEN reporting(SysErrorMessage(GetLastError));
  result:=VersionParams;
end;


// *****************************************************************************
// *****************************************************************************
// *****************************************************************************
procedure TForm1.GET_INFO_SMART;
var
  hSMARTIOCTL           : THandle;
  i                     : integer;
  VersionParams         : TGetVersionOutParams;
  bIDCmd, bDfpDriveMap  : BYTE; // Команда идентификации IDE или ATAPI
  scip                  : TSendCmdInParams;
  OutCmd                : TSendCmdOutParams;
  bSuccess              : bool;
  pids                  : PIDSECTOR;
begin
  OSVersionInfo.dwOSVersionInfoSize := SizeOf(OSVersionInfo);
  GetVersionEx(OSVersionInfo);
  bDfpDriveMap := 0;
  CurrentHandle := SMART_OpenSMART(0);

  // Получаем версию и т.п. SMART IOCTL
  VersionParams := SMART_GetVersionSMART(CurrentHandle);

  FOR i := 0 TO MAX_IDE_DRIVES-1 DO BEGIN
    Memo1.Lines.Add(IntToStr(i));
    hSMARTIOCTL := SMART_OpenSMART(i);
    // Если устройство с номером "i" - IDE, передаём ему команды.
    IF VersionParams.bIDEDeviceMap SHR i AND 1=1 THEN BEGIN
      // Игнорируем ATAPI-устройства.
      IF VersionParams.bIDEDeviceMap SHR i AND $10=0 THEN BEGIN
        ZeroMemory(@scip,sizeof(scip));
        ZeroMemory(@OutCmd,sizeof(OutCmd));
        // Пытаемся активировать SMART.
        IF SMART_DoEnableSMART(hSMARTIOCTL,@scip,@OutCmd,i) THEN BEGIN
          // Помечаем диск, как накопитель с активным SMART
          bDfpDriveMap := bDfpDriveMap OR (1 SHL i);
          // Теперь получаем ID сектора для всех устройств IDE в системе.
          // Если устройство - ATAPI, используем команду IDE_ATAPI_ID,
          // в противном случае используем команду IDE_ID_FUNCTION.
          IF VersionParams.bIDEDeviceMap SHR i AND $10=1 THEN bIDCmd := IDE_ATAPI_ID
          ELSE bIDCmd := IDE_ID_FUNCTION;
          ZeroMemory(@scip,sizeof(scip));
          ZeroMemory(@IdOutCmd,sizeof(IdOutCmd));
          IF SMART_DoIDENTIFY(hSMARTIOCTL,@scip,PSENDCMDOUTPARAMS(@IdOutCmd),bIDCmd,i) THEN BEGIN
            pids := @PSENDCMDOUTPARAMS(@IdOutCmd).bBuffer;
            SMART_ChangeByteOrder(pids.sModelNumber,sizeof(pids.sModelNumber));
            SMART_ChangeByteOrder(pids.sFirmwareRev,sizeof(pids.sFirmwareRev));
            SMART_ChangeByteOrder(pids.sSerialNumber,sizeof(pids.sSerialNumber));
            Memo1.Lines.Add('disk_1#'+inttostr(i)+'#'+trim(pids.sModelNumber)+'#'+trim(pids.sFirmwareRev)+'#'+trim(pids.sSerialNumber+'#'));
          END
          ELSE reporting('Команда Identify не выполнена на диске: '+inttostr(i)+#10#13+'DriverStatus: bDriverError = '+inttostr(PSENDCMDOUTPARAMS(@IdOutCmd).DriverStatus.bDriverError)+', bIDEStatus = '+inttostr(PSENDCMDOUTPARAMS(@IdOutCmd).DriverStatus.bIDEStatus));
        END
        ELSE reporting('Команда запуска S.M.A.R.T. не выполнена, диск: '+inttostr(i)+#10#13+'DriverStatus: bDriverError = '+inttostr(OutCmd.DriverStatus.bDriverError)+', bIDEStatus = '+inttostr(OutCmd.DriverStatus.bIDEStatus));
      END;
    END;
  END;
  // Перебираем все возможные IDE-приводы и посылаем команды тем, которые поддерживают SMART.
  FOR i := 0 TO MAX_IDE_DRIVES-1 DO BEGIN
    IF bDfpDriveMap SHR i AND 1=1 THEN BEGIN
      ZeroMemory(@AttrOutCmd,sizeof(AttrOutCmd));
      ZeroMemory(@ThreshOutCmd,sizeof(ThreshOutCmd));
      bSuccess := SMART_DoReadAttributesCmd(CurrentHandle,@scip,PSENDCMDOUTPARAMS(@AttrOutCmd),i);
      IF bSuccess=false THEN reporting('Ошибка при выполнении команды чтения атрибутов S.M.A.R.T. на диске: '+inttostr(i)+#10#13+'DriverStatus: bDriverError = '+inttostr(PSENDCMDOUTPARAMS(@AttrOutCmd).DriverStatus.bDriverError)+', bIDEStatus = '+inttostr(PSENDCMDOUTPARAMS(@AttrOutCmd).DriverStatus.bIDEStatus))
        // Команда чтения атрибутов выполнена успешно. Пытаемся прочитать пороговые значения атрибутов.
      ELSE
        IF NOT SMART_DoReadThresholdsCmd(CurrentHandle,@scip,PSENDCMDOUTPARAMS(@ThreshOutCmd),i) THEN reporting('Ошибка при выполнении команды чтения пороговых значений атрибутов S.M.A.R.T. на диске: '+inttostr(i)+#10#13+'DriverStatus: bDriverError = '+inttostr(PSENDCMDOUTPARAMS(@ThreshOutCmd).DriverStatus.bDriverError)+', bIDEStatus = '+inttostr(PSENDCMDOUTPARAMS(@ThreshOutCmd).DriverStatus.bIDEStatus));
      // Если функции DoReadAttributesCmd и DoReadThresholdsCmd выполнены успешно,
      // процедура DoPrintData выводит оба значения атрибутов. Если DoReadThresholdsCmd
      // не поддерживается, выводятся только текущие значения атрибутов
      IF bSuccess<>false THEN SMART_DoPrintData(@PSENDCMDOUTPARAMS(@AttrOutCmd).bBuffer,@PSENDCMDOUTPARAMS(@ThreshOutCmd).bBuffer);
    end;
  END;
end;

// *****************************************************************************
// *****************************************************************************
// *****************************************************************************
procedure TForm1.Button1Click(Sender: TObject);
begin
  GET_INFO_SMART;
end;

end.



Для IDE/ATAPI устройств информацию показывает отлично, но для SSD полный голяк. Как исправить? Подскажите, направьте, дайте ссылку :)
...
Рейтинг: 0 / 0
SMART SSD в Delphi
    #39833315
Maxwellion
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Никто не читал СМАРТ с SSDшек? :(
...
Рейтинг: 0 / 0
SMART SSD в Delphi
    #39833341
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
SMART SSD в Delphi
    #39833365
Фотография Gator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxwellion,

ЕМНИП Wmi Delphi Code Creator это умел?
...
Рейтинг: 0 / 0
SMART SSD в Delphi
    #39833656
Maxwellion
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
X-Cite,

Там на С++, я в нём не силён:( Скопировал код, при компиляции ругается на
Код: plaintext
1.
[bcc32 Error] Unit1.cpp(81): E2451 Undefined symbol 'SENDCMDINPARAMS'
...
Рейтинг: 0 / 0
SMART SSD в Delphi
    #39833729
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntdddisk/ns-ntdddisk-_sendcmdinparams

Опишите структуру самостоятельно, если ее нет из коробки...
...
Рейтинг: 0 / 0
SMART SSD в Delphi
    #39834147
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxwellion,

существуют конвертеры заголовков, если вручную сложно.
...
Рейтинг: 0 / 0
SMART SSD в Delphi
    #39834168
Фотография defecator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
makhaonMaxwellion,

существуют конвертеры заголовков, если вручную сложно.
лучше вручную, всё равно за конверторами потом и мусор чистить, и правильность проверять
...
Рейтинг: 0 / 0
8 сообщений из 8, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / SMART SSD в Delphi
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]