Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2004.08.22;
Скачать: [xml.tar.bz2];

Вниз

Загрузка и выгрузка dll в чужой процесс   Найти похожие ветки 

 
bar   (2004-07-08 15:16) [0]

Загружаю свой дллку в процесс explorer`a с помощью хука на WH_GETMESSAGE. Загрузка проходит нормально. Но потом не могу выгрузить эту библиотеку. Хотя по идеи всё должно быть OK. Дескриптор загруженной в эксплорер библиотеки я первоночально сохранял в FileMapping и потом пытался выгрузить дллку по этому дескриптору из хука эксплорера(адресного пространства). Потом заметил, что при очередной загрузки loadlibrary возвращает одинаковый дескриптор уже загруженной дллки и использовал это для выяснения дескриптора библиотеки в адреснов пространстве explorer`а, но все равно не выгружается. Ж:-(
Помогите кто понял суть проблемы, может предложите другой мметод загрузки и выгрузки библиотеки в чужой процесс или объясните где у меня ошибка.

Пример кода из библиотеки хука.
type
   PGlobalDLLData = ^TGlobalDLLData;
   TGlobalDLLData = packed record
       SysHook: HWND; // дескриптор установленной ловушки
       MyAppWnd: HWND; // дескриптор нашего приложения
       Flag: Boolean;
       HLIB: THANDLE;
   end;
var
   GlobalData: PGlobalDLLData;
   MMFHandle: THandle;
   H: THAndle;
   GetAndSet: procedure(h: integer); stdcall; // процедура из 2-ой ДЛЛки, которая заменит оконную процедуру часов.

..............

//Процедура хука
function CallWndProc(
   nCode: integer; // hook code
   wParam: WPARAM; // current-process flag
   lParam: LPARAM // address of structure with message data
   ): LRESULT; stdcall;
var
   hl: THAndle;
   ok, a: boolean;
begin
   if nCode = HC_ACTION then
   begin
       ok := false;
       if tmsg(pointer(lparam)^).hwnd = H then
       begin
           ok := true;
           if GlobalData^.Flag then
{ Если GlobalData^.Flag=true загружаем дллку в процесс окна с хендлом H}
           begin
               GlobalData^.HLIB := loadlibrary(remdll);
               @GetAndSet := nil;
               if GlobalData^.HLIB > HINSTANCE_ERROR then
               begin
                   @GetAndSet := GetProcAddress(GlobalData^.HLIB, "GetAndSet");
                   if @GetAndSet <> nil then
                       GetAndSet(H)
               end else
           end else
           begin{ Если GlobalData^.Flag=false загружаем дллку в процесс окна с хендлом H}
               PostMessage(H, WM_User + 456, 0, 0);
               sleep(1000);
               hl := loadlibrary(remdll);
               repeat
                   a := FreeLibrary(Hl);
                   PostMessage(GlobalData^.MyAppWnd,
                       WM_MYCMD, $55, HL);
                   PostMessage(GlobalData^.MyAppWnd,
                       WM_MYCMD, $56, integer(a));
               until a;
           end;
       end;
       result := CallNextHookex(GlobalData^.SysHook, ncode, wparam, lparam);
       if ok then

           UnHookWindowsHookEx(GlobalData^.SysHook);
   end
   else
       result := CallNextHookex(GlobalData^.SysHook, ncode, wparam, lparam);
   //
end;
......


 
DeadMeat ©   (2004-07-08 23:50) [1]

Дай угадаю... Ты прочитал статью на xakep.ru, про невидимый процесс?? Просто интересно...

---
...Death Is Only The Begining...


 
Kerk ©   (2004-07-09 08:31) [2]

Попробуй GetModuleHandle / FreeLibrary


 
Digitman ©   (2004-07-09 08:41) [3]


> bar   (08.07.04 15:16)  


открой процесс эксплорера (см. OpenProcess)

запроси в АП эксплорера блок вирт.памяти c параметром защиты страниц PAGE_EXECUTE_READWRITE под дальнейшее размещение там кода поточной ф-ции (см. VirtualAllocEx)

скопируй в этот блок памяти код поточной ф-ции (см. WriteProcessMemory)

стартуй в АП эксплорера удаленный кодовый поток вызовом CreateRemoteThread(), в качестве параметра, указывающего адрес поточной ф-ции, передай адрес точки входа в скопированную поточную ф-цию в АП эксплорера

при удаленном старте потока поточная ф-ция получает управление и загружает твою библиотеку в АП эксплорера, после чего завершается


 
Digitman ©   (2004-07-09 08:49) [4]


> bar   (08.07.04 15:16)  


а если уж пошел методом глоб.хука, то выкрутасы с обработкой WH_GETMESSAGE и иже с ним вовсе не нужны для этой цели

в момент загрузки хук-модуля в АП процесса эксплорера процедура иниц-ции хук-модуля получает управление, и в этот момент как раз и можно выполнить loadlibrary() ... но перед тем как выполнить loadlibrary() процедура иниц-ции хук-модуля должна проанализировать имя тек.процесса и выполнить loadlibrary() лишь в том случае, если вызов GetModuleFileName вернул именно explorer.exe, иначе библ-ка будет загружена во все GUI-процессы, а не только в эксплорер


 
SammIk ©   (2004-07-09 09:50) [5]

Дескриптор возвращаемыи лоадлиброри, это адрес
куда грузится библеотека.
А винлоадер старается грузить их в одно место,
по этому возвращает один хендл


 
bar   (2004-07-09 10:14) [6]

>>DeadMeat ©   (08.07.04 23:50) [1]
Нет не процесс невидимка. Просто нужно отловить некоторые сообщения SHELLDLL_DefView, а хук на него не работает(Runtime error 216 at FF640227 при нажатии win+d )( см ветку)
http://delphimaster.net/view/4-1089095680/
Кстати кто нибудь знает что такое Runtime error 216 ?

>>Digitman ©   (09.07.04 08:49) [4]
Знаю. Делал загрузку dll-ки в процесс в момент загрузки библиотеки хука, результат такой же, даже гдето глюков больше (скорее всего код корявый)а с WH_GETMESSAGE это второй более отлаженный вариант. Кроме того разве влияет то кога грузить dll.?
>>Digitman ©   (09.07.04 08:41) [3]
а как её потом выгрузить

>>Kerk ©   (09.07.04 08:31) [2]
Попробуй GetModuleHandle / FreeLibrary
В каком процессе? В споем приложении пробовал http://delphiworld.narod.ru/base/kill_dll.html не работает. В процессе explorer`a сейчас попробую.


 
DeadMeat ©   (2004-07-09 10:23) [7]


> Нет не процесс невидимка

Ну извини... Просто код взят из этой статьи...

---
...Death Is Only The Begining...


 
bar   (2004-07-09 10:38) [8]

>>DeadMeat ©   (09.07.04 10:23) [7]
Ну да, скоприровал откуда-то и подправил для свох нужд.
Но скопировал не с xakep.ru
Кстати а там про выгрузку длл есть инфа. Пойду посмотрю.


 
Тимохов ©   (2004-07-09 10:41) [9]

не совсем въехал про что тут говорится (квалификации не хватает), но про запуск потока в другом прочессе через загрузку/выгрузку библиоткb подробно рассказывается в главе 21, 22 или 23 рихтера 4 издание (ключевое слово для поиска CreateRemoteThread).


 
Digitman ©   (2004-07-09 10:42) [10]


> bar   (09.07.04 10:14) [6]


> как её потом выгрузить


все просто - вновь стартуй удаленный трэд, который выполнит freelibrary()


 
Тимохов ©   (2004-07-09 10:50) [11]

Это не офф, т.к. в струе вопроса.

> Digitman ©   (09.07.04 10:42) [10]

Я так понимаю, что Вы имеете в виду стартовать удаленный поток с поточкной функцией, равной FreeLibrary. Но при этом должна быть уверенность в том, что kernel32.dll загружена по тому же базовому адресу. По факту оказывается именно так - kernel32.dll загруже всегда по одному и тому же базовому адресу. Я уже подинмал этот вопрос, но тогда ответа не получил  - где факт того, что kernel32.dll загружена по одному адресу описан в msdn?


 
bar   (2004-07-09 11:12) [12]

>>Digitman ©   (09.07.04 10:42) [10]
А пример можно пожалуйста. А то я с WriteProcessMemory не общался.


 
Digitman ©   (2004-07-09 11:16) [13]


> Тимохов ©   (09.07.04 10:50) [11]
> Это не офф, т.к. в струе вопроса.
>
> > Digitman ©   (09.07.04 10:42) [10]
>
> Я так понимаю, что Вы имеете в виду стартовать удаленный
> поток с поточкной функцией, равной FreeLibrary


неправильно понимаешь
поточная ф-ция вызывает FreeLibrary

> bar   (09.07.04 11:12) [12]
> >>Digitman ©   (09.07.04 10:42) [10]
> А пример можно пожалуйста. А то я с WriteProcessMemory не
> общался.


а почитать для начала справку и первоисточники ?


 
bar   (2004-07-09 11:20) [14]

Я думал Вам просто дать пример. Или ссылку хорошую по теме.
Ну ладно буду искать.

см http://delphimaster.net/view/4-1089095680/
А первоисточники на русском не посоветуете. Лучше в инете.


 
Digitman ©   (2004-07-09 11:23) [15]


> bar   (09.07.04 11:20) [14]


ну держи, не жалко

на авторство не претендую, текст этот взят когда-то где-то только для анализа варианта решения


//
// внедрение dll в чужой процесс с помощью CreateRemoteThread.
// работать будет только там, где эта самая CreateRemoteThread реализована,
// а это nt/w2k/xp
// использовать так:
//   loader.exe идентификатор_процесса  полный_путь_и_имя_dll
// paul_shmakov@mail.ru
//
program loader;

{$APPTYPE CONSOLE}

uses
Windows, Messages, SysUtils;

function SetDebugPriv: Boolean;
var
Token: THandle;
tkp: TTokenPrivileges;
begin
Result := false;
if OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, Token) then
begin
  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, PTokenPrivileges(nil)^, PDWord(nil)^);
  end;
