Any business that is running a Microsoft AD network automatically generates the new ( client ) user that has just logged in if the account does not exist on the machine.
If the business you describe does not have a Microsoft AD network .. then ( as you mention ) the cloned 'user' will be the same for each machine.
When I use WNetGetUser() .. I bounce the results against a User Table maintained in my application... if that result does not match I throw up a login screen for each user to put in their own userid that I have assigned in the User Table. That way you control the users ( id ) in your table and can then assign roles to those users to manager rights in your application.
Consider ONLY the "logic" in this code ..the data tables are ADO and not DBF ..
// check for valid user and get and set global rights
// login.prg
lOK 聽 聽:= .F.
oDLG 聽 := NIL
cSAY 聽 := " "
xREAD 聽:= " "
xWRITE := " "
xLOGIN := " "
xSUPER := " "
xAdmin := " "
cAUTH 聽:= 'N'
lOK1 聽 := .F.
DEFINE DIALOG oDlg 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽;
聽 聽 聽 聽FROM 5, 8 to 10, 75 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽;
聽 聽 聽 聽TITLE "Logging In ...... Please be patient" 聽 聽 聽 聽 聽 聽;
聽 聽 聽 聽STYLE nOr( WS_POPUP,WS_CAPTION,WS_THICKFRAME )
聽 聽 聽 聽cSAY := 聽"Validating User "
聽 聽 聽 聽@ 1,13 SAY oSAY VAR cSAY of oDLG //COLOR "N/W"
聽 聽 聽 聽oDLG:bStart := { || lOK1 := _Login( cAUTH, oDLG, @oSAY, @cSAY)}
ACTIVATE DIALOG oDLG CENTERED
IF lOK1 = .F.
聽 聽RETURN(NIL)
ENDIF
IF xLOGIN = "UNKNOWN"
聽 聽SAYING := "The System could not resolve your UserID "+CHR(10)
聽 聽SAYING += UPPER( WNetGetuser() )+CHR(10)
聽 聽SAYING += "Would you like to Login Manually ?"+CHR(10)
聽 聽IF MsgYesNo( SAYING )
聽 聽 聽 IF _log_in("L") 聽 聽 聽 聽 聽 聽 聽// log_in.prg
聽 聽 聽 ELSE
聽 聽 聽 聽 聽CLOSE DATABASES
聽 聽 聽 聽 聽RETURN(NIL)
聽 聽 聽 ENDIF
聽 聽ELSE
聽 聽 聽 CLOSE DATABASES
聽 聽 聽 RETURN(NIL)
聽 聽ENDIF
ENDIF
...
...
// end
//---------------------
FUNC _LOGIN( cAUTH, oDLG, oSAY, cSAY )
LOCAL cNAME,SAYING,nPOS,cDEFA,lOK := .F.
LOCAL oRsStaff,cSql,oErr,cFind,lFirst
Local nEid
#INCLUDE "FIVEWIN.CH"
// -- initial setup
cDEFA 聽:= SET(7)
xLOGIN := substr(upper(WNetGetuser()+space(25)),1,25) 聽 // fivewin
cSAY := "Validating User "+xLOGIN
oSAY:ReFresh()
SysReFresh()
lFirst := .f.
oRsStaff := TOleAuto():New( "ADODB.Recordset" )
oRsStaff:CursorType 聽 聽 := 1 聽 聽 聽 聽// opendkeyset
oRsStaff:CursorLocation := 3 聽 聽 聽 聽// local cache
oRsStaff:LockType 聽 聽 聽 := 3 聽 聽 聽 聽// lockoportunistic
// redundant check .. should never happen unless
// all staff users get deleted
cSql := "Select * From [Staff] where [UserId] = '"+alltrim(xLOGIN)+"'"
TRY
聽 聽oRsStaff:Open( cSQL, xCONNECT )
CATCH oErr
聽 聽MsgInfo( "Error in Opening STAFF table" )
聽 聽oDLG:END()
聽 聽RETURN(.F.)
END TRY
IF oRsStaff:eof
聽 聽xLOGIN := "UNKNOWN"
聽 聽xREAD 聽:= 'Y'
聽 聽xWRITE := 'N'
聽 聽xSUPER := 'N'
ELSE
聽 聽xREAD 聽 := if(empty(oRsStaff:Fields("ReadOnly"):Value), "Y",oRsStaff:Fields("ReadOnly"):Value )
聽 聽xWRITE 聽:= if(empty(oRsStaff:Fields("WriteOnly"):Value),"N",oRsStaff:Fields("WriteOnly"):Value )
聽 聽xSUPER 聽:= if(empty(oRsStaff:Fields("Super"):Value), 聽 聽"N",oRsStaff:Fields("Super"):Value )
聽 聽xLogin 聽:= alltrim(oRsStaff:Fields("UserId"):Value) 聽// 25
聽 聽oRsStaff:Fields("LastLog"):Value := dtoc(date())+" "+time()
聽 聽oRsStaff:Update()
ENDIF
oRsStaff:Close()
oRsStaff := nil
oDLG:END()
RETURN(.T.)
//---------------------
FUNC _log_in( cFROM )
Local lOK
Local oBTN1,oBTN2,oUSERID,oPASS,cUSERID,cPASS,SAYING
Local oDLG, oRsUser, oErr, cSQL, oBMP
Local cMODE := "E"
Local cDEFA := SET(7)
// cFROM is where the variable was passed
// 聽if "M" .. main menu login .. if password is blank 聽deny login
// 聽if "L" .. first login screen .. allow
IF EMPTY( cFROM )
聽 聽cFROM := "M"
聽* 聽 cFROM := "L"
ENDIF
lOK := .F.
oRsUser := TOleAuto():New( "ADODB.Recordset" )
oRsUser:CursorType 聽 聽 := 1 聽 聽 聽 聽// opendkeyset
oRsUser:CursorLocation := 3 聽 聽 聽 聽// local cache
oRsUser:LockType 聽 聽 聽 := 3 聽 聽 聽 聽// lockoportunistic
cSQL := "SELECT * From [Staff] Order by [Lname]"
TRY
聽 oRsUser:Open(cSQL,xCONNECT )
CATCH oErr
聽 MsgInfo( "Error in Opening Staff table" )
聽 RETURN(.F.)
END TRY
cUSERID 聽 := SPACE(25)
cPASS 聽 聽 := SPACE(15)
//------
DEFINE BITMAP oBmp RESOURCE "USERVIEW"
DEFINE DIALOG oDlg RESOURCE "LOGIN"
聽 聽REDEFINE GET oUSERID var cUSERID ID 110 of oDLG 聽 UPDATE
聽 聽REDEFINE GET oPASS 聽 var cPASS 聽 ID 120 of oDLG 聽 UPDATE
聽 聽REDEFINE BTNBMP oBtn1 ID 111 OF oDlg 聽 ;
聽 聽 聽 聽 聽RESOURCE "OK", "DOK", "DOK" ;
聽 聽 聽 聽 聽PROMPT " 聽&Ok 聽 聽" LEFT 2007;
聽 聽 聽 聽 聽ACTION ( IF(cMODE = "V",lOK := .T. , lOK := _busrules( oRsUser, cFROM,;
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 @cUserid,@cPass,oUserId,oPass,@lOk,oDlg) ), ;
聽 聽 聽 聽 聽 聽 聽 聽 聽 IF(cMODE = "V",lOK := .T. , if(lOK = .T., _doit( oRsUser,cUserId,cPass,@lOk,oDlg), )),;
聽 聽 聽 聽 聽 聽 聽 聽 聽 IF(lOK = .T., oDLG:END(), ))
聽 聽REDEFINE BTNBMP oBtn2 ID 112 OF oDlg 聽 ;
聽 聽 聽 聽 聽RESOURCE "CANCEL", "DCANCEL", "DCANCEL" ;
聽 聽 聽 聽 聽PROMPT "&Cancel 聽 " LEFT 2007;
聽 聽 聽 聽 聽ACTION ( lOK := .F., oDLG:END() )
ACTIVATE DIALOG oDlg CENTERED ;
聽 聽 聽 聽 聽ON PAINT (PalBmpDraw( hDC, 0, 0, oBmp:hBitmap ))
oBmp:End()
oRsUser:Close()
RETURN(lOK)
//----------------------------
Static FUNC _Busrules( oRsUser,cFROM,cUserid,cPass,oUserId,oPass,lOk,oDlg )
LOCAL SAYING,xPASS,xUserid
IF EMPTY( cUSERID ) 聽.or. cUSERID = " 聽"
聽 聽SAYING := "SORRY ... USERID can not be left Blank"
聽 聽MsgInfo( SAYING )
聽 聽oUSERID:SetFocus()
聽 聽RETURN(.F.)
ENDIF
IF EMPTY( cPASS ) .or. cPASS = " 聽"
聽 聽SAYING := "SORRY ... PASSWORD can not be left Blank"
聽 聽MsgInfo( SAYING )
聽 聽oPASS:SetFocus()
聽 聽RETURN(.F.)
ENDIF
cUserId := upper(cUSERID)
cPASS 聽 := substr(alltrim( cPASS )+space(15),1,15)
oRsUser:MoveFirst()
oRsUser:Find("[UserId] = '"+cUSERID+"'" )
IF oRsUser:eof
聽 聽SAYING := "SORRY ... UserId 聽 "+alltrim(cUSERID)+" 聽 could not be found "+CHR(10)
聽 聽SAYING += "Would you like to try again ?"+CHR(10)
聽 聽IF MsgYesNo( SAYING )
聽 聽 聽 cUSERID := SPACE(25)
聽 聽 聽 oUSERID:ReFresh()
聽 聽 聽 oUSERID:SetFocus()
聽 聽 聽 RETURN(.F.)
聽 聽ELSE
聽 聽 聽 lOK := .F.
聽 聽 聽 RETURN(.F.)
聽 聽ENDIF
ENDIF
IF empty(oRsUser:Fields("PASSWORD"):Value) .or.;
聽 聽oRsUser:Fields("PASSWORD"):Value = " 聽"
聽 聽IF cFROM = "L"
聽 聽ELSE
聽 聽 聽 SAYING := "SORRY ... there is no Password set for "+cUSERID+CHR(10)
聽 聽 聽 SAYING += "You can not Login from the Main Menu Login screen"+chr(10)
聽 聽 聽 SAYING += "without a Password .. Please contact your SYSTEM Admin"+chr(10)
聽 聽 聽 SAYING += "to have them re-set or create your password"+chr(10)
聽 聽 聽 MsgInfo( saying )
聽 聽 聽 cPASS := SPACE(25)
聽 聽 聽 oPASS:ReFresh()
聽 聽 聽 oPASS:SetFocus()
聽 聽 聽 RETURN(.F.)
聽 聽ENDIF
聽 聽SAYING := "No Password has been set for User 聽"+cUSERID+CHR(10)
聽 聽SAYING += "Would you like '"+cPASS+"' to be your Password ?"+CHR(10)
聽 聽IF MsgYesNo( SAYING )
聽 聽 聽 oRsUser:Fields("PASSWORD"):Value := substr(ENCRYPT( cPASS )+space(15),1,15)
聽 聽 聽 oRsUser:Update()
聽 聽ELSE
聽 聽 聽 cPASS := SPACE(15)
聽 聽 聽 oPASS:ReFresh()
聽 聽 聽 oPASS:SetFocus()
聽 聽 聽 RETURN(.F.)
聽 聽ENDIF
ENDIF
xPASS := ALLTRIM(oRsUser:Fields("PASSWORD"):Value)
xPASS := DENCRYPT( xPASS )
xPASS := substr(alltrim( xPASS )+space(15),1,15)
IF cPASS = xPASS
ELSE
聽 聽SAYING := "SORRY ... You have typed in the Wrong Password "+CHR(10)
聽 聽SAYING += "Would you like to try again ?"+CHR(10)
聽 聽IF MsgYesNo( SAYING )
聽 聽 聽 cPASS:= SPACE(15)
聽 聽 聽 oPASS:ReFresh()
聽 聽 聽 oPASS:SetFocus()
聽 聽 聽 RETURN(.F.)
聽 聽ELSE
聽 聽 聽 lOK := .F.
聽 聽 聽 oDLG:END()
聽 聽 聽 Return(.f.)
聽 聽ENDIF
ENDIF
If empty(oRsUser:FIelds("Active"):Value) .or. ;
聽 聽 聽 聽 聽oRsUser:Fields("Active"):Value = "N"
聽 聽Saying := "Sorry .. "+cUSERID+" has been marked INACTIVE and can not Login"
聽 聽MsgInfo( Saying )
聽 聽lOK := .F.
聽 聽oDLG:END()
聽 聽Return(.f.)
Endif
RETURN(.T.)
//----------------------------
Static FUNC _doit( oRsUser,cUserId,cPass,lOk,oDlg )
Local cName
xLOGIN 聽 := alltrim(oRsUser:Fields("UserId"):Value)
xREAD 聽 聽:= oRsUser:Fields("READONLY"):Value
xWRITE 聽 := oRsUser:Fields("WRITEONLY"):Value
xSUPER 聽 := oRsUser:Fields("SUPER"):Value
xAdmin 聽 := " "
oRsUser:Fields("lastlog"):Value := dtoc(DATE())+" "+Time()
oRsUser:Update()
lOK := .T.
oDLG:END()
RETURN(lOK)