Application Exception - Intermittent in C11 app

Hi
Having the occasional issue with Application Exceptions on an app created by C11.1.
Messages like these appear.
I cannot reproduce it but a couple of users have it occurring intermittently.
Any clues on how to intercept it?
image

Thanks
Paul

Iā€™d recommend shipping your application with the debug build of the clarion runtime (Clarion11\bin\debug\ClaRUN.dll) and building your application with Debug info >= min and ā€œAdd line Number informationā€ parameter on.


The next time your application throws an exception, it should have detailed info where your exception took place.

2 Likes

Install the Clarion debugger as the system debugger on the machines that are seeing the issue, you could then examine the memory (locateoffset) when this window appears and you might be able to workout what api call is happening without the source clw, in my experience its usually a pointer error, ie not got the right address(somevar) or *parameterprototype. You can drop the source code file in question onto the machine where this happens in case you have a few api calls within the procedure but then you are sharing the code which you might not want to do?

If you have debugview in your code and the machine has internet access you can run debugview from the internet \live.sysinternals.com\tools\Dbgview.exe and then see what the debugoutput string is.

Something to watch out for with some Windows apiā€™s is MS uses Long Pointers (memory addresses) which point/link to other Long Pointers (memory addresses). In the pic, the memory addresses which are highlighted in the red boxes are all LPā€™s to LPā€™s and I cant work out why MS have done it this way.

ConvertSidToStringSidA function (sddl.h) - Win32 apps | Microsoft Docs

[in] Sid

A pointer to the SID structure to be converted.

[out] StringSid

A pointer to a variable that receives a pointer to a null-terminated SID string. To free the returned buffer, call the LocalFree function.

This might also be useful if you want to explore the stack? This is supposedly how Clarion handles its stack, which may be relevant if you are not using Pascal or C as the passing convention, it depends on if this access violation is a windows api call failing and what you prototyped in the module(ā€˜someapiā€™).

TopSpeed / Clarion / JPI - x86 calling conventions - Wikipedia

Iā€™ve been debating whether to sell this as an addon, its a template which makes it easy to prototype parameters basically.

The red box is a bug in C11, its the drop down part which should be attached to the Data Type: Byte bit of the template window on the right.

Read this post

2 Likes

Thanks for the replies. Lots of good knowledge there. I will pass it on and see whether it gets us to point B.
Cheers
Paul :slight_smile:

I think the two most common sources for those in my experience are (a) trying to access an object that has not yet been instantiated in that context, or (b) failing to return a value from a procedure that is prototyped to return a string.

Iā€™d say that missing/incorrect project defines cause more hair loss than anything else.

(c) Accessing disposed data.
Always check IF NOT object &= NULL THEN and set object &= NULL after DISPOSE. n.b. this last one is already done for you, but i prefer to both in the same code that is responsible for object &= NEW

Neither of those 2 suggestions is necessary.

If you pass a null reference to DISPOSE(), it will ignore it.
When you pass a reference to DISPOSE(), the reference gets nulled.

 PROGRAM
 
StringRef &STRING

  MAP
  END
  
  CODE
   
   StringRef &= NEW STRING(20)
   DISPOSE(StringRef)
   MESSAGE(CHOOSE(StringRef &= NULL,'StringRef is now null','StringRef is NOT NULL'))
   DISPOSE(StringRef)
   MESSAGE('The world did not end, and ' & CHOOSE(StringRef &= NULL,'StringRef is still null after DISPOSE','StringRef is NOT NULL'))
2 Likes

Perhaps Ericā€™s statement was ambiguous and you read it not as intended?

I think it was intended to be read as two separate things:

  1. Always check IF NOT object &= NULL THEN

ie. check object before using it

  1. and set object &= NULL after DISPOSE

this is a good idea especially for things like strings where the dispose does not zero the size (and yes I know we have had this conversation lots of times before but it bears repeating)

   StringRef &= NEW STRING(20)
   DISPOSE(StringRef) 
   message('after dispose the size is ' & size(StringRef))    ! size still 20
   stringRef &= null
   message('after setting to null the size is ' & size(StringRef))  ! size now 0
2 Likes

Hi there,

I need to query the SID and then validate it. Would you please share some piece of code of how are you prototyping the LookupAccountNameA?

Thanks!

In the image here https://clarionhub.com/uploads/default/original/2X/0/0a51c7523fbf5475dc663d32adc47e68f0e847f5.png

to get the SID string you have a long pointer (lp) to long pointer (lp) seen in the bottom left field lplp Sid string. This then gives you the pointer/address to lp sid string and that gives you the pointer to the actual Sid string seen in Sid string.

So it goes like this:
lplp sid string
V
lp sid string
V
Sid string

And these are just longs in clarion.

Iā€™d have to dig out my code to lookup any lookupaccountnamea code which if I get time in the next few days i will.

HTH

