مدیریت خطا در اکسس
بسم الله الرحمن الرحیم
سلام
یکی از شاخصههای یک برنامه کاربر پسند و کاربردی، نمایش هشدار و خطاهای مناسب برای راهنمایی اپراتور و کاربر نرم افزار است.
از آنجایی که اکسس به دلیل سادگی و امکانات فراوان، برای تولید نرم افزارهای کوچک و متوسط مناسب است، مدیریت خطاها نیز اهمیت خاص خود را داره.
معمولا برنامهنویس خطاهای احتمالی کدهای خود را مدیریت میکنه و پیامهای مناسبی رو به کاربر نشون میده ولی پیامهای پیشفرض اکسس چطور؟
در این آموزش سعی دارم تا روند کنترل خطاهای معمول اکسس و مدیریت خطا در اکسس رو براتون قرار بدم.
همه میدونند تقریبا نوشتن کدهای VBA سخت است و برای تازه کاران سخت تر! ولی نوشتن کدهایی برای اشکال زدایی یا دیباگ کردن به معنای واقعی کلمه سخت است.
بیشتر توسعه دهندگان وقت خود را صرف نوشتن کدهای بخش دیباگ یا اشکال زدایی میکنند.
در این مقاله قصد دارم به جای اشکال زدایی، به مدیریت صحیح خطا در VBA بپردازم.
بذارید یک مثال برای شما بزنم؛
بررسی تله موش
فرض کنید در خانه شما یک موش (خطا) وجود دارد که در هر لحظه در حال جابجایی و تغییر مکان است.
شما بدون اطلاع از اینکه موش (خطا) در کدام موقعیت (کدام خط کد شما) ظاهر میشود، مدام در حال جستجوی خانه خودتان برای پیدا کردن و شکار موش هستید.
ولی یک پیشنهاد بهتر هم وجود دارد! اینکه شما از چند تله موش در نقاط مختلف استفاده کنید و کمی صبر کنید تا با پای خودش به تله بیافتد!.
خب پس سوال این میشود: در چه زمانی از خطای VBA صحبت میکنیم؟ بله هنگامی که یک قطعه کد مشخصی رو در نظر داشته باشیم.
استفاده از On Error در VBA
شما با استفاده از On Error مشخص میکنید که در کدام Function یا Sub در زمان بروز خطا چه عکس العملی نشان داد! این دقیقا مثل کار گذاشتن تله موش است، با این تفاوت که میتوانید مشخص کنید در صورت بروز خطا پیام یا عملکرد مشخصی انجام شود و یا از اجرای ادامه کدها صرف نظر کند.
خب برای شروع یک گرامر و Syntax کامل از On Error رو با هم مرور کنیم.
On Error { GoTo [ line | 0 ] | Resume Next }
سعی میکنم تا از MSDN حالتهای مختلف خطای VBA را که با On Error مدیریت شده است را بررسی کنم.
On Error Goto – or On Error GoTo [ lineLabel | 0 | -1 ] در صورت بروز خطا به شما اجازه میدهد تا یک کد خاص را برای پیگیری به سه روش داده میشود. lineLabel – به یک برچسب شماره خاص مراجعه کنید 0 – هر پردازش خطای قبلا تنظیم شده در روش فعلی غیرفعال خواهد شد Resume Next – نگران نباشید هر گونه خطا مطرح شده و اجرای کد را به خط بعدی منتقل کنید.
نمونههای On Error
حالا که با گرامر و ساختار On Error آشنا شدید، چند نمونه را با هم بررسی میکنیم.
On Error Resume Next 'هر گونه خطا مطرح شده را رها کنید Dim x, y x = y /0 'تقسیم به خطای صفر! On Error Resume Next x = y /0 'خطایی رخ نداد
On Error Goto 0 'از کار انداختن هر خطای قبلی Dim x, y On Error Resume Next 'پرش از روی خطاها x = y /0 'خطایی رخ نداد On Error Goto 0 'از کار انداختن کنترل خطا x = y /0 'تقسیم به خطای صفر!
On Error Goto Label 'در صورت بروز خطای به یک برچسب خط ویژه پرش کن Dim x, y On Error Goto ErrorHandl x = y /0 'خطایی رخ نداد On Error Goto 0 'از کار انداختن کنترل خطا x = y /0 'تقسیم به خطای صفر!
شی Err در VBA
هر زمان که یک خطای VBA ایجاد میشود، تابع Err با اطلاعات مربوطه مورد نیاز برای تشخیص خطا به روز میشود. اجازه بدهید نگاهی به این موضوع بیاندازیم.
توابع و خواص Err
شی Err توابع و خواص زیر را فراهم میکند:
- Number (شماره) - مهمترین ویژگی شی Err، شماره خطا مطرح شده است. در MSDN شما میتوانید لیست کامل خطاهای VBA را پیدا کنید. محدوده در دسترس برای خطاهای کاربر سفارشی 513-65535 است.
- Clear (پاک کردن) - پاک کردن خطای فعلی. در صورت استفاده از Resume Next مفید است.
Raise(Number, [Source], [Description], [HelpFile], [HelpContext]) – خطا را افزایش میدهد. شما باید شماره خطایی را ارائه دهید. برای دیدن یک لیست کامل از شماره خطاهای VBA اینجا را ببینید. آیا می خواهید یک خطای سفارشی بسازید؟ محدوده در دسترس برای خطاهای کاربر سفارشی 513-65535 است.
- Source (منبع) - منبع خطا - معمولا VBA Project شماست.
- Description (شرح) - شرح خطا
Dim errMsg As String On Error Resume Next '7 = خارج از حافظه Err.Raise (7) If Err.Number <> 0 Then errMsg = "Error number: " & Str(Err.Number) & vbNewLine & _ "Source: " & Err.Source & vbNewLine & _ "Description: " & Err.Description Debug.Print errMsg Err.Clear End If
خطا هنگام جابهجایی بهترین شیوهها
حالا که ما روش خود را در مورد کنترل خطای VBA میدانیم، اجازه دهید برخی از روشهای خوب را در مورد جابجایی خطای VBA را مرور کنیم. بهترین روش برای کنترل خطا این است که تمام کنترلرها را در انتهای کدهای خود قرار دهید - چه Sub باشد یا Function.
مثال زیر نشان میدهد که چگونه انجام میشود:
یک کنترلر خطای تکی
اگر میخواهید تمام خطاهای موجود در یک بخش را بررسی کنید ، مثال زیر را ببینید:
On Error GoTo ErrorHandler Dim x, y x = y / 0 'تقسیم به صفر! Exit Sub ErrorHandler: Debug.Print "Error number: " & Err.Number Err.Clear
به کد Exit Sub
که قبل از عبارت ErrorHandler
آمده است دقت کنید! این جمله مهم است چرا که مطمئن میشویم تا ErrorHandler
تنها در صورت بروز خطا اجرا میشود.
یک کنترلر خطای چندگانه
اگر میخواهید چندین اشتباه را هم زمان مدیریت کنید. به عنوان مثال براساس تعداد خطا مانند موارد زیر است:
On Error GoTo ErrorHandler Dim x, y x = y / 0 'تقسیم به صفر! Exit Sub ErrorHandler: Select Case Err.Number Case 6: GoTo DivideByZeroError Case 7: GoTo OutOfMemoryError Case Default: GoTo OtherError End Select DivideByZeroError: Debug.Print "تقسیم به صفر!" Err.Clear Exit Sub OutOfMemoryError: Debug.Print "خارج از حافظه!" Err.Clear Exit Sub OtherError: Debug.Print "خطای دیگر!" Err.Clear Exit Sub
قسمت ErrorHandler در این حالت، به بخش خطای تعیینشده بر اساس مدل Err.Numb هدایت میشود. خطاهای ناشناخته به بلوک OtherError هدایت میشوند. این کار باعث میشود خطای VBA تمیز و مرتب باشد. لذا قطعا مفسر خطای چندگانه بهتر است چون به شما و کاربر قدرت کنترل بیشتری نسبت به خطاهای ایجاد شده توسط VBA میدهد.
خطای VBA سفارشی
در برخی موارد، شما میخواهید خطای سفارشی را ایجاد کنید. بهترین روش برای انجام این کار استفاده از روش Err.Raise است.
هنگام ایجاد خطاهای سفارشی، اطمینان حاصل کنید که آنها را به خوبی ثبت کردهاید. من ایجاد یک شی Enum و لیست کردن تمام خطاهای سفارشی مانند زیر را توصیه میکنم:
Enum CustomErrors CustomErr1 = 514 'اولین شماره خطای سفارشی CustomErr2 = 515 '... End Enum
حال ما میتوانیم از شماره خطای سفارشی خود در مدیریت خطای VBA استفاده کنیم:
On Error GoTo ErrorHandler Err.Raise CustomErrors.CustomErr1 'Raise a customer error using the Enum Exit Sub ErrorHandler: Select Case Err.Number Case CustomErrors.CustomErr1: GoTo CustomErr1Handler Case CustomErrors.CustomErr2: GoTo CustomErr1Handler Case Else: GoTo OtherError End Select CustomErr1Handler: Debug.Print "CustomErr1" Err.Clear Exit Sub CustomErr2Handler: Debug.Print "CustomErr2" Err.Clear Exit Sub OtherError: Debug.Print "Other error!, Error: " & Err.Number Err.Clear Exit Sub
خوب حالا زمان مرتب کردن است! اما در مورد تمیز کردن این Error باید چه اقداماتی انجام دهیم؟ قطعا قصد تکرار شرح خطاها را در میان کدها نداریم، لذا یک Function ساده میتواند کمک کند:
Function GetErrorMsg(no As Long) Select Case no Case CustomErr1: GetErrorMsg = "This is CustomErr1" Case CustomErr1: GetErrorMsg = "This is CustomErr2" End Select End Function
بیایید آنچه را که ما در یک نمونه کد منسجم میدانیم را جمعآوری کنیم:
مدیریت خطا در VBA
On Error GoTo ErrorHandler Err.Raise CustomErrors.CustomErr1 Exit Sub ErrorHandler: Select Case Err.Number Case CustomErrors.CustomErr1: GoTo CustomerErr1Handler Case CustomErrors.CustomErr2: GoTo CustomerErr2Handler Case Else: GoTo OtherError End Select CustomerErr1Handler: Debug.Print GetErrorMsg(CustomErr1) 'Handle the error Err.Clear Exit Sub CustomerErr2Handler: Debug.Print GetErrorMsg(CustomErr1) 'Handle the error Err.Clear Exit Sub OtherError: Debug.Print GetErrorMsg(Err.Number) 'Handle the error Err.Clear Exit Sub
در مورد Resume Next
Resume Next عالی است زمانیکه شما در مورد یک خطا که میخواهید اجرا شود، درخواست کنید تا به قطعه بعدی حرکت کند و اجرای کد را ادامه دهید. شما می توانید از دستور Resume Next برای ادامه اعمال که مستقیما از متصدی خطای VBA خود استفاده کنید:
On Error GoTo ErrorHandler Dim x, y x = y / 0 'Divide by zero! Debug.Print "Continue execution" Exit Sub ErrorHandler: Debug.Print "Error: " & Err.Description Resume Next 'Return to line 4
VBA Error Log
خطاهای Logging در تطبیق با مفاهیم کنترل خطای VBA بسیار مفید هستند. این به شما این امکان را میدهد تا مطمئن شوید که هیچ خطایی را (که ممکن است در Workbooks رخ داده باشد) از دست ندهید، اگر چه ممکن است بخواهید این خطاها را مستقیما اداره کنید. اگر میخواهید بیشتر در مورد نوشتن در فایلهای متنی مطالعه کنید.
روش LogError، پیغام خطا را با زمان فعلی ( تاریخ و زمان ) الحاق خواهد کرد:
Sub LogError(msg As String) Dim fileName As String, fileNo As Integer fileNo = FreeFile 'Get first free file number fileName = CurrentProject.Path & "\error_log.txt" Open fileName For Append As #fileNo Print #fileNo, Now & ":" & msg Close #fileNo End Sub Sub TestErrorLog() On Error GoTo ErrorHandler Dim x, y x = y / 0 'Divide by zero! Debug.Print "Continue execution" Exit Sub ErrorHandler: LogError Err.Description Resume Next End Sub
و در انتها یک نمونه کد که حداقل خطای مناسب را برگرداند!
On Error GoTo ERROR_HANDLER Dim V As Variant ... ... str_location_flt.Value = Empty str_code_process_source_flt.SetFocus Exit Sub ERROR_HANDLER: Select Case Err.Number Case 3022 Err.Clear source_docs_query_subform.Form.Undo str_code_process_source_flt.SetFocus V = MsgBox("DUPLICATE RECORD") Case Else source_docs_query_subform.Form.Undo str_code_process_source_flt.SetFocus V = MsgBox(Err.Description, , Err.Number) Err.Clear End Select