1

I'm developing a small Windows Service in C# that needs to do interop with Win32 API at some point. I'm getting the following exception which does not make sense to me:

System.ComponentModel.Win32Exception: The operation completed successfully

Right after the last line in this C# snippet:

var sessionId = Kernel32.WTSGetActiveConsoleSessionId();
var userTokenPtr = new IntPtr();
if (!WtsApi32.WTSQueryUserToken(sessionId, out userTokenPtr))
{
    throw new Win32Exception(Marshal.GetLastWin32Error());
}

Here's how I'm declaring WTSQueryUserToken in WtsApi32:

[DllImport("Wtsapi32.dll", EntryPoint="WTSQueryUserToken")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool WTSQueryUserToken
(
    [In, MarshalAs(UnmanagedType.U8)] ulong sessionId, 
    [Out] out IntPtr phToken
);

Some facts:

  • This works perfectly on 64bit Win7, but fails on a 32bit Win7.
  • There's no way the 10,000 handle limit has been reached when this is executed, it's the first Win32 call in a very small windows service.
  • I think there might be some underlying Win32 error but some bug overwrote the errorcode with a 0, thus giving me the "success" error message, but I don't know how to confirm or even diagnose this.
  • When I catch the exception, sessionId is 1 and userTokenPtr is 0. However, GetLastError returns 0 so I have no idea what happened.
  • Nearly all of the answers I found to this problem had to do with improper disposal of user controls. Since this is a Windows service, this is not the case.

I'm guessing there must be something wrong with my WTSQueryUserToken declaration, since it only fails on 32bit Windows, which leads me to think it's a marshaling problem. However, I still can't see what it might be.

Axel Magagnini
  • 855
  • 1
  • 8
  • 19
  • 1
    `bool` is not the same as `BOOL` as far as I know. I think their size differs. You certain that prototype for C# is correct in that light? – 0xC0000022L Jul 05 '12 at 18:57
  • It works on x64, that's all the certainty I have so far. :) Or maybe it's not the x64/x86 difference but something else that's breaking it. I'm looking into it right now. – Axel Magagnini Jul 05 '12 at 19:05

1 Answers1

4

Your sessionId parameter us defined as a c# ulong - an unsigned 64-bit integer, whereas the actual function export is expecting a Win32 ulong - an unsigned 32-bit integer.

c# ulong data type

Win32 data types

Sam Axe
  • 33,313
  • 9
  • 55
  • 89
  • It works, thank you so much! Actually I had thought of this and tried `UnmanagedType.U4` to fix it, but it seems that it was changing `ulong` to `UInt32` that did the trick. The line now reads: `[In, MarshalAs(UnmanagedType.U4)] UInt32 sessionId`. – Axel Magagnini Jul 05 '12 at 19:18
  • 64bit vs 32bit can be tricky sometimes. Glad the fix was so easy this time. – Sam Axe Jul 06 '12 at 04:29