Iā€™ve had a look for some code, but I cant find the files using the computers Iā€™ve got to use. When I get round to buying one Iā€™ll have another look, but the main point is where you see lplp in some of the apiā€™s these are long pointers to another long pointer which then leads you to the required info.

HTH

Cool, when you find that code, if you can please share it, still donā€™t get to read the SID.

Thanks

1 Like

This might help get you started.

I think youā€™ll find two trains of thought for prototyping (pass by reference/pass by value). For LookupAccountNameA , MSDN says this ā€¦

BOOL LookupAccountNameA(
  [in, optional]  LPCSTR        lpSystemName,
  [in]            LPCSTR        lpAccountName,
  [out, optional] PSID          Sid,
  [in, out]       LPDWORD       cbSid,
  [out, optional] LPSTR         ReferencedDomainName,
  [in, out]       LPDWORD       cchReferencedDomainName,
  [out]           PSID_NAME_USE peUse
);

I go for the ADDRESS by value method so no RAW *CSTRINGs, like this ā€¦

jhLookupAccountNameA(LONG lpszSystemName, |
  LONG lpszAccountName,|
  LONG lpSID, |
  LONG cbSid, |
  LONG lpsReferencedDomainName, |
  LONG lpcchReferencedDomainName, |
  LONG lpPSID_NAME_USE ),PASCAL,Name('LookupAccountNameA')

I declare variables as MSDN describes

szSystemName CSTRING(128)
szAccountName CSTRING(128)
SID STRING(1024)
cbSID LONG
sReferencedDomain STRING(1024)
lpSIDName LONG

dwResult LONG

To do it ā€œcorrectlyā€, MSDN describes making the call with ADDRESS values of ā€œzeroā€ in order to determine the buffer/STRING sizes (then you should create them accordingly) but given than it describes ā€˜pointers to buffersā€™ you can just use big STRINGs and call thus ā€¦

dwResult = jhLookupAccountName(Address(szSystemName), |
 Address(szAccountName), |
 Address(SID), |
 Address(cbSID),|
 Address(sReferenceDomain), |
 Address(lpSIDName))

Iā€™m still going through code, apps and sorting out whats what but have a look at this clw, it might be useful, but iirc its populating some of the info seen in this window here:0a51c7523fbf5475dc663d32adc47e68f0e847f5.png (1182Ɨ581) (clarionhub.com)

And some of this code is work in progress, and Win11 has introduced new changes.



   MEMBER('pcWorkTime.clw')                                ! This is a MEMBER module

                     MAP
                       INCLUDE('PCWOR043.INC'),ONCE        !Local module procedure declarations
                     END




LookupUsers          PROCEDURE  (pManual)                  ! Declare Procedure
Loc:NetUserInfoID    LONG                                  !
Loc:ServerNameAddress LONG                                 !
Loc:level            LONG                                  !
Loc:filter           LONG                                  !
Loc:bufptr           LONG                                  !
Loc:prefmaxlen       LONG                                  !
Loc:entriesread      LONG                                  !
Loc:totalentries     LONG                                  !
Loc:resume_handle    LONG                                  !
Loc:NetUserEnumResult LONG                                 !
Loc:Address          LONG                                  !
Loc:Address2         LONG                                  !
Loc:NetUserGetInfoFilter LONG                              !
Loc:NetUserGetInfobufptr LONG                              !
Loc:NetUserGetInfoResult LONG                              !
Loc:NetUserGetInfoAddress LONG                             !
Loc:NetUserGetInfoAddress2 LONG                            !
Loc:NetAPIResult     LONG                                  !
Loc:TotalSeconds     ULONG                                 !
Loc:Years            ULONG                                 !
Loc:Days             ULONG                                 !
Loc:Hours            ULONG                                 !
Loc:Mins             ULONG                                 !
Loc:Secs             ULONG                                 !
Loc:Flags            ULONG                                 !
Loc:Auth_Flags       ULONG                                 !
Loc:Time             LONG                                  !
Loc:Date             LONG                                  !
Loc:SidBoolResult    BYTE                                  !
Loc:lstrcpyAResult   LONG                                  !
Loc:IS_ProcedureName    Cstring(256)
Loc:IS_ModuleFilename   Cstring(256)
Loc:IS_ThreadNo         Long()
Loc:IS_DebugViewCstring Cstring(1024)
Loc:USER_INFO_3     Like(USER_INFO_3)       !Everything excuding SID & Internet Stuff
Loc:USER_INFO_23    Like(USER_INFO_23)      !Sid
Loc:USER_INFO_24    Like(USER_INFO_24)      !Internet Stuff
FilesOpened     BYTE(0)
  CODE
