So for the past days I have been stuck with LogonUserA which always threw an error 1008 - ERROR_NO_TOKEN "An attempt was made to reference a token that does not exist.". It did not matter what logon type or logon provider I passed to the function - it could be interactive/network logon for domain profiles or even interactive logon for a local account. It just always failed.
After I had almost pulled my hair out, I checked out the LogonUserW function. They both have identical signatures and their documentation is absolutely the same to the letter.
LogonUserA https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-logonusera
LogonUserW https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-logonuserw
These were my signatures
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUserA(
string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken
);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUserW(
string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken
);
I have also tried using phToken as a ref for LogonUserA, but it did not change anything.
Now, my question is, is there someone who knows the difference? Or perhaps the reason for the 1008 while using LogonUserA?
Thanks!
CodePudding user response:
Almost every Win32 function that handles strings or text exists as either an "A" or a "W" function.
- The "A" functions accept ANSI text in
char
buffers, and were used in the Windows 9x family (95/98/98SE/ME) which lacked true Unicode support within the OS. - The "W" functions ("W" for "Wide Character", i.e. 16-bit) accept UTF-16 text in
wchar_t
buffers, and originated in the Windows NT family.
- The "A" functions accept ANSI text in
Generally speaking, you should not be using "A" functions anymore, simply because they won't work if you need to handle Unicode text input - though Windows still supports "A" functions for the sake of backwards compatibility.
When you use
[DllImport]
on a Win32 function that accepts string/text input you you need to specify theCharSet
parameter:- Use
CharSet.Ansi
for "A" functions. This is your bug: you're incorrectly usingCharSet.Unicode
withLogonUserA
. - Use
CharSet.Unicode
for "W" functions. - The
CharSet
option means you don't need to annotate everystring
parameter with its own[MarshalAs( UnmanagedType.LPStr )]
or[MarshalAs( UnmanagedType.LPWStr )]
attribute (for "A" and "W" respectively) (and other marshalling legwork too...)
- Use
Also, imported Win32
BOOL
functions should additionally be annotated with[return: MarshalAs(UnmanagedType.Bool)]
to ensure correct handling of return values.
So change your code to this:
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
[return: MarshalAs( UnmanagedType.Bool )]
public static extern bool LogonUserA(
string lpszUsername,
string? lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken
);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs( UnmanagedType.Bool )]
public static extern bool LogonUserW(
string lpszUsername,
string? lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken
);