Wednesday, July 22, 2020

Token Privilege in Windows [CheckPrivilegeState, ShowPrivilegeInfo, ShowEnabledPrivileges]

Viewing Token Privileges

Download from ME
Download from VBForums

Privileges control access to system resources and system-related tasks, whereas access rights control access to securable objects. Most API functions typically used by VB6 applications do not relate to system resources, but there are some WinAPI functions which require specific privileges to be enabled before they will function. If the application does not have access to the required privileges, the privilege can’t be enabled, and the function will fail. If the application does have access to the required privileges, the application may have to first enable the privilege.

The privileges available to an application are primarily determined by the logged user credentials, and whether the user has elevated credentials. The privileges allocated to user and groups are defined in the Group Policy User Rights.

This application displays the privileges that are provided by Windows, the subset that are available to the process token, and the privileges which are currently enabled. This application also provides the facility to enable or disable a privilege.

The application form lists all the available OS Privileges as a collection of privilege option buttons, provides buttons to display 3 pre-configured Privilege sets, and selecting any option button will display the status of that Privilege. Selecting the Enable and Disabled buttons will attempt to set the state of the selected privilege option button.

The 3 pre pre-configured displays of Privilege sets are:

  1. CheckPrivilegeState
    Lists the state of all the OS Privileges to show which Privileges are enabled with the current process token. The state is either “Disabled” or “Enabled”. Note the “Disabled” privileges state does not indicate if this privilege is available with the process token.

  1. ShowPrivilegeInfo
    Lists the state of all the privileges available with the process token. The state is either “Disabled”, or “Enabled” and/or “Enabled(default)”.

  1. ShowEnabledPrivileges
    Lists all the privileges which are currently Enabled.

Figure 1. Example display for a process running with elevated administrators

The count boxes shows 24 of the 36 privileges are available with elevated credentials, of which 3 are enabled. With these user credentials, only 5 of the 34 privileges are available, and only one is enabled.

The Count textboxes are show the number of privileges. The LookUp counts are calculated when the form is loaded based on the LookupPrivilegeValue and LookupPrivilegeName results. These two totals should be the same, any difference would indicate a program error. The Token Counts are updated whenever the Token Privileges buttons are selected. The CheckPrivileges State updates the Check count and the Enabled Count, the Show Privileges Information updates the Info count, and the Show Enabled Privileges updates the Enabled Count and the Check count. Selecting the Enabled and Disable buttons does not update these totals.

As an example of API’s which require specific privileges and those which don’t, the functions to create a process have differing privilege requirements:

must have the SE_IMPERSONATE_NAME privilege.
must have the SE_INCREASE_QUOTA_NAME privilege and may require the SE_ASSIGNPRIMARYTOKEN_NAME privilege if the token is not assignable
requires no special privileges as the new process runs in the security context of the Logon User
requires no special privileges as the new process runs in the security context of the calling process

Windows API functions used to view and change Privileges state

There are two WinAPI functions to view the privileges available with a process token, PrivilegeCheck API, and GetTokenInformation API with the TokenPrivileges option. The AdjustTokenPrivileges API is used to enable or disable privileges

  • The PrivilegeCheck API returns the Enabled status of a specific privilege or group of privileges.

  • The GetTokenInformation API with the TokenPrivileges option returns an array of all the privileges available to a process token, together with the privileges attributes including the Enabled status.

  • The AdjustTokenPrivileges API sets the enabled state to either Enabled or Disabled for a specific privilege or group of privileges. It can also return the previous state.  The AdjustTokenPrivileges function cannot add new privileges to the access token.

Important : The PrivilegeCheck declared in the API.Txt file used with the VB6 API viewer may be incorrect. The last argument should be byref and not byval.

Each OS has a set of privilege names, and these are listed in the MSDN document “Privilege Constants”. The set of privileges rarely changes between OS version.

Each privilege is assigned a LUID value. The WinAPI function LookupPrivilegeValue returns the Privilege LUID for a Privilege Name. The corresponding function LookupPrivilegeName returns the Privilege Name for a Privilege LUID.