? DEBUGHOOK(NetUserInfo:Record)
? DEBUGHOOK(NetUserLookup:Record)
    !Loc:IS_DebugViewCstring = 'DebugViewTemplate 1st message output - Loc:IS_ProcedureName =LookupUsers, Loc:IS_ModuleFilename =pcWor043, Loc:IS_ThreadNo = ' & Thread()
    Loc:IS_DebugViewCstring = 'LookupUsers pcWor043 ' & Thread() &' ' & Format(Today(), @d7) &' '& Format(Clock(), @t8)
    Loc:IS_ProcedureName    ='LookupUsers'
    Loc:IS_ModuleFilename   ='pcWor043'
    Loc:IS_ThreadNo         = Thread()
    IS_DebugView(Loc:IS_DebugViewCstring)
    DO OpenFiles
    DO NetUserEnum
    Do CloseFiles
NetUserEnum     Routine

    Loc:ServerNameAddress   = 0 !This Computer
    Loc:level               = NetUserEnumLevel3
    Loc:filter              = FILTER_TEMP_DUPLICATE_ACCOUNT + FILTER_NORMAL_ACCOUNT + FILTER_INTERDOMAIN_TRUST_ACCOUNT + FILTER_WORKSTATION_TRUST_ACCOUNT + FILTER_SERVER_TRUST_ACCOUNT
    Loc:bufptr              = Address(Loc:USER_INFO_3)
    Loc:prefmaxlen          = Len(Loc:USER_INFO_3)

    DO AddNetUserLookup

    Loc:entriesread     = 0
    Loc:totalentries    = 0
    Loc:resume_handle   = 0
    Loop
        Loc:NetUserEnumResult = IS_NetUserEnum(Loc:ServerNameAddress,Loc:level,Loc:filter,Loc:bufptr,Loc:prefmaxlen,Address(Loc:entriesread),Address(Loc:totalentries),Address(Loc:resume_handle))
        IF Loc:NetUserEnumResult = NERR_Success !or Loc:NetUserEnumResult = 234 !ERROR_MORE_DATA

            DO NetUserEnumLookupResults

            Loc:NetAPIResult = IS_NetApiBufferFree(Loc:bufptr)
            IF Loc:NetAPIResult = NERR_Success
            Else
                RecordError('NetUserEnum NetApiBufferFree 1 Return Value Error:' & Loc:NetAPIResult )
            End

            Break
        ElsIF Loc:NetUserEnumResult = 234 !ERROR_MORE_DATA
            DO NetUserEnumLookupResults

            Loc:NetAPIResult = IS_NetApiBufferFree(Loc:bufptr)
            IF Loc:NetAPIResult = NERR_Success
            Else
                RecordError('NetUserEnum NetApiBufferFree 2 Return Value Error:' & Loc:NetAPIResult )
            End

        Else
            RecordError('NetUserEnum Return Value Error:' & Loc:NetUserEnumResult &' '& Loc:entriesread &' '& Loc:totalentries &' '& Loc:resume_handle )

            Loc:NetAPIResult = IS_NetApiBufferFree(Loc:bufptr)
            IF Loc:NetAPIResult = NERR_Success
            Else
                RecordError('NetUserEnum NetApiBufferFree 3 Return Value Error:' & Loc:NetAPIResult )
            End

            Break
        End
    End
AddNetUserLookup       Routine

    NUL:SessionID               = GLO:SessionID
    NUL:Date                    = Today()
    NUL:Time                    = Clock()
    NUL:Manual                  = pManual
    NUL:ComputerName            = GLO:ComputerName
    NUL:Username                = GLO:WindowAccountName
    NUL:LookupComputerName      = GLO:ComputerName
    NUL:LookupUser_Info_Type    = Loc:level !NetUserEnumLevel3 
    NUL:DuplicateAccount        = 1 !Loc:NUDuplicateAcc
    NUL:NormalAccount           = 1 !Loc:NUNormalAcc
    NUL:InterDomainTrustAccount = 1 !Loc:NUInterDomainTrustAcc
    NUL:WorkstationTrustAccount = 1 !Loc:NUWorkStationTrustAcc
    NUL:ServerTrustAccount      = 1 !Loc:NUServerTrustAcc
    IF NOT Access:NetUserLookup.Insert() = Level:Benign
        RecordError('NetUserLookup Insert Error:' & ErrorCode() &' '& Error() )
    Else
        Loc:NetUserInfoID = NUL:NetUserLookupID
    End