end;
end;

function Start(ProcessID: Cardinal; DllFileName: string): Boolean;
var
hProcess, hTh: THandle;
BytesWritten, ThreadID, DllNameLen: Cardinal;
LoadLibraryProc, MemPtr: Pointer;
ExitCode: DWord;
begin
Result := false;

//
// этот вызов нужен только для внедрения в системные процессы
// btw, нужны привилегии администратора
//
SetDebugPriv();

hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or PROCESS_VM_WRITE,
  true, ProcessID);

if hProcess <> 0 then
begin
  DllNameLen := Length(DllFileName) + 1;

  MemPtr := VirtualAllocEx(hProcess, nil, DllNameLen, MEM_COMMIT, PAGE_READWRITE);

  if MemPtr <> nil then
  begin
    if WriteProcessMemory(hProcess, MemPtr, PChar(DllFileName), DllNameLen, BytesWritten) then
    begin
      LoadLibraryProc := GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");

      hTh := CreateRemoteThread(hProcess, nil, 0, LoadLibraryProc, MemPtr, 0, ThreadID);

      if hTh <> 0 then
      begin
        if (WaitForSingleObject(hTh, INFINITE) = WAIT_OBJECT_0) and
          GetExitCodeThread(hTh, ExitCode) then
          Result := ExitCode <> 0;

        CloseHandle(hTh);
      end;
    end;

    VirtualFreeEx(hProcess, MemPtr, 0, MEM_RELEASE);
  end;

  CloseHandle(hProcess);
