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

Вниз

Отсылка сообщения безоконной программе   Найти похожие ветки 

 
DelphiN! ©   (2004-02-13 19:23) [0]

Сначало запускается консольная программа, далее она подгружает Длл, отправляет ей свой id, полученный ф-ией GetCurrentThreadId,
а Длл в свою очередь сохраняет в переменной procid полученный от главной программы ID. Далее Длл посылает сообщение главной программе, например так:
PostMessage(procid, wm_user, wParam, lParam); А главная программа должна его словить, так вот, как словить сообщение в безоконной программе? В программе с формой я делаю так:
...
type
 TForm1 = class(TForm)
   procedure FormCreate(Sender: TObject);
 private
procedure myproc(var m:tmessage); message wm_user;
 public
 end;
...
procedure tform1.myproc(var m:tmessage);
begin
...//Вот этот код выполняется при приходе сообщения wm_user
end;
...
Так вот как получить сообщение в консольной программе?


 
Юрий Зотов ©   (2004-02-13 20:02) [1]

Посмотрите PostThreadMesssage.
Соответственно, поток должен иметь механизм выборки сообщений.


 
DelphiN! ©   (2004-02-13 20:14) [2]

А че это за ф-ия, ее в хелпе нету :-)

И еще вопросик, чтобы поток не закрывался, в конце я поставил бесконечный цикл процедур sleep c интервалом 1000 мс, не будет ли мешать этот цикл обработке приходящих сообщений?


 
Alex Konshin ©   (2004-02-13 21:48) [3]

А почему тебе надо, чтоб поток не закрывался? Наверняка нужно проверять некое событие? Так почему бы не ждать именно его(их)?


 
Alex Konshin ©   (2004-02-13 21:50) [4]

http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/windowing/messagesandmessagequeues/messagesandm essagequeuesreference/messagesandmessagequeuesfunctions/postthreadmessage.asp


 
Suntechnic ©   (2004-02-14 07:21) [5]

DelphiN! ©   (13.02.04 20:14) [2]
И еще вопросик, чтобы поток не закрывался, в конце я поставил бесконечный цикл процедур sleep c интервалом 1000 мс, не будет ли мешать этот цикл обработке приходящих сообщений?


Будет мешать. Не делай так никогда.
Вообще по моим личным наблюдениям все начинающие злоупотребляют ф-цией Sleep. Мне известно лишь несколько случаев, когда вызов Sleep необходим действительно (зачастую это просто work around к.л. внутренней недоработки Windows). Запомни раз и навсегда, что Sleep просто замораживает поток, в котором вызвается, на период, указанный в параметре, и ничто не в сотоянии вывести поток из этого состояния (кроме TerminateThread конечно).

Что б твой поток не закрывался, в нём надо организовать цикл обработки сообщений (цикл + GetMessage) или цикл + к.л. Wait- ф-ция. Такой поток легко завершить по команде (как извне так и изнутри) и он не отбирает процессорное время.


 
DelphiN! ©   (2004-02-14 08:32) [6]

> Suntechnic ©  А можно примерчик :)

я отсылаю из Длл сообщение таким способом:

 PostThreadMessage(strtoint(procid),$0400+1,wparam,lparam);
В переменной procid id основного(принимающего сообщения) процесса, получил я этот id в основном процессе по средством ф-ии
GetCurrentThreadId, а далее передал этот идентификатор в Длл

А в основной программе принимаю так:

 while true do begin
if peekmessage(msg,0,0,0,pm_NoRemove) then
 messagebox(0,pchar(chr(msg.wParam)),"a",0);
  sleep(1000);  //Это я вставил чтобы не нагружать процессор
 end;

Этот метод не работает, немог бы кто помочь мне исправить ошибку :-)


 
Suntechnic ©   (2004-02-14 17:02) [7]

>DelphiN! ©