NetUserEnumLookupResults        Routine

    peek(Loc:bufptr,Loc:Address)
    Loop Loc:entriesread times
        !NUI:NetUserInfoID
        NUI:NetUserLookupID     = Loc:NetUserInfoID !NUL:NetUserLookupID

        peek(Loc:Address,NUI:nameAddress)               ;   DO LookupName
        peek(Loc:Address+4,NUI:passwordAddress)         ;   Do LookupPassword
        peek(Loc:Address+8,NUI:password_age_seconds)    ;   Do LookupPasswordAge          !sec !mins  !hours   !
        peek(Loc:Address+12,NUI:privilege)              ;   Do LookupPrivilege
        peek(Loc:Address+16,NUI:home_dirAddress)        ;   Do LookupHome_Dir
        peek(Loc:Address+20,NUI:commentAddress)         ;   Do LookupCommentAddress
        peek(Loc:Address+24,NUI:flags)                  ;   Do LookupFlags
        peek(Loc:Address+28,NUI:script_pathAddress)     ;   Do LookupScript_Path
        peek(Loc:Address+32,NUI:auth_flags)             ;   Do LookupAuth_Flags
        peek(Loc:Address+36,NUI:full_nameAddress)       ;   Do LookupFull_Name
        peek(Loc:Address+40,NUI:usr_commentAddress)     ;   Do LookupUsr_Comment
        peek(Loc:Address+44,NUI:parmsAddress)           ;   Do LookupParms
        peek(Loc:Address+48,NUI:workstationsAddress)    ;   Do LookupWorkstations
        peek(Loc:Address+52,NUI:last_logon)             ;   Do LookupLast_Logon
        peek(Loc:Address+56,NUI:last_logoff)            ;   Do LookupLast_Logoff
        peek(Loc:Address+60,NUI:acct_expires)           ;   Do LookupAcct_Expires
        peek(Loc:Address+64,NUI:max_storage)                !   Nothing to do
        peek(Loc:Address+68,NUI:units_per_week)             !   Nothing to do
        peek(Loc:Address+72,NUI:logon_hoursAddress)     ;   Do LookupLogon_Hours
        peek(Loc:Address+76,NUI:bad_pw_count)               !   Nothing to do Only works on Domain Controllers and Backup Domain Controls
        peek(Loc:Address+80,NUI:num_logons)                 !   Nothing to do
        peek(Loc:Address+84,NUI:logon_serverAddress)    ;   Do LookupLogon_Server
        peek(Loc:Address+88,NUI:country_code)               !   Nothing to do
        peek(Loc:Address+92,NUI:code_page)                  !   Nothing to do
        peek(Loc:Address+96,NUI:user_id)                    !   Nothing to do
        peek(Loc:Address+100,NUI:primary_group_id)          !   Nothing to do
        peek(Loc:Address+104,NUI:profileAddress)        ;   Do LookupProfile
        peek(Loc:Address+108,NUI:home_dir_driveAddress) ;   Do LookupHome_Dir_Drive
        peek(Loc:Address+112,NUI:password_expired)          !   Nothing to do


        Do LookupUser_Info_23   !Get the SID

        DO LookupUser_Info_24   !Get the Internet Account Settings From Win8 onwards


        IF NOT Access:NetUserInfo.Insert() = Level:Benign
            RecordError('NetUserInfo.Insert Error:' & ErrorCode() &' '& Error() )
        End
        Loc:Address += Len(Loc:USER_INFO_3)
    End


LookupName          Routine

    IF NUI:nameAddress
        NUI:nameLen             = IS_lstrlenW(NUI:nameAddress)
        Clear(NUI:name)
        IF NUI:nameLen
            UnicodeToAnsi(NUI:nameAddress,Address(NUI:name))
        Else
            NUI:name = 'Null'
        End
    Else
        NUI:name = 'Null Address'
    End
LookupPassword      Routine

    IF NUI:passwordAddress
        NUI:passwordLen         = IS_lstrlenW(NUI:passwordAddress)
        Clear(NUI:password)
        IF NUI:passwordLen
            UnicodeToAnsi(NUI:passwordAddress,Address(NUI:password))
        Else
            NUI:password = 'Null'
        End
    Else
        NUI:password = 'Null Address'
    End
LookupPasswordAge       Routine

    IF NUI:password_age_seconds
        Loc:TotalSeconds    = NUI:password_age_seconds
        Loc:Years           = Loc:TotalSeconds / 31536000 !31557600
        Loc:TotalSeconds    = Loc:TotalSeconds - (Loc:Years * 31536000)
        Loc:Days            = Loc:TotalSeconds / 86400
        Loc:TotalSeconds    = Loc:TotalSeconds - (Loc:Days * 86400)
        Loc:Hours           = Loc:TotalSeconds / 3600
        Loc:TotalSeconds    = Loc:TotalSeconds - (Loc:Hours * 3600)
        Loc:Mins            = Loc:TotalSeconds / 60
        Loc:TotalSeconds    = Loc:TotalSeconds - (Loc:Mins * 60)
        Loc:Secs            = Loc:TotalSeconds
        NUI:Password_Age_Readable   = Loc:Years &' Years ' & Loc:Days & ' Days '& Loc:Hours &' Hours '& Loc:Mins &' mins '& Loc:Secs &' seconds'
    Else
        NUI:Password_Age_Readable = 'Null'
    End
LookupPrivilege     Routine

    Case NUI:privilege
    Of 0
        NUI:privilege_Readable  = 'Guest'
    Of 1
        NUI:privilege_Readable  = 'User'
    Of 2
        NUI:privilege_Readable  = 'Admin'
    Else
        NUI:privilege_Readable  = 'Null'
    End