end;

end;

var
ProcessID: Cardinal;
DllName: string;
begin
if ParamCount < 2 then
begin
  WriteLn("usage: loader.exe process_id dll_full_path_and_name");
  Exit;
end;

ProcessID := StrToInt(ParamStr(1));
WriteLn("process id: " + IntToStr(ProcessID));

DllName := ParamStr(2);
WriteLn("dllname: " + DllName);

if ProcessID <> 0 then
begin
  if Start(ProcessID, DllName) then
    WriteLn("success")
  else
    WriteLn("fail");
end;
end.



 
Тимохов ©   (2004-07-09 11:27) [16]


>
> Digitman ©   (09.07.04 11:16) [13]
> неправильно понимаешь
> поточная ф-ция вызывает FreeLibrary

Да?
У рихтера пример имеено с передачей FreeLibrary в качестве поточной функции

    // Get the real address of LoadLibraryW in Kernel32.dll
     PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)
        GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "FreeLibrary");
     if (pfnThreadRtn == NULL) __leave;

     // Create a remote thread that calls LoadLibraryW(DLLPathname)
     hThread = CreateRemoteThread(hProcess, NULL, 0,
        pfnThreadRtn, me.modBaseAddr, 0, NULL);
     if (hThread == NULL) __leave;


Все-таки - где доказательство того, что kernel32.dll всегда по одному адресу? Понимаю, что вопрос не совсем практичен, т.к. это и так ясно - но все же документальное подтверждение было бы не лишним.


 
Игорь Шевченко ©   (2004-07-09 11:30) [17]


