WMI. Введение.

Личный блог местного доктора. Здесь даются бесплатные медицинские консультации, обсуждаются вопросы здравоохранения и конечно же, программирования.

Модератор: dr.MIG

dr.MIG
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1441
Зарегистрирован: 18.12.2004 (Сб) 9:53
Откуда: г.Ярославль

WMI. Введение.

Сообщение dr.MIG » 17.04.2008 (Чт) 16:24

Эта статья посвящена технологии WMI. Чтобы дать исчерпывающие описание данного аспекта программирования, необходима целая книга, возможно даже не одна. В нашей статье мы рассмотрим частные вопросы взаимодействия с системой, используя WMI. Надеюсь, кому-нибудь она будет полезна и периодически появляющихся вопросов о том, что такое WMI, станет меньше. Тем более на сайте имеется всего одна статья, посвящённая WMI, да и та для VB.Net.

Взаимодействие с системой через WMI

Понятие о WMI
Windows Management Instrumentation (WMI), или инструментарий управления Windows – это промышленная инициатива по разработке стандартизированной технологии по доступу к информации управления в корпоративных средах. Эта информация включает в себя состояние памяти системы, информацию об установленных клиентских приложениях и другие данные о статусе клиента. Кроме того, WMI может использоваться для построения приложений, которые позволяют отслеживать и соответствующим образом реагировать на события системы.

Доступ к WMI может осуществляться через интерфейсы COM+ и .NET Framework. Таким образом, любой язык программирования, который поддерживает взаимодействие с COM+ и .NET Framework, может использоваться для работы с WMI.

Технология WMI реализована для всех 32-разрядных версий Windows, начиная с Windows 95 OSR 2 и заканчивая Windows Server 2003. В операционных системах Windows Me/2000/XP и Windows Server 2003 никакой дополнительной установки WMI не требуется, так как здесь уже функционирует ядро WMI версии 1.5. Для операционных систем Windows 9x/NT необходимо обновить ядро WMI до версии 1.5. Необходимый для этого инсталляционный файл wmicore.exe можно скачать с сервера Microsoft.

Структура WMI
Структуру WMI составляют:

    • Менеджер объектов общей информационной модели, или Common Information Model Object Manager (CIMOM). Он обеспечивает обработку всех запросов к WMI и доставку информации в ответ на этот запрос.
    • Репозиторий CIM. Представляет собой хранилище классов.
    Все классы, составляющие CIM, группируются в пространства имён (namespaces). Таким образом пространство имён WMI – это ни что иное как раздел (директория) репозитория WMI, которая призвана группировать классы и объекты WMI по назначению, а также определять атрибуты безопасности при доступе к классам и объектам в каждом таком контейнере.
    • Провайдеры WMI. Представляют собой COM-серверы, которые обеспечивают возможность получения системных данных из различных источников, таких как журнал событий, системны реестр и т.д.
    • Библиотека поддержки сценариев (WMI scripting library).

Подключение к WMI
Для подключения к WMI в своей программе можно использовать WMI-моникер (WMI moniker) или объект SWbemLocator. Независимо от того, каким способом осуществляется подключение, возвращается объект SWbemServices.

Подключение с помощью WMI-моникер
Моникер – это строка определённой структуры, задающая путь к классу, экземпляр которого должен быть создан.
Моникер состоит из следующих частей:

    • Обязательный префикс "winmgmts:".
    • Настройки безопасности WMI.
    Необязательный параметр, указывается после префикса “winmgmts:” в скобках {}.
    • Путь к нужному объекту WMI.
    Необязательный параметр, указывается после “!” или, в случае отсутствия настроек безопасности, сразу после префикса “winmgmts:”.
    Полный путь к классу CIM имеет следующую структуру:
    \\ComputerName\Namespace:ClassName.KeyProperty1=Value1, KeyProperty2=Value2 ...
    , где:
    ComputerName - сетевое имя компьютера. Для задания локального компьютера необходимо использовать символ ".".
    Namespace - название пространства имён.
    ClassName - имя класса.
    KeyProperty1=Value1, KeyProperty2=Value2 ... - список ключевых свойств объекта и их значений.

Примером моникера может служить следующая строка:
"winmgmts:{impersonationLevel=Impersonate, authenticationLevel=PktPrivacy, (Shutdown)}!\\ .\ROOT\CIMV2"

