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

Вниз

ProcessMessages   Найти похожие ветки 

 
dmirror   (2006-10-31 14:08) [0]

В чистом приложении вызов Application.processmessages работает.
Создаю поток

type
TServiceThread = class(TThread)
 public
   procedure Execute; override;
 end;
---
var
 ServiceThread: TServiceThread;

и на processmessages компилятор начинает ругаться что не видит такой функции.

что может быть и как исправить?


 
Eraser ©   (2006-10-31 14:13) [1]

> [0] dmirror   (31.10.06 14:08)


> и на processmessages компилятор начинает ругаться что не
> видит такой функции.

код показываей, где ругается.

ЗЫ
 не вздумай вызывать processmessages из доп. потока.


 
Сергей М. ©   (2006-10-31 14:14) [2]

processmessages - это не функция, а процедурный метод объекта класса TApplication.


 
YuRock ©   (2006-10-31 15:55) [3]


> Eraser ©   (31.10.06 14:13) [1]
>
> ЗЫ
>  не вздумай вызывать processmessages из доп. потока.
>


Почему?


 
Ketmar ©   (2006-10-31 16:02) [4]

>[3] YuRock(c) 31-Oct-2006, 15:55
>Почему?
поверь на слово пока. ибо это с 1917 года надо про шпингалеты пояснять.


 
YuRock ©   (2006-10-31 16:05) [5]


> поверь на слово пока. ибо это с 1917 года надо про шпингалеты
> пояснять.


Хорошо. Я тогда тоже дам совет. Не пользуйся никогда компонентом TButton. Почему? Поверь на слово - я знаю, почему...


 
Ketmar ©   (2006-10-31 16:10) [6]

>[5] YuRock(c) 31-Oct-2006, 16:05
ещё один надмозг. сезон, что ли? игнор.


 
Eraser ©   (2006-10-31 16:13) [7]

> [3] YuRock ©   (31.10.06 15:55)


> Почему?

Зачем?
Зачем понадобилось вызывать ProcessMessages в доп. потоке?

Нельзя вызывать, потому что ProcessMessages позволяет перейти к обработке всей очереди сообщений основного потока приложения, тем самым прервав выполнение кода в основном же потоке, до тех пор, пока метод ProcessMessages не выполнится.
Если вызвать ProcessMessages из доп. потока, то программа или этот поток, в лучшем случае, скорее всего подвиснут.


 
Сергей М. ©   (2006-10-31 16:17) [8]


> YuRock ©   (31.10.06 15:55) [3]



> Почему?


Дурацкий вопрос.

Ну, если желаешь ответ на него, то хотя бы потому что поле TApplication.FTerminate не защищено крит.секцией. И при этом нет никаких гарантий, что потоку не послано WM_QUIT.

Смотреть и изучать исходники класса TApplication до полного просветления)


 
Игорь Шевченко ©   (2006-10-31 16:44) [9]

Eraser ©   (31.10.06 16:13) [7]


> Нельзя вызывать, потому что ProcessMessages позволяет перейти
> к обработке всей очереди сообщений основного потока приложения,
>  тем самым прервав выполнение кода в основном же потоке,
>  до тех пор, пока метод ProcessMessages не выполнится.


С этого момента подробнее - каким образом ProcessMessages вызыванный из неосновного потока позволяет перейти к обработке всей очереди сообщений основного потока приложения.


 
Eraser ©   (2006-10-31 16:47) [10]

> [9] Игорь Шевченко ©   (31.10.06 16:44)

в том то и дело что никаким.


 
YuRock ©   (2006-10-31 17:07) [11]

> Ketmar c   (31.10.06 16:10) [6]
> Eraser c   (31.10.06 16:13) [7]
> Сергей М. c   (31.10.06 16:17) [8]

Пасиба, олбанский выучил!

> dmirror   (31.10.06 14:08)

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

TApplication.ProcessMessages вполне допустимо для выкрутки сообщений любого потока. Ведь это простой цикл PeekMessage. Единственное, с чем может случиться заморочка - это со свойством OnMessage у TApplication. Если оно присвоено - то будет вызываться из того потока, откуда вызвано ProcessMessages. И тут уже все зависит от того, что за код там написан. Если этого свойства нет - проблем быть не может.

Другой вопрос - зачем вызывать ProcessMessages? Оно удобно для того, чтобы выкрутить накопившуюся очередь. Принудительно.
Но не предназначено для ожидания и выкрутки сообщений, тут надо использовать цикл GetMessage.