When a process token is created, a subset of the OS privileges is added to the token. These are determined by the User Logon credentials. Some may be set to ENABLED state by default, others are DISABLED by default. The state of each of the privileges included in the token can be changed to ENABLE the privilege or DISABLE the privilege using the AdjustTokenPrivileges API.

The AdjustTokenPrivileges requires the token must have been opened with TOKEN_ADJUST_PRIVILEGES access, and the TOKEN_QUERY to view the previous state access). In this application, the Token is opened with the MAXIMUM_ALLOWED Access.

Using the TokenPrivilege Application

Selecting any of the Privilege option buttons will display both the Info State (as in ShowPrivilegeInfo), and the Enabled State (as in CheckPrivilegeState) for the selected Privilege. In addition the Enable and Disable button will attempt to change the Enabled State of any selected privilege.

When a Privilege option button is selected, both the GetTokenInformation API and the PrivilegeCheck API are used to query the specific privilege as follows:
  • Query a privilege with the GetTokenInformation API to determine if the privilege is available and if it is enabled
    1. Open the token for the current process using the the OpenProcessToken(GetCurrentProcess()..) API functions.
    2. Lookup the Privilege LUID form the selected Privilege Name using the  LookupPrivilegeValue API.
    3. Call the GetTokenInformation API with the TokenPrivileges option to create an array of Privileges for the token.
    4. Search the array of Privileges for a matching Privilege LUID. If there is no match, the specific Privilege is not available.
    5. Test the attribute bits for the Enabled bit &H2.
  • Query a privilege enable state with PrivilegeCheck API
    1. Open the token for the current process using the the OpenProcessToken(GetCurrentProcess()..) API functions .
    2. Lookup the Privilege LUID form the selected Privilege Name using the LookupPrivilegeValue API.
    3. Create a PRIVILEGE_SET structure with this Privilege LUID, setting the control member to zero, and the count to one.
    4. Call the PrivilegeCheck API with this PRIVILEGE_SET structure, if his call fails then the privilege does not exist.
    5. Test the attribute bits in the returned PRIVILEGE_SET structure, set to a value of &H80000000 if it is enabled.

When either the Enabled or Disabled button is selected, this application uses the AdjustTokenPrivileges API to attempt to change the Enabled state as follows:
  • Change the state of the selected privilege with AdjustTokenPrivileges
a.       Open the token for the current process using the the OpenProcessToken(GetCurrentProcess(),<access mask>) API functions.
b.      Lookup the Privilege LUID form the selected Privilege Name using the  LookupPrivilegeValue API.
c.       Create a TOKEN_PRIVILEGES structure for a single privilege, setting the Attributes to either SE_PRIVILEGE_ENABLED to enable the privilege, or to 0 to disable the privilege.
d.      Call the AdjustTokenPrivileges API with the TokenPrivileges structure.
e.       Test the result for ERROR_NOT_ALL_ASSIGNED which indicates the selected privilege is not available in the token.
f.       Report the updated result using the PrivilegeCheck API.

This application illustrates the privileges available for current process token. The Token is opened using the OpenProcessToken(GetCurrentProcess(),<access mask>) API functions. The <acces mask> is set to “MAXIMUM_ALLOWED”. There are other tokens that could be used, for example if the application included the impersonating of another user, it could open the Token using OpenProcessToken(GetCurrentThread(),<access mask>) API functions. 


Tuesday, July 14, 2020

Class Module clStrings

Class Module clStrings

Download from VBForums
Download from ME

This class module is another in a series of library modules that are designed to work with Visual Basic 6 (VB6) and all versions of Visual Basic for Applications (VBA). The code runs equally well in any of these environments which I will refer to as “VB” instead of VB6 or VBA or VB6/VBA. All routines including those dealing with Windows API calls or file reads/writes are Unicode all the time.

This module has a large set of routines to work with “BigString” which is up to 1,000 times faster than VB’s string functions in some cases. In addition there is a complete set of text and binary file read/write functions that fill a large void in VB’s file handling capabilities, especially for text files.