LookupHome_Dir      Routine

    IF NUI:home_dirAddress
        NUI:home_dirLen         = IS_lstrlenW(NUI:home_dirAddress)
        Clear(NUI:home_dir)
        IF NUI:home_dirLen
            UnicodeToAnsi(NUI:home_dirAddress,Address(NUI:home_dir))
        Else
            NUI:home_dir = 'Null'
        End
    Else
        NUI:home_dir = 'Null Address'
    End
LookupCommentAddress        Routine

    IF NUI:commentAddress
        NUI:commentLen          = IS_lstrlenW(NUI:commentAddress)
        Clear(NUI:comment)
        IF NUI:commentLen
            UnicodeToAnsi(NUI:commentAddress,Address(NUI:comment))
        Else
            NUI:comment = 'Null'
        End
    Else
        NUI:comment = 'Null Address'
    End
LookupFlags     Routine

    Loc:Flags = NUI:flags
    IF Loc:Flags => UF_USE_AES_KEYS !134217728
        NUI:flags_Use_AES_Keys                          = 1
        Loc:Flags -= UF_USE_AES_KEYS
    End
    IF Loc:Flags => UF_PARTIAL_SECRETS_ACCOUNT  !67108864
        NUI:flags_Partial_Secrets_Account               = 1
        Loc:Flags -= UF_PARTIAL_SECRETS_ACCOUNT
    End
    IF Loc:Flags => UF_NO_AUTH_DATA_REQUIRED    !33554432
        NUI:flags_No_Auth_Data_Rrequired                = 1
        Loc:Flags -= UF_NO_AUTH_DATA_REQUIRED
    End
    IF Loc:Flags => UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION   !16777216
        NUI:flags_Trusted_To_Autheticate_For_Delegation = 1
        Loc:Flags -= UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
    End
    IF Loc:Flags => UF_PASSWORD_EXPIRED         !8388608
        NUI:flags_Password_Expired                      = 1
        Loc:Flags -= UF_PASSWORD_EXPIRED
    End
    IF Loc:Flags => UF_DONT_REQUIRE_PREAUTH     !4194304
        NUI:flags_Dont_Require_PreAuth                  = 1
        Loc:Flags -= UF_DONT_REQUIRE_PREAUTH
    End
    IF Loc:Flags => UF_USE_DES_KEY_ONLY         !2097152
        NUI:flags_Use_DES_Key_Only                      = 1
        Loc:Flags -= UF_USE_DES_KEY_ONLY
    End
    IF Loc:Flags => UF_NOT_DELEGATED            !1048576
        NUI:flags_Not_Delegated                         = 1
        Loc:Flags -= UF_NOT_DELEGATED
    End
    IF Loc:Flags => UF_TRUSTED_FOR_DELEGATION   !524288
        NUI:flags_Trusted_For_Delegation                = 1
        Loc:Flags -= UF_TRUSTED_FOR_DELEGATION
    End
    IF Loc:Flags => UF_SMARTCARD_REQUIRED       !262144
        NUI:flags_Smartcard_Required                    = 1
        Loc:Flags -= UF_SMARTCARD_REQUIRED
    End
    IF Loc:Flags => UF_MNS_LOGON_ACCOUNT        !131072
        NUI:flags_MNS_Logon_Account                     = 1
        Loc:Flags -= UF_MNS_LOGON_ACCOUNT
    End
    IF Loc:Flags => UF_DONT_EXPIRE_PASSWD        !65536
        NUI:flags_Dont_Expire_Passwd                    = 1
        Loc:Flags -= UF_DONT_EXPIRE_PASSWD
    End
    IF Loc:Flags => UF_ACCOUNT_TYPE_MASK         !15104
        NUI:flags_Account_Type_Mask                     = 1
        Loc:Flags -= UF_ACCOUNT_TYPE_MASK
    End
    IF Loc:Flags => UF_MACHINE_ACCOUNT_MASK      !14336
        NUI:flags_Machine_Account_Mask                  = 1
        Loc:Flags -= UF_MACHINE_ACCOUNT_MASK
    End
    IF Loc:Flags => UF_SERVER_TRUST_ACCOUNT     !8192
        NUI:flags_Server_Trust_Account                  = 1
        Loc:Flags -= UF_SERVER_TRUST_ACCOUNT
    End
    IF Loc:Flags => UF_WORKSTATION_TRUST_ACCOUNT    !4096
        NUI:flags_Workstation_Trust_Account             = 1
        Loc:Flags -= UF_WORKSTATION_TRUST_ACCOUNT
    End
    IF Loc:Flags => UF_INTERDOMAIN_TRUST_ACCOUNT    !2048
        NUI:flags_InterDomain_Trust_Account             = 1
        Loc:Flags -= UF_INTERDOMAIN_TRUST_ACCOUNT
    End
    IF Loc:Flags => UF_UNDOCUMENTED1024   !Unknown
        NUI:flags_Undocumented1024                      = 1
        Loc:Flags -= 1024
    End
    IF Loc:Flags => UF_NORMAL_ACCOUNT               !512
        NUI:flags_Normal_Account                        = 1
        Loc:Flags -= UF_NORMAL_ACCOUNT
    End
    IF Loc:Flags => UF_TEMP_DUPLICATE_ACCOUNT       !256
        NUI:flags_Temp_Duplicate_Account                = 1
        Loc:Flags -= UF_TEMP_DUPLICATE_ACCOUNT
    End
    IF Loc:Flags => UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED  !128
        NUI:flags_Encrypted_Text_Password_Allowed       = 1
        Loc:Flags -= UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED
    End
    IF Loc:Flags => UF_PASSWD_CANT_CHANGE               !64
        NUI:flags_Passwd_Cant_Change                    = 1
        Loc:Flags -= UF_PASSWD_CANT_CHANGE
    End
    IF Loc:Flags => UF_PASSWD_NOTREQD                   !32
        NUI:flags_Passwd_NotReqd                        = 1
        Loc:Flags -= UF_PASSWD_NOTREQD
    End
    If Loc:Flags => UF_LOCKOUT                          !16
        NUI:flags_Lockout                               = 1
        Loc:Flags -= UF_LOCKOUT
    End
    IF Loc:Flags => UF_HOMEDIR_REQUIRED                 !8
        NUI:flags_HomeDir_Required                      = 1
        Loc:Flags -= UF_HOMEDIR_REQUIRED
    End
    IF Loc:Flags => UF_UNDOCUMENTED4   !Unknown
        NUI:flags_Undocumented4                         = 1
        Loc:Flags -= 4
    End
    IF Loc:Flags => UF_ACCOUNTDISABLE                   !2
        NUI:flags_AccountDisable                        = 1
        Loc:Flags -= UF_ACCOUNTDISABLE
    End
    IF Loc:Flags => UF_SCRIPT                           !1
        NUI:flags_Script                                = 1
        Loc:Flags -= UF_SCRIPT
    End

