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

For example if the Unit Test project is called MyUnitTests.csproj and the target work project with internals methods and classes to expose; is called MyLibrary.csproj Then insert into MyLibrary.csproj project file the following lines:

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

Substitute Related Friend Error

I had some unit tests that failed because I was using Substitute to create a Substitute logger like so:
MyClass myclass = new MyClass(Substitute.For<ILogger<CCTVCommands>>(), fileSystem);
but then I got a horrible bug that looked like this:
Can not create proxy for type Microsoft.Extensions.Logging.ILogger`1[[MyClass, MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] because type MyClass is not accessible. Make it public, or internal and mark your assembly with [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2
This was caused by the class being declared an internal class, to fix it I had to add:
  <ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
        <_Parameter1>DynamicProxyGenAssembly2</_Parameter1>
    </AssemblyAttribute>
  </ItemGroup>
to the project file of the project containing the internal class.

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