Ниже пример с использованием Application.ProcessMessages в другом потоке. Все работает великолепно - только
неправильно логически - "оно" для другого надо. И из-за этого 100% проца жрется. Да и далеко не все сообщения "оно" обрабатывает.
Так что если этот цикл закомментить и раскомментить следующий - будет намного лучше.


unit Unit1;

interface

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

type
 TTestThread = class( TThread )
 protected
   procedure Execute; override;
 end;

 TForm1 = class(TForm)
   procedure FormCreate(Sender: TObject);
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
 private
   FTread: TTestThread;
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

function TestThreadWndProc( hWindow: HWND; msg: Cardinal; wParam: WPARAM; lParam: LPARAM ): Integer; stdcall;
begin
 Result := DefWindowProc( hWindow, msg, wParam, lParam );
end;

procedure TTestThread.Execute;
var
 hWindow: HWND;
 Msg: TMSG;
begin
 hWindow := CreateWindow( "___TestThreadWndClass", "Îêíî èç äðóãîãî ïîòîêà ( Îáðàáàòûâàåòñ&# 255; Application.ProcessMessages )", WS_VISIBLE or WS_SIZEBOX or WS_SYSMENU or WS_MINIMIZEBOX or WS_MAXIMIZEBOX, 100, 100, 600, 200, 0, 0, hInstance, nil );

 while not Terminated do
   Application.ProcessMessages;

 {while not Terminated and GetMessage( Msg, 0, 0, 0 ) do begin
   TranslateMessage( Msg );
   DispatchMessage( Msg );
 end;}

 DestroyWindow( hWindow );
end;

procedure TForm1.FormCreate(Sender: TObject);
var
 wc: WNDCLASS;
begin
 FillChar( wc, sizeof( WNDCLASS ), 0 );
 wc.lpfnWndProc := @TestThreadWndProc;
 wc.hInstance := hInstance;
 wc.hCursor := LoadCursor( 0, IDC_ARROW );
 wc.lpszClassName := "___TestThreadWndClass";
 wc.hbrBackground := CreateSolidBrush( GetSysColor( COLOR_BTNFACE ) );
 Windows.RegisterClass( wc );

 FTread := TTestThread.Create( True );
 with FTread do begin
   FreeOnTerminate := True;
   Resume;
 end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 FTread.Terminate;
end;

end.


 
Eraser ©   (2006-10-31 17:17) [12]

> [11] YuRock ©   (31.10.06 17:07)


> Пасиба, олбанский выучил!

учи еще.
только потом не удивляйся, что приложение будет "вываливаться" с AV в самых неожиданных местах.

> Да и далеко не все сообщения "оно" обрабатывает.

это с каких пор?


 
YuRock ©   (2006-10-31 17:21) [13]

> Eraser ©   (31.10.06 17:17) [12]

1. Йа пастаянна учу, пасиба исчо рас! Да, приложения, написанные мной, работают месяцами, пока винда не сдохнет.

2. С тех пор, как борланд так реализовал этот метод. Как минимум с D6 - более старых версий у меня нет под рукой.


 
Игорь Шевченко ©   (2006-10-31 17:22) [14]

Eraser ©   (31.10.06 16:47) [10]


> Нельзя вызывать, потому что ProcessMessages позволяет перейти
> к обработке всей очереди сообщений основного потока приложения,
>  тем самым прервав выполнение кода в основном же потоке,
>  до тех пор, пока метод ProcessMessages не выполнится.
> Если вызвать ProcessMessages из доп. потока, то программа
> или этот поток, в лучшем случае, скорее всего подвиснут.
>



> в том то и дело что никаким.


Вот две твоих цитаты. Ты их связать можешь ? А то у меня не получается.


 
@!!ex ©   (2006-10-31 17:46) [15]

А я почемуто всегда думал, что ProcessMessages нужно для того чтобы прервать текущее действие основного потока и обработать мессаги....
Вопрос: зачем из стороннего потока вызывать обработку сообщений главного потока?
Ответ: Чтобы напороться на AV.


 
YuRock ©   (2006-10-31 17:48) [16]


> @!!ex ©   (31.10.06 17:46) [15]
> Вопрос: зачем из стороннего потока
> вызывать обработку сообщений главного потока?Ответ: Чтобы
> напороться на AV.


:))))))))))))))))))))))))))))))))))))))))))))))


 
Eraser ©   (2006-10-31 17:57) [17]

> [14] Игорь Шевченко ©   (31.10.06 17:22)

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

