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

Вниз

Логгирование исключений с последующим их перевозбуждением.   Найти похожие ветки 

 
>|   (2010-11-26 16:33) [0]

Прошу мастеров просмотреть данный код на предмет подводных камней.
Будет ли он правильно работать и какие могут быть нюансы.
procedure TDMMain.KMSExceptionHandler(Sender: TObject; E: Exception);
var fn:string;
   LOB: TLOBLocator;
   MyBlobStream: TMemoryStream;
   ComponentName:string;

begin
 try
   try
     Fn := ExtractFilename(Application.ExeName)+"_"+
           Screen.ActiveForm.Name+
           FormatDateTime("_ddmmyyyy_hhnnss",now)+
           "_debug";
     MyBlobStream:= TMemoryStream.Create;
     DoGenerateScreenshot;

     LOB:= TLOBLocator.CreateTemporary(DMMain.OracleSession, otBLOB, True);
     try
       oqInsertError.ClearVariables;
       oqInsertError.SetVariable("V_FORM_NAME",Screen.ActiveForm.Name+":"+Screen.ActiveForm.Caption);
       oqInsertError.SetVariable("V_ERROR_TEXT",E.Message);
       oqInsertError.SetVariable("V_ID_USER",DMMain.UserID);
       oqInsertError.SetVariable("V_DATETIME",Now);
       oqInsertError.SetVariable("V_OSUSER_NAME",CollectUserName);
       oqInsertError.SetVariable("V_COMP_NAME",CollectComputerName);
       oqInsertError.SetVariable("v_exception_name", E.ClassName);
       if Sender is TComponent then
         ComponentName := TComponent(Sender).Name
         //TODO: Попытаться вытянуть из сендера текстовое заглавие  компонента, который возбудил ошибку
       else
         ComponentName := "<имя неизвестно>";
       oqInsertError.SetVariable("v_object_name",Sender.ClassName+":"+ ComponentName);
       MyBlobStream.Position := 0;
       LOB.CopyFrom(MyBlobStream, MyBlobStream.Size);
       oqInsertError.SetComplexVariable("V_SCREENSHOT", LOB);
       oqInsertError.Execute;
       DMMain.OracleSession.Commit;
     finally
       LOB.Free;
       MyBlobStream.Free;
     end;
   except
     on E_local:Exception do
     begin
         raise E_local.Create("Ошибка логгирования:"#10#13+ E_local.Message);
         MyBlobStream.SaveToFile(fn+".jpg");
     end;
   end;
 finally
   Application.OnException := nil;
   raise E.Create("Произошло исключение, которое было записано в БД.");
   Application.OnException := KMSExceptionHandler;
 end;
end;


 
Rouse_ ©   (2010-11-26 16:42) [1]

вот это работать не будет:

  raise E.Create("Произошло исключение, которое было записано в БД.");
  Application.OnException := KMSExceptionHandler; <<< вызвано не будет


 
Rouse_ ©   (2010-11-26 16:42) [2]

ну и вот это тоже :)
MyBlobStream.SaveToFile(fn+".jpg");


 
Юрий Зотов ©   (2010-11-26 16:43) [3]

Весь код не смотрел, но вот здесь 2 ошибки:

finally
  Application.OnException := nil;
  raise E.Create(...); // Е - это не класс, а экземпляр объекта.
  Application.OnException := ... // Эта строка никогда не выполнится
end;


 
Сергей М. ©   (2010-11-26 16:44) [4]


> на предмет подводных камней


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


 
Rouse_ ©   (2010-11-26 16:47) [5]

Ну и кстати да: весь код нитей в собственный глухой try except завернут, зачем не понятно...


 
Сергей М. ©   (2010-11-26 16:50) [6]


> Rouse_ ©   (26.11.10 16:47) [5]


> весь код нитей в собственный глухой try except завернут,
>  зачем не понятно


Если ты о TThread, то оч даже понятно - для формошлепов это сделано)


 
>|   (2010-11-26 17:14) [7]


> Весь код не смотрел, но вот здесь 2 ошибки:
>
> finally
>   Application.OnException := nil;
>   raise E.Create(...); // Е - это не класс, а экземпляр
> объекта.
>   Application.OnException := ... // Эта строка никогда не
> выполнится
> end;

в принципе, это ключевое место
тогда вопрос, как перевозбудить исключение, которое содержится в объекте E?
Можно ли написать следующим образом:
finally
  Application.OnException := nil;
   try
    raise // каким образом здесь перевозбудить исключение?
   finally
     Application.OnException := KMSExceptionHandler;
   end;
end;


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

Таки да, в приложении будут работать потоки, для которых будет своя обработка.
Цитирую:
"При использовании TThread у вас уже есть возможности для манёвра. Дело в том, что функция потока в TThread оборачивает вызов Execute в try/except. Любое исключение, сбежавшее из Execute, заносится в свойство FatalException потока. Исключение будет удалено в деструкторе TThread. А вы можете проанализировать этот код из события OnTerminate или из кода главного потока, например:

T := TMyThread.Create(False);
try

 // ... <- Выполняем какие-то действия. Поток в это время также выполняет работу.

 // Мы свою работу выполнили - ждём конца работы потока.
 T.WaitFor;
 // Анализируем: успешно ли завершился поток?
 if T.FatalException <> nil then // есть ошибка
 begin
   // Обработка ошибки потока.
 end;
finally
 FreeAndNil(T);
end;"


 
>|   (2010-11-26 17:16) [8]

Вопрос остается открытым:
Каким образом перевозбудить исключение после записи его в лог?


 
>|   (2010-11-26 17:20) [9]

Можно ли таким образом поступить?
finally
   Application.OnException := nil;
   try
    raise E;
   finally
     Application.OnException := KMSExceptionHandler;
   end;
 end;


 
Сергей М. ©   (2010-11-26 17:28) [10]


> Можно ли таким образом поступить?
> finally
>    Application.OnException := nil;
>    try
>     raise E;
>    finally
>      Application.OnException := KMSExceptionHandler;
>    end;
>  end;


Непонятно зачем эти пляски с бубном вокруг обниления и восстановления обработчика Application.OnException в теле самого обработчика ..


 
>|   (2010-11-26 17:36) [11]


> Непонятно зачем эти пляски с бубном вокруг обниления и восстановления
> обработчика Application.OnException в теле самого обработчика
> ..

Капитан Очевидность спешит с ответом:
Для логирования ошибок:-)


 
>|   (2010-11-26 17:39) [12]

Если не выключать обработчик, полагаю, возникнет циклическое исключение.


 
Сергей М. ©   (2010-11-26 17:40) [13]

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


 
clickmaker ©   (2010-11-26 17:40) [14]

мне тоже непонятно...

Log(E_local.Message);
raise E_local;

и всё


 
Rouse_ ©   (2010-11-26 17:41) [15]

местами строчки поменять и всего делов, но все равно не понятно, зачем все так сложно? Возьми джеди - там хороший обработчик SEH фреймов имеется.


 
Сергей М. ©   (2010-11-26 17:45) [16]


> Если не выключать обработчик, полагаю, возникнет циклическое
> исключение


А зачем его перевозбуждать-то ?


 
Юрий Зотов ©   (2010-11-26 17:53) [17]


> >|<   (26.11.10 17:16) [8]
> Каким образом перевозбудить исключение после записи его
> в лог?


Например, так:

type
 EMyException = class(Exception)
 public
   constructor Create(E: Exception);
 end;

constructor EMyException.Create(E: Exception);
begin
 inherited Create(
  Format("Произошло и записано в БД исключение класса %s: %s",
     [E.ClassName, E.Message])
end;


Вызов такой:

Application.OnException := nil;
try
 raise EMyException.Create(E)
finally
 Application.OnException := KMSExceptionHandler;
end;


Но вместо всех этих плясок с перевозбуждением исключения можно просто вызвать ShowMessage и выдать сообщение:
Format("Произошло и записано в БД исключение класса %s: %s", E.ClassName, E.Message])


 
KSergey ©   (2010-11-26 17:59) [18]

> clickmaker ©   (26.11.10 17:40) [14]
> мне тоже непонятно...

Автор опасается, что исключение, возникшее в Application.OnException приведет к вызову того же Application.OnException, где опять исключение - и по кругу.

Прав ли он - надо в код VCL смотреть или натурный эксперимент ставить.


 
Сергей М. ©   (2010-11-26 18:03) [19]


> KSergey ©   (26.11.10 17:59) [18]


> Прав ли он


Прав.

Но перевозбуждать (или возбуждать новое) исключение в обработчике, СПЕЦИАЛЬНО предназначенном для обработки необработанных исключений, - это ничем не оправданная блажь.

Чтобы уронить свой процесс великого ума не требуется)


 
KSergey ©   (2010-11-26 18:09) [20]

> Сергей М. ©   (26.11.10 18:03) [19]

Ну тогда надо делать как обычно: код обработки исключений не должен исключения генерировать
Т.е. тупо try/except по краям в него - и все.
Как вариант - в except вставить диалоговое окно "была ошибка, но сохранить в базу не сумели, делайте скриншот". Если уж диалоговое окно вызовет исключение - ну это явно совсем не повезло юзеру, на карму его и свалить :)


 
KSergey ©   (2010-11-26 18:11) [21]

К стати, а зачем именно исключение возбуждать с текстом "Произошло исключение, которое было записано в БД."? достаточно это в виде диалогового окна отобразить - да и все. Ну раз уж взяли на себя работу стандартного обработчика - ее надо делать до конца.


 
>|   (2010-11-26 18:14) [22]

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


 
Сергей М. ©   (2010-11-26 18:18) [23]

все что нужно - это

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

//покажем юзеру, если так уж надо, оригинальное исключение
ShowException(E);


 
>|   (2010-11-26 18:19) [24]

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


 
Сергей М. ©   (2010-11-26 18:26) [25]


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


А он и не подумает что все в порядке)

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

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

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


 
>|   (2010-11-26 18:47) [26]


> Сергей М. ©   (26.11.10 18:26) [25]

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

Всем спасибо за помощь и внимание к моему вопросу.)


 
_Юрий   (2010-11-26 18:52) [27]

Совсем гасить текст оригинального исключения - тоже нехорошо,  потому что может оказаться так, что пользователь в состоянии самостоятельно разрулить проблему, не дергая саппорт.
например, если в настройках путь к БД неверный, вывод даже сообщения типа
"Cannot open file c:\myPath\MyFile.db"  может оказаться полезным.


 
>|   (2010-11-26 18:56) [28]


> Совсем гасить текст оригинального исключения - тоже нехорошо,
>   потому что может оказаться так, что пользователь в состоянии
> самостоятельно разрулить проблему, не дергая саппорт.
> например, если в настройках путь к БД неверный, вывод даже
> сообщения типа
> "Cannot open file c:\myPath\MyFile.db"  может оказаться
> полезным.

По этому поводу буду выводить следующее сообщение:
ErrorDlg("Возникла ошибка:"+#10#13+E.Message+
            #10#13+"Для ее устранения обратитесь к разработчикам."+
            #10#13+"Желательно повторить действия, которые привели к ее возникновению и"+
            #10#13+"убедиться, что причина ошибки определена.");


 
_Юрий   (2010-11-26 19:07) [29]


> >|<   (26.11.10 18:56) [28]


кстати начиная с 2009 наконец то появились InnerException, что позволяет при определенных усилиях получить весь "логический стек" ,начиная с момента возникновения ошибки.
Если используется такая версия, рекомендую посмотреть статью:
http://www.gunsmoker.ru/2010/04/exception-delphi-2009.html


 
KSergey ©   (2010-11-26 21:49) [30]

> >|<   (26.11.10 18:14) [22]
> Идея даже не в том, чтобы погасить все исключения.
> Это неприемлемо, поскольку произойдет ошибка, а пользер
> будет и дальше работать как ни в чем не бывало.
>
> Вот для этого я и перевозбуждаю его, чтобы пользер не думал,  что все в порядке.

Я понял в чем ошибка вашего миропонимания. Вы просто перевозбудились! (сугубо каламбур, ничего личного)

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

Однако Application.OnException - это как раз и есть та самая последняя подушка, которая собственно эти исключения перехватывает. Ну т.е. перехватывает, конечно, блок try/exception вокруг кода обработки собщения, но при задании пользователем обработчика для Application.OnException собственно этому обработчику и отдается на откуп вся логика по обработке факта возникновения исключения.

Но давайте от словоблудия- к коду.
Вот что есть с VCl:

procedure TApplication.Run;
begin
 FRunning := True;
 try
   AddExitProc(DoneApplication);
   if FMainForm <> nil then
   begin
     case CmdShow of
       SW_SHOWMINNOACTIVE: FMainForm.FWindowState := wsMinimized;
       SW_SHOWMAXIMIZED: MainForm.WindowState := wsMaximized;
     end;
     if FShowMainForm then
       if FMainForm.FWindowState = wsMinimized then
         Minimize else
         FMainForm.Visible := True;
     repeat
       try
         HandleMessage;
       except
         HandleException(Self);
       end;

     until Terminated;
   end;
 finally
   FRunning := False;
 end;
end;

Это как раз тот метод объекта Application, который тупо крутит цикл выборки сообщений repeat/until все время существования Windows-приложения.
Обратите внимание на выделенный фрагмент. Именно внутри метода HandleMessage выполняются решительно весь тот код, который вы собственно и пишите. Потому как любой код есть лишь реакция на какое-либо сообщение. Ни в какое другое место (кроме Initialization/finalization и событий создение/уничтожение главной формы) свой код вы внедрить не можете. Только внутрь обработчика какого-либо сообщений Windows.
И что же мы видим? а мы видим, что все необработанные исключения здесь тупо гасятся, при этом вызывается HandleException, который весьма прост:

procedure TApplication.HandleException(Sender: TObject);
begin
 if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
 if ExceptObject is Exception then
 begin
   if not (ExceptObject is EAbort) then
     if Assigned(FOnException) then
       FOnException(Sender, Exception(ExceptObject))
     else
       ShowException(Exception(ExceptObject));
 end else
   SysUtils.ShowException(ExceptObject, ExceptAddr);
end;

Что же мы видим в выделеном фрагменте? если установлен свой обработчки исключений для приложения - то вызовется он. Если не установлен - вызовется просто отображение информационного окна. Все! Т.е. перевозбуждать в том месте исключение просто не имеет смысла, его попросту некому будет обработать! дальше только run-time error и принудительное завершение процесса.

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

Надеюсь, объяснил понятно.


 
Leonid Troyanovsky ©   (2010-11-28 22:27) [31]


> >|<   (26.11.10 18:14) [22]

> Это неприемлемо, поскольку произойдет ошибка, а пользер
> будет и дальше работать как ни в чем не бывало.

Хорошее имя - пользер. Записал себе в мемо.

> KSergey ©   (26.11.10 21:49) [30]

Про перевозбуждение тоже понравилось.

--
Regards, LVT.


 
_oxffff   (2010-11-29 08:48) [32]


> в принципе, это ключевое место
> тогда вопрос, как перевозбудить исключение, которое содержится
> в объекте E?


Reraising ExceptionsFrom RAD Studio
Go Up to Exception handling Index

Sometimes when you handle an exception locally, you want to augment the handling in the enclosing block, rather than replace it. Of course, when your local handler finishes its handling, it destroys the exception instance, so the enclosing block"s handler never gets to act. You can, however, prevent the handler from destroying the exception, giving the enclosing handler a chance to respond. You do this by using the raise command with no arguments. This is called reraising or rethrowing the exception. The following example illustrates this technique:

try
{ statements }
 try
{ special statements }
 except
   on ESomething do
   begin
{ handling for only the special statements }
     raise;{ reraise the exception }
   end;
 end;
except
 on ESomething do ...;{ handling you want in all cases }
end;


 
_oxffff   (2010-11-29 09:29) [33]

Также в новых версиях есть поддержка вложенных исключений

см. Exception.InnerException (specifies the inner exception)

Read the value of the InnerException property to obtain the inner exception. If there are no exceptions that triggered the current one, InnerException returns nil; otherwise InnerException returns the inner exception that triggered a specific exception.


 
Дмитрий Белькевич   (2010-11-29 11:03) [34]


> Идея состояла только в том, чтобы вклиниться в очередь возникновения
> ошибок и перед ее возникновением отправить скриншот(другие
> данные) в БД, чтобы можно было проанализировать причину.
>


Можно посмотреть в сторону эврикалог еще. Сильно помогает, делает то, что написал и еще много всяких вкусностей, типа снятия стёка процедур.


 
Ega23 ©   (2010-11-29 12:18) [35]


> По этому поводу буду выводить следующее сообщение:
> ErrorDlg("Возникла ошибка:"+#10#13+E.Message+


Не вдаваясь в подробности всей ветки и разбирание самого вопроса, хочу спросить: а почему #10#13?
$0D - конец строки
$0A - возврат каретки
Или я не прав?


 
Anatoly Podgoretsky ©   (2010-11-29 12:26) [36]

> Ega23  (29.11.2010 12:18:35)  [35]

Ну наверно автор решил разместить их по возрастанию и это он сделал зря.


 
Ega23 ©   (2010-11-29 12:28) [37]


> Ну наверно автор решил разместить их по возрастанию и это
> он сделал зря.


Я просто такой код настолько часто вижу, что уже начинаю сомневаться, что #13#10 - правильный вариант.


 
Anatoly Podgoretsky ©   (2010-11-29 13:52) [38]

> Ega23  (29.11.2010 12:28:37)  [37]

Он правильный (#10#13), но только хакерский
А #13#10 это стандартный разделитель ДОС/Виндоус


 
clickmaker ©   (2010-11-29 14:28) [39]

> Он правильный (#10#13), но только хакерский

дядя Толя, поделился бы своим опытом бывшего хакера. )
почему именно "хакерский" я до сих пор не понимаю


 
Anatoly Podgoretsky ©   (2010-11-29 19:45) [40]

Чего тут делиться, есть три стандартных разделителя, в зависимости от ОС
CR, LF, CRLF
Но хакерам хотелось быть особыми, не похожемы на других, вот они и предумали четвертую комбинацию, которая не признается ни одной ОС - LFCR

Вот и весь секрет.


 
Leonid Troyanovsky ©   (2010-11-29 21:44) [41]


> Anatoly Podgoretsky ©   (29.11.10 19:45) [40]

> Вот и весь секрет.

Перепутывание от перевозбуждения.

--
Regards, LVT.


 
Игорь Шевченко ©   (2010-11-29 23:55) [42]


> Вот и весь секрет.


только вот мессадж-боксам это по барабану. Эти разделители имеют смысл в файлах :)

unit main;

interface

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

type
 TForm1 = class(TForm)
   Button1: TButton;
   Button2: TButton;
   Button3: TButton;
   Button4: TButton;
   Button5: TButton;
   Button6: TButton;
   Button7: TButton;
   Button8: TButton;
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
   procedure Button3Click(Sender: TObject);
   procedure Button4Click(Sender: TObject);
   procedure Button8Click(Sender: TObject);
   procedure Button7Click(Sender: TObject);
   procedure Button6Click(Sender: TObject);
   procedure Button5Click(Sender: TObject);
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
 ShowMessage(#10+#13+"foo"+#10+#13+"bar");
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 ShowMessage(#13+#10+"foo"+#13+#10+"bar");
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
 ShowMessage(#13+"foo"+#13+"bar");
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
 ShowMessage(#10+"foo"+#10+"bar");
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
 MessageBox (0, PChar(#10+#13+"foo"+#10+#13+"bar"), "FOO", MB_OK);
end;

procedure TForm1.Button6Click(Sender: TObject);
begin
 MessageBox (0, PChar(#13+#10+"foo"+#13+#10+"bar"), "FOO", MB_OK);
end;

procedure TForm1.Button7Click(Sender: TObject);
begin
 MessageBox (0, PChar(#13+"foo"+#13+"bar"), "FOO", MB_OK);
end;

procedure TForm1.Button8Click(Sender: TObject);
begin
 MessageBox (0, PChar(#10+"foo"+#10+"bar"), "FOO", MB_OK);
end;

end.


 
Inovet ©   (2010-11-30 00:21) [43]

> [42] Игорь Шевченко ©   (29.11.10 23:55)
> только вот мессадж-боксам это по барабану

Странно, всегда пользуюсь разделителями, 0x0a который, в MessageBox, и новая строка получается.


 
Anatoly Podgoretsky ©   (2010-11-30 00:24) [44]

Извращений много разных, вот и Inovet такой же извращенец, наверно его жизнь не била, но все впереди.


 
Anatoly Podgoretsky ©   (2010-11-30 00:25) [45]

Вообще то правильнее использовать LineBreak


 
Inovet ©   (2010-11-30 00:41) [46]

> [44] Anatoly Podgoretsky ©   (30.11.10 00:24)
> вот и Inovet такой же извращенец,

> [45] Anatoly Podgoretsky ©   (30.11.10 00:25)
> Вообще то правильнее использовать LineBreak

Путаю я эти коды в цифрах, вот такой вобщем и изпользую "\n" - новая строка, а код его таки 0x0a.

> [38] Anatoly Podgoretsky ©   (29.11.10 13:52)
> А #13#10 это стандартный разделитель ДОС/Виндоус

Блин, открыл SysUtils.pas посдледовательность 0D 0A в конце строк.


 
Anatoly Podgoretsky ©   (2010-11-30 00:43) [47]

> Inovet  (30.11.2010 00:41:46)  [46]

LineBreak и путаться не будешь, Дельфи сама будет учитывать ОС
Рекомендую справку взглянуть, если она есть.


 
Inovet ©   (2010-11-30 00:55) [48]

> [47] Anatoly Podgoretsky ©   (30.11.10 00:43)
> Рекомендую справку взглянуть

Угу, так.
Из MSDN о MessageBox

lpText
[in] Pointer to a null-terminated string that contains the message to be displayed. If the string consists of more than one line, you can separate the lines using a carriage return and/or linefeed character between each line.

Так что нет изварещения

> [46] Inovet ©   (30.11.10 00:41)
> открыл SysUtils.pas посдледовательность 0D 0A в конце строк.

В смысле открыл Hex вьювере, на концы строк посмотреть.


 
Inovet ©   (2010-11-30 01:11) [49]

> [46] Inovet ©   (30.11.10 00:41)
> > [38] Anatoly Podgoretsky ©   (29.11.10 13:52)
> > А #13#10 это стандартный разделитель ДОС/Виндоус
>
> 0D 0A в конце строк.

Ты же это самое и написал.

Кстати, у меня как запомнилось когда-то на слух "carriage return linefeed", так и осталось, а коды, как коснётся приходится вспоминать какой из них какой, раньше помнил, но всё равно заменял символьным сочетанием.


 
Германн ©   (2010-11-30 01:41) [50]


> Кстати, у меня как запомнилось когда-то на слух "carriage
> return linefeed", так и осталось, а коды, как коснётся приходится
> вспоминать какой из них какой

Так тебе АП уже несколько раз сказал "используй LineBreak"!
LineBreak - это константа в Дельфи (если ты еще этого не понял :)


 
Inovet ©   (2010-11-30 02:18) [51]

> [50] Германн ©   (30.11.10 01:41)
> LineBreak - это константа в Дельфи (если ты еще этого не
> понял :)

Я то понял, но не только же Делфи на свете.


 
Германн ©   (2010-11-30 02:37) [52]


> Я то понял, но не только же Делфи на свете.

Да? Ну и кто же ещё существует на свете? :)
А уж на ДМ просто неприлично упоминать что-то, что не Дельфи. :)


 
Anatoly Podgoretsky ©   (2010-11-30 09:08) [53]


> Я то понял, но не только же Делфи на свете.

Я поганой метлой вымету всех отсюда, кто не с Дельфи.



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

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

Наверх





Память: 0.63 MB
Время: 0.005 c
2-1291200879
Демерго
2010-12-01 13:54
2011.02.20
Вытащить часть текста из Memo


15-1288465490
Делфиец
2010-10-30 23:04
2011.02.20
Зацените прогу


15-1289472620
Movement_boy
2010-11-11 13:50
2011.02.20
Анализ бинарника


2-1290948836
delphilamer
2010-11-28 15:53
2011.02.20
нужна помощь новичку (записи)


15-1289338193
Юрий
2010-11-10 00:29
2011.02.20
С днем рождения ! 10 ноября 2010 среда





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