В этой строке impersonationLevel=Impersonate – уровень имперсонации, authenticationLevel=PktPrivacy – уровень аутентификации, (Shutdown) – привилегия.
Более подробную информацию вы найдёте в разделе «Настройки безопасности WMI»

Для подключения к указанному пространству имён, необходимо передать моникер как параметр функции GetObject:

Код: Выделить всё
Set objWMIServices = GetObject("winmgmts:{impersonationLevel=Impersonate, authenticationLevel=PktPrivacy, (Shutdown)}!\\ .\ROOT\CIMV2")


Подключение с помощью объекта SWbemLocator
Для подключения SWbemLocator, добавьте ссылку (меню Project->References) на объект Microsoft WMI Scripting V1.2 Library и добавьте объявления в секцию Declaration:

Код: Выделить всё
Private objSWbemLocator As New SWbemLocator
Private objSWbemServices As SWbemServices


Конечно, можно использовать и позднее связывание:
Код: Выделить всё
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")

Однако раннее связывание имеет ряд преимуществ: возможность познакомится со структурой библиотеки Microsoft WMI Scripting в Object Browser; лёгкость написания кода в IDE; меньше шансов допустить ошибку в синтаксисе, более высокая скорость кода.


Единственный метод ConnectServer объекта SWbemLocator позволяет подключиться к WMI и получить ссылку на объект SWbemServices. Синтаксис вызова метода:

Set objSWbemServices = objSWbemLocator.ConnectServer([strServer], [strNamespace], [strUser], [strPassword], [strLocale], [strAuthority], [iSecurityFlags], [objWbemNamedValueSet])
, где:
strServer - имя компьютера.
strNamespace - пространство имён.
strUser - имя пользователя в формате «Домен/Имя пользователя». Параметр используется только для удалённого соединения.
strPassword - пароль пользователя.
strLocale - код локализации. Формат строки - "MS_xxxx", где xxxx - строка в шестнадцатеричной форме, которая указывает LCID.
strAuthority - имя домена.
Если домен уже определен в параметре strUser, повторное указание домена в этом параметре приведёт к ошибке.
iSecurityFlags – флаг, который влияет на время ожидания подключения. Если параметр установлен в 0, управление будет передано на следующую строку программы только после того, как подключение к серверу будет установлено. Если параметр установлен в 128, максимальное время ожидания подключения - 2 минуты.
objWbemNamedValueSet - ссылка на объект SWbemNamedValueSet.
Объект SWbemLocator позволяет установить соединение с определённым пространством имён WMI на удалённом компьютере от имени заданной учётной записи или на локальном компьютере от имени текущей учётной записи. Использование этого объекта необходимо, если в сценарии нужно явно задать имя пользователя и пароль для подключения к пространству имён WMI.

Настройки безопасности WMI
В основе вопросов безопасности WMI лежит три понятия – имперсонация (олицетворение), аутентификация (проверка подлинности) и привилегии.

Пользователь, который подключается к WMI на удалённом компьютере выступает в роли клиента, а объект WMI, к которому он подключается – в роли сервера. Для того, чтобы определить, какие права будут применяться при работе с WMI, используют уровни имперсонации. Возможные уровни имперсонации перечислены ниже:

Default (0) - Уровень имперсонации по умолчанию.
Anonymous (1) - Анонимный уровень имперсонации, маскирующий учетную запись клиента. Обычно этот уровень не используется, так как вызов с ним может завершиться ошибкой.
Identify (2) - Уровень имперсонации – идентификация. Позволяет серверу запрашивать учетные данные у клиента. Вызов WMI с этим уровнем имперсонации может завершиться ошибкой при попытке запуска сценария на удалённой машине.
Impersonate (3) - Уровень имперсонации – обычная имперсонация. Позволяет серверу использовать все учетные данные клиента для совершения своих действий. Этот уровень используется наиболее часто.
Delegate (4) - Уровень имперсонации – делегирование. Разрешает использовать серверу учетные данные клиента для обращения к третьим объектам. Этот уровень может нести в себе потенциальную угрозу, так как промежуточному объекту в этом случае могут быть присвоены неоправданно высокие привилегии.

При работе с WMI также используется аутентификация – проверка подлинности. Возможные её уровни представлены ниже:

