Friday, October 08, 2004

The ExecutionContext class in the .NET Framework 2.0

The following example shows a basic use of the new ExecutionContext class. This class allows you to capture the current context where the code is executing in (e.g. security, syncronization, call context, etc.)

If you use both ThreadPool.UnsafeQueueUserWorkItem and ThreadPool.UnsafeRegisterForWaitForSingleObject methods, you will notice that in your callback method you don't have access to a bunch of context data like the the security context. If you impersonate an User before calling any of the ThreadPool.Unsafe* methods, the identity that will use your callback method will be the process identity, not the impersonated one.

This example shows you how to access the impersonated identity from the callback executed by ThreadPoolUnsafeQueueUserWorkItem.

// Author: danielvl(removethis)@microsoft.com

using System;
using System.Text;
using System.Threading;
using System.Security.Principal;
using System.Runtime.InteropServices;
class Program
{
[DllImport("advapi32.dll")]
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
static void Main(string[] args)
{
WindowsImpersonationContext ctxt = null;
try
{
// Impersonate other user
IntPtr userToken;
LogonUser("SimpleUser", "MyLocalMachine", "T.hisIsMy.Secret0", 2, 0, out userToken);
// At this point I am MyDomain\danielvl
ctxt = WindowsIdentity.Impersonate(userToken);
// At this point I am MyLocalMachine\SimpleUser
// Save my current context (MyLocalMachine\SimpleUser)
ExecutionContext savedContext = ExecutionContext.Capture();
// Call the unsafe version of ThreadPool.QueueUserWorkItem
ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(MyUserWorkItem), savedContext);
}
finally
{
// Revert identity to MyDomain\danielvl
if (ctxt != null)
ctxt.Undo();
}
Console.Read();
}
///
/// Method invoked from ThreadPool.UnsafeQueueUserWorkItem
///

static void MyUserWorkItem(object state)
{
// Restore the ExecutionContext object
ExecutionContext context = (ExecutionContext)state;
// Get the curren username where ThreadPool.UnsafeQueueUserWorkItem is executing
string userNameFromUnsafeContext = WindowsIdentity.GetCurrent().Name;
// Execute myContextCallbackHandler in the context saved
ExecutionContext.Run(context.CreateCopy(), myContextCallbackHandler, userNameFromUnsafeContext);
}
///
/// The handler to the ContextCallback delegate
///

static ContextCallback myContextCallbackHandler = new ContextCallback(MyContextCallback);
///
/// Method invoked from ExecutionContext.Run
///

static void MyContextCallback(object state)
{
string userNameFromUnsafeContext = (string)state;
string userNameFormSavedContext = WindowsIdentity.GetCurrent().Name;
Console.WriteLine("Username from unsafe context is {0}", userNameFromUnsafeContext);
Console.WriteLine("Username from context saved is {0}", userNameFormSavedContext);
}
}


- Output -
Username from unsafe context is MyDomain\danielvl
Username from context saved is MyLocalMachine\SimpleUser

Tuesday, August 10, 2004

The OVERLAPPED structure in C#

The OVERLAPPED structure is widely used in the Win32 functions (some examples are the functions ReadFile, WriteFile, DeviceIOControl, etc.). This structure is used to hold information about asynchronous operations.
The OVERLAPPED structure is defined as follows:

typedef struct _OVERLAPPED
{
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED;
typedef OVERLAPPED* LPOVERLAPPED;


If you want to P/Invoke a Win32 function that has defined a parameter as LPOVERLAPPED (a pointer to a OVERLAPPED structure), I recommend you to use the already defined and documented System.Threading.NativeOverlapped structure instead of define your own OVERLAPPED structure in C# (or any other .NET-language).

See some examples at http://www.pinvoke.net/, I already changed all references to the OVERLAPPED structure to System.Threading.NativeOverlapped instead. Be aware that System.Threading.NativeOverlapped is not included in the Microsoft .NET Compact Framework.

Tuesday, June 15, 2004

How to Ping in C# using System.Management

If you are using Windows XP, Windows Server 2003 or above perhaps you might want to avoid using unsupported code for emulating the Ping.exe utility that comes with Windows. Microsoft has introduced the new Win32_PingStatus WMI class. You can use the System.Management classes to access an Win32_PingStatus object directly or generate a wrapper by using the Management Strongly Typed Class Generator Tool.
Following the second option, open the Visual Studio .NET Command Prompt and type:

C:\>mgmtclassgen.exe Win32_PingStatus

This will generate the file "PingStatus.CS". Create a new C# project and add the "PingStatus.CS" file. Use the PingStatus class as follows:

using System;
using ROOT.CIMV2.Win32;
sealed class MyPing {
static void Main(string[] args)
{
if(args.Length == 0)
{
Console.Error.WriteLine("Usage: myping");
return;
}
PingStatus ping = Ping(args[0]);
// Check if we got an answer
if(ping.PrimaryAddressResolutionStatus == 0)
{
Console.WriteLine("Resolved: {0}", ping.ProtocolAddress);
}
else
{
Console.Error.WriteLine("Error: '{0}' not resolved.", ping.Address);

}
}
static PingStatus Ping(string address)
{
string condition = string.Format("Address='{0}'", address);
foreach(PingStatus ping in PingStatus.GetInstances(condition))
{
return ping;
}
return null;
}}


The C# code above pings an address (IP or host name) and checks if it got an answer. Please check the Win32_PingStatus WMI class documentation on the
MSDN for property descriptions and status codes.



Tuesday, May 11, 2004

P/Invoke Add-in for Visual Studio.NET

This is a very, very useful tool that can help you to find quickly the P/Invoke definition for almost any Win32 API function into the Visual Studio .NET. If the P/Invoke definition does not exist, but you did make it work, you can share your definition with other developers in the globe!.
This tool was developed by
Adam Nathan, a P/Invoke expert here at Microsoft that wrote a great book Interoperability in .NET.
This tool communicates with a
P/Invoke WiKi Web Site through a Web Service.
Try it out, it might save you several minutes debugging...