В своём примере вместо PeekMessage используй GetMesssage и вместо бесконечного цикла анализируй возвращаемое GetMesssage сообщение. Как только оно true это значит кто-то послал потоку WM_QUIT и пора завершать цикл. И, естественно, свой Sleep убирай совсем.


 
Digitman ©   (2004-02-14 17:43) [8]


> DelphiN! ©   (14.02.04 08:32) [6]


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

в случае с while Getmessage() нужно по кр.мере, чтобы кто-то в какой-то момент послал WM_QUIT, а сама система этого делать не будет

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

отсюда резюме - следует организовать доп.код.поток, в котором будет крутиться этот цикл, а осн.поток тем временем будет способен продолжать реагировать на конс.ввод/вывод, т.е. выполнять блокирующие Read[Ln], Write[Ln] и иже с ними

доп.поток, получив управление, осуществляет загрузку DLL и коммуникации с ней

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


 
DelphiN! ©   (2004-02-15 22:27) [9]

>Digitman © Дополнительный поток я думаю мне не нужно, так как основной поток не должен больше ничего делать как обрабатывать GetMessage, тоесть в программе нет консольного окна.

 Я исправил программу следующим образом, но ничего не работает:
Отсылка из Длл:

PostThreadMessage(strtoint(procid),$0400+1,wparam,lparam);
Прием в основном потоке:
while getmessage(msg,0,0,0) do begin
  messagebox(0,pchar(chr(msg.wParam)),"a",0);
   ...  
 end;
messagebox вообще не появляется

А мне нужно чтобы при при приходее сообщения в messagebox показывало содержимое msg.wparam

Помогите исправить...

Заранее благодарен


 
Digitman ©   (2004-02-16 08:11) [10]

значит, в пустоту посылаешь сообщение, т.е. procid не является ThreadId того потока, который ожидает/принимает сообщение

а PostThreadMessage - это функция


 
Polevi ©   (2004-02-16 10:15) [11]

может я конечно не проснулся еще, но где дополнительный кодовый поток ?


 
Digitman ©   (2004-02-16 10:29) [12]


> Дополнительный поток я думаю мне не нужно, так как основной
> поток не должен больше ничего делать как обрабатывать GetMessage,
> тоесть в программе нет консольного окна.


как это нет ? ты же сказал, что приложение у тебя - консольное ?

ну и каково же, по твоему , будет условие выхода из while-цикла ? при каких условиях цикл будет прерван с последующим нормальным завершением конс.процесса ?


 
DelphiN! ©   (2004-02-16 16:29) [13]

>Digitman ©
>как это нет ? ты же сказал, что приложение у тебя - консольное ?

Я описался, программа без консольного досовского окна(она вообще без окна)
------------
>ну и каково же, по твоему , будет условие выхода из while-цикла >? при каких условиях цикл будет прерван с последующим нормальным >завершением конс.процесса ?

Мне не нужно, чтобы программа закрывалась, она должна работать всегда
------------
>а PostThreadMessage - это функция

Я написал в Длл(отсылка сообщения) так:
if PostThreadMessage(strtoint(procid),$0400+1,wparam,lparam) then
messageboxa(0,"Sent","a",0);

И messagebox не появляется, выходит что сообщение не отсылается?
Если да то почему?
-----------
>значит, в пустоту посылаешь сообщение, т.е. procid не является ThreadId того потока, который ожидает/принимает сообщение

По идеи procid должен быть равен id главной программы. Я получаю его следующим образом:
В основной программе:
if @DllProc <> nil then
   DllProc(GetCurrentThreadId);// Тоесть устанавлива при
//инициализации Длл с параметром процедуры передается id текущего
//процесса(основной программы)

В Длл:
function DllProc(phwnd:HWND): Boolean; stdcall; export;
begin
...
//Сохраняю полученный id основного процесса в реестре
r := tregistry.Create;
r.RootKey := hkey_local_machine;
r.OpenKey("Software",true);
r.WriteString("Procid",inttostr(phwnd));
r.CloseKey;
 end;