LookupScript_Path       Routine

    IF NUI:script_pathAddress
        NUI:script_pathLen      = IS_lstrlenW(NUI:script_pathAddress)
        Clear(NUI:script_path)
        IF NUI:script_pathLen
            UnicodeToAnsi(NUI:script_pathAddress,Address(NUI:script_path))
        Else
            NUI:script_path = 'Null'
        End
    Else
        NUI:script_path = 'Null Address'
    End
LookupAuth_Flags        Routine

    Loc:auth_flags = NUI:auth_flags
    IF Loc:auth_flags => AF_SETTABLE_BITS
        NUI:auth_flags_SETTABLE_BITS    = 1
        Loc:auth_flags  -= AF_SETTABLE_BITS
    End
    IF Loc:auth_flags => AF_OP_ACCOUNTS
        NUI:auth_flags_OP_ACCOUNTS      = 1
        Loc:auth_flags  -= AF_OP_ACCOUNTS
    End
    IF Loc:auth_flags => AF_OP_SERVER
        NUI:auth_flags_OP_SERVER        = 1
        Loc:auth_flags  -= AF_OP_SERVER
    End
    IF Loc:auth_flags => AF_OP_COMM
        NUI:auth_flags_OP_COMM          = 1
        Loc:auth_flags  -= AF_OP_COMM
    End
    IF Loc:auth_flags => AF_OP_PRINT
        NUI:auth_flags_OP_PRINT         = 1
        Loc:auth_flags  -= AF_OP_PRINT
    End

LookupFull_Name     Routine

    IF NUI:full_nameAddress
        NUI:full_nameLen        = IS_lstrlenW(NUI:full_nameAddress)
        Clear(NUI:full_name)
        IF NUI:full_nameLen
            UnicodeToAnsi(NUI:full_nameAddress,Address(NUI:full_name))
        Else
            NUI:full_name = 'Null'
        End
    Else
        NUI:full_name = 'Null Address'
    End

LookupUsr_Comment       Routine

    IF NUI:usr_commentAddress
        NUI:usr_commentLen        = IS_lstrlenW(NUI:usr_commentAddress)
        Clear(NUI:usr_comment)
        IF NUI:usr_commentLen
            UnicodeToAnsi(NUI:usr_commentAddress,Address(NUI:usr_comment))
        Else
            NUI:usr_comment = 'Null'
        End
    Else
        NUI:usr_comment = 'Null Address'
    End
LookupParms         Routine

    IF NUI:parmsAddress
        NUI:parmsLen        = IS_lstrlenW(NUI:parmsAddress)
        Clear(NUI:parms)
        IF NUI:parmsLen
            UnicodeToAnsi(NUI:parmsAddress,Address(NUI:parms))
        Else
            NUI:parms = 'Null'
        End
    Else
        NUI:parms = 'Null Address'
    End