Default (0) - Уровень аутентификации по умолчанию.
None (1) - Аутентификация не используется.
Connect (2) - Аутентификация клиента происходит только при установлении соединения с сервером. В течении всего последующего сеанса никаких проверок подлинности не происходит.
Call (3) - Аутентификация клиента происходит перед каждым вызовом объекта WMI.
Pkt (4) - Аутентификация всех данных, получаемых от клиента, с подтверждением подлинности отправителя для каждого пакета.
PktIntegrity (5) - Аутентификация и проверка целостности передаваемых данных для каждого пакета.
PktPrivacy (6) - Аутентификация, проверка целостности и шифрование данных каждого передаваемого пакета.

Привилегии представляют собой дополнительный механизм защиты, суть которого заключается в том, что для выполнения какого-либо запроса к объекту WMI, необходимо в программном коде перед этим запросом явно указать соответствующую привилегию, иначе запрос выполнен не будет, даже если клиент обладает достаточными для этого привилегиями.

Список и описание привилегий представлены ниже.
Здесь в качестве названия привилегии приведено два значения – первое используется при подключении к WMI, используя объект SWbemLocator, второе – при подключении через моникер:

wbemPrivilegeCreateToken | CreateToken (1) - Привилегия требуется для создания основного токена безопасности процесса
wbemPrivilegePrimaryToken | AssignPrimaryToken (2) -Привилегия требуется для замены (назначения нового) основного токена безопасности процесса
wbemPrivilegeLockMemory | SeLockMemoryPrivilege (3) - Привилегия требуется для закрепления соответствия между страницами физической памяти и логического адресного пространства
wbemPrivilegeIncreaseQuota | IncreaseQuotaPrivilege (4) - Привилегия требуется для назначения квот процессу
wbemPrivilegeMachineAccount | MachineAccount (5) - Привилегия требуется для создания учетной записи компьютера
wbemPrivilegeTcb | Tcb (6) - Привилегия обозначает ее владельца как часть Trusted Computer Base
wbemPrivilegeSecurity | Security (7) - Привилегия требуется для выполнения ряда функций, связанных с безопасностью, например просмотр журналов аудита. Привилегия определяет её владельца как Security Operator
wbemPrivilegeTakeOwnership | TakeOwnership ( 8 ) - Привилегия требуется для получения права владельца объекта на объекты безопасности в отсутствии явных на то разрешений
wbemPrivilegeLoadDriver | LoadDriver (9)
- Привилегия требуется для загрузки и выгрузки драйверов устройств
wbemPrivilegeSystemProfile | SystemProfile (10)
- Привилегия требуется для сбора профилирующей информации всей системы
wbemPrivilegeSystemtime | Systemtime (11) - Привилегия требуется для изменения системного времени
wbemPrivilegeProfileSingleProcess | ProfileSingleProcess (12)
- Привилегия требуется для сбора профилирующей информации для одного процесса
wbemPrivilegeIncreaseBasePriority | IncreaseBasePriority (13) - Привилегия требуется для увеличения базового проиритета процесса
wbemPrivilegeCreatePagefile | CreatePagefile (14) - Привилегия требуется для создания и (или) изменения файла подкачки
wbemPrivilegeCreatePermanent | CreatePermanent (15) - Привилегия требуется для создания постоянного общего объекта
wbemPrivilegeBackup | Backup (16) - Привилегия требуется для выполнения резервного копирования
wbemPrivilegeRestore | Restore (17) - Привилегия требуется для выполнения операции восстановления. Эта привилегия позволяет ее владельцу устанавливать для любого объекта произвольный существующий SID в качестве владельца объекта
wbemPrivilegeShutdown | Shutdown ( 18 ) - Привилегия требуется для перезагрузки и завершения работы ОС
wbemPrivilegeDebug | Debug (19) - Привилегия требуется для отладки процессов
wbemPrivilegeAudit | Audit (20) - Привилегия требуется для записи в журналы аудита
wbemPrivilegeSystemEnvironment | SystemEnvironment (21) - Привилегия требуется для модификации энергонезависимой памяти в тех системах, которые используют ее для хранения своей конфигурации
wbemPrivilegeChangeNotify | ChangeNotify (22) - Привилегия требуется для получения нотификаций об изменении файлов и директорий. Так же эта привилегия отменяет перекрестную проверку доступа к файлам и папкам. Эта привилегия по умолчанию дана всем пользователям
wbemPrivilegeRemoteShutdown | RemoteShutdown (23) - Привилегия требуется для завершения работы ОС по сети
wbemPrivilegeUndock | Undock (24) - Привилегия требуется для снятия компьютера с док-станции
wbemPrivilegeSyncAgent | SyncAgent (25) - Привилегия требуется для вызова процедуры синхронизации службы каталога
wbemPrivilegeEnableDelegation | EnableDelegation (26) - Привилегия требуется для доверия пользователям или группам при делегировании
wbemPrivilegeManageVolume | ManageVolume (27) - Привилегия требуется для операций обслуживания дисковых томов

