Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Консольное окно. Как его перерисовать? Физически меняет заголовок.. 
:(
    Опции темы
ЧеловекБорща
Дата 2.9.2011, 13:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 5.6.2010

Репутация: нет
Всего: нет



Доброго времени суток! 

В моей программе была задача "менять заголовки консольных окон". 
Реализовал успешно. Но вот проблема:
Юзер задал заголовок "test"(Стандартный: "Console")

ФИЗИЧЕСКИ заголовок меняется... (Тыкаешь свойства окна, и там показывает "Свойства: "Test").
На экране отображает "Console".

Если перезапустить задачу в программе, то заголовок успешно изменится... 

Получается что не может задать заголовок, когда программа запускается и запускает задачи.. 

Как обновить окно консоли? И где можно подробно почитать про консольные окна и их работу и реализацию... 

PM MAIL   Вверх
Keeper89
Дата 2.9.2011, 23:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 14
Всего: 58



ЧеловекБорща, а можно в картинках?


--------------------
PM MAIL WWW   Вверх
ЧеловекБорща
Дата 2.9.2011, 23:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 5.6.2010

Репутация: нет
Всего: нет



Без проблем: 
user posted image

Где 123456 это тот заколовок который я задал окну.. 
Как перерисовать окно консольки? 
PM MAIL   Вверх
Keeper89
Дата 3.9.2011, 01:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 14
Всего: 58



А какой код для изменения заголовка?


--------------------
PM MAIL WWW   Вверх
ЧеловекБорща
Дата 3.9.2011, 01:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 5.6.2010

Репутация: нет
Всего: нет



вот такой: 
Код

            Sleep(Appinfo.ConNameChangeTime); //ждём...
            AttachConsole(Pinfo.dwProcessId); //привязывам консоль
            AppInfo.WindowHande := GetConsoleWindow; //Передаём хэндл окна
            //SetConsoleTitle(PChar(AppInfo.OtherCaption));
            SetWindowText(AppInfo.WindowHande, PChar(AppInfo.OtherCaption)); //пишем свой заголовок
            FreeConsole; //отваливаем


Но думаю вопрос может решить и CreateRemoteThread
PM MAIL   Вверх
~FoX~
Дата 4.9.2011, 10:54 (ссылка) |   (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЕ рыжий!!!
****


Профиль
Группа: Участник Клуба
Сообщений: 2819
Регистрация: 8.10.2003
Где: Зеленоград

Репутация: 0
Всего: 68



Цитата

Remarks

If the target window is owned by the current process, SetWindowText causes a WM_SETTEXT message to be sent to the specified window or control. If the control is a list box control created with the WS_CAPTION style, however, SetWindowText sets the text for the control, not for the list box entries.

To set the text of a control in another process, send the WM_SETTEXT message directly instead of calling SetWindowText.

The SetWindowText function does not expand tab characters (ASCII code 0x09). Tab characters are displayed as vertical bar (|) characters. 

Примерно так:
Код

SendMessage(AppInfo.WindowHande, WM_SETTEXT, 0, LPARAM(PChar('new console capture')));


Это сообщение отредактировал(а) ~FoX~ - 4.9.2011, 10:58


--------------------
user posted image
…множественность никогда не следует полагать без необходимости…
PM MAIL WWW ICQ Jabber   Вверх
ЧеловекБорща
Дата 4.9.2011, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 5.6.2010

Репутация: нет
Всего: нет



~FoX~, интересно! Работает. Но если запускать подряд 3 консольных окна, то изменяет заголовки то у 1 из 3 илиу 2 из 3 то вообще ни у одного. 
PM MAIL   Вверх
~FoX~
Дата 4.9.2011, 16:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЕ рыжий!!!
****


Профиль
Группа: Участник Клуба
Сообщений: 2819
Регистрация: 8.10.2003
Где: Зеленоград

Репутация: 0
Всего: 68



Значит не верно ловишь хэндл...


--------------------
user posted image
…множественность никогда не следует полагать без необходимости…
PM MAIL WWW ICQ Jabber   Вверх
ЧеловекБорща
Дата 4.9.2011, 17:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 5.6.2010

Репутация: нет
Всего: нет



~FoX~, как прикажешь его ловить? 

Имя окна Console класс ConsoleWindowClass


PM MAIL   Вверх
Keeper89
Дата 4.9.2011, 18:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 14
Всего: 58



ЧеловекБорща, ну так их же и должно быть несколько -> изменять надо несколько, изменив код на нахождение всех окон такого класса.


--------------------
PM MAIL WWW   Вверх
ЧеловекБорща
Дата 4.9.2011, 23:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 5.6.2010

Репутация: нет
Всего: нет



Так ведь и прикол то весь в том что для каждого консольного окна которое я запускаю. нужен СВОЙ заголовок. 
Нашёл из этого выход, подгружать dll внутрь процесса(грузится, меняет заголовок и выгружается).

Код dll:
Код

Library HookDLL;

const
  kernel32='kernel32.dll';
  DLL_PROCESS_ATTACH = 1;

type
    BOOL = LongBool;
    DWORD = LongWord;

function SetConsoleTitle(lpConsoleTitle: PChar): BOOL; stdcall; external kernel32 name 'SetConsoleTitleA';
procedure FreeLibraryAndExitThread(hLibModule: HMODULE; dwExitCode: DWORD); stdcall; external kernel32 name 'FreeLibraryAndExitThread';
function GetModuleHandle(lpModuleName: PChar): HMODULE; stdcall; external kernel32 name 'GetModuleHandleA';

procedure DLLEntryPoint(dwReason: DWORD);
begin
  case dwReason of
    DLL_PROCESS_ATTACH:
    begin
      SetConsoleTitle('THE BEST of the test!');
      FreeLibraryAndExitThread(GetModuleHandle('hooklib.dll'), 0);
      ExitCode := 0;
    end;
  end;
end;

begin
  DLLProc := @DLLEntryPoint;
  DLLEntryPoint(DLL_PROCESS_ATTACH);
end.


Код программы: 
Код

////////////////////////////////////////////////////////////////////////////////
//
//  ****************************************************************************
//  * Project   : Inject/Eject Library Demo
//  * Unit Name : main
//  * Purpose   : Демонстрационный пример внедрения
//  *           : библиотеки через CreateRemoteThread
//  * Author    : Александр (Rouse_) Багель
//  * Version   : 1.01
//  * HomePage  : http://rouse.drkb.ru
//  ****************************************************************************
//

unit main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, TlHelp32;

resourcestring
  BTN_INJECT = 'Inject';
  BTN_EJECT  = 'Eject';
  
const
  DLLName = 'hooklib.dll';

type
  TfrmMain = class(TForm)
    btnInjectEject: TButton;
    GroupBox: TGroupBox;
    lbStatus: TListBox;
    cbProcess: TComboBox;
    Label1: TLabel;
    procedure btnInjectEjectClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    UnloadAddrOffset: DWORD;
    procedure FillProcessCombo;
    function InjectLib(const ProcessID: DWORD): Boolean;
    function EjectLib(const ProcessID: DWORD): Boolean;
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

{ TfrmMain }

//  Обработчик кнопки на внедрение/выгрузку библиотеки
// =============================================================================
procedure TfrmMain.btnInjectEjectClick(Sender: TObject);
var
  PID: Integer;
begin
  PID := DWORD(cbProcess.Items.Objects[cbProcess.ItemIndex]);
    if InjectLib(PID) then
      lbStatus.Items.Add('Library injected succes.')
    else
      lbStatus.Items.Add('Library injected fail.');
end;

//  Пока наш процесс не получит отлабочные привилегии,
//  весь этот код работать не будет
// =============================================================================
function SetDebugPriv: Boolean;
var
  Token: THandle;
  tkp: TTokenPrivileges;
  ReturnLength: DWORD;
begin
  Result := false;
  // Получаем токен текущего процесса
  if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, Token) then
  try
    // Получаем Luid привилегии
    if LookupPrivilegeValue(nil, PChar('SeDebugPrivilege'), tkp.Privileges[0].Luid) then
    begin
      // Заполняем необходимые параметры
      tkp.PrivilegeCount := 1;
      tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      // Включаем привилегию
      Result := AdjustTokenPrivileges(Token, false, tkp, 0, nil, ReturnLength);
    end;
  finally
    CloseHandle(Token);
  end;
end;    

//  Функция внедряет библиотеку в удаленный процесс с PID равным ProcessID
//  Для успешного внедрения нужно передать адрес функции LoadLibraryA
//  и путь к загружаемой библиотеке.
//  Строку с путем необходимо разместить в алресном пространстве удаленного процесса
// =============================================================================
function TfrmMain.InjectLib(const ProcessID: DWORD): Boolean;
var
  Process: HWND;
  ThreadRtn: FARPROC;
  DllPath: String;
  RemoteDll: Pointer;
  BytesWriten: DWORD;
  Thread: DWORD;
  ThreadId: DWORD;
begin
  // Устанавливаем отладочные привилегии для нашего процесса
  Result := SetDebugPriv;
  if not Result then Exit;
  Process := 0;
  Thread := 0;
  try
    // Открываем процесс
    Process := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
      PROCESS_VM_WRITE, True, ProcessID);
    if Process = 0 then Exit;
    // Выделяем в нем память под строку
    DllPath := ExtractFilePath(ParamStr(0)) + DLLName;
    RemoteDll := VirtualAllocEx(Process, nil, Length(DllPath),
      MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
    if RemoteDll = nil then Exit;
    // Пишем путь к длл в его адресное пространство
    if not WriteProcessMemory(Process, RemoteDll, PChar(DllPath),
      Length(DllPath), BytesWriten) then Exit;
    if BytesWriten <> DWORD(Length(DllPath)) then Exit;
    // Получаем адрес функции из Kernel32.dll
    ThreadRtn := GetProcAddress(GetModuleHandle('Kernel32.dll'), 'LoadLibraryA');
    if ThreadRtn = nil then Exit;
    // Запускаем удаленный поток
    Thread := CreateRemoteThread(Process, nil, 0, ThreadRtn, RemoteDll, 0, ThreadId);
    if Thread = 0 then Exit;
    // Ждем пока удаленный поток отработает...
    if (WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0) then
      Result := True;
  finally
    // Удаленный поток свою задачу выполнил и загрузил нашу библиотеку,
    // можно освобождать занятую память...
    if RemoteDll <> nil then
      VirtualFreeEx(Process, @RemoteDll, 0, MEM_RELEASE);
    if Thread <> 0 then CloseHandle(Thread);
    if Process <> 0 then CloseHandle(Process);  
  end;
end;

//  Данная функция запускает в удаленном процессе поток
//  который стартует с инструкции JMP [EBX]
//  В EBX будет лежать адрес функции SelfUnload,
//  который будет выгружать библиотеку.
//  Адрес функции рассчитывается отдельно и равен
//  адресу загрузки библиотеки + смещение на саму функцию
// =============================================================================
function TfrmMain.EjectLib(const ProcessID: DWORD): Boolean;
var
  hModuleSnap: THandle;
  ModuleEntry: TModuleEntry32;
  Process: HWND;
  BytesWriten: DWORD;
  Thread: DWORD;
  ThreadId: DWORD;
  ExitCode: DWORD;
  PLibHandle: PDWORD;
  OpCode: PWORD;
  CurrUnloadAddrOffset: DWORD;
begin
  Result := False;
  // Находим адрес библиотеки
  hModuleSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessID);
  if hModuleSnap <> INVALID_HANDLE_VALUE then
  try
    FillChar(ModuleEntry, SizeOf(TModuleEntry32), #0);
    ModuleEntry.dwSize := SizeOf(TModuleEntry32);
    if not Module32First(hModuleSnap, ModuleEntry) then Exit;
    repeat
      if AnsiUpperCase(ModuleEntry.szModule) =
        AnsiUpperCase(DLLName) then
      begin
        // Получаем адрес функции
        CurrUnloadAddrOffset := ModuleEntry.hModule + UnloadAddrOffset;
        Break;
      end;
    until not Module32Next(hModuleSnap, ModuleEntry);
  finally
    CloseHandle(hModuleSnap);
  end;


  // Устанавливаем отладочные привилегии для нашего процесса
  Result := SetDebugPriv;
  if not Result then Exit;

  Process := 0;
  Thread := 0;
  try
    // Открываем процесс
    Process := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
      PROCESS_VM_WRITE, True, ProcessID);
    if Process = 0 then Exit;

    // Пишем опкод jmp [ebx]
    OpCode := VirtualAllocEx(Process, nil, 2,
      MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
    ModuleEntry.hModule := $23FF;
    if not WriteProcessMemory(Process, OpCode, @ModuleEntry.hModule,
      2, BytesWriten) then Exit;

    // Пишем адрес функции выгрузки (он будет лежать в EBX при старте потока)
    PLibHandle := VirtualAllocEx(Process, nil, 4,
      MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
    if not WriteProcessMemory(Process, PLibHandle, @CurrUnloadAddrOffset,
      4, BytesWriten) then Exit;

    // запускаем поток
    Thread := CreateRemoteThread(Process, nil, 0, OpCode,
      PLibHandle, 0, ThreadId);

    if Thread = 0 then Exit;
    // Ждем пока удаленный поток отработает...
    if (WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0) then
      if GetExitCodeThread(Thread, ExitCode) then
        Result := ExitCode = 0;
  finally
    // Удаленный поток свою задачу выполнил и загрузил нашу библиотеку,
    // можно освобождать занятую память...
    if OpCode <> nil then
      VirtualFreeEx(Process, @OpCode, 0, MEM_RELEASE);
    if PLibHandle <> nil then
      VirtualFreeEx(Process, @PLibHandle, 0, MEM_RELEASE);
    if Thread <> 0 then CloseHandle(Thread);
    if Process <> 0 then CloseHandle(Process);
  end;
end;

type
  PSYSTEM_THREADS = ^SYSTEM_THREADS;
  SYSTEM_THREADS  = packed record
    KernelTime: LARGE_INTEGER;
    UserTime: LARGE_INTEGER;
    CreateTime: LARGE_INTEGER;
    WaitTime: ULONG;
    StartAddress: Pointer;
    UniqueProcess: DWORD;
    UniqueThread: DWORD;
    Priority: Integer;
    BasePriority: Integer;
    ContextSwitchCount: ULONG;
    State: Longint;
    WaitReason: Longint;
  end;

  PSYSTEM_PROCESS_INFORMATION = ^SYSTEM_PROCESS_INFORMATION;
  SYSTEM_PROCESS_INFORMATION = packed record
    NextOffset: ULONG;
    ThreadCount: ULONG;
    Reserved1: array [0..5] of ULONG;
    CreateTime: FILETIME;
    UserTime: FILETIME;
    KernelTime: FILETIME;
    ModuleNameLength: WORD;
    ModuleNameMaxLength: WORD;
    ModuleName: PWideChar;
    BasePriority: ULONG;
    ProcessID: ULONG;
    InheritedFromUniqueProcessID: ULONG;
    HandleCount: ULONG;
    Reserved2 : array[0..1] of ULONG;
    PeakVirtualSize : ULONG;
    VirtualSize : ULONG;
    PageFaultCount : ULONG;
    PeakWorkingSetSize : ULONG;
    WorkingSetSize : ULONG;
    QuotaPeakPagedPoolUsage : ULONG;
    QuotaPagedPoolUsage : ULONG;
    QuotaPeakNonPagedPoolUsage : ULONG;
    QuotaNonPagedPoolUsage : ULONG;
    PageFileUsage : ULONG;
    PeakPageFileUsage : ULONG;
    PrivatePageCount : ULONG;
    ReadOperationCount : LARGE_INTEGER;
    WriteOperationCount : LARGE_INTEGER;
    OtherOperationCount : LARGE_INTEGER;
    ReadTransferCount : LARGE_INTEGER;
    WriteTransferCount : LARGE_INTEGER;
    OtherTransferCount : LARGE_INTEGER;
    ThreadInfo: array [0..0] of SYSTEM_THREADS;
  end;

  function NtQuerySystemInformation(
    SystemInformationClass: DWORD;
    SystemInformation : Pointer;
    SystemInformationLength : DWORD;
    var ReturnLength: DWORD
    ): DWORD; stdcall; external 'ntdll.dll';

procedure TfrmMain.FillProcessCombo;
const
  SystemProcessesAndThreadsInformation = 5;
  STATUS_INFO_LENGTH_MISMATCH = $C0000004;
var
  SystemInformation, Temp: PSYSTEM_PROCESS_INFORMATION;
  ReturnLength: DWORD;
begin
  cbProcess.Items.BeginUpdate;
  try
    cbProcess.Items.Clear;
    ReturnLength := 0;
    // Запрашиваем размер требуемой памяти
    if NtQuerySystemInformation(
      SystemProcessesAndThreadsInformation,
      nil, 0, ReturnLength) <> STATUS_INFO_LENGTH_MISMATCH then Exit;
    if ReturnLength > 0 then
    begin
      // Выделяем память
      GetMem(SystemInformation, ReturnLength);
      try
        // Получаем список процессов
        if NtQuerySystemInformation(SystemProcessesAndThreadsInformation,
          SystemInformation, ReturnLength, ReturnLength) = 0 then
        begin
          // Бежим по списку и заносим каждый в список
          Temp := SystemInformation;
          repeat
            // Добавляем все процессы за исключение системного и IDLE
            if (Temp^.ModuleName <> nil) and (Temp^.ProcessID <> 4) then
              cbProcess.Items.AddObject(
                Temp^.ModuleName, Pointer(Temp^.ProcessID));
            Temp := Pointer(DWORD(Temp) + Temp^.NextOffset);
          until Temp^.NextOffset = 0;
        end;
      finally
        FreeMem(SystemInformation);
      end;
    end;
  finally
    cbProcess.Items.EndUpdate;
  end;
end;

procedure TfrmMain.FormCreate(Sender: TObject);
var
  hLibHandle: THandle;
begin
  // Находим адрес функции
  FillProcessCombo;  
  hLibHandle := LoadLibraryEx(
    PChar(ExtractFilePath(ParamStr(0)) + DLLName), 0,
    DONT_RESOLVE_DLL_REFERENCES);
  try
    UnloadAddrOffset :=
      DWORD(GetProcAddress(hLibHandle, 'SelfUnload')) - hLibHandle;
    if UnloadAddrOffset = -hLibHandle then Exit;
  finally
    FreeLibrary(hLibHandle);
  end;
end;

end.



Теперь вопрос: 
Как из моей программы, передать DLL нужный мне текст. 


PM MAIL   Вверх
ЧеловекБорща
Дата 5.9.2011, 19:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 5.6.2010

Репутация: нет
Всего: нет



Народ=) Подсобите пожалуйста
PM MAIL   Вверх
Yanis
Дата 9.11.2011, 11:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 2937
Регистрация: 9.2.2004
Где: Москва

Репутация: 13
Всего: 111



Для задания заголовка консольным приложениям существует специальный параметр lpTitle в структуре TStartupInfo. Описание из MSDN:

Цитата
lpTitle
      For console processes, this is the title displayed in the title bar if a new console window is created.
      If NULL, the name of the executable file is used as the window title instead.
      This parameter must be NULL for GUI or console processes that do not create a new console window.


Код
var
  si: TStartupInfo;
  pi: TProcessInformation;
begin
  ZeroMemory(@si, SizeOf(si));
  with si do
  begin
    cb := SizeOf(cb);
    // Присваиваем консольному окну свой заголовок.
    // http://msdn.microsoft.com/en-us/library/windows/desktop/ms686331%28v=vs.85%29.aspx
    lpTitle := PChar(TimeToStr(Now) + ' | ' + IntToStr(GetTickCount));

    dwFlags := STARTF_USESHOWWINDOW;
    wShowWindow := SW_SHOWNORMAL;
  end;

  if not CreateProcess('c:\windows\system32\cmd.exe', nil, nil, nil, False,
    NORMAL_PRIORITY_CLASS, nil, nil, si, pi) then
    ShowMessage(SysErrorMessage(GetLastError));
end;



--------------------
user posted image *щёлк*
PM MAIL WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: WinAPI и системное программирование"
Snowybartram
MetalFanbems
PoseidonRrader
Riply

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Delphi обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • 99% ответов по WinAPI можно найти в MSDN Library, оставшиеся 1% здесь

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема »


 




[ Время генерации скрипта: 0.0908 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.