> зачем из стороннего потока вызывать обработку сообщений
> главного потока?

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


 
YuRock ©   (2006-10-31 18:00) [18]

Я извиняюсь перед админами форума, просто нервы - ни к черту...
Через пару часов на стадион идти - Шахтер-Валенсия - и меня колбаси не по детски... Делать ничего не могу.

Орешник уже перечитал полностью. Оценил :)
Но мало. А, как оказалось, обсуждения обычных вопросов, споры и советы специалистов тут не хуже орехов :)

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


 
Игорь Шевченко ©   (2006-10-31 18:09) [19]

Eraser ©   (31.10.06 17:57) [17]


> надо было уточнить, что вызывать ProcessMessages следует
> из осн. потока.


Почему ?


 
Eraser ©   (2006-10-31 18:13) [20]

> [19] Игорь Шевченко ©   (31.10.06 18:09)

потому что borland не рекомендует вызывать методы VCL объектов из доп. потока.


 
YuRock ©   (2006-10-31 18:14) [21]

> Игорь Шевченко ©   (31.10.06 18:09) [19]
> Почему ?

Я уже задавал этот вопрос  - [3].
Поступило около 15 ответов - неужели Вам не достаточно? :)


 
@!!ex ©   (2006-10-31 18:16) [22]


> 1. Йа пастаянна учу, пасиба исчо рас! Да, приложения, написанные
> мной, работают месяцами, пока винда не сдохнет.


Винда дохнет из-за ваших приложений? ;)


> Игорь Шевченко ©   (31.10.06 18:09) [19]

Теоретически может привести к AB  в ОЧЕНЬ редких случаях как уже было сказано в > Сергей М. ©   (31.10.06 16:17) [8] .
Мьютекс на FTerminate...
ТОка это всего лишь один из вариантов, которые могут привести к AV.


 
Игорь Шевченко ©   (2006-10-31 18:21) [23]

Eraser ©   (31.10.06 18:13) [20]


> потому что borland не рекомендует вызывать методы VCL объектов
> из доп. потока.


Все методы всех объектов ?


 
Eraser ©   (2006-10-31 18:22) [24]

> [21] YuRock ©   (31.10.06 18:14)

вот код метода ProcessMessage, который вызывается в цикле из ProcessMessages.
function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
var
 Unicode: Boolean;
 Handled: Boolean;
 MsgExists: Boolean;
begin
 Result := False;
 if PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
 begin
   Unicode := (Msg.hwnd <> 0) and IsWindowUnicode(Msg.hwnd);
   if Unicode then
     MsgExists := PeekMessageW(Msg, 0, 0, 0, PM_REMOVE)
   else
     MsgExists := PeekMessage(Msg, 0, 0, 0, PM_REMOVE);
   if not MsgExists then Exit;
   Result := True;
   if Msg.Message <> WM_QUIT then
   begin
     Handled := False;
     if Assigned(FOnMessage) then FOnMessage(Msg, Handled); // может привести к серьезным проблемам,
                                                            // если этот обработчик расчитан для работы в осн. потоке.
     if not IsPreProcessMessage(Msg) and not IsHintMsg(Msg) and // есть подозрение, что эти методы тоже не потоко-безопасны.
       not Handled and not IsMDIMsg(Msg) and // тут вообще код лезет к объекту TScreen...
       not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
     begin
       TranslateMessage(Msg);
       if Unicode then
         DispatchMessageW(Msg)
       else
         DispatchMessage(Msg);
     end;
   end
   else
     FTerminate := True; // про это сказано в [8].
 end;
end;


 
Eraser ©   (2006-10-31 18:25) [25]

> [23] Игорь Шевченко ©   (31.10.06 18:21)

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


 
YuRock ©   (2006-10-31 18:37) [26]

> if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
> // может привести к серьезным проблемам,
> // если этот обработчик расчитан для работы в осн. потоке.

А может и не привести. Все зависит от того, что за код программист написал в OnMessage. И вообще - написал ли. Я этот момент упомянул в [11].

> // есть подозрение, что эти методы тоже не потоко-безопасны.

Они вполне безопасны. В них используются только элементарные функции WinApi - и нечего более.

> FTerminate := True; // про это сказано в [8].

Ну и что там сказано про это? Читаем: "поле TApplication.FTerminate не защищено крит.секцией. И при этом нет никаких гарантий, что потоку не послано WM_QUIT."

Что из этого? Ну послано - отлично! Присвоется эта переменная - так она и должна была присвоиться. НИЧЕГО страшного в этом нет.


 
Eraser ©   (2006-10-31 18:45) [27]