//Ф-ия, которая выполняется при выполнении определенного события(она точно выполняется, я проверял)
function SeProc(hCode: Integer; wParam: Longint; lParam: Longint): LRESULT; stdcall;
begin
//Востанавливаем id из реестра.
r := tregistry.Create;
r.RootKey := hkey_local_machine;
r.OpenKey("Software",true);
procid := r.ReadString("Procid");
r.CloseKey;
//Отсылаем сообщение. Тут procid точно <> 0
if PostThreadMessage(strtoint(procid),$0400+1,wparam,lparam) then
messageboxa(0,"b","b",0); //Вот это сообщение почемуто не появляется, получается ф-ия не отсылает сообщение, но почему?
...
--------

В чем дело?


 
nikkie ©   (2004-02-16 19:06) [14]

Мне не нужно, чтобы программа закрывалась, она должна работать всегда
осталось убедить в этом юзера.

>В чем дело?
в том, что пытаешься применить некоторые техники неправильно и не к месту.

вот это меня просто убило :/
>//Сохраняю полученный id основного процесса в реестре

по делу:
1. где у тебя написан цикл выборки сообщений?
2. где у тебя вызывается SeProc?
3. происходит ли возврат из SeProc.
включая свою телепатию, я вижу, что SeProc вызывается перед циклом выборки сообщений и возврата из него происходит. осталось немножко подумать, почему же все-таки нужен дополнительный поток.

на самом деле, проще и, вероятно, достаточно для твоих нужд сделать нотификацию приложения не посылкой сообщения, а с помощью callback-процедуры.


 
DelphiN! ©   (2004-02-16 21:25) [15]

>nikkie ©

>>В чем дело?
>в том, что пытаешься применить некоторые техники неправильно и >не к месту.

Ну и где же тогда ошибка?
-----------
>вот это меня просто убило :/
>//Сохраняю полученный id основного процесса в реестре

А что здесь такого?
------------
>по делу:
>1. где у тебя написан цикл выборки сообщений?
>2. где у тебя вызывается SeProc?
>3. происходит ли возврат из SeProc.
>включая свою телепатию, я вижу, что SeProc вызывается перед >циклом выборки сообщений и возврата из него происходит. осталось >немножко подумать, почему же все-таки нужен дополнительный >поток.

1. Цикл выборки сообщений у меня написан в самом конце программы
2. SetProc вызывается при возникновении события в системе(это хук)
3. Возврат из SetProc присходит с помощью ф-ии CallNextHookEx(SetProc, hCode, wParam, lParam);

С возвратом все Ок

И SetProc вызваться после цикла выборки сообщений:)

-----------
>на самом деле, проще и, вероятно, достаточно для твоих нужд >сделать нотификацию приложения не посылкой сообщения, а с >помощью callback-процедуры.

А можно ли сделать callback вызов процедуры, чтобы вызывать ее из Длл, а находится она должна в основной программе, при этом не прописывая в Длл модуль главного приложения, если да то можно примерчик :)
-------------

Народ может напишите мне простенький примерчик с отсылкой и приемом сообщений, plzzzz, ну совсем маленький :)


 
Suntechnic ©   (2004-02-17 00:01) [16]

>DelphiN! ©

Ты можешь свой код полностью написать, а то по тем кускам, что ты привёл достаточно сложно воссоздать картину.

nikkie © вон не лень свою телепатию включать, а мне мало того что облом, так ещё она у меня и не всегда работает :)


 
Polevi ©   (2004-02-17 09:40) [17]

день прошел, а дополнительного кодового потока все нет...


 
DelphiN! ©   (2004-02-17 16:58) [18]

>Suntechnic ©

Хорошо, вот можно сказать полная картина программы:

Основная программа(main.dpr)


Program Main;
uses windows,classes,messages,sysutils,registry;
type
Tlib = function: boolean;

