Category Archives: WPF

Windows Presentation Framework

Get Logged In User while Impersonate or Run as Admin

Sometimes when a program is run as Administrator, using the System.Security.Principal.WindowsIdentity.GetCurrent().Name will return always System or NT Authority\System. This happens while running the exe under windows service or by Installer class in the windows application.

The below code will solve this issue.

Code Snippet
  1. public static string GetParentUser(int pid)
  2.         {
  3.             string parentUserAccount = null;
  4.             string queryString = String.Format("select ParentProcessId from win32_process where ProcessId={0}", pid);
  5.             using (ManagementObjectSearcher query = new ManagementObjectSearcher(new
  6.             SelectQuery(queryString)))
  7.             {
  8.                 foreach (ManagementObject mo in query.Get())
  9.                 {
  10.                     uint parentPid = (uint)mo.Properties["ParentProcessId"].Value;
  11.                     queryString = String.Format("select Handle from win32_process where ParentProcessId = {0}", parentPid);
  12.                     using (ManagementObjectSearcher subQuery = new ManagementObjectSearcher(new
  13.                     SelectQuery(queryString)))
  14.                     {
  15.                         foreach (ManagementObject mo1 in subQuery.Get())
  16.                         {
  17.                             string handle = (string)mo1.Properties["Handle"].Value;
  18.                             RelatedObjectQuery relatedQuery =
  19.                             new RelatedObjectQuery("associators of {Win32_Process.Handle=\"" + handle + "\"}");
  20.                             relatedQuery.RelatedClass = "Win32_LogonSession";
  21.                             using (ManagementObjectSearcher relQuery = new ManagementObjectSearcher(relatedQuery))
  22.                             {
  23.                                 foreach (ManagementObject mo2 in relQuery.Get())
  24.                                 {
  25.                                     RelatedObjectQuery relQuery2 =
  26.                                     new RelatedObjectQuery("associators of {Win32_LogonSession.LogonId='" +
  27.                                     mo2["LogonId"] + "'}");
  28.                                     relQuery2.RelationshipClass = "win32_LoggedonUser";
  29.                                     using (ManagementObjectSearcher searcher2 = new ManagementObjectSearcher(relQuery2))
  30.                                     {
  31.                                         foreach (ManagementObject mo3 in searcher2.Get())
  32.                                         {
  33.                                             parentUserAccount = String.Format(@"{0}\{1}", mo3["Domain"], mo3["Name"]);
  34.                                         }
  35.                                     }
  36.                                 }
  37.                             }
  38.                         }
  39.                     }
  40.                 }
  41.             }
  42.             return parentUserAccount;
  43.         }

 

You can download the code here

 

Hope the above code works. It works for me.

Thanks to the original post

http://bytes.com/topic/c-sharp/answers/631036-getting-currently-logged-user

C# Enum To String Using Attributes

There are certain situation we need to have custom string value to a Enum and later need to retrieve the string value. The string value should be independent of the enum constant. The below example will use the system.attribute class to achieve this.

Step 1: Declare a Enum

public enum GameConsole
{
    PSP=0,
    PS2=1,
    XBOX=2,
    Nitendo=3
}

Step 2: Create a custom Attribute called EnumValue

public class EnumValue : System.Attribute
{
    private string _value;
    public EnumValue(string value)
    {
         _value = value;
    }
    public string Value
    {
        get { return _value; }
    }
}

Step 3: Create a example to retrieve a attribute value

public static class EnumString
{
    public static string GetStringValue(Enum value)
    {
    string output = null;
    Type type = value.GetType();
    FieldInfo fi = type.GetField(value.ToString());
    EnumValue[] attrs = fi.GetCustomAttributes(typeof(EnumValue),false) as EnumValue[];
    if (attrs.Length > 0)
    {
        output = attrs[0].Value;
    }
        return output;
    }
}

Step 4: Change the Enum to add the string with attribute

