urock
Участник
Offline
|
|
« : 15-03-2010 16:38 » |
|
Добрый день! Моему PCI драйверу позарез нужно знать Код Экземпляра Устройства (как в Device Manager) или по-английски: Device Instance ID. ( http://msdn.microsoft.com/en-us/library/dd567984.aspx). Следую MSDN, я узнаю сначала Device ID (или Hardware ID) через вызов IoGetDeviceProperty. Получаю что-то типа "PCI\VENDOR_XXXX_and_so_on" - прямо то что мне надо. Затем к этому надо добавить Instance ID. Опять же следуя MSDN создаю IRP_MJ_PNP (IRP_MN_QUERY_ID) и посылаю его драйверу шины асинхронным способом (то есть, создаю запрос с помощью IoAllocateIrp, и устанавливаю свою CompletionRoutine). В этой функции завершения я и получаю заветный указатель на нужную мне строчку. Проблема только в том, что я получаю какую-то урезанную строку! Конкретнее: в Device Manager вижу, что мой Device Instance ID = "PCI\VENDOR_XXXX_and_so_on\5&12D884F0&0&2020F0", т.е. сам Instance ID = "5&12D884F0&0&2020F0". А драйвер шины возвращает моему драйверу указатель на такую строку: "2020F0" - т.е. состоящую только из 6ти последних символов. Что за черт? Может кто сталкивался с подобным? Спасибо!
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #1 : 15-03-2010 17:00 » |
|
по моему, там часть кода - физический номер шины, куда девайс воткнут. возможно именно его обрубила винда? вы посмотрите сколько вобще Instance ID в спецификации PCI занимает) это в конфиг-спейсе PCI должно быть.
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #2 : 15-03-2010 17:01 » |
|
Во-первых, есть подозрение, что когда сам создаешь IRP, то CompletionRoutine можно не устанавливать.
Что касается остального, то неплохо бы код привести, по формированию IRP (IRP_MN_QUERY_ID). Посмотреть как поля заданы. Вчастности, я бы поэксперементировал (от недостатка опыта) с полем Parameters.QueryId.IdType
|
|
« Последнее редактирование: 15-03-2010 17:03 от resource »
|
Записан
|
|
|
|
urock
Участник
Offline
|
|
« Ответ #3 : 15-03-2010 18:49 » |
|
Ochkarik, в MSDN значение Instance ID, к сожалению, конкретно не определено. Вот цитата: The following is an example of an instance ID ("1&08") concatenated to a device ID for a PCI device:
PCI\VEN_1000&DEV_0001&SUBSYS_00000000&REV_02\1&08 как я понимаю, ничего общего с идентификатором устройства PCI на шине (DDDD:BB:DD:F, где DDDD - домен, BB - номер шины, DD - номер устройства, F - номер функции) это не имеет. resource, CompletionRoutine можно не устанавливать, когда посылаешь синхронный IRP, т.е. завершение которого ты хочешь дождаться. Например с помощью функции IoBuildSynchroniuosFsdRequest. Я так кстати тоже пробовал, но че-то не заработало - в поле Information не было указателя на строку.. Сам код остался на работе, но заверю, что поля заполнены так как сказано тут http://msdn.microsoft.com/en-us/library/ms806519.aspx. В частности поле Parameters.QueryId.IdType было равно BusQueryInstanceID.
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #4 : 15-03-2010 19:31 » |
|
Ну не обязательно IoBuildSynchroniuosFsdRequest. IoAllocateIrp'ом можно создать любой IRP.
Скажу честно, не обладаю достаточным опытом, чтобы сразу понять в чем может быть причина. А потому, я бы на твоем месте попробовал бы IRP_MN_QUERY_ID с разными значениями Parameters.QueryId.IdType и сравнил бы каждый результат с данными Device Manager'а. Подход с одной стороны дилетантский, но с другой - практика это лучший путь познания.
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #5 : 15-03-2010 19:47 » |
|
Походу насчет IoAllocateIrp я действительно не прав
|
|
|
Записан
|
|
|
|
urock
Участник
Offline
|
|
« Ответ #6 : 16-03-2010 06:44 » |
|
вот привожу код создания IRP (делаю я это в самом конце функции AddDevice) status1 = IoAcquireRemoveLock(&pdx->RemoveLock, (PVOID) 42); KdPrint((DRIVERNAME " - IoAcquireRemoveLock returned\n")); if (!NT_SUCCESS(status1)) { KdPrint((DRIVERNAME " - IoAcquireRemoveLock error!\n")); break; } Irp = IoAllocateIrp(pdx->LowerDeviceObject->StackSize, FALSE); KdPrint((DRIVERNAME " - IoAllocateIrp returned \n")); if (!Irp) { KdPrint((DRIVERNAME " - Irp = NULL!\n")); IoReleaseRemoveLock(&pdx->RemoveLock,(PVOID) 42); break; }
PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(Irp); KdPrint((DRIVERNAME " - IoGetNextIrpStackLocation returned \n")); if (!stack) { KdPrint((DRIVERNAME " - IoGetNextIrpStackLocation error!\n")); IoFreeIrp(Irp); IoReleaseRemoveLock(&pdx->RemoveLock,(PVOID) 42); break; }
stack->MajorFunction = IRP_MJ_PNP; stack->MinorFunction = IRP_MN_QUERY_ID; stack->Parameters.QueryId.IdType = BusQueryInstanceID; Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoSetCompletionRoutine(Irp,(PIO_COMPLETION_ROUTINE)QueryCompletionRoutine,pdx,TRUE,TRUE,TRUE); KdPrint((DRIVERNAME " - IoSetCompletionRoutine returned\n")); status1 = IoCallDriver(pdx->LowerDeviceObject, Irp); KdPrint((DRIVERNAME " - IoCallDriver returned with status %x\n",status1)); Вот функция завершения: NTSTATUS QueryCompletionRoutine(PDEVICE_OBJECT junk,PIRP Irp,PDEVICE_EXTENSION pdx) { PTSTR instanceId; ULONG instLen; NTSTATUS status; KdPrint((DRIVERNAME " - Entering QueryCompletionRoutine! \n")); instanceId = (PTSTR) Irp->IoStatus.Information; KdPrint((DRIVERNAME " - Got Instance Id = %ws\n",instanceId)); // AAAA // status = RtlStringCbCopyW(pdx->instanceId,100,(const wchar_t*)instanceId); wcscpy(pdx->instanceId,(const wchar_t*)instanceId); KdPrint((DRIVERNAME " - Saved Instance Id = %ws\n",pdx->instanceId)); IoFreeIrp(Irp); IoReleaseRemoveLock(&pdx->RemoveLock,(PVOID) 42); swprintf(pdx->devInstId,L"%ws\\%ws",pdx->hardwareId,pdx->instanceId); KdPrint((DRIVERNAME " - DevInstId = %ws\n",pdx->devInstId));
return STATUS_MORE_PROCESSING_REQUIRED; } На метке //AAAA я уже получаю неправильную (обрезанную) строку. Я тут подумал, что может я рано посылаю свой Query IRP? Может к концу функции AddDevice система еще не до конца сформировала Instance ID, и я получаю просто недоделанный вариант? Попробую сейчас посылать этот запрос из функции StartDevice или вообще в ответ на пользовательский IOCTL запрос.
|
|
|
Записан
|
|
|
|
urock
Участник
Offline
|
|
« Ответ #7 : 16-03-2010 07:12 » |
|
идея с переносом запроса в функцию StartDevice не прошла - возвращается точно то же.
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #8 : 16-03-2010 07:44 » |
|
В QueryCompletionRoutine не мешало бы смотреть поле IoStatus.Status.
Вот ты не хочешь попробовать посмотреть разные Parameters.QueryId.IdType. Ну за неимением вариантов, все же рекомендую. Мне самому интересно, что тебе придет для: BusQueryDeviceID, BusQueryHardwareIDs, BusQueryCompatibleIDs и BusQueryContainerID.
|
|
|
Записан
|
|
|
|
urock
Участник
Offline
|
|
« Ответ #9 : 16-03-2010 07:56 » |
|
да ща гляну - отпишусь.
|
|
|
Записан
|
|
|
|
urock
Участник
Offline
|
|
« Ответ #10 : 16-03-2010 08:28 » |
|
ну BusQueryDeviceID выдает DeviceID, BusQueryHardwareIDs - HardwareIDs, выдает BusQueryCompatibleIDs - CompatibleIDs. Значение ContainerID у меня не определено (WIN XP DDK2600). Зато в wdm.h определено значение BusQueryDeviceSerialNumber. Но когда его используешь - комп перезагружается.
имеет смысл обновить версию DDK может?
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #11 : 16-03-2010 08:34 » |
|
Имеет смысл WDK поставить. Но что касается BusQueryDeviceSerialNumber, то в WDK/DDK написано The following ID type is reserved: BusQueryDeviceSerialNumber Так, что не надо так делать. Жаль что ты конкретные значения не написал (выданные для BusQueryDeviceID и остальные). Интересно (для себя) посмотреть.
|
|
|
Записан
|
|
|
|
urock
Участник
Offline
|
|
« Ответ #12 : 16-03-2010 08:44 » |
|
Слушай, они такие же как и в DeviceManagere. Свойства устройства, вкладка Сведения. Если есть еще необходимость выложить мои - сделаю
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #13 : 16-03-2010 08:51 » |
|
Да ладно. Если ты сам их видел, и видел что они приходят в нормальном виде, то можно не приводить
Просто я всё это к тому, что возможно в твоём запросе ничего не обрубается, а та строка для InstanceID, которую ты видишь в device manager'е на самом деле составная. Вот только из чего она составлена. Может быть посмотреть в сторону DEVICE_CAPABILITIES->UniqueID
|
|
« Последнее редактирование: 16-03-2010 09:20 от resource »
|
Записан
|
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #15 : 18-03-2010 21:09 » |
|
Может он формируется самой системой? Всмысле драйвером шины
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #16 : 18-03-2010 21:21 » |
|
ага. проглядел сразу...Device Instance ID формируется системой и не прописан в железе. ну нечему там, кроме географии расположения быть. больше признаков же никаких нет?
|
|
« Последнее редактирование: 18-03-2010 21:36 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Ochkarik
|
|
« Ответ #17 : 18-03-2010 21:47 » |
|
кстати попробуйте в реестре посмотреть. в каком нибудь HKEY_CURRENT_CONFIG\System\CurrentControlSet\Enum\PCI это может быть вообще адресом памяти, где какая нибудь структура лежит.
|
|
« Последнее редактирование: 18-03-2010 21:50 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #18 : 18-03-2010 21:57 » |
|
Мне всё-таки кажется что ничего не обрубается, а именно device manager показывает уже в каком-то собранном виде. Может быть так приплетены Device Instance ID родительских PDO или типа того. Надо попробовать послать такой запрос к PDO и посмотреть что там придет, и сравнить с тем что показывает Device Manager.
Дело в том, что Device Manager полюбому получает инфу из реестра. А в реестр она известно как попадает. Устройства перечисляются "деревом", от корневого и там дальше уже.
|
|
« Последнее редактирование: 18-03-2010 22:05 от resource »
|
Записан
|
|
|
|
urock
Участник
Offline
|
|
« Ответ #19 : 24-03-2010 06:44 » |
|
Ochkarik, да Device Instance ID должен где-то лежать в реестре, тока где это я не нашел) Но я просто плохо искал.
Решил проблему по-другому. Этого обрезанного кода мне хватает для идентификации устройства. Задача стояла следующая. Пользовательское приложение управляет несколькими одинаковыми платами. На платах ПЛИСы с PCI Express интерфейсом. Глобальная задача была обеспечить реконфигурацию ПЛИС без перезагрузки ОС. Сводилась она к тому, что надо перед реконфигурацией отключить устройство (disable), чтоб к нему никто не обращался, а после реконфигурации сделать рескан шины и включить устройство. Хотелось сделать это автоматически, т.е. чтоб пользовательское приложение управляло всем, оператор бы нажал кнопку и программа сама отключила бы устройство, перезалила прошивку, и включила его. Для этого мне и нужен был этот идентификатор - чтоб знать какое устройство отключать. А дальше я разбирал код программы devcon из DDK и совмещал его с моим кодом. Если интересно - позже могу рассказать как это делать подробнее.
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #20 : 24-03-2010 09:33 » |
|
Конечно интересно. Расскажешь
зы Мне кажется что для твоей задачи вполне достаточно было номера устройства относительно шины
|
|
|
Записан
|
|
|
|
PredatorAlpha
Помогающий
Offline
|
|
« Ответ #21 : 24-03-2010 18:12 » |
|
На платах ПЛИСы с PCI Express интерфейсом. Если не секрет, какие именно FPGA? PCI Express интерфейс сами разрабатывали или встроен в чип стандартный контроллер? Скольки линейный PCI Express? Хотя судя по тому что надо отключить, залить и включить то сами его разрабатывали....
|
|
|
Записан
|
|
|
|
urock
Участник
Offline
|
|
« Ответ #22 : 26-03-2010 07:21 » |
|
FPGA Xilinx Virtex 6. PCI Express ядро сами не разрабатывали. Там уже есть железное ядро + готовая обертка. Мы добавляли только user logic в проект. Сам модуль поддерживает 8 лэйнов.
|
|
|
Записан
|
|
|
|
PredatorAlpha
Помогающий
Offline
|
|
« Ответ #23 : 27-03-2010 07:42 » |
|
У нас на пятом виртексе четырёхлинейка. Не вполне понятно, зачем там нужна реконфигурация. Полной перепрошивки FPGA не может быть, иначе поплывёт логика PCIE (или вы пишете прошивку через драйвер куда-то на плату, запускаете и ждёте??).
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #24 : 27-03-2010 21:09 » |
|
PredatorAlpha, urock, кстати если не ошибаюсь была возможность грузить виртекс частями... или спартан. не разбирался, но ребята говорили что похожая возможность вроде была. кроме того - я подозреваю что можно по горячему платы менять(пусть не механически но на уровне логики шины). по крайней мере - существует же ExpressCard который включает PCI-E и USB. так что - почему бы и нет?
PS кстати а чем прошиваете? мы через PCI свой контроллер JTAG сваяли... по ieee1532. вот только xilinx bsdl-файлы описания не всегда с первого раза правильные выпускает)))
|
|
« Последнее редактирование: 27-03-2010 21:13 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
PredatorAlpha
Помогающий
Offline
|
|
« Ответ #25 : 28-03-2010 20:44 » |
|
PS кстати а чем прошиваете? мы через PCI свой контроллер JTAG сваяли... по ieee1532. вот только xilinx bsdl-файлы описания не всегда с первого раза правильные выпускает)))
Через стандарный внешний JTAG зашиваем бутовую флешку, из которой Xilinx сам грузит конфигурацию FPGA вместе с микропрограммой к встроенному PowerPC440. Переконфигурирование нам не требуется ... пока что, как минимум.
|
|
« Последнее редактирование: 28-03-2010 20:45 от PredatorAlpha »
|
Записан
|
|
|
|
urock
Участник
Offline
|
|
« Ответ #26 : 29-03-2010 07:04 » |
|
PredatorAlpha, да у нас разные схемы загрузки прошивки в ПЛИС. По одному варианту мы загружаем прошивку сначала в SPI Flash, затем я даю команду на перезагрузку, которая по таймеру откладывается на пару секунд, за которые программа как раз выключает устройство. Потом прошивка перезагружается, я делаю рескан шины и включаю устройство. Необходимость в этом может возникнуть у пользователя, когда тому надо будет другой алгоритм прокрутить на ПЛИС. По другому варианту прошивку можно грузить не из Flash, а из другого ПЛИС, установленного на модуле. Ochkarik, да эта частичная реконфигурация давно уже заявлена и Xilinx и Altera но никто пока не сделал нормальную возможность это использовать. По крайней мере я не пока не сталкивался с реально работающими системами, использующими частичную реконфигурацию. Вот тут Altera в очередной раз заявляет что в ее 28nm кристаллах будет user friendly partial reconfiguration http://fpgablog.com/posts/embedded-hardcopy-fpga/?utm_source=feedburner&utm_medium=email&utm_campaign=Feed:+fpgablog+(FPGA+Blog)
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #27 : 29-03-2010 12:16 » |
|
user friendly - это обнадеживает))) правда мы на Xilinx исторически сидим)
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
WWX
Участник
Offline
|
|
« Ответ #28 : 17-12-2019 09:57 » |
|
Практически аналогичная ситуация - тоже в драйвере хотелось бы получить "Instance ID". В принципе как получить в общем-то понятно (хотя пока не пробовал). Но меня смущает последнее предложение из документации Microsoft по запросу IRP_MN_QUERY_ID: After the IRP completes and the driver is finished with the ID, the driver must free the ID structure returned by the driver(s) that handled the query IRP. ( https://docs.microsoft.com/ru-ru/windows-hardware/drivers/kernel/irp-mn-query-id) Не совсем понятно чем освобождать возвращённую строку? ExFreePool здесь наверное не уместен?
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #29 : 17-12-2019 10:07 » |
|
добрый день! я так понимаю как раз ExFreePool - уместен, потому что: 1. If a driver returns ID(s) in response to this IRP, it allocates a WCHAR structure from paged pool to contain the ID(s). 2. The PnP manager frees the structure when it is no longer needed. а поскольку запрос посылает не PnP manager а вы то и освобождать - тоже вам.
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
WWX
Участник
Offline
|
|
« Ответ #30 : 17-12-2019 11:33 » |
|
Спасибо. Буду пробовать...
|
|
|
Записан
|
|
|
|
WWX
Участник
Offline
|
|
« Ответ #31 : 19-12-2019 11:45 » |
|
Получилось всё в точности, как и было описано выше - возвращается только последняя часть Instance ID (или это и есть сам Instance ID, а перед ним что-то вставляется?).
Получить полный можно с помощью IoGetDevicePropertyData (с параметром PropertyKey=&DEVPKEY_Device_InstanceId). Но этот способ не работает на Windows 7 (работает на Windows 10).
В связи с этим вопрос: Можно ли считать этот "обрубленный" Instance ID уникальным среди всех одинаковых плат (с одинаковыми VEN ID и DEV ID)?
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #32 : 20-12-2019 23:30 » |
|
не совсем понял вам надо в API получить или все таки в ядре? вот тут человек втыкал две клавиатуры, и вроде как пишет что в одном порту их винда ID не различала, а в разных - давала разный ID. Additional tests I tested the aforementioned Netgear USB WiFi card, and it has the same Device Instance ID, even when plugged in different ports, and even when plugged in different machines. I tested a generic USB key which provides a USB Serial number, and its behavior was the same as the USB WiFi card. In these cases, the Device Instance ID will be something like:
USB\VID_1221&PID_3234\00004700356 I tested two identical generic USB keyboards, and I plugged them (one at a time) in the same USB hub port. The Device Instance ID remained the same (and additionally, Windows didn't show the "Installing hardware" popup when I plugged in the second keyboard. The Device Instance ID was:
USB\VID_1C4F&PID_0002\7&15cdfaa&0&3 Then, I plugged one of the keyboards on a different USB port, and the Device Instance ID changed to:
USB\VID_1C4F&PID_0002\5&2eab04ab&0&1 и я уже подзабывать начал... мысль пришла - а этот ID не сам драйвер устройства формирует в ответ на IRP_MN_QUERY_ID?
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
WWX
Участник
Offline
|
|
« Ответ #33 : 23-12-2019 09:21 » |
|
не совсем понял вам надо в API получить или все таки в ядре? Всё это нужно для однозначной идентификации среди одинаковых PCIe плат (т. е. получить нужно и там и там). Проблема в том, что в user mode возвращается длинная строка, что-то вроде: PCI\VEN_xxxx&DEV_xxxx&SUBSYS_0000xxxx&REV_00\4&25438C51&0&0008 , т. е. в точности то же, что и в диспетчере устройств. В драйвере в ответ на запрос IRP_MN_QUERY_ID с: stack->Parameters.QueryId.IdType = BusQueryInstanceID; мне возвращается только хвост: "0008". А хотелось бы целиком всю строку: "4&25438C51&0&0008", которая судя по документации Microsoft однозначно идентифицирует одну плату (из всех одинаковых). Или хотя бы уверенность, что возвращаемого хвоста достаточно для такой идентификации. Из документаций Microsoft https://docs.microsoft.com/en-us/windows-hardware/drivers/install/device-instance-idshttps://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/irp-mn-query-idи т. п. не совсем понятно, что в моём примере является "instance ID". вот тут человек втыкал две клавиатуры, и вроде как пишет что в одном порту их винда ID не различала, а в разных - давала разный ID. Целиком вся эта строка (с VEN ID и DEV ID), насколько я понял, называется "Device Instance ID" и однозначно определяет устройство в системе. Первая её половина называется "device-ID". Вторая (после последнего слеша) называется то ли "instance ID" то ли хрен знает как, нося при этом гордый статус "opaque", т. е. её нельзя пытаться парсить. а этот ID не сам драйвер устройства формирует в ответ на IRP_MN_QUERY_ID? Судя по второй ссылке этот запрос должен обрабатывать драйвер шины. ---------- Замечено, что подобные строки ("4&25438C51&0&0008") располагаются в реестре в разделе оборудования (экземпляра) (HKLM\SYSTEM\CurrentControlSet\Enum) , и похоже что являются названиями подразделов конкретных устройств. Но, драйверу чуть ли не запрещено рыскать по реестру в поисках подобных имён. ---------- Моя же конкретная задача (раз уж речь пошла про реестр), возможно, решается проще без всяких ID. Драйвер сам формирует уникальный номер платы и записывает его в разделе оборудования (экземпляра) реестра. Приложение при перечислении устройств (функционал SetupApi) будет читать этот раздел и сравнивать считанный номер с нужным. Возможно придётся так делать, если с этими ID всё так запутано...
|
|
|
Записан
|
|
|
|
|
WWX
Участник
Offline
|
|
« Ответ #35 : 26-12-2019 07:20 » |
|
IoGetDevicePropertyData у меня отработал только на Windows 10, а нужно было, чтоб работало и на Windows 7. Последний способ (если это способ) мне не совсем понятен, больше похоже на описание, из чего эта строка состоит. Но всё равно на это описание нельзя полагаться, т. к. в будущих версиях всё может поменяться. Полностью согласен с: MSDN doc seems really vague on this! Свою же подзадачу я решил так, как описал в своём предыдущем сообщении. В любом случае: спасибо за помощь.
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #36 : 26-12-2019 08:36 » |
|
да, похоже на формат строки, но я не проверял насколько он верен. удачи)
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
|