Понятие о WMI
Все события можно разделить на три группы:

    • Внешние события, происходящие в объекте, не имеющем в CIM собственного отдельного класса. Внешние события представлены классом __ExtrinsicEvent.
    Примером может служить изменение определённого значения в реестре.
    • Внутренние события, происходящие в объекте, который представлен в CIM отдельным классом, а также изменения, происходящие в самом CIM. Внутренние события представлены классами __NamespaceOperationEvent, __ClassOperationEvent, __InstanceOperationEvent, а так же производными от класса __InstanceOperationEvent - __InstanceCreationEvent, __InstanceModificationEvent и __InstanceDeleionEvent, отвечающими за создание, модификацию и удаление экземпляра класса соответственно.
    • События таймера, которые происходят через определённый интервал времени. События таймера представлены классом __TimerEvent.


Обработка событий может осуществляться в трёх режимах – синхронном, полусинхронном и асинхронном. Кроме того, возможно создание постоянных потребителей событий WMI.

Суть синхронной обработки события заключается в том, что выполнение программы не продолжится до тех пор, пока вызываемый метод не будет выполнен до конца.

При полусинхронном режиме управление передаётся в программу сразу после вызова метода, даже если возвращены ещё не все данные.

Асинхронная обработка подразумевает, что процесс подписывается на определённое событие (выполняется уведомляющий запрос), затем управление передаётся в программу, которая продолжает выполнять свои задачи. Когда это событие возникает, работа программы приостанавливается, управление передаётся на зарегистрированный обработчик события. После обработки события, выполнение программы возобнавляется.

Процесс создание постоянных потребителей событий WMI заключается в трёх последовательных этапах – регистрация фильтра события (создание экземпляра класса __EventFilter), регистрация потребителя события (создание экземпляра одного из потомков класса __EventConsumer), установка связи между фильтром и потребителем события (создание экземпляра класса __FilterToConsumerBinding).

Упрощение работы с WMI
Для помощи написания программного кода, существует множество различных утилит. Одной из наиболее удобной является WMI Code Creator, которую можно скачать с официального сайта Microsoft. Данная программа вам позволит познакомиться со структурой WMI и иерархией классов, кроме того при помощи её вы сможете с лёгкостью создавать различные WMI-скрипты, а так же очень быстро получать контекстную справку из on-line библиотеки MSDN по выбранному классу WMI.

Примеры использования WMI в программе
Для иллюстрации всего описанного в этой статье, создадим несколько примеров работы с WMI.

Пример 1. Получение некоторой информации о компьютере.
Данный пример иллюстрирует получение данных из классов WMI в полусинхронном режиме.

Добавьте на форму кнопку с именем cmdPCInfo. При нажатии на неё вы получите некоторую информацию о компьютере:

Код: Выделить всё