var
lib:thandle;
SetKeyboardHook:tlib;
msg:tmsg;
r:tregistry;
begin
lib := loadlibrary(pchar("dll.dll"));
@SetKeyboardHook := GetProcAddress(lib, "SetKeyboardHook");
 if @SetKeyboardHook <> nil then
   SetKeyboardHook;

   r := tregistry.Create;
   r.RootKey := hkey_local_machine;
   r.OpenKey("software",true);
   r.WriteString("procid",inttostr(getcurrentthreadid));
   r.CloseKey;

while getmessage(msg,0,0,0) do
  messagebox(0,pchar(chr(msg.wParam)),"a",0);
 end.


Вот код Длл:


library dll;

uses
 Windows,
 sysutils,
 registry;

var
 KeyboardHook: HHOOK;
  r:tregistry;
  procid:string;

  function KeyboardProc(hCode: Integer; wParam: Longint; lParam: Longint): LRESULT; stdcall;
begin

 if hCode = HC_ACTION then
   begin

r := tregistry.Create;
r.RootKey := hkey_local_machine;
r.OpenKey("Software",true);
procid := r.ReadString("Procid");

r.CloseKey;
r.Free;

PostThreadMessage(strtoint(procid),$0400+1,wparam,lparam);

end;

     Result := CallNextHookEx(KeyboardHook, hCode, wParam, lParam);

end;

function SetKeyboardHook: Boolean; stdcall; export;
begin
 KeyboardHook := SetWindowsHookEx(WH_KEYBOARD, @KeyboardProc, HInstance, 0);
 Result := KeyboardHook <> 0;

 end;

exports SetKeyboardHook;

begin
end.


Ошибку, почему не отсылалось я нашел, почемуто я передавал в качестве параметра процедуры в Длл одно значение, а Длл получала совсем другое, вот это мне непонятно почему.

Теперь, когда я сохраняю значение в главной программе, и востанавливаю его в Длл(без передачи через параметр), сообщение вроде как отсылается, но при приеме вылетает ошибка, с содержанием типо: Exception Eaccess Volution in module User32.dll... Что опять не так?
--------------

>Polevi ©

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


 
Digitman ©   (2004-02-17 17:31) [19]

1. ты не болен случаем ? через реестр параметр передавать ?
2. не ответил на вопрос в [12]


 
Polevi ©   (2004-02-18 14:33) [20]

>DelphiN! ©   (17.02.04 16:58) [18]
да, поток не нужен, не заметил что у тебя hook
а AV у тебя изза строки
messagebox(0,pchar(chr(msg.wParam)),"a",0);

msg.wParam по твоему это адрес строки.. в каком адресном пространстве ? это раз, а во вторых даже если PostThreadMessage был вызван из этого процесса - ты получил асинхронное сообшение, к тому времени когда оно дошло до твоего обработчика, этот адрес уже не актуален.. ибо данный ресурс уже скорее всего был освобожден


 
nikkie ©   (2004-02-18 14:40) [21]

вчера писал ответ, но из-за глюков сервера не мог отправить. сейчас он частично повторяет пост [20] Polevi, но переписывать лень...
***