This class module contains an enhanced version of the BigString routines (sometimes call StringBuilder) that greatly speed up VB’s string handling especially when dealing with concatenating a large number of strings. This module also has a simple-to-use but comprehensive system for reading/writing text files and binary files (I have done up to 500 MB files in one read). An obvious question is why combine these in one module? When we read a text file it is much more efficient to read from a disk in one read into a large memory buffer and then make individual lines of text out of it. A BigString is very convenient for this. Also, when we write strings to a text file it is more efficient to do the physical write in one call which means the entire set of strings needs to be in one large data buffer, very much like a BigString. Thus it makes sense to me to combine them. I have had earlier versions of these as separate modules but I was almost always using them together so I combined and optimized them.

The BigString set of routines enable you to greatly speed up string operations when there are many changes and concatenations and/or when string lengths exceed a few hundred characters. Normally, VB re-allocates the entire string any time there is any operation on the string to change it. When you use this module, a large string is allocated once and then the subsequent string operations occur within the large string. The difference can be speed increases of up to 1,000 times versus standard string handling using built-in VB functions. If you are dealing with 100 strings o les then it likely is a bit quicker to use VB’s built-in procedures but the BigString concept excels when dealing with thousands of strings.

The file Read/Write functions are as fast as anything you can do in any language. As a VB programmer you are likely painfully aware that even though the language deals with Unicode strings, when text files are read or written, all of the Unicode gets converted to ANSI, causing all sorts of problems. This module totally eliminates that problem. Most of what we do is via Windows API calls (all Unicode) so there is no inherent slowdown due to using Visual Basic. We can read or write text files in UTF-8 (today’s text standard used almost exclusively now for web pages since it efficiently handles all Unicode characters), UTF-16 which by convention has a BOM, ANSI (Default, OEM, CurrentThread or whatever code page you want to use), and UTF-8 with a BOM even though this is discouraged now. You can specify the file type or the routine can auto-detect which one it is.

By the way, a BOM is a Byte Order Mark which is 2 or three bytes of data sometimes used for a UTF-8 file and always for a UTF-16 file to more or less announce what type of format the text will be in. UTF-8 has become so widely used that the use of a BOM is discouraged. If you wish to read more about the different types of text files exist in the Windows world, see any of the following links: UTF-8UTF-16ANSI Code Pages (mid-article for Windows code pages) and here for a Microsoft discussion on the various Windows code pages you can use (if you really need to) when you convert to/from ANSI/Unicode.

I have recently incorporated the ability to read and write binary files. It doesn’t fit with the rest of the module being related to strings but it required very little code beyond that necessary for the text read/write routines so I incorporated the features in this module.

This class module contains many string handling functions to address some VB shortcomings and to extend their capabilities. This module works in total Unicode and works with VB6 and all 32 and 64-bit flavors of VBA. All of the calls to clStrings require regular module mUCCore in order to function. This module contains many string functions on its own that you likely will find useful in addition to a whole host of routines I use every day including file operations, error handling, the operating system and so forth. Below is a list of string-related functions included in both the class module clStrings and module mUCCore.

BigString – String operations are very slow in VB6/VBA because every little change requires the string(s) to be totally reallocated. For a few characters this isn’t bad but it gets very bad when dealing with long strings and files. There is a whole subsystem described later that works around all of this, providing an alternate system to append, insert, search, remove, etc. strings at very high speeds.

