Will GetLastError ever work properly in VFP8.0?

For this post: GetLastError: how does it work with DECLARE DLL ?, I received this question:


I was sent here by someone from UT regarding a problem I’m having with GetLastError API call.  It always returns 0 even if I enter a bogus password to LogonUser().

Base on what I read above, are you saying that GetLastError will never properly work in VFP 8.0?



“Never” is a strong word. I don’t see any code showing how the user is calling any APIs, so I can’t tell what is happening for the user, so I can’t propose a way to make it work. Perhaps the user can try it in VFP9 and see if their code behaves differently. If so, then the the GetLastError fix that I implemented for VFP9 probably helps in this scenario.



So I had to figure out how to call LogonUser:




#define LOGON32_LOGON_NETWORK           3

#define LOGON32_LOGON_BATCH             4

#define LOGON32_LOGON_SERVICE           5

#define LOGON32_LOGON_UNLOCK            7


#define ERROR_LOGON_FAILURE              1326


DECLARE integer LogonUser IN WIN32API string lpszUsername,string lpszDomain,;

      string lpszPassword,integer dwLogonType,integer dwLogonProvider, integer @ phToken

DECLARE integer CloseHandle IN  WIN32API integer

DECLARE integer GetLastError IN  WIN32API


IF LogonUser(“calvinh”,”redmond“,””,LOGON32_LOGON_BATCH,LOGON32_PROVIDER_DEFAULT,@hToken) != 0

      ?”Login success”,hToken

      IF hToken!= 0




*     MESSAGEBOX(“This is a Win32API call”)

      ?”Login failed”,GetLastError()





I tried running the code I n both VFP8 and VFP9, with and without my password as the 3rd parameter, and I received the same results: success with the correct password, and “Login failed   1326” with the incorrect password.


Thus, in this case, GetLastError was correct in VFP8.

Because GetLastError means to get the single global last error code, if there are any intervening API calls, they will change the last error code. So, if you uncomment the MessageBox and run the code in VFP8, the intervening call causes the GetLastError to return 0, because there was no error in calling the MessageBox.

Run the modified code in VFP9 and the error code is preserved, because of the changes I made in VFP9.


Wait a minute, you say. Didn’t the MessageBox call reset the global last error code in VFP9 as well? Yes it did, but it wasn’t called via DECLARE DLL , which is where the GetLastError code was preserved.


Comments (6)

  1. I was writing a sample about DECLARE DLL to show some of its features which I implemented about 12 years…

  2. Rodd Harris says:


    Thanks for taking time to answer my question … and I appologize for not posting any code for you .

    I’m a little stumped though as to how you got things to work in VFP 8.

    Here is the code I’m running.  I’ve tried this both from a command window as well as from a prg executed from the command window:

    DECLARE integer GetLastError IN kernel32

    DECLARE integer CloseHandle IN kernel32 integer hObject

    DECLARE integer LogonUser IN advapi32 string lpzUser, string lpzDomain, string lpzPass, integer dwLogonType, integer dwLogonProvider, integer @phToken

    nToken = 0

    cPass = INPUTBOX("Password:")

    IF LogonUser("username","domain",cPass,3,0,@nToken) = 0

      lnResult = GetLastError()

      = MESSAGEBOX(lnResult)


      = MESSAGEBOX("Success!!")

      = CloseHandle(nToken)





    When I run this code with a valid password, great!  However, if I run with an invalid password, I consistently get a 0 in lnResult.

    Is there something I’m doing wrong?  I don’t see anything that should be clearing the value of GetLastError before I’m storing it.  For the most part, the code you posted and what I’m doing are almost identical.

    Any ideas?

  3. I received a comment on this post: Will GetLastError ever work properly in VFP8.0?.  I was consistently…

  4. Rodd Harris says:

    Hello again Calvin,

    Okay, i ran the code you had listed and was able to determine why my code wasn’t working.  It still doesn’t make sense to me, but I found it just the same.

    If I run the exact code that I posted but replace this line:

    cPass = inputbox("Password:")

    with this one:

    cPass = "12345"

    Then I get the proper results.  What confuses me though is that inputbox runs BEFORE the LongonUser function but it seems like running the InputBox function before LogonUser causes the results of LogonUser to be wiped out.

    Any ideas on why this is happening?