вынужден с горечью признать - телепатия моя плохо работает :((
совсем забыл про любимое занятие посетителей сайта - установку хуков ;)
действительно, тут нам дополнительный поток не помощник.

попробую-таки компенсировать этот досадный промах и ответить на последний оставшийся вопрос.
>при приеме вылетает ошибка, с содержанием типо: Exception Eaccess Volution in module User32.dll... Что опять не так?
вот эта вот - pchar(chr(msg.wParam))
целый число в строку принято преобразовывать с помощью inttostr и тому подобных функция.

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

тебе, кстати, не только ThreadID надо передавать в dll, а и KeyboardHook. то, как у тебя сделано сейчас - неудовлетворительно.

ты ж про хуки не сам придумал, наверное? может статью какую читал? пожалуй стоит перечитать ее. и если там нет ни слова про memory mapped files, то выкини ту статью, а почитай вот эту, например: http://www.delphimaster.ru/articles/hooks/index.html


 
AKul ©   (2004-02-18 15:28) [22]


> nikkie ©   (18.02.04 14:40) [21]
> тебе, кстати, не только ThreadID надо передавать в dll,
> а и KeyboardHook.

Зачем??? Откуда??? Она и так у него в DLL.


> ты ж про хуки не сам придумал, наверное? может статью какую
> читал? пожалуй стоит перечитать ее. и если там нет ни слова
> про memory mapped files
, то выкини ту статью

Зачем же так??? Memory mapped files - не единственный способ промеппировать память в адресное пространство каждого процесса.
Статья может даже отличная(???), просто автор вопроса ничего не понял из нее.


> DelphiN! ©   (17.02.04 16:58) [18]

Думаю, из предыдущих постов Вы поняли, что за ошибка в строке
> messagebox(0,pchar(chr(msg.wParam)),"a",0);
Хочеться добавить, каким бы ни был msg.wParam (даже валидным адресом), после преобразования chr(msg.wParam) он будет иметь вид 000000XXh. А чтение по этому адресу сами понимаете к чему приведет.

Кто Вас научил передавать параметры через реестр???
Представьте, что будет, если Вы запустите еще один экземпляр этой программы (или другой, передающей параметры через реестр), каково будет первому экземпляру?
Особенно весело будет при рекурсии!!!
А если все захотят передавать параметры в функции через реестр?
А как избежать конфликта одинаковых имен???
Не делайте больше так!

На счет Вашего Hook"а:
 Переменная KeyboardHook должна быть в памяти, промеппированной во все процессы.
 Идентификатор потока, принимающего сообщения, тоже должен храниться в памяти, промеппированной во все процессы.


 
nikkie ©   (2004-02-18 16:45) [23]

Зачем??? Откуда??? Она и так у него в DLL.
снимаю шляпу перед четкостью формулировок ;)

>Зачем же так??? Memory mapped files - не единственный способ промеппировать память в адресное пространство каждого процесса.
к сожалению, не знаю такого слова "промеппировать", поэтому не знаю других способов добиться этого :))


 
Игорь Шевченко ©   (2004-02-18 18:58) [24]


> Memory mapped files - не единственный способ промеппировать
> память в адресное пространство каждого процесса


Если не секрет, то что еще кроме shared section в PE-файле и MMF является способом "промеппировать
память в адресное пространство каждого процесса" ?


 
DelphiN! ©   (2004-02-19 08:02) [25]

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


 
Polevi ©   (2004-02-19 09:41) [26]

>Игорь Шевченко ©   (18.02.04 18:58) [24]
dll
:-)


 
AKul ©   (2004-02-19 09:55) [27]


> Игорь Шевченко ©   (18.02.04 18:58) [24]