LookupWorkstations      Routine

    IF NUI:workstationsAddress
        NUI:workstationsLen        = IS_lstrlenW(NUI:workstationsAddress)
        Clear(NUI:workstations)
        IF NUI:workstationsLen
            UnicodeToAnsi(NUI:workstationsAddress,Address(NUI:workstations))
        Else
            NUI:workstations = 'Null'
        End
    Else
        NUI:workstations = 'Null Address'
    End
LookupLast_Logon        Routine

    IF NUI:last_logon
        Loc:TotalSeconds    = NUI:last_logon
        Loc:Years           = Loc:TotalSeconds / 31536000 !31557600
        Loc:TotalSeconds    = Loc:TotalSeconds - (Loc:Years * 31536000)
        Loc:Days            = Loc:TotalSeconds / 86400
        Loc:TotalSeconds    = Loc:TotalSeconds - (Loc:Days * 86400)
        Loc:Hours           = Loc:TotalSeconds / 3600
        Loc:TotalSeconds    = Loc:TotalSeconds - (Loc:Hours * 3600)
        Loc:Mins            = Loc:TotalSeconds / 60
        Loc:TotalSeconds    = Loc:TotalSeconds - (Loc:Mins * 60)
        Loc:Secs            = Loc:TotalSeconds

        Loc:Date            = (Loc:Years * 365) + Loc:Days + Date(1,1,1970)
        Loc:Time            = (((Loc:Hours * 3600) + (Loc:Mins * 60) + Loc:Secs) * 100) + 1

        NUI:last_logon_Readable = Format(Loc:Date,@d17) &' '& Format(Loc:Time,@T8)
    Else
        NUI:last_logon_Readable = 'Null'
    End
LookupLast_Logoff       Routine

    NUI:last_logoff_Readable    = 'Not Used in Windows'
LookupAcct_Expires      Routine

    IF NUI:acct_expires
        Loc:TotalSeconds    = NUI:acct_expires
        Loc:Years           = Loc:TotalSeconds / 31536000 !31557600
        Loc:TotalSeconds    = Loc:TotalSeconds - (Loc:Years * 31536000)
        Loc:Days            = Loc:TotalSeconds / 86400
        Loc:TotalSeconds    = Loc:TotalSeconds - (Loc:Days * 86400)
        Loc:Hours           = Loc:TotalSeconds / 3600
        Loc:TotalSeconds    = Loc:TotalSeconds - (Loc:Hours * 3600)
        Loc:Mins            = Loc:TotalSeconds / 60
        Loc:TotalSeconds    = Loc:TotalSeconds - (Loc:Mins * 60)
        Loc:Secs            = Loc:TotalSeconds
        Loc:Date            = (Loc:Years * 365) + Loc:Days + Date(1,1,1970)
        Loc:Time            = (((Loc:Hours * 3600) + (Loc:Mins * 60) + Loc:Secs) * 100) + 1
        NUI:acct_expires_Readable = Format(Loc:Date,@d17) &' '& Format(Loc:Time,@T8)
    Else
        NUI:acct_expires_Readable = 'Null'
    End
LookupLogon_Hours       Routine

    NUI:logon_hoursLen         = IS_lstrlenW(NUI:logon_hoursAddress)
LookupLogon_Server      Routine

    IF NUI:logon_serverAddress
        NUI:logon_serverLen         = IS_lstrlenW(NUI:logon_serverAddress)
        Clear(NUI:logon_server)
        IF NUI:logon_serverLen
            UnicodeToAnsi(NUI:logon_serverAddress,Address(NUI:logon_server))
        Else
            NUI:logon_server = 'Null'
        End
    Else
        NUI:logon_server = 'Null Address'
    End

LookupProfile       Routine

    IF NUI:profileAddress
        NUI:profileLen         = IS_lstrlenW(NUI:profileAddress)
        Clear(NUI:profile)
        IF NUI:profileLen
            UnicodeToAnsi(NUI:profileAddress,Address(NUI:profile))
        Else
            NUI:profile = 'Null'
        End
    Else
        NUI:profile = 'Null Address'
    End
LookupHome_Dir_Drive        Routine

    IF NUI:home_dir_driveAddress
        NUI:home_dir_driveLen         = IS_lstrlenW(NUI:home_dir_driveAddress)
        Clear(NUI:home_dir_drive)
        IF NUI:home_dir_driveLen
            UnicodeToAnsi(NUI:home_dir_driveAddress,Address(NUI:home_dir_drive))
        Else
            NUI:home_dir_drive = 'Null'
        End
    Else
        NUI:home_dir_drive = 'Null Address'
    End