Private Sub cmdPCInfo_Click()
    Dim strReport As String, strComputer As String
    strComputer = "."
    Set objSWbemService = GetObject( _
        "winmgmts:\\" & strComputer & "\ROOT\CIMV2")
    Set colItemsOS = objSWbemService.ExecQuery( _
        "SELECT * FROM Win32_OperatingSystem", , 48)
    Set colItemsProcessor = objSWbemService.ExecQuery( _
        "SELECT * FROM Win32_Processor", , 48)
    For Each objItem In colItemsOS
        strReport = "---------------------------------------------------------------------" & vbCrLf _
            & "ОС: " & objItem.Caption _
            & " " & objItem.CSDVersion & vbCrLf _
            & "Версия: " & objItem.Version & vbCrLf _
            & "Производитель: " & objItem.Manufacturer & vbCrLf _
            & "Пользователь: " & objItem.RegisteredUser & vbCrLf _
            & "Организация: " & objItem.Organization & vbCrLf _
            & "Серийный номер: " & objItem.SerialNumber & vbCrLf _
            & "ОЗУ: " & CLng(objItem.TotalVisibleMemorySize / 1024) & " Мб" & vbCrLf
    Next
    For Each objItem In colItemsProcessor
        strReport = strReport & "---------------------------------------------------------------------" & vbCrLf _
            & "Процессор: " & objItem.Name & vbCrLf _
            & objItem.Version & vbCrLf _
            & "Разрядность процессора: " & objItem.AddressWidth & vbCrLf _
            & "---------------------------------------------------------------------" & vbCrLf
    Next
            MsgBox strReport, vbOKOnly, "Инфрмация о компьютере"
End Sub


В этом примере используется метод ExecQuery (strQuery, [strQueryLanguage = "WQL"], [iFlags = 16], [objWbemNamedValueSet = null]). Этот метод выполняет запрос на языке WQL и возвращает коллекцию объектов SWbemObjectSet.
Параметры:
strQuery - текст запроса.
strQueryLanguage - язык запросов. Единственное возможное значение – “WQL”.
iFlags - комбинация флагов. В нашем случае 48 = 16 + 32, где:
16 (wbemFlagReturnImmediately) - немедленный возврат результатов запроса (полусинхронный режим),
32 (wbemFlagForwardOnly) – навигация по коллекции осуществляется только вперёд, при этом осуществляется максимальная производительность и экономия памяти.
objWbemNamedValueSet - ссылка на объект SWbemNamedValueSet.

Пример 2. Выключение компьютера.
Данный пример иллюстрирует выполнение метода одного из классов WMI.

Добавьте на форму кнопку с именем cmdShutdown. При нажатии на неё компьютер выключится:
Код: Выделить всё

Private Sub cmdShutdown_Click()
    Dim strComputer As String
    strComputer = "."
    Set objSWbemService = GetObject( _
    "winmgmts:{impersonationLevel=Impersonate, authenticationLevel=PktPrivacy, (Shutdown)}!\\" _
    & strComputer & "\ROOT\CIMV2")
    Set colItems = objSWbemService.ExecQuery( _
        "SELECT * FROM Win32_OperatingSystem", , 48)
    For Each objItem In colItems
        Set objOutParams = objSWbemService.ExecMethod( _
        "Win32_OperatingSystem.Name='" & CStr(objItem.Name) & "'", "Shutdown")
    Next
End Sub


Метод ExecMethod(strObjectPath, strMethodName, [objWbemInParams = null], [iFlags = 0], [objWbemNamedValueSet = null]) исполняет указанный метод определённого объекта.
Параметры:
strObjectPath - путь к объекту.
strMethodName - имя метода.
objWbemInParams - ссылка на объект SWbemObject, содержащий входные параметры для исполняемого метода.
iFlags – параметр зарезервирован, обязательно должен быть равен нулю.
objWbemNamedValueSet - ссылка на объект SWbemNamedValueSet.

Так же обратите внимание на строку подключения: "winmgmts:{impersonationLevel=Impersonate, authenticationLevel=PktPrivacy, (Shutdown)}!\\" _
& strComputer & "\ROOT\CIMV2")
. В ней мы явно задали привилегию, необходимую, для выключения компьютера (Shutdown). Если бы мы этого не сделали, то даже, если бы наша программа обладала достаточными для этого действия полномочиями, выключения не произошло бы (см. раздел «Настройки безопасности WMI»).

Пример 3. Контроль за изменениями значения параметра в реестре.
Данный пример иллюстрирует подписку на внешнее событие и его асинхронную обработку. Кроме того в примере показано, как, используя WMI, можно работать с реестром.

Добавьте на форму два переключателя с именами optRegHook и optRegUnHook. Пока выбран первый будет осуществляться контроль за значением определённого параметра в реестре, и в случае его изменения, будет восстановлено прежнее значение. Выбор второго переключателя останавливает контроль за реестром.

