August 7, 2009

C++/CLI Casting Basics

C++/CLI Casting Basics
  • reinterpret_cast<> unsafe standard C++ cast
  • static_cast<> relies only on compile time information
  • const_cast<> is used to remove the const, volatile, and __unaligned
  • dynamic_cast<> relies both on compile time and run time information. if the cast is unsafe then this the cast returns NULL
  • __try_cast<> same as dynamic cast except it throws an exception if the cast fails
Recommendation for downcasting

If you are absolutely sure that the cast is going to be safe, you can use any of the four cast operators above, but I'd suggest that you use static_cast because that'd be the most efficient way of casting. If you are even a microscopic percentage unsure as to the safety of your cast, you must simply *avoid* static_cast and reinterpret_cast both of which are quite dangerous here. You may use either dynamic_cast or __try_cast depending on whether you like to check for NULL or you like to have an exception raised and handled.

Recommendations for upcasting

In most situations upcasting should be quite safe except when you have a bad derived class pointer (bad in the sense that it points to the wrong object). Therefore my recommendation for upcasting is to use static_cast which should be the most efficient. If your upcasts are unsafe it's probably time for you to sit down and figure out what's going wrong in your code rather than using dynamic_cast or __try_cast. In addition keep in kind that upcasting would probably be implicitly done in most situations.

Friend Assemblies

'InternalsVisibleToAttribute' indicates that all internal types in that assembly would be visible to another assembly, whose name is specified in the attribute constructor. In other words, that assembly becomes a friend assembly. The usage would be something like:
[assembly:InternalsVisibleToAttribute("MyFriendAssembly”)]
Or (for a strong-named friend)
[assembly:InternalsVisibleToAttribute("MyFriendAssembly, PublicKeyToken=45cb56a45e0a69a1")]

This entry goes in "AssemblyInfo.cs" of the assembly whose internal classes are being exposed. The assembly mentioned in the attribute is the one that is being given permission to access those internal definitions.
For example if Assembly A is a business logic assembly and assembly B is a unit test assembly requiring access to the internals of assembly A then the attribute definition is placed inside assembly A mentioning assembly B inside the attribute so that it may have the required access.

This has changed from .NET 5.0

Add the following to you target project, the one with internals that need to be exposed for unit testing:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
      <_Parameter1>UnitTestProject</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

Standby, Hibernate or Shut Down In .NET

See Standby or Hibernate Windows Programmatically
Using Windows forms static methods is the fastes way
Suspend is:
System.Windows.Forms.Application.SetSuspendState(PowerState.Suspend, false, false);
Hibernate is:
System.Windows.Forms.Application.SetSuspendState(PowerState.Hibernate, true, true);
Alternatively invoke the underlying API SetSuspendState directly.
To shut windows down
[Flags]
public enum ExitWindows : uint
{
    // ONE of the following five:
    LogOff = 0x00,
    ShutDown = 0x01,
    Reboot = 0x02,
    PowerOff = 0x08,
    RestartApps = 0x40,
    // plus AT MOST ONE of the following two:
    Force = 0x04,
    ForceIfHung = 0x10,
}

[Flags]
enum ShutdownReason : uint
{
    MajorApplication = 0x00040000,
    MajorHardware = 0x00010000,
    MajorLegacyApi = 0x00070000,
    MajorOperatingSystem = 0x00020000,
    MajorOther = 0x00000000,
    MajorPower = 0x00060000,
    MajorSoftware = 0x00030000,
    MajorSystem = 0x00050000,

    MinorBlueScreen = 0x0000000F,
    MinorCordUnplugged = 0x0000000b,
    MinorDisk = 0x00000007,
    MinorEnvironment = 0x0000000c,
    MinorHardwareDriver = 0x0000000d,
    MinorHotfix = 0x00000011,
    MinorHung = 0x00000005,
    MinorInstallation = 0x00000002,
    MinorMaintenance = 0x00000001,
    MinorMMC = 0x00000019,
    MinorNetworkConnectivity = 0x00000014,
    MinorNetworkCard = 0x00000009,
    MinorOther = 0x00000000,
    MinorOtherDriver = 0x0000000e,
    MinorPowerSupply = 0x0000000a,
    MinorProcessor = 0x00000008,
    MinorReconfig = 0x00000004,
    MinorSecurity = 0x00000013,
    MinorSecurityFix = 0x00000012,
    MinorSecurityFixUninstall = 0x00000018,
    MinorServicePack = 0x00000010,
    MinorServicePackUninstall = 0x00000016,
    MinorTermSrv = 0x00000020,
    MinorUnstable = 0x00000006,
    MinorUpgrade = 0x00000003,
    MinorWMI = 0x00000015,

    FlagUserDefined = 0x40000000,
    FlagPlanned = 0x80000000
}

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason);

internal void ShutDownWindows()
{
    AddShutDownPrivilegeToApp();
    bool res = ExitWindowsEx(
        ExitWindows.ShutDown | ExitWindows.Force, 
        ShutdownReason.MajorOther | ShutdownReason.MinorOther);
}
taken from PInvoke
Trouble is the application must have the correct privileges:
#region Adjust Priveleges

//This snippet is tested on WinXP and Vista, only needed in Vista when using SetTimeZoneInformation
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GetCurrentProcess();

[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr
phtok);

[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name,
ref long pluid);

[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
    public int Count;
    public long Luid;
    public int Attr;
}

internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
internal const string SE_TIME_ZONE_NAMETEXT = "SeTimeZonePrivilege"; //http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx
internal const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";

private bool AddShutDownPrivilegeToApp()
{
    try
    {
        bool retVal;
        TokPriv1Luid tp;
        IntPtr hproc = GetCurrentProcess();
        IntPtr htok = IntPtr.Zero;
        retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
        tp.Count = 1;
        tp.Luid = 0;
        tp.Attr = SE_PRIVILEGE_ENABLED;
        retVal = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);
        retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
        return retVal;
    }
    catch (Exception ex)
    {
        //throw;
        return false;
    }

}
#endregion

Again taken from PInvoke a great web-site