public enum GameConsole
{
    [EnumValue(“Play Station Portable”)]
    PSP=0,
    [EnumValue(“Play Station 2”)]
    PS2=1,
    [EnumValue(“Microsoft Gaming Console”)]
    XBOX=2,
    [EnumValue(“WII Nitendo”)]
    Nitendo=3
}

Step 5: Get the Enum Attribute value

String enumStringValue = EnumString.GetStringValue(GameConsole.PSP);

Custom Logger in Prism (Composite Application Library) using log4Net

Composite Application library implements its own IloggerFacade for logging. If we need to have our own logger to log the debug information to file or other source we can always add our custom logger implementation. This blog describes you how to have a custom logger using the log4Net component. Log4Net is a tool to help the programmer output log statements to a variety of output targets. You can download the recent version of the component from this link.

This blog assumes that you have a basic knowledge in creating a Composite Application Library.

Please follow the below steps to implement the custom logger for Composite Application Library

  • Make sure your project has a reference to the Microsoft.Practices.Composite.Desktop assembly.
  • Make sure you download the latest log4net component and unzip the library.
  • Copy the log4Net.dll and the xml config file from the bin folder to the application directory. The folder structure of the log4Net is shown below.

 

  • Add the below config section to the app.config file for the log4Net configuration. If the app.config file is not present add a new app.config using the right click new item menu from Visual Studio.
    =======================================================================
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
</configSections>
<log4net>
<root>
<level value="DEBUG" />
<appender-ref ref="LogFileAppender" />
</root>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender" >
<param name="File" value="C:\temp\log.txt" />
<param name="AppendToFile" value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n" />
</layout>
</appender>
</log4net>
</configuration>

================================================================================

  • Create a logger class (for example, CustomLogger) that implements the ILoggerFacade interface. Implement the Log function of the ILoggerFacade as shown below
=======================================================================
public class CustomLogger:ILoggerFacade
{
 
#region ILoggerFacade Members
protected static readonly ILog log = LogManager.GetLogger(typeof(CustomLogger));
 
public void Log(string message, Category category, Priority priority)
{
log4net.Config.XmlConfigurator.Configure();
switch(category)
{
case Category.Debug:
log.Debug(message);
break;
case Category.Warn:
log.Warn(message);
break;
case Category.Exception:
log.Error(message);
break;
case Category.Info:
log.Info(message);
break;
}
}
 
#endregion
==================================================================================
  • In your application’s bootstrapper, override the LoggerFacade property and return a new instance of your custom logger class , as shown here.
using Microsoft.Practices.Composite.Logging;
private CustomLogger MyLogger = new CustomLogger();
/// <summary>
///
/// </summary>
protected override Microsoft.Practices.Composite.Logging.ILoggerFacade LoggerFacade
{

get

{

return MyLogger;

}
}

Now the implementation is complete you can add the logging method wherever you want to call within the application. The logger will write the log in the directory mentioned in the app.config.

 

WPF Localization or XAML Localization

I am currently assigned to a project to come up with a best approach for the WPF application architecture right from UI design to the Data Services. It’s a complex work which involves multiple layers and modules to be designed. As a part of my work I was doing some R&D on WPF or XAML localization approach.

When it comes to localization for WPF application we have so many thoughts and approach. Let me start with my favorite site and ultimate site (MSDN). Before making any decision on solution or technology for Microsoft Platform MSDN is the best way to start with. MSDN articles give you a very good understanding about technology and the concepts…

Microsoft recommended approach

http://msdn.microsoft.com/en-us/library/ms788718.aspx

http://msdn.microsoft.com/en-us/library/ms746621.aspx

I started off by reading the above article from MSDN for localization. I felt pretty complex to perform localization for WPF, because it involves too many steps to convert resx files or resource dictionary into satellite assembly. But the advantage is no need to modify XAML, development & localization can happen in parallel and can be updated later, sounds cool rt. But I want to do further more research…

Using LocBaml tool

http://www.codeproject.com/KB/WPF/Localization_in_WPF.aspx

The above article gives a good idea about how to use the LocBaml tool. But again it discuss the same LocBaml approach.

WPF Globalization using external xml file

http://www.codeproject.com/KB/WPF/WPF-Mulit-Lingual.aspx

The above approach was so cool; they use XML and XMLdataprovider with XPath and query to load the language string. The advantage of the above approach is no binary dll or the satellite dll. All the languages are saved in the xml file and changing the language is very easy and no need to compile the resource again if the text changes. But the problem is XML file management will be night mare if the application is too big like ours. So this option also ruled out in my case.

Choice of Approach discussed in codeproject

http://www.codeproject.com/KB/WPF/WPFUsingLocbaml.aspx

Above article discusses 3 approaches:

1. Using Resx and adding namespace to the XAML

2. LocBaml tool to extract csv and compile to satellite assembly using ResourceDictionary.

3. LocBaml tool using Resx files to build the satellite assembly

Also the article discusses the pros and cons of each method at the last. By this time I finished reading all those articles, now I am well versed with the available approaches and what needs to be done for WPF globalization. But still my mind was in dilemma to which approach to use.

Additional Resource

http://robbbloggg.blogspot.com/2008/03/xaml-localization.html

The above blog is similar to mine where he discusses about all the approaches and finally used his own approach to fit his requirement. But I am not convinced with his approach. Because his one of the concern is the resource binding can be applied ONLY to the dependency properties of the DependencyObject descendants. But in my case I do binding only to the DependencyObject descendants.

LinoBit Product

http://www.lingobit.com/products/index.html

With enough knowledge on the XAML localization I don’t want to re invent the wheel so I thought of any already available component or the product which can make localization easier for my application. The above product is available but to be frank I haven’t tried that product. So I cannot comment on this. So as a default IT guy I started looking for free component which does an easy job for me.

WPL Localization Extension

http://www.codeplex.com/WPFLocalizeExtension

Finally I landed here in this site. The home page alone lists down the feature the component supports. Wow its awesome it has all the functionality which I was looking for. Its ultimate feature is that is the localized text is available in the design time in VS 2008 sp1. And another good feature is that the language can be changed at runtime without touching the Threading cultureinfo.

Below are the features it supports