Сначала создадим параметр реестра, для этого в процедуру загрузки формы добавим следующий код:
Не забудьте в секции Declaration модуля формы объявить:
Код: Выделить всё
Private Const HKEY_LOCAL_MACHINE = &H80000002
Private objReg As Object

Private Sub Form_Load()
    Dim strComputer As String
    strComputer = "." 'локальный компьютер
    'добавляем новое значение в реестр
    Set objReg = GetObject( _
    "winmgmts:{impersonationLevel = Impersonate}!\\" _
    & strComputer & "\ROOT\DEFAULT:StdRegProv")
    objReg.CreateKey HKEY_LOCAL_MACHINE, "SOFTWARE\WMIProgram\"
    objReg.SetStringValue HKEY_LOCAL_MACHINE, "SOFTWARE\WMIProgram\", "DefValue", "myValue"
End Sub


Теперь осуществим подписку на внешнее событие – изменение значения параметра реестра (RegistryValueChangeEvent). Для этого добавьте в процедуру обработки выбора переключателя с именем optRegHook следующий код, а в секцию Declaration модуля формы добавьте Private WithEvents objSink As SWbemSink:

Код: Выделить всё
Private Sub optRegHook_Click()
    Set objSWbemServices = GetObject( _
    "winmgmts:\\.\ROOT\DEFAULT")
    Set objSink = New SWbemSink
    objSWbemServices.ExecNotificationQueryAsync _
        objSink, "SELECT * FROM RegistryValueChangeEvent " _
        & "WHERE Hive='HKEY_LOCAL_MACHINE' AND " _
        & "KeyPath='SOFTWARE\\WMIProgram' " _
        & "AND ValueName='DefValue'"
End Sub


Метод ExecNotificationQueryAsync(objWbemSink As Object, strQuery As String, [strQueryLanguage As String = "WQL"], [iFlags As Long], [objWbemNamedValueSet As Object], [objWbemAsyncContext As Object]) осуществляет асинхронный уведомляющий запрос.
Параметры:
objWbemSink - специальный объект, события которого обрабатываются, когда возникает событие, на которое выполнена подписка.
strQuery - текст запроса.
strQueryLanguage - язык запросов. Единственное возможное значение – “WQL”.
iFlags - комбинация флагов.
objWbemNamedValueSet - ссылка на объект SWbemNamedValueSet.
objWbemAsyncContext - ссылка на объект SWbemAsyncContext.

Так как объект objSink был объявлен WithEvents, мы можем обрабатывать его события. Когда изменяется значение нашего параметра реестра, генерируется событие objSink_OnObjectReady, добавим в процедуру его обработки, код, который восстановит исходное значение параметра реестра:

Код: Выделить всё
Private Sub objSink_OnObjectReady(ByVal objWbemObject As WbemScripting.ISWbemObject, ByVal objWbemAsyncContext As WbemScripting.ISWbemNamedValueSet)
    ‘Восстанавливаем исходное значение параметра реестра
    objReg.SetStringValue HKEY_LOCAL_MACHINE, "SOFTWARE\WMIProgram\", "DefValue", "myValue"
End Sub


Выполнение следующего кода, добавленного в процедуру обработки выбора переключателя с именем optRegUnHook, остановит процесс слежения за значением параметра реестра.

Код: Выделить всё
Private Sub optRegUnHook_Click()
    objSink.Cancel
    Set objSink = Nothing
End Sub


При выходе из программы удалим созданный нами параметр реестра:

Код: Выделить всё
Private Sub Form_Unload(Cancel As Integer)
    objReg.DeleteKey HKEY_LOCAL_MACHINE, "SOFTWARE\WMIProgram\"
    If optRegHook.Value = True Then
        objSink.Cancel
    End If
    Set objSink = Nothing
End Sub


Для того, чтобы проверить работу этой программы, запустите её, выберите переключатель с именем optRegHook. После этого откройте редактор реестра, найдите созданный параметр и измените его значение. Посмотрите ещё раз его значение и вы увидите, что оно прежнее.

О WMI вы также можете почитать на официальном сайте Microsoft http://msdn2.microsoft.com/en-us/library/aa384642(VS.85).aspx
При написании статьи использовался материал http://www.samag.ru/art/02.2006/02.2006_02.html
У вас нет доступа для просмотра вложений в этом сообщении.
Salus populi suprema lex

Вернуться в dr.MIG

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6

    TopList