LookupUser_Info_23      Routine

        Loc:NetUserGetInfoFilter    = NetUserEnumLevel23
        Loc:NetUserGetInfobufptr    = Address(Loc:USER_INFO_23)
        Loc:NetUserGetInfoResult    = IS_NetUserGetInfo(Loc:ServerNameAddress,NUI:nameAddress,Loc:NetUserGetInfoFilter,Loc:NetUserGetInfobufptr)
        IF Loc:NetUserGetInfoResult = NERR_Success
            peek(Loc:NetUserGetInfobufptr,Loc:NetUserGetInfoAddress)
            peek(Loc:NetUserGetInfoAddress+16,Loc:NetUserGetInfoAddress2)

            Loc:SidBoolResult = IS_ConvertSidToStringSid(Loc:NetUserGetInfoAddress2,Address(NUI:user_sidAddress)) !Sends the Sid String address to NUI:user_sidAddress
            IF Loc:SidBoolResult = 0
                RecordError('ConvertSidToStringSid Return Value Error:' & GetLastError() )
                NUI:user_sidLen = 0
                NUI:user_sid    = 'Null'
            Else
                NUI:user_sidLen = IS_lstrlenA(NUI:user_sidAddress)
                Clear(NUI:user_sid)
                Loc:lstrcpyAResult = IS_lstrcpyA(address(NUI:user_sid),NUI:user_sidAddress)
                IF NOT Loc:lstrcpyAResult
                    RecordError('lstrcpyA Return Value Error:' & GetLastError() ) !Dont know if GetLastError will work here
                End
            End
        Else
            RecordError('NetUserGetInfo 1 Return Value Error:' & Loc:NetUserGetInfoResult )
        End

        Loc:NetAPIResult = IS_NetApiBufferFree(Loc:NetUserGetInfobufptr)
        IF Loc:NetAPIResult = NERR_Success
        Else
            RecordError('NetUserGetInfo NetApiBufferFree 1 Return Value Error:' & Loc:NetAPIResult )
        End
LookupUser_Info_24      Routine

        Loc:NetUserGetInfoFilter    = NetUserEnumLevel24
        Loc:NetUserGetInfobufptr    = Address(Loc:USER_INFO_24)
        Loc:NetUserGetInfoResult    = IS_NetUserGetInfo(Loc:ServerNameAddress,NUI:nameAddress,Loc:NetUserGetInfoFilter,Loc:NetUserGetInfobufptr)
        IF Loc:NetUserGetInfoResult = NERR_Success !or Loc:NetUserEnumResult = 234 !ERROR_MORE_DATA
            peek(Loc:NetUserGetInfobufptr,Loc:NetUserGetInfoAddress)

            peek(Loc:NetUserGetInfoAddress,NUI:internet_identity)  !Bool

            
            peek(Loc:NetUserGetInfoAddress+4,NUI:internet_provider_nameAddress)
            IF NUI:internet_provider_nameAddress
                NUI:internet_provider_nameLen         = IS_lstrlenW(NUI:internet_provider_nameAddress)
                Clear(NUI:internet_provider_name)
                IF NUI:internet_provider_nameLen
                    UnicodeToAnsi(NUI:internet_provider_nameAddress,Address(NUI:internet_provider_name))
                Else
                    NUI:internet_provider_name = 'Null'
                End
            Else
                NUI:internet_provider_name = 'Null Address'
            End

            peek(Loc:NetUserGetInfoAddress+8,NUI:internet_principal_nameAddress)
            IF NUI:internet_principal_nameAddress
                NUI:internet_principal_nameLen         = IS_lstrlenW(NUI:internet_principal_nameAddress)
                Clear(NUI:internet_principal_name)
                IF NUI:internet_principal_nameLen
                    UnicodeToAnsi(NUI:internet_principal_nameAddress,Address(NUI:internet_principal_name))
                Else
                    NUI:internet_principal_name = 'Null'
                End
            Else
                NUI:internet_principal_name = 'Null Address'
            End

        Else
            RecordError('NetUserGetInfo 2 Return Value Error:' & Loc:NetUserGetInfoResult )
            IF Loc:NetUserGetInfoResult = 124
                NUI:internet_provider_name = 'Null - Not Supported'
                NUI:internet_principal_name = 'Null - Not Supported'
            End
        End

        Loc:NetAPIResult = IS_NetApiBufferFree(Loc:NetUserGetInfobufptr)
        IF Loc:NetAPIResult = NERR_Success
        Else
            RecordError('NetUserGetInfo NetApiBufferFree 2 Return Value Error:' & Loc:NetAPIResult )
        End

!--------------------------------------
OpenFiles  ROUTINE
  Access:NetUserLookup.Open                                ! Open File referenced in 'Other Files' so need to inform it's FileManager
  Access:NetUserLookup.UseFile                             ! Use File referenced in 'Other Files' so need to inform it's FileManager
  Access:NetUserInfo.Open                                  ! Open File referenced in 'Other Files' so need to inform it's FileManager
  Access:NetUserInfo.UseFile                               ! Use File referenced in 'Other Files' so need to inform it's FileManager
  FilesOpened = True
!--------------------------------------
CloseFiles ROUTINE
  IF FilesOpened THEN
     Access:NetUserLookup.Close
     Access:NetUserInfo.Close
     FilesOpened = False
  END
````Preformatted text`