  • first of all: ITS FREE (and will stay free)
  • supports binding-like write style like "Text = {LocText ResAssembly:ResFile:ResKey}"
  • if ResAssembly and / or ResFile is the default, you can skip these parameters to ResAssembly::ResKey, ResFile:ResKey or only ResKey
  • works with the .resx-fallback mechanism (e.g. en-us -> en -> independent culture)
  • supports culture forcing (e.g. "this has to be English all the time")
  • works with normal dependency properties
  • works with control templates
  • can be used in xaml (really :P) without any additional namespace
  • can be used in code behind to bind localized values to dynamic generated controls
  • implements INotifyPropertyChanged for advanced use
  • supports formatting e.g. "this is the ‘{0}’ value"
  • supports prefix and suffix values (currently with LocText extension)
  • is in use in productive systems (like my public relation product)
  • switching of the language to runtime affects NO time slice
  • can be used with any resource file (.resx) across all assemblies (also the dynamic loaded one at runtime)
  • don’t need any initializing process (like "call xyz to register a special localize dictionary")
  • is available at design time (MS Expression Blend, MS Visual Studio 2008 (Normal and SP1)
  • not for dynamic loaded assemblies which only can be found at runtime and as long the resource (.resx) is builded at designtime
  • change of the choosen language is possible at designtime
  • can localize any type of data type, as long a converter (TypeConverter) for it exists (extend LocalizeExtension)
  • has build in support for Text, upper Text, lower Text, Images, Brushes, Double and Thickness
  • leaves the UID property untouched
  • offers a "SpecificCulture" to use as IFormatProvider (e.g. (123.20).ToString(LocalizeDictionary.SpecificCulture) = "123.20" or "123,20")
  • offers some functionality to check and get resource values in code behind
  • don’t alter the culture on Thread.CurrentCulture or Thread.CurrentUICulture (can be changed easily)