> [26] YuRock ©   (31.10.06 18:37)


> Они вполне безопасны. В них используются только элементарные
> функции WinApi - и нечего более.

уверен?
CancelHint к примеру? или ObjectFromHWnd? а в IsMDIMsg прямо вся состоит из вызова API? )


 
Eraser ©   (2006-10-31 18:52) [28]

> [26] YuRock ©   (31.10.06 18:37)


> Что из этого? Ну послано - отлично! Присвоется эта переменная
> - так она и должна была присвоиться. НИЧЕГО страшного в
> этом нет.

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


 
YuRock ©   (2006-10-31 19:02) [29]


> уверен?CancelHint к примеру? или ObjectFromHWnd? а в IsMDIMsg
> прямо вся состоит из вызова API? )


Уверен на 100%. К этой строке выполнение может дойти только тогда, когда в потоке созданы VCL-ные хинты. А в дополнительных потоках их создать и работать с ними если не невозможно, то довольно сложно, как и с любыми VCL-объектами.

А IsMDIMsg, да, состоит вся из вызова API.


> таки слона то мы все и не приметели )) как только доп. потоку
> будет послано WM_QUIT - приложение завершиться )


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

P.S. Все, спасибо всем за положительные эмоции - пора выдвигаться на стадио :)


 
Eraser ©   (2006-10-31 19:17) [30]

> [29] YuRock ©   (31.10.06 19:02)


> А IsMDIMsg, да, состоит вся из вызова API.

и чтения свойств визуальных VCL объектов.
при завершении приложения, если доп. поток еще будет ативен, в этом месте AV обязательно вылетит.
function TApplication.IsMDIMsg(var Msg: TMsg): Boolean;
begin
 Result := False;
 if (MainForm <> nil) and (MainForm.FormStyle = fsMDIForm) and
    (Screen.ActiveForm <> nil) and (Screen.ActiveForm.FormStyle = fsMDIChild) then
   Result := TranslateMDISysAccel(MainForm.ClientHandle, Msg);
end;


> Да, должно завершиться.

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

не слишкол ли много "если" надо учесть, чтобы код работал как надо?
по-моему
while not Terminated and GetMessage(Msg, 0, 0, 0) do begin
  TranslateMessage( Msg );
  DispatchMessage( Msg );
end;

гораздо проще и безопаснее.


 
@!!ex ©   (2006-10-31 20:46) [31]


> YuRock

ощущени, что вы с потоками не работали....
В курсе, что будет если к одной переменной одновременно обратяться из двух разных потоков?
Семафоры и мьютексы не просто так придумали.


 
Дмитрий Белькевич ©   (2006-11-01 02:44) [32]

Господа, вам в жизни проблем мало, что бы еще и на эти грабли наступать - в appllication.processmessage может случится многое - нажатия на кнопки, перерисовка итд. И коматоз обеспечен.


 
Игорь Шевченко ©   (2006-11-01 10:53) [33]

Eraser ©   (31.10.06 19:17) [30]


>  if (MainForm <> nil) and (MainForm.FormStyle = fsMDIForm)


property FormStyle: TFormStyle read FFormStyle

property ActiveForm: TForm read FActiveForm;

И чего ?


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


Пример не затруднит ?


 
dmirror   (2006-11-01 11:58) [34]

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

Код слующий

procedure TForm1.ScanStartClick(Sender: TObject);
var
 i,j : integer;
 sx,sy,vx,vy : string;
 uclen, k,h  : integer;
 temp : real;