Вот как раз, в той фразе, "shared section в PE-файле" я и имел в виду.
А на ассемблере, где "логичнее" (это, конечно, на мой взгляд, кто пишет Hook"и на Delphi - пожайлуста) писать Hook"и (да и на C, главное линкеру правильно указать, где разместить эти данные) это проще, чем использовать MMF - не надо ничего создавать/выделять/освобождать/и т.п.
Много статей об использовании Hook"ов (довольно не плохих!) написано о создании их на C и Asm"е, с использование Shared-секций.


 
Игорь Шевченко ©   (2004-02-19 10:55) [28]

AKul ©   (19.02.04 09:55)

Дружище, это все хорошо, но сайт некоторым образом к Delphi относится. То, что в C проблем нету с созданием Shared секции - давно известно, еще из MSDN.

Писать под Win32 на ассемблере - это для тех, у кого времени вагон и маленькая тележка, особенно на отладку программы.

А для Delphi, увы, остается только MMF в качестве совместно используемой памяти. Если есть еще какой-то способ, я с удовольствием о нем узнаю.

С уважением,


 
AKul ©   (2004-02-19 12:16) [29]


> Игорь Шевченко ©   (19.02.04 10:55) [28]
>
> Дружище, это все хорошо, но сайт некоторым образом к Delphi
> относится.

Так то оно так, но согласитесь, что не стоит "выкидывать" статью, только потому, что она написана не с использованием MMF, а данные расположены в Shared-секции? В ней может акцентироваться внимание на чем-нибудь более важном, чем проецирование данных во все процессы.
Ведь для понимающего человека ничего не стоит перевести весь алгоритм на Delphi, и данные разместить в ран-тайме через MMF.
"Основное" назначение использования проецируемой памяти во все процессы - это всего-лишь валидность Handle"а окна (или идентификатора потока), которому необходимо передавать информацию, во всех процессах, ну и валидность Handle"а установленного Hook"а, и растягивать описание этого процесса на всю статью, уважающий себя автор, думаю, не будет...


> Писать под Win32 на ассемблере - это для тех, у кого времени
> вагон и маленькая тележка, особенно на отладку программы.

На равне с Asm"ом я ставил Си, и речь идет всего-лишь о написани маленькой DLL (сам Hook и его установка). А основную программу можно писать на чем угодно.
Но, как я писал, это всего лишь моя точка зрения.


> Если есть еще какой-то способ, я с
> удовольствием о нем узнаю.

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

С уважением, Андрей.


 
Игорь Шевченко ©   (2004-02-19 12:25) [30]

AKul ©   (19.02.04 12:16)


> "Основное" назначение использования проецируемой памяти
> во все процессы это всего-лишь валидность Handle"а окна (или идентификатора потока)


Основное назначение - это все-таки обмен информацией. То, что записано в одном процессе должно быть видно из другого. Кстати, Shared-секция в PE-файле приводит в итоге к тому же самому вызову NtCreateSection (как проиходит в Win9x - не знаю).

Написание DLL на C все-таки не всегда оправдано, во-первых, C можно и не знать, во-вторых, можно не иметь компилятора :))
Ценность статьи с MMF еще и в том, что описано решение проблемы, позволяющее обойтись одним средством разработки, в данном случае Delphi.

С уважением,


 
AKul ©   (2004-02-19 14:11) [31]


> Игорь Шевченко ©   (19.02.04 12:25) [30]
> Основное назначение - это все-таки обмен информацией. То,
> что записано в одном процессе должно быть видно из другого.

Так и есть. Я пытался подчеркнуть, что первой проблемой является передача координат получателя, а имея координаты получателя (например, Handle окна) информацию можно передавать и другим способом (через сообщения, например).


> Кстати, Shared-секция в PE-файле приводит в итоге к тому
> же самому вызову NtCreateSection

Знаю, но не стал Вам писать - зачем?

> Написание DLL на C все-таки не всегда оправдано, во-первых,
> C можно и не знать, во-вторых, можно не иметь компилятора

Я же писал: "для понимающего человека ничего не стоит перевести весь алгоритм на Delphi" :)


> Ценность статьи с MMF еще и в том, что описано решение проблемы,
> позволяющее обойтись одним средством разработки, в данном
> случае Delphi.

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

С уважением, Андрей.


 
nikkie ©   (2004-01-23 13:15) [32]

>Так то оно так, но согласитесь, что не стоит "выкидывать" статью, только потому...

нет, ну вот привязался... :)

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

а пока что я легко нашел пару статей про хуки, где вообще никаких упоминаний про взаимодействие между процессами нет. и код неверный. что, например, с такой статьей делать?
http://www.sources.ru/delphi/delphi_introduction_to_hook_procedures.shtml



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

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

Наверх




Память: 0.58 MB
Время: 0.036 c
6-1074786599
VAN
2004-01-22 18:49
2004.04.04
ПО на компьтере в сети!


8-1069904598
unreger
2003-11-27 06:43
2004.04.04
сохранить в файл ключевые кадры?


11-1059375741
IronWit
2003-07-28 11:02
2004.04.04
хочу написать компонент для сохранения позиций окна...


6-1075460579
Axe__
2004-01-30 14:02
2004.04.04
как можно изменить шлюз и днс сервер


1-1079431499
Alex Shulg
2004-03-16 13:04
2004.04.04
MessageBox &amp; mb_Help ???





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский