Exceptions.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "Common.h"
  5. #include "Exceptions.h"
  6. #include "TextsCore.h"
  7. #include "HelpCore.h"
  8. #include "Configuration.h"
  9. #include "CoreMain.h"
  10. //---------------------------------------------------------------------------
  11. #pragma package(smart_init)
  12. //---------------------------------------------------------------------------
  13. static bool __fastcall WellKnownException(
  14. Exception * E, UnicodeString * AMessage, const wchar_t ** ACounterName, Exception ** AClone, bool Rethrow)
  15. {
  16. UnicodeString Message;
  17. const wchar_t * CounterName;
  18. std::unique_ptr<Exception> Clone;
  19. bool Result = true;
  20. // EAccessViolation is EExternal
  21. if (dynamic_cast<EAccessViolation*>(E) != NULL)
  22. {
  23. if (Rethrow)
  24. {
  25. throw EAccessViolation(E->Message);
  26. }
  27. Message = LoadStr(ACCESS_VIOLATION_ERROR3);
  28. CounterName = L"AccessViolations";
  29. Clone.reset(new EAccessViolation(E->Message));
  30. }
  31. // EIntError and EMathError are EExternal
  32. else if ((dynamic_cast<EListError*>(E) != NULL) ||
  33. (dynamic_cast<EStringListError*>(E) != NULL) ||
  34. (dynamic_cast<EIntError*>(E) != NULL) ||
  35. (dynamic_cast<EMathError*>(E) != NULL) ||
  36. (dynamic_cast<EVariantError*>(E) != NULL))
  37. {
  38. if (Rethrow)
  39. {
  40. throw EIntError(E->Message);
  41. }
  42. Message = E->Message;
  43. CounterName = L"InternalExceptions";
  44. Clone.reset(new EIntError(E->Message));
  45. }
  46. else if (dynamic_cast<EExternal*>(E) != NULL)
  47. {
  48. if (Rethrow)
  49. {
  50. throw EExternal(E->Message);
  51. }
  52. Message = E->Message;
  53. CounterName = L"ExternalExceptions";
  54. Clone.reset(new EExternal(E->Message));
  55. }
  56. else if (dynamic_cast<EHeapException*>(E) != NULL)
  57. {
  58. if (Rethrow)
  59. {
  60. throw EHeapException(E->Message);
  61. }
  62. Message = E->Message;
  63. CounterName = L"HeapExceptions";
  64. Clone.reset(new EHeapException(E->Message));
  65. }
  66. else
  67. {
  68. Result = false;
  69. }
  70. if (Result)
  71. {
  72. if (AMessage != NULL)
  73. {
  74. (*AMessage) = Message;
  75. }
  76. if (ACounterName != NULL)
  77. {
  78. (*ACounterName) = CounterName;
  79. }
  80. if (AClone != NULL)
  81. {
  82. (*AClone) = NOT_NULL(Clone.release());
  83. }
  84. }
  85. return Result;
  86. }
  87. //---------------------------------------------------------------------------
  88. static bool __fastcall ExceptionMessage(Exception * E, bool Count,
  89. bool Formatted, UnicodeString & Message, bool & InternalError)
  90. {
  91. bool Result = true;
  92. const wchar_t * CounterName = NULL;
  93. InternalError = false;
  94. // this list has to be in sync with CloneException
  95. if (dynamic_cast<EAbort *>(E) != NULL)
  96. {
  97. Result = false;
  98. }
  99. else if (WellKnownException(E, &Message, &CounterName, NULL, false))
  100. {
  101. InternalError = true;
  102. }
  103. else if (E->Message.IsEmpty())
  104. {
  105. Result = false;
  106. }
  107. else
  108. {
  109. Message = E->Message;
  110. }
  111. if (!Formatted)
  112. {
  113. Message = UnformatMessage(Message);
  114. }
  115. if (InternalError)
  116. {
  117. Message = FMTLOAD(REPORT_ERROR, (Message));
  118. }
  119. if (Count && (CounterName != NULL) && (Configuration->Usage != NULL))
  120. {
  121. Configuration->Usage->Inc(CounterName);
  122. }
  123. return Result;
  124. }
  125. //---------------------------------------------------------------------------
  126. bool __fastcall ExceptionMessage(Exception * E, UnicodeString & Message)
  127. {
  128. bool InternalError;
  129. return ExceptionMessage(E, true, false, Message, InternalError);
  130. }
  131. //---------------------------------------------------------------------------
  132. bool __fastcall ExceptionMessageFormatted(Exception * E, UnicodeString & Message)
  133. {
  134. bool InternalError;
  135. return ExceptionMessage(E, true, true, Message, InternalError);
  136. }
  137. //---------------------------------------------------------------------------
  138. bool __fastcall ShouldDisplayException(Exception * E)
  139. {
  140. UnicodeString Message;
  141. return ExceptionMessageFormatted(E, Message);
  142. }
  143. //---------------------------------------------------------------------------
  144. TStrings * __fastcall ExceptionToMoreMessages(Exception * E)
  145. {
  146. TStrings * Result = NULL;
  147. UnicodeString Message;
  148. if (ExceptionMessage(E, Message))
  149. {
  150. Result = new TStringList();
  151. Result->Add(Message);
  152. ExtException * ExtE = dynamic_cast<ExtException *>(E);
  153. if ((ExtE != NULL) && (ExtE->MoreMessages != NULL))
  154. {
  155. Result->AddStrings(ExtE->MoreMessages);
  156. }
  157. }
  158. return Result;
  159. }
  160. //---------------------------------------------------------------------------
  161. UnicodeString __fastcall GetExceptionHelpKeyword(Exception * E)
  162. {
  163. UnicodeString HelpKeyword;
  164. ExtException * ExtE = dynamic_cast<ExtException *>(E);
  165. UnicodeString Message; // not used
  166. bool InternalError = false;
  167. if (ExtE != NULL)
  168. {
  169. HelpKeyword = ExtE->HelpKeyword;
  170. }
  171. else if ((E != NULL) && ExceptionMessage(E, false, false, Message, InternalError) &&
  172. InternalError)
  173. {
  174. HelpKeyword = HELP_INTERNAL_ERROR;
  175. }
  176. return HelpKeyword;
  177. }
  178. //---------------------------------------------------------------------------
  179. UnicodeString __fastcall MergeHelpKeyword(const UnicodeString & PrimaryHelpKeyword, const UnicodeString & SecondaryHelpKeyword)
  180. {
  181. if (!PrimaryHelpKeyword.IsEmpty() &&
  182. !IsInternalErrorHelpKeyword(SecondaryHelpKeyword))
  183. {
  184. // we have to yet decide what we have both
  185. // PrimaryHelpKeyword and SecondaryHelpKeyword
  186. return PrimaryHelpKeyword;
  187. }
  188. else
  189. {
  190. return SecondaryHelpKeyword;
  191. }
  192. }
  193. //---------------------------------------------------------------------------
  194. bool __fastcall IsInternalErrorHelpKeyword(const UnicodeString & HelpKeyword)
  195. {
  196. return
  197. (HelpKeyword == HELP_INTERNAL_ERROR);
  198. }
  199. //---------------------------------------------------------------------------
  200. __fastcall ExtException::ExtException(Exception * E) :
  201. Exception("")
  202. {
  203. AddMoreMessages(E);
  204. FHelpKeyword = GetExceptionHelpKeyword(E);
  205. }
  206. //---------------------------------------------------------------------------
  207. __fastcall ExtException::ExtException(Exception* E, UnicodeString Msg, UnicodeString HelpKeyword):
  208. Exception(Msg)
  209. {
  210. AddMoreMessages(E);
  211. FHelpKeyword = MergeHelpKeyword(HelpKeyword, GetExceptionHelpKeyword(E));
  212. }
  213. //---------------------------------------------------------------------------
  214. __fastcall ExtException::ExtException(UnicodeString Msg, Exception* E, UnicodeString HelpKeyword) :
  215. Exception("")
  216. {
  217. // "copy exception"
  218. AddMoreMessages(E);
  219. // and append message to the end to more messages
  220. if (!Msg.IsEmpty())
  221. {
  222. if (Message.IsEmpty())
  223. {
  224. Message = Msg;
  225. }
  226. else
  227. {
  228. if (FMoreMessages == NULL)
  229. {
  230. FMoreMessages = new TStringList();
  231. }
  232. FMoreMessages->Append(Msg);
  233. }
  234. }
  235. FHelpKeyword = MergeHelpKeyword(GetExceptionHelpKeyword(E), HelpKeyword);
  236. }
  237. //---------------------------------------------------------------------------
  238. __fastcall ExtException::ExtException(UnicodeString Msg, UnicodeString MoreMessages,
  239. UnicodeString HelpKeyword) :
  240. Exception(Msg),
  241. FHelpKeyword(HelpKeyword)
  242. {
  243. if (!MoreMessages.IsEmpty())
  244. {
  245. FMoreMessages = new TStringList();
  246. FMoreMessages->Text = MoreMessages;
  247. }
  248. }
  249. //---------------------------------------------------------------------------
  250. __fastcall ExtException::ExtException(UnicodeString Msg, TStrings* MoreMessages,
  251. bool Own, UnicodeString HelpKeyword) :
  252. Exception(Msg),
  253. FHelpKeyword(HelpKeyword)
  254. {
  255. if (Own)
  256. {
  257. FMoreMessages = MoreMessages;
  258. }
  259. else
  260. {
  261. FMoreMessages = new TStringList();
  262. FMoreMessages->Assign(MoreMessages);
  263. }
  264. }
  265. //---------------------------------------------------------------------------
  266. void __fastcall ExtException::AddMoreMessages(Exception* E)
  267. {
  268. if (E != NULL)
  269. {
  270. if (FMoreMessages == NULL)
  271. {
  272. FMoreMessages = new TStringList();
  273. }
  274. ExtException * ExtE = dynamic_cast<ExtException *>(E);
  275. if (ExtE != NULL)
  276. {
  277. if (ExtE->MoreMessages != NULL)
  278. {
  279. FMoreMessages->Assign(ExtE->MoreMessages);
  280. }
  281. }
  282. UnicodeString Msg;
  283. ExceptionMessageFormatted(E, Msg);
  284. // new exception does not have own message, this is in fact duplication of
  285. // the exception data, but the exception class may being changed
  286. if (Message.IsEmpty())
  287. {
  288. Message = Msg;
  289. }
  290. else if (!Msg.IsEmpty())
  291. {
  292. FMoreMessages->Insert(0, Msg);
  293. }
  294. if (FMoreMessages->Count == 0)
  295. {
  296. delete FMoreMessages;
  297. FMoreMessages = NULL;
  298. }
  299. }
  300. }
  301. //---------------------------------------------------------------------------
  302. __fastcall ExtException::~ExtException()
  303. {
  304. delete FMoreMessages;
  305. }
  306. //---------------------------------------------------------------------------
  307. ExtException * __fastcall ExtException::Clone()
  308. {
  309. return new ExtException(this, L"");
  310. }
  311. //---------------------------------------------------------------------------
  312. UnicodeString __fastcall LastSysErrorMessage()
  313. {
  314. int LastError = GetLastError();
  315. UnicodeString Result;
  316. if (LastError != 0)
  317. {
  318. Result = FORMAT(System_Sysconst_SOSError, (LastError, SysErrorMessage(LastError)));
  319. }
  320. return Result;
  321. }
  322. //---------------------------------------------------------------------------
  323. __fastcall EOSExtException::EOSExtException(UnicodeString Msg) :
  324. ExtException(Msg, LastSysErrorMessage())
  325. {
  326. }
  327. //---------------------------------------------------------------------------
  328. __fastcall EFatal::EFatal(Exception* E, UnicodeString Msg, UnicodeString HelpKeyword) :
  329. ExtException(Msg, E, HelpKeyword),
  330. FReopenQueried(false)
  331. {
  332. EFatal * F = dynamic_cast<EFatal *>(E);
  333. if (F != NULL)
  334. {
  335. FReopenQueried = F->ReopenQueried;
  336. }
  337. }
  338. //---------------------------------------------------------------------------
  339. ExtException * __fastcall EFatal::Clone()
  340. {
  341. return new EFatal(this, L"");
  342. }
  343. //---------------------------------------------------------------------------
  344. ExtException * __fastcall ESshTerminate::Clone()
  345. {
  346. return new ESshTerminate(this, L"", Operation);
  347. }
  348. //---------------------------------------------------------------------------
  349. __fastcall ECallbackGuardAbort::ECallbackGuardAbort() : EAbort(L"callback abort")
  350. {
  351. }
  352. //---------------------------------------------------------------------------
  353. Exception * __fastcall CloneException(Exception * E)
  354. {
  355. Exception * Result;
  356. // this list has to be in sync with ExceptionMessage
  357. ExtException * Ext = dynamic_cast<ExtException *>(E);
  358. if (Ext != NULL)
  359. {
  360. Result = Ext->Clone();
  361. }
  362. else if (dynamic_cast<ECallbackGuardAbort *>(E) != NULL)
  363. {
  364. Result = new ECallbackGuardAbort();
  365. }
  366. else if (dynamic_cast<EAbort *>(E) != NULL)
  367. {
  368. Result = new EAbort(E->Message);
  369. }
  370. else if (WellKnownException(E, NULL, NULL, &Result, false))
  371. {
  372. // noop
  373. }
  374. else
  375. {
  376. Result = new Exception(E->Message);
  377. }
  378. return Result;
  379. }
  380. //---------------------------------------------------------------------------
  381. void __fastcall RethrowException(Exception * E)
  382. {
  383. // this list has to be in sync with ExceptionMessage
  384. if (dynamic_cast<EFatal *>(E) != NULL)
  385. {
  386. throw EFatal(E, L"");
  387. }
  388. else if (dynamic_cast<ECallbackGuardAbort *>(E) != NULL)
  389. {
  390. throw ECallbackGuardAbort();
  391. }
  392. else if (dynamic_cast<EAbort *>(E) != NULL)
  393. {
  394. throw EAbort(E->Message);
  395. }
  396. else if (WellKnownException(E, NULL, NULL, NULL, true))
  397. {
  398. // noop, should never get here
  399. }
  400. else
  401. {
  402. throw ExtException(E, L"");
  403. }
  404. }