begin
 vx := Edit16.Text;
 vy := Edit17.Text;
 sx := Edit18.Text;
 sy := Edit19.Text;
 Stringcounter :=1;
 IsFastScan:=true;
 cRecBufSizeMaxF:=trunc(cSamplPS*StrToInt(sx)/StrToInt(vx));
 cRecBufSizeMaxFBin:=(cRecBufSizeMaxF - (cRecBufSizeMaxF mod 2))*2;

 for i:=1 to StrToInt(numlines.Text) do
   begin
     sleep(200);
     isReady :=false;

     cport.WriteStr("@0A 0,5000,"+sy+","+vy+#13#10);
     start;

     j:=0;

     repeat
     inc(j);
      application.ProcessMessages();
     until IsReady;{ or (j>=15);
     if (j>=15) then begin
      ShowMessage("Каретка не дошла до конца");
     end;           }

     sleep(200);
     isReady :=false;
     Cport.WriteStr("@0A 0,5000,"+"-"+sy+","+vy+#13#10);
     repeat
       application.ProcessMessages();
     until isReady = true;

     sleep(200);
     isReady :=false;
     Cport.WriteStr("@0A"+sx+","+vx+",0,5000"+#13#10);
     repeat
      stringcounter:=Stringcounter+1;
      application.ProcessMessages();
     until isReady;

   end;

 IsFastScan:=false;
end;

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

Всем спасибо!


 
dmirror   (2006-11-01 11:58) [35]

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

Код слующий

procedure TForm1.ScanStartClick(Sender: TObject);
var
 i,j : integer;
 sx,sy,vx,vy : string;
 uclen, k,h  : integer;
 temp : real;

begin
 vx := Edit16.Text;
 vy := Edit17.Text;
 sx := Edit18.Text;
 sy := Edit19.Text;
 Stringcounter :=1;
 IsFastScan:=true;
 cRecBufSizeMaxF:=trunc(cSamplPS*StrToInt(sx)/StrToInt(vx));
 cRecBufSizeMaxFBin:=(cRecBufSizeMaxF - (cRecBufSizeMaxF mod 2))*2;

 for i:=1 to StrToInt(numlines.Text) do
   begin
     sleep(200);
     isReady :=false;

     cport.WriteStr("@0A 0,5000,"+sy+","+vy+#13#10);
     start;

     j:=0;

     repeat
     inc(j);
      application.ProcessMessages();
     until IsReady;{ or (j>=15);
     if (j>=15) then begin
      ShowMessage("Каретка не дошла до конца");
     end;           }

     sleep(200);
     isReady :=false;
     Cport.WriteStr("@0A 0,5000,"+"-"+sy+","+vy+#13#10);
     repeat
       application.ProcessMessages();
     until isReady = true;

     sleep(200);
     isReady :=false;
     Cport.WriteStr("@0A"+sx+","+vx+",0,5000"+#13#10);
     repeat
      stringcounter:=Stringcounter+1;
      application.ProcessMessages();
     until isReady;

   end;

 IsFastScan:=false;
end;

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

Всем спасибо!


 
Сергей М. ©   (2006-11-01 13:30) [36]


> нужно было убить библиотеку svcmgr


А как она у тебя оказалась в проекте обычного GUI-приложения ?


 
YuRock ©   (2006-11-01 15:17) [37]


> ощущени, что вы с потоками не работали....В курсе, что будет
> если к одной переменной одновременно обратяться из двух
> разных потоков?Семафоры и мьютексы не просто так придумали.
>


Да, знаю. В худшем случае - логические ошибки. Которые, конечно, могут повлечь за собой все, что угодно. А могут и не повлечь, как в случае с безобидным сравнение двух чисел:
 if (MainForm <> nil) and (MainForm.FormStyle = fsMDIForm)


 
Eraser ©   (2006-11-01 15:20) [38]

> [33] Игорь Шевченко ©   (01.11.06 10:53)

мда.. насчет AV в (MainForm <> nil) and (MainForm.FormStyle = fsMDIForm) эт я погорячился, не учел тот факт, что форма не уничтожается, когда заканчивается Run. Но сути дела это не меняет. Я б не стал использовать методы TApplication для обработки сообщений в доп. потоке.


 
Anatoly Podgoretsky ©   (2006-11-01 15:23) [39]

> Eraser  (01.11.2006 15:20:38)  [38]

>  (MainForm <> nil) and (MainForm.FormStyle = fsMDIForm)

С потоками, я бы не назвал это код безобидным, легко получить как минимум AV
Это не атомарная операция.


 
Eraser ©   (2006-11-01 15:24) [40]

> [37] YuRock ©   (01.11.06 15:17)


> (MainForm <> nil) and (MainForm.FormStyle = fsMDIForm)

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



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

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

Наверх




Память: 0.58 MB
Время: 0.04 c
2-1171739873
DimitrySDA
2007-02-17 22:17
2007.03.11
Статистика подключения к Internet


2-1171896060
Ezorcist
2007-02-19 17:41
2007.03.11
Удалить первые N байт из MemoryStream?


6-1149689410
Damaty
2006-06-07 18:10
2007.03.11
SHH


11-1150407283
parovoZZ
2006-06-16 01:34
2007.03.11
Demo2Forms - не понял юмора


15-1171440220
ANB
2007-02-14 11:03
2007.03.11
Чет мне это сильно напоминает :)





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