> Все-таки - где доказательство того, что kernel32.dll всегда
> по одному адресу?


Практика - критерий истины


 
Тимохов ©   (2004-07-09 11:34) [18]


> Игорь Шевченко ©   (09.07.04 11:30) [17]
> Практика - критерий истины


Если бы меня спросли на интервью при приеме на работу "Всегда ли kernel32.dll расположена по одному базовому адресу". Я бы сказал конечно да и был бы прав. Так что здесь не вопрос опыта. А вопрос скрытых пока от меня мест в документации, которые не плохо бы иметь на примете :)))


 
Digitman ©   (2004-07-09 11:36) [19]


> Тимохов ©   (09.07.04 11:27) [16]


> Да?
> У рихтера пример имеено с передачей FreeLibrary в качестве
> поточной функции


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


> Все-таки - где доказательство того, что kernel32.dll всегда
> по одному адресу?


ну нашута это надо - трюки эти ? ничем они не оправданы, кроме сомнительной экономии пару-тройки сотен байт АП целевого процесса ..


 
Тимохов ©   (2004-07-09 11:41) [20]


> Digitman ©   (09.07.04 11:36) [19]

Я вас не понимаю.
Особенно это

> ну нашута это надо - трюки эти

Какие трюки?
Вы сами привели пример, где адрес LoadLibraryA находите в одном процессе, а запускаете поток в другом. Ясно, что вы предполагаете, что адрес загрузки kernel32.dll одинаков. Вот и вопрос - почему вы так полагаете. Игорь говорит, что "практика критерий истинины". Все же кроме практики должна быть дока! :)

А вот это вообще к чему?

> кроме сомнительной экономии пару-тройки сотен байт АП целевого
> процесса ..


ЗЫ. А рихтер, что рихтер. Виноват я что-ли, что книжка хорошая.


 
bar   (2004-07-09 11:43) [21]

>>Digitman ©   (09.07.04 11:23) [15]
Спасибо большое. Буду пробовать.
А кто такой Рихтер??


 
Игорь Шевченко ©   (2004-07-09 11:44) [22]

bar   (09.07.04 11:43)


> А кто такой Рихтер??


Пианист


 
Тимохов ©   (2004-07-09 11:46) [23]


> bar   (09.07.04 11:43) [21]

Это дядька такой, который написал хорошую книгу по windows.

http://www.books.ru/shop/books/8283


 
Digitman ©   (2004-07-09 12:10) [24]


> Тимохов ©   (09.07.04 11:41) [20]


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

и приведен он НЕ для подражания, а в качестве примера использования вызова WriteProcessMemory() (см. [12]) и сопутствующих вызовов .. не более того


 
Тимохов ©   (2004-07-09 12:14) [25]


> Digitman ©   (09.07.04 12:10) [24]

делаю выводы (подвожу итог):
1. Вы считаете, что закладываться на одинаковость базового адреса Kernel32.dll во всех процессах из области трюков, которые исползовать не нужно.
2. У вас есть свое ноухау как можно сделать CreateRemoteThread без того, чтобы полагаться на удиный базовый адрес Kernel32.dll, а например в удаленном процессе явно строите поточную фунцию, с использованием WriteProcessMemory.


 
Digitman ©   (2004-07-09 12:28) [26]