DelimGet or set the delimiter string (initially set to vbCrLf). Must be 1 or 2 characters. Defaults to vbCrLf which is standard for Windows text files.
AppendAdd a string onto the end of bigString. Optionally set the starting character in the string to append.
AppendWDelimAdd a string and the Delimiter (initially vbCrLf)
InsertInsert a string into the big string. Tell it what character position to insert ahead of, specify a string & optional start character in that string and whether or not to put the delimiter sequence onto the end of the inserted string.
InsertWDelimSame as Insert above but with the current Delimiter tacked on to the string to insert.
LengthReturn the current length of the string being built (same as normal “Len()”)
RemoveRemove a specified # of characters from a place in the string.
SplitLike normal Split but operates on our bigString. The delimiter is whatever has been set with Delim (default vbCrLf). Specify start/end character positions, Limit sets the number of split strings found. Compare sets how text is searched.
FindFind a sub-string in the big string (equivalent to normal string’s InStr). Specify the string to find, what character to start looking and the compare method.
CapacityReturn current max length of the string with the current “chunks” (it will auto grown for more data)
ChunkSizeGet or set the Unicode character chunk size. The default value is 32,768 characters (65,536 bytes).
GetAStringReturns part or all of the big string. Specify the start and stop character (default to the whole string in the BigString).
bigStringSet the value of the big string starting to be built (to erase set it to "").
GrowWithGarbageLengthen our internal string by a specified # of characters. Useful for later dropping in data from an API call etc. (Advanced).
AppendPtrDataQuicker append using pointer to string and how many characters to append. (Advanced)
InsertPtrDataInsert a string using a pointer to the string (Advanced).
HeapMinimizeShrink the allocated memory for bigString down to a minimum (can still grow after this).
GetToIntCharsCopy part or all of the big string to an integer array.

Below are string functions found in the standard module mUCCore.

SubstStr – Substitute environment variables, drive label convert to drive letters, current time and date into a string.

StringW – Unicode replacement for VB function String$ which only uses chars 1-255.

iPad – Left and right-justify 2 strings over a given width. Good especially for tabular output to the Immediate Window since in both VBA and VB6 it is monospaced (all characters are the same width). I use it a lot for debugging.

AllocString – Makes a string containing a certain number of characters. Faster than Space$ for strings longer than about 400 characters. Not of much use by itself but it does provide a nice buffer for return string buffers from Windows API calls.

For those of you who dive deeper into programming than normal VB6/VBA coding, the following are Public procedures that deal with strings and text using pointers (although as we all know, nobody using VB6/VBA knows anything about pointers…). These procedures are extremely useful especially when dealing with many Windows API calls. If you don’t use pointers and memory buffers then you can ignore the below procedures. They are used internally in many of my other procedures but almost all of them take in and return normal VB variables and do not require any knowledge of pointers.

Ptr2VBStr – Makes a string in VBA and copy the data in memory to that string. You can specify the number of characters or have it find the end of the string (marked by a null character).

Ptr2Str – Even faster than Ptr2VBStr using a different algorithm. The function determines the string length.

lstrlenW – Find the length of a string in memory (characters followed by the null character).

RTLMoveMemory - Not just a string function. Copy memory data from one location to another.

File Functions

ReadTextFile – Read a text file into string array or BigString. File encoding can be UTF-8, UTF-16 or ANSI.

WriteTextFile – write a text files from string array or BigString to a file encoded in UTF-8, UTF-16 or ANSI.

ReadBinaryFile – Read a binary file into a byte array.

WriteBinaryFile – Write binary (non-text) data from a Buy buffer to a file.

SetFilePtr – Set then return the read/write file pointer in the open file. In 32-bit code the position is held in a Currency data type and in 64-bit code it the position is in a 64-bit LongPtr. Both use the Windows API function SetFilePointerEx.

CloseOpenHandle – Close the file handle for our read/write functions (if the file has been left open).

Setup and Use

The class module clStrings requires only that module mUCCore is included in the program. If you want to run the code in Excel or VB6 you need do nothing other than use the code. Just insert the class module clStrings and the standard module mUCCore into a new or existing VB6 or VBA project and you are ready to go.

