30. oktober 2000 - 23:05Der er
18 kommentarer og 1 løsning
Run-time error hvordan fanger jeg den så jeg kan behandle den ???
Jeg har et program der authenticates på serveren. Hvis jeg logger korekt på er der ikke noget, men hvis jeg skriver forkert brugernavn eller password skriver den følgende : Run-timer error \'-2147023570(8007052e)\':
Automation error Login failure: Unknown username or bad password.
Hvordan fanger jeg den og får sådan jeg kan få loadet en form, og fortælle brugeren det er forkert, og derefter vender tilbage til den form jeg kom fra, og bede om brugernavn og pass en gang til ???
Tjaa... jeg mente det var noget med Raise, Err, ErrNum eller Catch (og en eller anden sammen med den), men her er hvad MSDN siger om sagen (VB5Advanced): Tip 3: Raise exceptions when possible because return values will be ignored. This tip supplements Tip 1: “Inconsistent as it is, try to mimic Visual Basic’s own error handling scheme as much as possible.” Since Visual Basic 4, a function can be called like a subroutine. (In Visual Basic 3 and earlier, it couldn’t.) To demonstrate this, consider the following code fragments:
Sub Command1_Click ()
Debug.Print SomeFunc() Call SomeFunc
End Sub
Function SomeFunc () As Integer
SomeFunc = 42
End Function The line Call SomeFunc is illegal in Visual Basic 3 but legal in Visual Basic 4 and later. (It’s VBA!) In case you’re wondering why this is so, the facility was added to VBA (Visual Basic for Applications) to allow you to write routines that were more consistent with some of Visual Basic’s own routines, such as MsgBox, which acts sometimes like a function and sometimes like a statement (or a C type procedure if you’re used to that language). (In Tip 4, you’ll find out how to write your own MsgBox routine.)
A side effect of all this is that routines that return some indication of success or failure might now have that result ignored. As C and SDK programmers know only too well, this will cause problems! In Visual Basic 3, the programmer always had to use the return value. Typically, he or she would use it correctly. If a programmer can ignore a routine’s returned value (say it’s not a database handle but a True/False value—that is, either it worked or it failed), however, he or she usually will ignore it.
Exceptions, on the other hand, cannot easily be ignored (except by using On Error Resume Next or On Error Resume 0—both easy to test for and legislate against). Also, keep in mind that “newer” Visual Basic developers sometimes lack the necessary self-discipline to use and test return values correctly. By raising exceptions, you force them to test and then to take some appropriate action in one place: the error handler.
Another reason to use exceptions is that not using them can cause your code to become more difficult to follow—all those (un)necessary conditional tests to see that things have worked correctly. This kind of scheme, in which you try some code and determine that it didn’t work by catching a thrown exception, is pretty close to “structured exception handling” as used in C++ and Microsoft Windows NT. For more on structured exception handling, see the Visual C++ 4.0 online help. (Select Contents, and follow this path: Visual C++ books; C/C++; Programming Techniques; Structured Exception Handling.)
Here’s an example of a structured exception handling type of scheme:
Private Sub SomeWhere()
If a() Then § If b() Then § If c() Then § End If End If End If
End Sub OK, I agree, this example is not too hard to figure out. But I’m sure you’ve seen far more complex examples of nesting conditionals and get the idea! Here’s the same code using exceptions to signal errors in a, b, or c:
Private Sub SomeWhere()
\' TRY On Error Goto ????
a() § b() § c() §
\' CATCH ????
\' Handle exception here.
End Sub Can you see the flow any easier here? What you cannot see is that to get to the call to b, a must function correctly—it’s only implied by the presence of the error handler. By losing the If, you’re losing some plain readability but you’re also gaining some—the code is certainly less cluttered. Of course, sometimes code is clear just because you’re used to it. Consider replacing b, for instance, with a call to Open. If you were to use the If…Then scheme to check for errors, you couldn’t check for any errors in Open because you can’t put conditional statements around a procedure. So it’s easy for you to accept the fact that after Open is called, if an error occurs, the statement following Open will not run. It works the same with the b function. If an error occurs in the b function, the error routine rather than the statement that follows b will execute.
If you adopt this kind of error handling scheme, just make sure that you have projectwide collaboration on error codes and meanings. And by the way, if the functions a, b, and c already exist (as used previously with the If statements), we’ll be using this “new” ability to ignore returned values to our advantage.
Note Once again, if a routine’s returned value can be ignored, a programmer will probably ignore it!
ELLER endnu bedre (Under \"How to Raise Errors\" -> Hardcore Visual Basic)
How to Raise Errors
You probably already know the tedious techniques required to raise your own errors. It’s covered in the manuals, so I’ll be brief. Let’s say we wanted to create and raise the bozo error from the GUtility module of the VBCore component. We might do it like this:
Err.Raise vbObjectError + 22000, “VBCore.Utility”, “You are a bozo”
You’re supposed to raise errors by adding the mysterious vbObjectError constant to your error number. But what exactly is vbObjectError? You can get a good idea by checking its hexadecimal value: &H80040000. To programmers who have worked with COM in other languages, this looks a lot like the status bits of an HRESULT. The 8 sets the severity bit, indicating that it is an error. The 4 sets the facility code to a standard value that C programmers know as FACILITY_ITF (ITF is an abbreviation for interface). There are other facility codes for errors from Windows, Win32, and some other sources, but since everything made public by Visual Basic is an interface, there’s no need to get creative.
The key point is that you’re combining the bits of your error code with the bits of a severity code and a facility code. Normally, you combine or test bits with logical operators, not arithmetic operators. That’s why I think it’s more accurate to code your errors like this:
Err.Raise 22000 Or vbObjectError, “VBCore.Utility”, “You are a bozo”
So what happens if, ignoring all warnings in the documentation, you simply raise your errors directly without vbObjectError?
Err.Raise 22001, “MyProject.MyModule”, “I am a bozo”
Will your program suddenly disappear in a puff of smoke? Will the error police break down your door in the middle of the night? No, but behind your back Visual Basic will set the facility code of error to FACILITY_CONTROL. In other words, your code will actually do this:
Err.Raise 22001 Or &H800A000,...
COM documentation says that FACILITY_CONTROL errors should be raised for control-related errors. I’m not sure, but I think they mean the system code that creates controls rather than the code in controls. As always, ignore documented instructions at your own risk.
For clients, the only thing that matters about these bits is that you have to get rid of them to get an intelligible error message. You can do that easily by masking out the high bits (the bit flags) of the error, leaving only the low bits containing the code. I use the following functions for masking out the irrelevant bits or masking in the relevant ones:
Function BasicError(ByVal e As Long) As Long BasicError = e And &HFFFF&End FunctionFunction COMError(e As Long) As Long COMError = e Or vbObjectErrorEnd Function
So if you raise the bozo error shown earlier, the client can get back the error number you set (22000 in this case) like this:
e = VBError(Err.Number)
You’re also supposed to raise errors with integer values greater than 512 in order to avoid conflicts with Visual Basic’s errors. That leaves me and all other component developers the range of 512 to 32768. I hereby claim the number 13000 as my unlucky number and order other component developers to cease and desist from using this number as the base for their error numbers. In exchange, I promise not to use up any more precious numbers than I have to. OK? Well, I know it’s a hopeless request. It’s inevitable that component error numbers will overlap occasionally. If you use two components with the same numbers, you’ll have to figure out who’s who from the context.
Notice also that you’re supposed to return the source in a project.module format. If you don’t fill in this optional parameter, Visual Basic will provide the project but not the module.
If you don’t provide an error message, one will be provided for you, but you probably won’t like it. This is pretty mechanical stuff, and we ought to be able to automate at least part of it. The module ERRORS.CLS provides procedures that allow you to shorten error raising code to this:
ErrRaise eeBozo
My system depends on convention. Each module gets an Enum for all the error messages it can raise. Here’s the one for UTILITY.CLS (and it’s the same in UTILITY.BAS):
Public Enum EErrorUtility eeBaseUtility = 13000 ‘ Utility eeNoMousePointer ‘ HourGlass: Object doesn’t have mouse pointer eeNoTrueOption ‘ GetOption: None of the options are True eeNotOptionArray ‘ GetOption: Not control array of OptionButtonEnd Enum
Here’s the procedure that makes it work in the ERRORS.CLS module of VBCore:
#If fComponent ThenSub ErrRaise(e As Long) MErrors.ErrRaise eEnd Sub#End If
Wait a minute! The global class version of ErrRaise is just delegating to a standard module version using the technique described in “Creating Global Procedures.” Delegation works better here because it avoids the requirement to qualify every single call with a global object. There’s no instance data in the error functions, and they aren’t called in situations where performance is critical. Most calls to ErrRaise will be from internal modules anyway. Therefore, the real work is done in the delegated standard module ERRORS.BAS:
#If fComponent ThenSub ErrRaise(e As Long) Dim sText As String, sSource As String If e > 1000 Then sSource = App.ExeName & “.” & LoadResString((e \\ 10) * 10) sText = LoadResString(e) Err.Raise e, sSource, sText Else ‘ Raise standard Visual Basic error Err.Raise e, sSource End If ‘ Challenge: Enhance to use help filesEnd Sub#End If
The component side of the code (where fComponent is True) loads error message strings out of the VBCore resource file. Here’s part of the VBCORE.RC file from which VBCORE.RES is built:
// VBCore.RC - Resource script for VBCoreSTRINGTABLEBEGIN#if !defined(idLang) 13000 “Utility” 13001 “HourGlass: Object doesn’t have mouse pointer” 13002 “GetOption: None of the options are True” 13003 “GetOption: Not a control array of OptionButton” §// #elif idLang == idOtherLang // Add other languages here#endifEND
Each module gets slots for ten strings. The first string is reserved for the name of the module, which will be returned as part of the source. If you really need more than nine errors per module (rare in my experience), you’ll need to duplicate the module string for each error block.
All you have to do to make VBCore work in Bulgarian is translate the error messages to Bulgarian and add them to VBCORE.RES. I’ll explain more about resources later.
One problem—I can’t make the same ErrRaise procedure work when ERRORS.BAS is used as a stand-alone module because I don’t know how the client wants to handle error strings. If users of UTILITY.BAS and other standard modules want to use resource strings, that’s up to them. They can write their own error resource files and their own ErrRaise function. The best I can do is provide private ErrRaise functions in the standard modules so that they’ll at least work in English as the default. Here, for example, is the one from UTILITY.BAS:
#If fComponent = 0 ThenPrivate Sub ErrRaise(e As Long) Dim sText As String, sSource As String If e > 1000 Then sSource = App.EXEName & “.Utility” Select Case e Case eeBaseUtility sText = “Utility” Case eeNoMousePointer sText = “HourGlass: Object doesn’t have mouse pointer” Case eeNoTrueOption sText = “GetOption: None of the options are True” Case eeNotOptionArray sText = “GetOption: Argument is not a control array” & _ “of OptionButtons” End Select Err.Raise COMError(e), sSource, sText Else ‘ Raise standard Visual Basic error Err.Raise e, sSource End IfEnd Sub#End If
Maintaining the error Enums and error strings is a nuisance. You have to update each error in three different places—the error Enum, the standard module Select Case block, and the VBCore resource file. This kind of mechanical work is unfit for human beings. If you’re going to use errors in this format frequently, consider writing a wizard to automate the process. I considered it, but unfortunately for you it never reached the top of my project stack.
An error handler is a routine for trapping and responding to errors in your application. You\'ll want to add error handlers to any procedure where you anticipate the possibility of an error (you should assume that any Basic statement can produce an error unless you explicitly know otherwise). The process of designing an error handler involves three steps:
Set, or enable, an error trap by telling the application where to branch to (which error-handling routine to execute) when an error occurs. The On Error statement enables the trap and directs the application to the label marking the beginning of the error-handling routine.
In the Errors.vpb sample application, the FileExists function contains an error-handling routine named CheckError.
Write an error-handling routine that responds to all errors you can anticipate. If control actually branches into the trap at some point, the trap is then said to be active. The CheckError routine handles the error using an If...Then...Else statement that responds to the value in the Err object\'s Number property, which is a numeric code corresponding to a Visual Basic error. In the example, if \"Disk not ready\" is generated, a message prompts the user to close the drive door. A different message is displayed if the \"Device unavailable\" error occurs. If any other error is generated, the appropriate description is displayed and the program stops.
Exit the error-handling routine. In the case of the \"Disk not ready\" error, the Resume statement makes the code branch back to the statement where the error occurred. Visual Basic then tries to re-execute that statement. If the situation has not changed, then another error occurs and execution branches back to the error-handling routine.
In the case of the \"Device unavailable\" error, the Resume Next statement makes the code branch to the statement following the one at which the error occurred.
Details on how to perform these steps are provided in the remainder of this topic. Refer to the FileExists function example as you read through these steps.
Setting the Error Trap An error trap is enabled when Visual Basic executes the On Error statement, which specifies an error handler. The error trap remains enabled while the procedure containing it is active — that is, until an Exit Sub, Exit Function, Exit Property, End Sub, End Function, or End Property statement is executed for that procedure. While only one error trap can be enabled at any one time in any given procedure, you can create several alternative error traps and enable different ones at different times. You can also disable an error trap by using a special case of the On Error statement — On Error GoTo 0.
To set an error trap that jumps to an error-handling routine, use a On Error GoTo line statement, where line indicates the label identifying the error-handling code. In the FileExists function example, the label is CheckError. (Although the colon is part of the label, it isn\'t used in the On Error GoTo line statement.)
For More Information For more information about disabling error handling, see the topic, \"Turning Off Error Handling,\" later in this chapter.
Writing an Error-Handling Routine The first step in writing an error-handling routine is adding a line label to mark the beginning of the error handling routine. The line label should have a descriptive name and must be followed by a colon. A common convention is to place the error-handling code at the end of the procedure with an Exit Sub, Exit Function, or Exit Property statement immediately before the line label. This allows the procedure to avoid executing the error-handling code if no error occurs.
The body of the error handling routine contains the code that actually handles the error, usually in the form of a Case or If…Then…Else statement. You need to determine which errors are likely to occur and provide a course of action for each, for example, prompting the user to insert a disk in the case of a \"Disk not ready\" error. An option should always be provided to handle any unanticipated errors by using the Else or Case Else clause — in the case of the FileExists function example, this option warns the user then ends the application.
The Number property of the Err object contains a numeric code representing the most recent run-time error. By using the Err object in combination with the Select Case or If...Then...Else statement, you can take specific action for any error that occurs.
Note The string contained in the Err object\'s Description property explains the error associated with the current error number. The exact wording of the description may vary among different versions of Microsoft Visual Basic. Therefore, use Err.Number, rather than Err.Description, to identify the specific error that occurred.
Exiting an Error-Handling Routine The FileExists function example uses the Resume statement within the error handler to re-execute the statement that originally caused the error, and uses the Resume Next statement to return execution to the statement following the one at which the error occurred. There are other ways to exit an error-handling routine. Depending on the circumstances, you can do this using any of the statements shown in the following table.
Statement Description Resume [0] Program execution resumes with the statement that caused the error or the most recently executed call out of the procedure containing the error-handling routine. Use it to repeat an operation after correcting the condition that caused the error. Resume Next Resumes program execution at the statement immediately following the one that caused the error. If the error occurred outside the procedure that contains the error handler, execution resumes at the statement immediately following the call to the procedure wherein the error occurred, if the called procedure does not have an enabled error handler. Resume line Resumes program execution at the label specified by line, where line is a line label (or nonzero line number) that must be in the same procedure as the error handler. Err.Raise Number:= number Triggers a run-time error. When this statement is executed within the error-handling routine, Visual Basic searches the calls list for another error-handling routine. (The calls list is the chain of procedures invoked to arrive at the current point of execution. See the section, \"Error-Handling Hierarchy,\" later in this chapter.)
The Difference Between Resume and Resume Next Statements The difference between Resume and Resume Next is shown in Figure 13.1.
Figure 13.1 Program flow with Resume and Resume Next
Generally, you would use Resume whenever the error handler can correct the error, and Resume Next when the error handler cannot. You can write an error handler so that the existence of a run-time error is never revealed to the user or to display error messages and allow the user to enter corrections.
For example, the Function procedure in the following code example uses error handling to perform \"safe\" division on its arguments without revealing errors that might occur. The errors that can occur when performing division are:
Error Cause \"Division by zero\" Numerator is nonzero, but the denominator is zero. \"Overflow\" Both numerator and denominator are zero (during floating-point division). \"Illegal procedure call\" Either the numerator or the denominator is a nonnumeric value (or can\'t be considered a numeric value).
In all three cases, the following Function procedure traps these errors and returns Null:
Function Divide (numer, denom) as Variant Dim Msg as String Const mnErrDivByZero = 11, mnErrOverFlow = 6 Const mnErrBadCall = 5 On Error GoTo MathHandler Divide = numer / denom Exit Function MathHandler: If Err.Number = MnErrDivByZero Or _ Err.Number = ErrOverFlow _ Or Err = ErrBadCall Then Divide = Null \' If error was Division by \' zero, Overflow, or Illegal \' procedure call, return Null. Else \' Display unanticipated error message. Msg = \"Unanticipated error \" & Err.Number Msg = Msg & \": \" & Err.Description MsgBox Msg, vbExclamation End If \' In all cases, Resume Next \' continues execution at Resume Next \' the Exit Function statement. End Function
Resuming Execution at a Specified Line Resume Next can also be used where an error occurs within a loop, and you need to restart the operation. Or, you can use Resume line, which returns control to a specified line label.
The following example illustrates the use of the Resume line statement. A variation on the FileExists example shown earlier, this function allows the user to enter a file specification that the function returns if the file exists.
Function VerifyFile As String Const mnErrBadFileName = 52, _ mnErrDriveDoorOpen = 71 Const mnErrDeviceUnavailable = 68, _ mnErrInvalidFileName = 64 Dim strPrompt As String, strMsg As String, _ strFileSpec As String strPrompt = \"Enter file specification to check:\" StartHere: strFileSpec = \"*.*\" \' Start with a default \' specification. strMsg = strMsg & vbCRLF & strPrompt \' Let the user modify the default. strFileSpec = InputBox(strMsg, \"File Search\", _ strFileSpec, 100, 100) \' Exit if user deletes default. If strFileSpec = \"\" Then Exit Function On Error GoTo Handler VerifyFile = Dir(strFileSpec) Exit Function Handler: Select Case Err.Number \' Analyze error code and \' load message. Case ErrInvalidFileName, ErrBadFileName strMsg = \"Your file specification was \" strMsg = strMsg & \"invalid; try another.\" Case MnErrDriveDoorOpen strMsg = \"Close the disk drive door and \" strMsg = strMsg & \"try again.\" Case MnErrDeviceUnavailable strMsg = \"The drive you specified was not \" strMsg = strMsg & \"found. Try again.\" Case Else Dim intErrNum As Integer intErrNum = Err.Number Err.Clear \' Clear the Err object. Err.Raise Number:= intErrNum \' Regenerate \' the error. End Select Resume StartHere \' This jumps back to StartHere \' label so the user can try \' another file name. End Function
If a file matching the specification is found, the function returns the file name. If no matching file is found, the function returns a zero-length string. If one of the anticipated errors occurs, a message is assigned to the strMsg variable and execution jumps back to the label StartHere. This gives the user another chance to enter a valid path and file specification.
If the error is unanticipated, the Case Else segment regenerates the error so that the next error handler in the calls list can trap the error. This is necessary because if the error wasn\'t regenerated, the code would continue to execute at the Resume StartHere line. By regenerating the error you are in effect causing the error to occur again; the new error will be trapped at the next level in the call stack.
For More Information For more details, see \"Error Handling Hierarchy\" later in this chapter.
Note Although using Resume line is a legitimate way to write code, a proliferation of jumps to line labels can render code difficult to understand and debug
Ideally, Visual Basic procedures wouldn\'t need error-handling code at all. Reality dictates that hardware problems or unanticipated actions by the user can cause run-time errors that halt your code, and there\'s usually nothing the user can do to resume running the application. Other errors might not interrupt code, but they can cause it to act unpredictably.
For example, the following procedure returns true if the specified file exists and false if it does not, but doesn\'t contain error-handling code:
Function FileExists (filename) As Boolean FileExists = (Dir(filename) <> \"\") End Function
The Dir function returns the first file matching the specified file name (given with or without wildcard characters, drive name, or path); it returns a zero-length string if no matching file is found.
The code appears to cover either of the possible outcomes of the Dir call. However, if the drive letter specified in the argument is not a valid drive, the error \"Device unavailable\" occurs. If the specified drive is a floppy disk drive, this function will work correctly only if a disk is in the drive and the drive door is closed. If not, Visual Basic presents the error \"Disk not ready\" and halts execution of your code.
To avoid this situation, you can use the error-handling features in Visual Basic to intercept errors and take corrective action. (Intercepting an error is also known as trapping an error.) When an error occurs, Visual Basic sets the various properties of the error object, Err, such as an error number, a description, and so on. You can use the Err object and its properties in an error-handling routine so that your application can respond intelligently to an error situation.
For example, device problems, such as an invalid drive or an empty floppy disk drive, could be handled by the following code:
Function FileExists (filename) As Boolean Dim Msg As String \' Turn on error trapping so error handler responds \' if any error is detected. On Error GoTo CheckError FileExists = (Dir(filename) <> \"\") \' Avoid executing error handler if no error \' occurs. Exit Function
CheckError: \' Branch here if error occurs. \' Define constants to represent intrinsic Visual \' Basic error codes. Const mnErrDiskNotReady = 71, _ mnErrDeviceUnavailable = 68 \' vbExclamation, vbOK, vbCancel, vbCritical, and \' vbOKCancel are constants defined in the VBA type \' library. If (Err.Number = MnErrDiskNotReady) Then Msg = \"Put a floppy disk in the drive \" Msg = Msg & \"and close the door.\" \' Display message box with an exclamation mark \' icon and with OK and Cancel buttons. If MsgBox(Msg, vbExclamation & vbOKCancel) = _ vbOK Then Resume Else Resume Next End If ElseIf Err.Number = MnErrDeviceUnavailable Then Msg = \"This drive or path does not exist: \" Msg = Msg & filename MsgBox Msg, vbExclamation Resume Next Else Msg = \"Unexpected error #\" & Str(Err.Number) Msg = Msg & \" occurred: \" & Err.Description \' Display message box with Stop sign icon and \' OK button. MsgBox Msg, vbCritical Stop End If Resume End Function
In this code, the Err object\'s Number property contains the number associated with the run-time error that occurred; the Description property contains a short description of the error.
When Visual Basic generates the error \"Disk not ready,\" this code presents a message telling the user to choose one of two buttons — OK or Cancel. If the user chooses OK, the Resume statement returns control to the statement at which the error occurred and attempts to re-execute that statement. This succeeds if the user has corrected the problem; otherwise, the program returns to the error handler.
If the user chooses Cancel, the Resume Next statement returns control to the statement following the one at which the error occurred (in this case, the Exit Function statement).
Should the error \"Device unavailable\" occur, this code presents a message describing the problem. The Resume Next statement then causes the function to continue execution at the statement following the one at which the error occurred.
If an unanticipated error occurs, a short description of the error is displayed and the code halts at the Stop statement.
The application you create can correct an error or prompt the user to change the conditions that caused the error. To do this, use techniques such as those shown in the preceding example. The next section discusses these techniques in detail.
For More Information See \"Guidelines for Complex Error Handling\" in \"Error-Handling Hierarchy\" later in this chapter for an explanation of how to use the Stop statement.
Det er godt nok en natbordsroman der er indsat som svar her. Jeg har ikke læst det igennem, kun skimmet. Men det morgenfriske svar fra tdaugaard ligger tættere op ad, hvad jeg også vil foreslå.
Kan jeg gå ud fra at serveren kører NT?
Kunne Tubber ikke her indsætte koden lige omkring sin login-procedure?
Ellers ved I vel begge hvorledes errorhandling anvendes hvis der f.eks. forsøges adgang til et netdrev, der ikke er tilgængeligt, eller der læses \"ud over enden\" af en fil el. lign. Hvis tvivl om dette, så skriv!
Jeg faldt næsten i søvn bare af at se hvor meget der var, og så så jeg til sidst at tubber ville have noget a\'la det jeg så skrev..
faktisk glemte jeg lige en ting ..
Private Sub LoginProc() On Local Error Goto ErrorHandler
.. din login kode ..
Exit Sub \' Meget vigtigt! ErrorHandler: If Err = -2147023570 Then MsgBox \"Error!\" Exit Sub \' VB er MEGET god til at beklage sig hvis ikke man gør det her! End Sub
Ja ok - men hvor smart er det at gå vidre hvis brugeren ikke har rettigheder til det. Hvis der ikke er nogen fejl har brugeren adgang til serveren :O)
I kender vel den fra OutLook ?
Koden ser sådan her ud (hvis det har interesse):
Private Sub cmdVerify_Click() On Local Error GoTo ErrorHandler vUser = txtUser.Text vPass = txtPass.Text vDomain = txtDomain.Text Set dso = GetObject(\"WinNT:\") Set domain = dso.OpenDSObject(\"WinNT://\" & vDomain & \"\", \"\" & vUser & \"\", \"\" & vPass & \"\", ADS_SECURE_AUTHENTICATION) Exit Sub ErrorHandler: If Err = -2147023570 Then MsgBox \"Unknown User or Bad Password\", , \"Login Failure\" If Err = -2147467259 Then MsgBox \"Unknown Domain\", , \"Login Failure\" Exit Sub End Sub
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.