> Тимохов ©   (09.07.04 12:14) [25]


1. Все верно. На то что недокументировано полагаться нельзя при любом раскладе.

2. Никаких ноу-хау. Все это старо как мир - с пом. WriteProcessMemory() из АП тек.процесса в АП целевого процесса копируется готовый к "употреблению" машкод, который при получении управления вызовает документированную ф-цию LoadLibrary или FreeLibrary


 
Тимохов ©   (2004-07-09 12:34) [27]


> Digitman ©   (09.07.04 12:28) [26]

Как бальзам на душу :)))))
Я честно говоря так не делал - т.к. не особо силен в создании машкода да еще готового к употреблению, но если бы знал как писать машкод, то делал бы именно так.

Я еще когда рихтера читал - как-то мне это не понравилось: полагаться на однозначность базового адреса kernel32.dll.

Спасибо, теперь, если придется это делать, буду знать, что нужно копировать маш код...


 
Тимохов ©   (2004-07-09 12:37) [28]

Скажу честно, то, что написано в 26 я и хотел услышать и в процессе прошлого обсуждения и сейчас.
:))


 
Digitman ©   (2004-07-09 12:41) [29]


> Тимохов ©   (09.07.04 12:34) [27]



> не особо силен в создании машкода да еще готового к употреблению,
> но если бы знал как писать машкод, то делал бы именно так.


занаешь ли, я думаю что редкий мазохист возьмется строить машкод (да еще и позиционно-независимый) в ран-тайм, когда под руками есть мощный/гибкий/изящный Делфи-компилятор, делающий то же самое без каких-либо затрат мозговых усилий))))


 
Тимохов ©   (2004-07-09 12:45) [30]


>  (да еще и позиционно-независимый)

вот об этом подробнее пожалуйста :)))
Как это можно в дельфи сделать?
Если посмотреть в момент выполнени, то видно много явных ссылок, например на константы строк. И как в дельфи сделать позиционно-независимый код?


 
bar   (2004-07-09 13:08) [31]

>>Digitman ©
А для выгрузки дллки как нужно делать? так как ниже или иначе?

function Unload(ProcessID: Cardinal; DllId: Cardinal): Boolean;
var
hProcess, hTh: THandle;
BytesWritten, ThreadID, DllNameLen: Cardinal;
LoadLibraryProc, MemPtr: Pointer;
ExitCode: DWord;
begin
Result := false;

//
// этот вызов нужен только для внедрения в системные процессы
// btw, нужны привилегии администратора
//
SetDebugPriv();

hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or PROCESS_VM_WRITE,
 true, ProcessID);

if hProcess <> 0 then
begin
 DllNameLen := SizeOf(DllId);

 MemPtr := VirtualAllocEx(hProcess, nil, DllNameLen, MEM_COMMIT, PAGE_READWRITE);
  //   FreeLibrary
      //  FreeLibrary()
 if MemPtr <> nil then
 begin
   if WriteProcessMemory(hProcess, MemPtr, Pointer(DllId), DllNameLen, BytesWritten) then
   begin
     LoadLibraryProc := GetProcAddress(GetModuleHandle("kernel32.dll"), "FreeLibrary");
     hTh := CreateRemoteThread(hProcess, nil, 0, LoadLibraryProc, MemPtr, 0, ThreadID);

     if hTh <> 0 then
     begin
       if (WaitForSingleObject(hTh, INFINITE) = WAIT_OBJECT_0) and
         GetExitCodeThread(hTh, ExitCode) then
         Result := ExitCode <> 0;
       CloseHandle(hTh);
     end;
   end;
   VirtualFreeEx(hProcess, MemPtr, 0, MEM_RELEASE);
 end;
 CloseHandle(hProcess);
end;
end;


 
bar   (2004-07-09 13:16) [32]

>> All
Спасибо, мастера Delphi, знатоки Рихтера и прочие гении.
С CreateRemoteThread разберусь позже а пока сделал чтобы работала загрузка/выгрузка с пом. хука.
Вот процедура хука кому интересно. Можете покритиковать.