If you are using this module for Office programs other than Excel, you must set an appropriate conditional compilation constant for your VBA project. There is no built-in way to distinguish between the Office programs at compile time so to do that we need to set our own conditional compilation constants which we use to check here. If you plan to use this in some code for Word, go to Tools | VBAProject Properties (2nd one from bottom) and in the General tab sheet, enter the value "Word = 1" (without quotes; case doesn't matter) to set the conditional compilation variable Word to 1. Do similar things in VBA projects you want to run in Access (Access = 1), PowerPoint (PowerPoint = 1) and Outlook (Outlook = 1). Excel and VB6 do not need a compilation constant because we can distinguish between VB6 and all of the VBA versions and we assume that you are using Excel unless modified above because most people who use VBA are using it in Excel. We can also automatically distinguish between 32 and 64-bit VBA code so you don’t need to do anything special for that.

HostRequired Conditional Compilation Constant
Visual Basic 6N/A
MS ExcelN/A
MS WordWord = 1
MS AccessAccess = 1
MS PowerPointPowerPoint = 1
MS OutlookOutlook = 1

The reason for the distinction in VBA hosts is that there are commands that exist in one host but not in the other. For example, in VBA our code is held within individual documents and often we want to know what document is holding/running our code. In Excel this is ThisWorkbook.Path but in Word it is ActiveDocument.Path, in PowerPoint it is ActivePresentation.Path, in Access it is CurrentProject.Path and in Outlook there is no equivalent. If I have a line of code that uses thisWorkbook.Path it will compile and run fine in Excel but it won’t even compile in any of those other hosts. In this particular case, I created a variable called AppPath that holds this path and I have code blocked out for each of the possible hosts so that they don’t “see” the statements that don’t exist in their version of VBA. It was a bit of a pain to set that up originally but once set up it works very well.


As with all class libraries, you must set a reference to the module before you can use it.

Dim Strs As clStrings

It doesn’t need to be named “Strs”. Then somewhere in your code you put the line

Set Strs = New clStrings

Initialization code sets the size of the big string for the string builder functions to a size of 32,769 characters (it actually doesn’t use any memory until you assign a string to it) and it also calls UCCoreInit in the module mUCCore if it hasn’t already been called by another routine.

When you are finished using the class module set it to Nothing.

Set Strs = Nothing

VB6 Users – There are controls that have been developed on the VBForums website by Krool which are enhanced versions of those Microsoft supplied with Visual Basic. Here is a link to his Common Controls Replacement Project. These controls enable Unicode and many other things. I highly recommend them. If you use them you must start your program with Sub Main and not a form and there is a bit of initialization code required to use a newer version of one of the Windows DLLs. That code is here in UCCoreInit so I recommend starting your programs with Sub Main and making the first line of code in that sub be a call to UCCoreInit. If you aren’t a VB6 user or none of this makes sense to you just skip it.

' Control Resizer Class Module
' This class module can be "attached" to a form and when the form is resized or maximized
' all of the controls on the form are resized and optionally all of the text associated
' with each control is resized as well.
'Version history
' v1.0.0 28 Nov 2016 Initial release by Paul Grimmer (PJG) (email @
' v1.1.0  5 Dec 2016
'    Incorporated Form_Resize into this class module using "WithEvents"
'    Ensured the first display is on an actual screen
'    This documentation was updated from earlier beta versions
' v2.0.0 11 Jul 2017
'    Frm is no longer declared as WithEvents so that we have control in the form code of resizing
'     i.e., the from's resize code is triggered and run and it does not automatically jump to the
'     code in this class module. Programmer has the choice to do that in the form resize
'     routine but it doesn't just bypass the form and come here automatically.
' v2.1.0 30 Aug 2017
'    Added SetFormPos to enable the form to be put on top (or not) at any time
' v2.1.001 23 Apr 2018 adding MDI child capabilities
' Dependencies - None
' To set up to use this class module with a VB6 Form, do the following to the Form:

' Set the following Form properties
'    BorderStyle = 2 (Resizable)
'    Optionally set MinButton to True and MaxButton to True

' In the declaration section at the top of the Form put
'Dim frmResize As New ControlResizer
'Public UniCaption As String

' In the Form_Load procedure start with this line after your code for setting up the
' controls on your form put the following line:
'frmResize.NewSetup Me

' That's all you need. An instance of this class is created when the Form is loaded. When
'  the Form is shown onscreen a Resize event is called and we catch the original state
'  of the form position.
' When the form is Unloaded this instance of the class module goes away too.
' Controlling the resizing
'The form can be resized either by you in code or by the user who can drag the edges of the
' form to resize &/or maximize the form.
'There are four variables you can set to control the resizing behavior for each form (each
' is separate. After your form is loaded you can set these variables. The efault for each
' is True.
'ResizeActive - True enables form resizing by the user.
'CanResizeFonts - True makes control font sizes change as control sizes change.
'KeepRatio - True keeps the height/width ratio the same as the starting form's
'  height/width ratio as the user resizes the form.
'Zoomable - True changes the size of each of the controls on the form as the
'  size of the form itself changes.
'You can set whether individual controls react to resizing by using the "Tag" property
' of the control ("Tag" is available for each control for you to put whatever text you want
' in the property at design-time.) Tag contents (if any) are totally up to the programmer.
' My code looks for the string "Skip" (not case sensitive) at the start of the tage for
'  each control. If that string is found then that control will not be resized or moved as
'  the rest of the form is moved and/or resized.


' Public Functions in this class module

' ReadTextFile - Read any text file into string array or BigString in UTF-8, ANSI or UTF-16 (UCS-2)
' WriteTextFile - Write any text file from string array or BigString to UTF-8, UTF-16 (UCS-2) or ANSI file
' ReadBinaryFile - Read art or all of a binary file into a byte array
' WriteBinaryFile - write part or all of a byte array to a binary file
' SetFilePtr -  Sets the file pointer in the open file from ReadTextFile (if still open)
' CloseOpenHandle - If the Read/Write handle has been left open this closes it.

' BigString (based on old StringBuilder code)
'  Get Length - Return the current length of the string being built (chars)
'  Get Capacity - Return current max length of the string (auto grown
'    for more data) (chars)
'  Get/Let ChunkSize - Return or set the the unicode character chunk size (chars)
'  Get/Let Delim - Return or set the end-of-line delimiter sequence (1 or 2 characters)
'    Iniitally is set to vbCrLf, but could be vbCr or vbLf or any other 1 or 2 character string for end-of-line

'  GetAString - Returns part or all of the built string
'  Let bigString - Set the value of the string starting to be built (can be "")
'  Sub Append - Add a string onto the end of bigString
'  Sub AppendWDelim - Append and add a delimiter sequence to the end
'  Sub AppendPtrData - Quicker append using pointer to string
'  Sub GrowWithGarbage - Lengthen our internal string by a specified # of characters
'  Sub Insert - Insert a string into the big string
'  Sub InsertWDelim - Insert a string (with delimiter) into the big string
'  Sub InsertPtrData - Insert a string using a pointer to the string
'  Sub Remove - Remove a specified # of characters from a place in the string
'  Function Find - Find a sub-string in the big string (like VB InStr)
'  Sub Split - Split part or all of BigString into sub-strings (like VB Split)
'  Sub HeapMinimize - shrink the allocated memory for bigString down to a
'    minimum (can still grow after this)
'  Sub GetToIntChars - Copy part or all of the big string to an integer array
' v2.2.4 30 Jul 2018
' ======================================================================================

Thursday, July 2, 2020

Matrix Algebra: It is ugly, but is truly advanced ! (by Elroy)

I was going through some of my stuff and thought maybe others could make use of some of it (and I've got tons).

Here's a little matrix (linear) algebra program. It does all the simple stuff as well as some more-or-less higher-level statistics stuff. It'll "solve" a matrix using the Jacobi method, and it also has Varimax, Quartimax, and Equimax rotations in it. I've got some non-orthogonal rotation code somewhere, but I'll have to find it.

Also, this code has a reference in it to "Microsoft Excel 14.0 Object Library" (Excel 2010) because I use Excel as a grid for the matrices. If someone asks, I could probably change this to late-binding so that this reference wouldn't be required (although some version of Excel on the machine would still be required).

Maybe someone can make some use of this stuff.

Also, just as an FYI, something I've always wanted to do in VB6 was to write a more general purpose matrix solution routine (as opposed to the Jacobi routine herein). These days, these routines are typically called SVD (or, Singular Value Decomposition) routines. One of the advantages they have over he Jacobi method is that they'll solve matrices that contain singularities. If someone knows of such a VB6 routine, I'd love to hear about it.

Again, Enjoy,

Download from ME
Download fromVBForums