function CallWndProc(
   nCode: integer; // hook code
   wParam: WPARAM; // current-process flag
   lParam: LPARAM // address of structure with message data
   ): LRESULT; stdcall;
var
   hl: THAndle;
   ok: boolean;
begin
   if nCode = HC_ACTION then
   begin
       ok := false;
       if tmsg(pointer(lparam)^).hwnd = H then
       begin
           ok := true;
           if GlobalData^.Flag then
           begin
               GlobalData^.HLIB := loadlibrary(remdll);

               @GetAndSet := nil;
               if GlobalData^.HLIB > HINSTANCE_ERROR then
               begin
                   @GetAndSet := GetProcAddress(GlobalData^.HLIB, "GetAndSet");
                   if @GetAndSet <> nil then
                       GetAndSet(H) ;
                   Invalidaterect(H, nil, false);
                  end else

           end else
           begin
{ я заменяю оконную процедуру в SHELLDLL_DefView и по этому сообщению(WM_User + 456) возвращаю на место старую WndProc }
               SendMessage(H, WM_User + 456, 0, 0);
               sleep(1000);{Дабы точно WndProc заменилась на старую. Пожет это параноя :-)}
               hl := loadlibrary(remdll);
               repeat
              until not FreeLibrary(Hl);;
           end;
       end;
       result := CallNextHookex(GlobalData^.SysHook, ncode, wparam, lparam);
       if ok then
       begin
           UnHookWindowsHookEx(GlobalData^.SysHook);
       end
   end
   else
       result := CallNextHookex(GlobalData^.SysHook, ncode, wparam, lparam);
   //

end;
Пока.


 
Digitman ©   (2004-07-09 15:16) [33]


> Тимохов ©   (09.07.04 12:45) [30]


чуть позже


 
Тимохов ©   (2004-07-12 12:06) [34]


> Digitman ©   (09.07.04 15:16) [33]
> чуть позже


Эххх :((
видать, я состарюсь раньше :))))


 
Бином Ньютоныч   (2004-07-12 18:33) [35]

Тимохов ©   (12.07.04 12:06) [34]

Пишешь дважды одну функцию под разными именами, компилишь. Сравнивая код, строишь таблицу коррекции адресов. Так еще под 580ВМ80 делали перемещаемый код.

О kernel32. Все системные библиотеки скомпонованы с неперекрывающимися базовыми адресами. Так что вероятность их загрузки по иному адресу практически равна нулю. Реальный адрес загрузки своей библиотеки можно посмотреть в окне Modules и соответственно скорректировать компоновку. Там же можно посмотреть адрес загрузки kernel32 и сравнить с показаниями TDUMP.exe. Кстати, в Visual Studio есть утилита Rebase.exe, которая позволяет произвести оптимизацию базовых адресов.

PS: Все это описано у Рихтера.


 
Тимохов ©   (2004-07-12 18:46) [36]


> PS: Все это описано у Рихтера.

читал, знаю.
спасибо.

все же именно на мой вопрос ответа нет (т.е. где явно описан факт одинаковости базового адреса загрузки kernel32.dll)


 
Бином Ньютоныч   (2004-07-12 20:35) [37]

>Тимохов ©   (12.07.04 18:46) [36]

Может и есть компоновщики, которые не размещают системные библиотеки первыми в секции импорта, но я о таком не слышал.



Страницы: 1 вся ветка

Форум: "WinAPI";
Текущий архив: 2004.08.22;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.58 MB
Время: 0.052 c
1-1092114772
Stype
2004-08-10 09:12
2004.08.22
Размер программы...


1-1092039455
Леван
2004-08-09 12:17
2004.08.22
Как емулировать CONDENSED для шрифта


3-1091186906
Pioneer
2004-07-30 15:28
2004.08.22
Компьютер виснет на большом отчете


1-1091799966
mouse_web
2004-08-06 17:46
2004.08.22
Привязка ProgressBar к поиску по базе


1-1091566494
димка
2004-08-04 00:54
2004.08.22
Поиск файлов





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский