WPF Commands (part 2)

Let’s start with a program that uses Cut, Copy and Paste in two TextBoxes without writing any C# code. This is not a typo. We only need XAML for this.

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="400" Width="400">    
    <DockPanel LastChildFill="True" >
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_Edit">
                <MenuItem Command="{x:Static ApplicationCommands.Cut}" CommandParameter="Cut it!"/>
                <MenuItem Command="{x:Static ApplicationCommands.Copy}" CommandParameter="Copy it!"/>
                <MenuItem Command="{x:Static ApplicationCommands.Paste}" CommandParameter="Paste it!"/>
            </MenuItem>
        </Menu>     

        <ToolBarTray Background="Gray" DockPanel.Dock="Top">
            <ToolBar Band="0" BandIndex="0" >
                <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
                <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
                <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
            </ToolBar>
            <ToolBar Band="1" BandIndex="1">
                <ToolBarPanel Orientation="Vertical">
                    <Label Content="Dummy0" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy1" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy2" ToolBar.OverflowMode="AsNeeded" />
                </ToolBarPanel>
            </ToolBar>
        </ToolBarTray>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="0" Grid.ColumnSpan="1" Margin="0" >It happened that a Fox caught its tail in a trap, and in struggling to release himself lost all of it but the stump. At first he was ashamed to show himself among his fellow foxes.</TextBox>
            <GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="1,0,0,0" Width="3"/>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="2" Grid.ColumnSpan="1" Margin="0" >But at last he determined to put a bolder face upon his misfortune, and summoned all the foxes to a general meeting to consider a proposal which he had to place before them.</TextBox>
        </Grid>
    </DockPanel>
</Window>

Editor

 

I added a Toolbar with some dummy labels just to keep the learning curve going. You remove them without any risk.

What is happening here?

Some input controls handle command events on their own. Everything is built-in already. All you need to do is to provide the Buttons or MenuItems which call these commands. The elements even enable/disable themselves. We have two textboxes in the example. These commands are applied to the element that has the focus.
How can this be achieved? The element finds the window instance and then determines what element was focused previously. This only works for Toolbars and Menus UNLESS you set the CommandTarget property  manually.

Let’s add standard buttons now. You cannot see any effect when you press them. The buttons are even ghosted. To solve this we assign the names TextBox1 and TextBox2 and link the Button CommandTargets to these elements.

 

NotWorking

 

You can now cut or copy from TextBox1 and paste it into TextBox2.
 

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="400" Width="400">    
    <DockPanel LastChildFill="True" >
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_Edit">
                <MenuItem Command="{x:Static ApplicationCommands.Cut}" CommandParameter="Cut"/>
                <MenuItem Command="{x:Static ApplicationCommands.Copy}" CommandParameter="Copy"/>
                <MenuItem Command="{x:Static ApplicationCommands.Paste}" CommandParameter="Paste"/>
            </MenuItem>
        </Menu>     

        <ToolBarTray Background="Gray" DockPanel.Dock="Top">
            <ToolBar Band="0" BandIndex="0" >
                <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
                <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
                <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
            </ToolBar>
            <ToolBar Band="1" BandIndex="1">
                <ToolBarPanel Orientation="Vertical">
                    <Label Content="Dummy0" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy1" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy2" ToolBar.OverflowMode="AsNeeded" />
                </ToolBarPanel>
            </ToolBar>
        </ToolBarTray>
<!-- changed -->
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
            <Button Command="{x:Static ApplicationCommands.Cut}" CommandTarget="{Binding ElementName=TextBox1}" Content="Cut" />
            <Button Command="{x:Static ApplicationCommands.Copy}" CommandTarget="{Binding ElementName=TextBox1}" Content="Copy" />
            <Button Command="{x:Static ApplicationCommands.Paste}" CommandTarget="{Binding ElementName=TextBox2}"  Content="Paste" />
        </StackPanel>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
<!-- changed -->
            <TextBox Name="TextBox1" TextWrapping="Wrap" Width="Auto" Grid.Column="0" Grid.ColumnSpan="1" Margin="0" >It happened that a Fox caught its tail in a trap, and in struggling to release himself lost all of it but the stump. At first he was ashamed to show himself among his fellow foxes.</TextBox>
            <GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="1,0,0,0" Width="3"/>
<!-- changed -->
            <TextBox Name="TextBox2" TextWrapping="Wrap" Width="Auto" Grid.Column="2" Grid.ColumnSpan="1" Margin="0" >But at last he determined to put a bolder face upon his misfortune, and summoned all the foxes to a general meeting to consider a proposal which he had to place before them.</TextBox>
        </Grid>

    </DockPanel>
</Window>

But hardcoding is a really bad approach. Therefore we are going to use FocusManager.IsFocusScope=”True” instead. WPF then checks the parent focus. By default, the Window class is a focus scope as are the Menu, ContextMenu, and ToolBar classes.
The following example is flawless.

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="400" Width="400">    
    <DockPanel LastChildFill="True" >
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_Edit">
                <MenuItem Command="{x:Static ApplicationCommands.Cut}" CommandParameter="Cut"/>
                <MenuItem Command="{x:Static ApplicationCommands.Copy}" CommandParameter="Copy"/>
                <MenuItem Command="{x:Static ApplicationCommands.Paste}" CommandParameter="Paste"/>
            </MenuItem>
        </Menu>     

        <ToolBarTray Background="Gray" DockPanel.Dock="Top">
            <ToolBar Band="0" BandIndex="0" >
                <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
                <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
                <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
            </ToolBar>
            <ToolBar Band="1" BandIndex="1">
                <ToolBarPanel Orientation="Vertical">
                    <Label Content="Dummy0" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy1" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy2" ToolBar.OverflowMode="AsNeeded" />
                </ToolBarPanel>
            </ToolBar>
        </ToolBarTray>
<!-- changed -->
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" FocusManager.IsFocusScope="True">
            <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
            <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
            <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
        </StackPanel>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="0" Grid.ColumnSpan="1" Margin="0" >It happened that a Fox caught its tail in a trap, and in struggling to release himself lost all of it but the stump. At first he was ashamed to show himself among his fellow foxes.</TextBox>
            <GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="1,0,0,0" Width="3"/>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="2" Grid.ColumnSpan="1" Margin="0" >But at last he determined to put a bolder face upon his misfortune, and summoned all the foxes to a general meeting to consider a proposal which he had to place before them.</TextBox>
        </Grid>

    </DockPanel>
</Window>

The IsFocusScope approach has the advantage that the same commands apply to several controls.

 
 
Custom Commands
 

We are going to write our own commands now. For this we need to create a class and add a property that returns a RoutedUICommand instance. This property needs to be static. And to initialize this class you also need a static constructor.

using System.Windows.Input;

namespace CustomCommands {
 
  public class PlaySound {

    static PlaySound() {
      KeyGesture lShortCut = new KeyGesture(Key.P, ModifierKeys.Control, "Ctrl+p");
      InputGestureCollection InputGestureCollection = new InputGestureCollection();
      InputGestureCollection.Add(lShortCut);
      PlaySoundCommand = new RoutedUICommand("Play", "PlaySound", typeof(PlaySound), InputGestureCollection);      
    } // static constructor

    public static RoutedUICommand PlaySoundCommand { get; private set; }
  } // class

} // namespace

The MainWindow class should look like this. The method CommandBinding_PlaySound_Executed plays the system beep sound.

using System.Windows;
using System.Windows.Input;

namespace DemoApp {

  public partial class MainWindow : Window {

    public MainWindow() {
      InitializeComponent();
    }

   private void CommandBinding_PlaySound_Executed(object sender, ExecutedRoutedEventArgs e) {
      System.Media.SystemSounds.Beep.Play();      
      MessageBox.Show("Source: " + e.Source.ToString() + Environment.NewLine + 
        "OriginalSource: " + e.OriginalSource.ToString() + Environment.NewLine + 
        "Parameter: " + e.Parameter.ToString());
    } //

  } // class
} // namespace

Add the class in your XAML namespace. I used xmlns:c=”clr-namespace:CustomCommands” .

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        xmlns:c="clr-namespace:CustomCommands"
        Title="MainWindow" Height="400" Width="400">
<!-- above was changed -->
    <Window.CommandBindings>
<!-- changed -->
        <CommandBinding Command="c:PlaySound.PlaySoundCommand" Executed="CommandBinding_PlaySound_Executed" />
    </Window.CommandBindings>
    <DockPanel LastChildFill="True" >
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_Edit">
                <MenuItem Command="{x:Static ApplicationCommands.Cut}" CommandParameter="Cut"/>
                <MenuItem Command="{x:Static ApplicationCommands.Copy}" CommandParameter="Copy"/>
                <MenuItem Command="{x:Static ApplicationCommands.Paste}" CommandParameter="Paste"/>
            </MenuItem>
            <MenuItem Header="_Media">
                <MenuItem Command="c:PlaySound.PlaySoundCommand" CommandParameter="Play"/>
            </MenuItem>
        </Menu>     

        <ToolBarTray Background="Gray" DockPanel.Dock="Top">
            <ToolBar Band="0" BandIndex="0" >
                <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
                <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
                <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
            </ToolBar>
            <ToolBar Band="1" BandIndex="1">
                <ToolBarPanel Orientation="Vertical">
                    <Label Content="Dummy0" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy1" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy2" ToolBar.OverflowMode="AsNeeded" />
                </ToolBarPanel>
            </ToolBar>
        </ToolBarTray>
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" FocusManager.IsFocusScope="True">
            <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
            <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
            <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
<!-- changed -->
            <Button Command="c:PlaySound.PlaySoundCommand" Content="Play" CommandParameter="What a lovely song!" />
        </StackPanel>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="0" Grid.ColumnSpan="1" Margin="0" >It happened that a Fox caught its tail in a trap, and in struggling to release himself lost all of it but the stump. At first he was ashamed to show himself among his fellow foxes.</TextBox>
            <GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="1,0,0,0" Width="3"/>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="2" Grid.ColumnSpan="1" Margin="0" >But at last he determined to put a bolder face upon his misfortune, and summoned all the foxes to a general meeting to consider a proposal which he had to place before them.</TextBox>
        </Grid>

    </DockPanel>
</Window>

PlaySound

There is a shortcut to calling commands. You can create an ICommand instance and provide it via a property. The downside – what did you expect? – is that you have no shortcut key or any other comfort.

Step 1: Create a class that inherits from interface ICommand.

using System;
using System.Windows.Input;

namespace CustomCommands {

  public class PlaySound2 : ICommand {
    object _DependencyObject;

    public PlaySound2(object xDependencyObject) {
      _DependencyObject = xDependencyObject;
    } // constructor

    public event EventHandler CanExecuteChanged {
      add { CommandManager.RequerySuggested += value; }
      remove { CommandManager.RequerySuggested -= value; }
    } //

    public bool CanExecute(object xParameter) {
      return (DateTime.Now.Second % 2 == 0); // timer based example
    } //

    public void Execute(object xParameter) {
      //_DependencyObject.DoSomething();
      System.Windows.MessageBox.Show("Parameter: " + xParameter.ToString());
      System.Media.SystemSounds.Beep.Play();
    } //


  } // class
} // namespace

Step 2: instantiate that class and provide it via a property. You do not need to expose the class in your MainWindow. You can use any class. Set the DataContext to your class where the property is (or use a precise path that leads to that object).

using CustomCommands;
using System;
using System.Windows;
using System.Windows.Input;

namespace DemoApp {

  public partial class MainWindow : Window {

    public MainWindow() {
      InitializeComponent();
      SimpleExecution = new PlaySound2("dummy");
      DataContext = this;
    }

    private void CommandBinding_PlaySound_Executed(object sender, ExecutedRoutedEventArgs e) {
      System.Media.SystemSounds.Beep.Play();
      MessageBox.Show("Source: " + e.Source.ToString() + Environment.NewLine +
        "OriginalSource: " + e.OriginalSource.ToString() + Environment.NewLine +
        "Parameter: " + e.Parameter.ToString());
    } //

    public ICommand SimpleExecution { get; private set; }

  } // class
} // namespace

Step 3: Bind the command in XAML.

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        xmlns:c="clr-namespace:CustomCommands"
        Title="MainWindow" Height="400" Width="400">
    <Window.CommandBindings>
        <CommandBinding Command="c:PlaySound.PlaySoundCommand" Executed="CommandBinding_PlaySound_Executed" />
    </Window.CommandBindings>
    <DockPanel LastChildFill="True" >
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_Edit">
                <MenuItem Command="{x:Static ApplicationCommands.Cut}" CommandParameter="Cut"/>
                <MenuItem Command="{x:Static ApplicationCommands.Copy}" CommandParameter="Copy"/>
                <MenuItem Command="{x:Static ApplicationCommands.Paste}" CommandParameter="Paste"/>
            </MenuItem>
            <MenuItem Header="_Media">
                <MenuItem Command="c:PlaySound.PlaySoundCommand" CommandParameter="Play"/>
            </MenuItem>
        </Menu>     

        <ToolBarTray Background="Gray" DockPanel.Dock="Top">
            <ToolBar Band="0" BandIndex="0" >
                <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
                <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
                <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
            </ToolBar>
            <ToolBar Band="1" BandIndex="1">
                <ToolBarPanel Orientation="Vertical">
                    <Label Content="Dummy0" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy1" ToolBar.OverflowMode="AsNeeded" />
                    <Label Content="Dummy2" ToolBar.OverflowMode="AsNeeded" />
                </ToolBarPanel>
            </ToolBar>
        </ToolBarTray>
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" FocusManager.IsFocusScope="True">
            <Button Command="{x:Static ApplicationCommands.Cut}" Content="Cut" />
            <Button Command="{x:Static ApplicationCommands.Copy}" Content="Copy" />
            <Button Command="{x:Static ApplicationCommands.Paste}" Content="Paste" />
            <Button Command="c:PlaySound.PlaySoundCommand" Content="Play" CommandParameter="What a lovely song!" />
<!-- changed -->
            <Button Command="{Binding SimpleExecution}" Content="StraightForward" CommandParameter="The German way!" />
       </StackPanel>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="0" Grid.ColumnSpan="1" Margin="0" >It happened that a Fox caught its tail in a trap, and in struggling to release himself lost all of it but the stump. At first he was ashamed to show himself among his fellow foxes.</TextBox>
            <GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="1,0,0,0" Width="3"/>
            <TextBox TextWrapping="Wrap" Width="Auto" Grid.Column="2" Grid.ColumnSpan="1" Margin="0" >But at last he determined to put a bolder face upon his misfortune, and summoned all the foxes to a general meeting to consider a proposal which he had to place before them.</TextBox>
        </Grid>

    </DockPanel>
</Window>

LastExample

That’s it for today :)

WPF Commands (part 1)

Due to personal time limitations I add a shorter post today. Nonetheless this post is vital for programmers without any WPF experience.

Events are fairly low-level and deprecated in WPF to a certain degree. They are against the idea of MVVM, which in simple terms is the separation of code and user interface. The new technology is task based – known as commands. Commands act like glue between the user interface and the code. You can avoid a lot of repetitive event-handling code. They deal with text captions and enabled/disabled state synchronizations. Let’s have a look at the ICommand interface:

namespace System.Windows.Input {

   public interface ICommand {
      event EventHandler CanExecuteChanged;
      bool CanExecute(object parameter);
      void Execute(object parameter);
   } // interface

} // namespace

The interface ICommand is inherited by RoutedCommand and indirectly by RoutedUICommand. RoutedUICommand has an additional descriptive text property, which RoutedCommand does not have. Besides this they are the same. RoutedUICommand inherits from RoutedCommand and is used for commands that display some text in the UI like menu items or tooltips.

namespace System.Windows.Input {

   public class RoutedUICommand : RoutedCommand {
      public RoutedUICommand();
      public RoutedUICommand(string text, string name, Type ownerType);
      public RoutedUICommand(string text, string name, Type ownerType, InputGestureCollection inputGestures);
      public string Text { get; set; }       // Text that describes this command.
   } // class

} // namespace

RoutedCommand is the only class in WPF that inherits from ICommand. All other classes are derived from RoutedCommand. An important feature of RoutedCommand in WPF is the so-called bubbling behavior. When you have a button in a StackPanel, then events will be executed in that order: Button -> StackPanel -> Window. I will keep it simple here and explain that behavior in another posts.

WPF has prebuild commands like Cut, Copy, Paste, Open and Print. There is no code behind these commands. You have to bind them to your code. Bubbling does play a big role here. You could press Ctrl+C to copy a text. The same command could be part of a TextBox and a window menu. The bubbling can be used to place the same command in two different places. The key input triggers the window command and provides enough information to process it.
Prebuild commands define a standard and generally increase code reusability.

Notice that RoutedCommand has its enhanced versions of CanExecute() and Execute():

namespace System.Windows.Input {

   public class RoutedCommand : RoutedCommand {
      public RoutedCommand();
      public RoutedCommand(string name, Type ownerType);
      public RoutedCommand(string name, Type ownerType, InputGestureCollection inputGestures);
      public InputGestureCollection InputGestures { get; }
      public string Name { get; }
      public Type OwnerType { get; }

      public event EventHandler CanExecuteChanged;
      public bool CanExecute(object parameter, IInputElement target);
      public void Execute(object parameter, IInputElement target);
   } // class

} // namespace

This is confusing. You naturally expect the same definition as in ICommand. The answer must be that the interface ICommand is implemented explicitly. Thus the interface method is hidden and can only be accessed indirectly via an interface variable. See below example:

public interface IMyInterface {
    void hello(object o);
} // interface

public class MyClass : IMyInterface {
  public void hello(object i, string s) { }
  void IMyInterface.hello(object o) {}
} // class

static void Main(string[] args) {
  MyClass x = new MyClass();       
  x.hello("abc", "abc");  // interface not accessible
  IMyInterface c = x;
  c.hello("abc");  // class not accessible
}

There are several groups (static classes) of prebuild commands in WPF.
ApplicationCommands provides classical commands that are in most applications (eg. Cut, Copy, Paste, Save, New, Print).
NavigationCommands provide commands for navigation that you know from browsers (eg. BrowseForward, BrowseBack).
EditingCommands are known from text editors (eg. Delete, MoveToDocumentEnd, MoveRightByWord, DecreaseFontSize).
ComponentCommands are used to move the cursor around (some duplicates are in EditingCommands; eg. MoveDown, MoveFocusBack, ExtendSelectionDown).
MediaCommands are self-explanatory (eg. Play, Pause, Record, BoostBass, ChannelDown).

These classes are static, there can only one instance in your application. They all have default keystrokes. For instance Ctrl+C is predefined for Copy. When you bind them to a command source and add that command source to a window, then the key combination becomes active. You don’t even need a visible control. An additional feature is that key combinations of commands are automatically shown in menus.

We had some theory now. Let’s get practical:

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="200">
    <StackPanel>
        <Button Command="{x:Static ApplicationCommands.New}" CommandParameter="NewProjectX" Content="New" FontSize="20" />
    </StackPanel>
</Window>
using System;
using System.Windows;
using System.Windows.Input;

namespace DemoApp {

  public partial class MainWindow : Window {

    public MainWindow() {
      InitializeComponent();

      CommandBinding lCommandBinding = new CommandBinding(ApplicationCommands.New);
      lCommandBinding.Executed += Button_Pressed;
      CommandBindings.Add(lCommandBinding); // add the binding object to our main "window" instance
    } //

    private void Button_Pressed(object sender, ExecutedRoutedEventArgs e) {
      MessageBox.Show(sender.ToString() + " did send the message: " + e.Parameter.ToString() + Environment.NewLine + "OriginalSource: " + e.OriginalSource);
    } //

  } // class
} // namespace

Window1

Window2

You don’t have to add the command in your C# code. You can add it directly in XAML. This can be more comfortable. Unfortunately there is a downside as well. The IntelliSense support suffers and I personally believe that it is more error-prone.

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="200">
    <Window.CommandBindings>
        <CommandBinding Command="{x:Static ApplicationCommands.New}" Executed="Button_Pressed" />
    </Window.CommandBindings>
    <StackPanel>
        <Button Command="{x:Static ApplicationCommands.New}" CommandParameter="NewProjectX" Content="New" FontSize="20" />
    </StackPanel>
</Window>
using System;
using System.Windows;
using System.Windows.Input;

namespace DemoApp {

  public partial class MainWindow : Window {

    public MainWindow() {
      InitializeComponent();

      //CommandBinding lCommandBinding = new CommandBinding(ApplicationCommands.New);
      //lCommandBinding.Executed += Button_Pressed;
      //CommandBindings.Add(lCommandBinding); // add the binding object to the window
    } //

    private void Button_Pressed(object sender, ExecutedRoutedEventArgs e) {
      MessageBox.Show(sender.ToString() + " did send the message: " + e.Parameter.ToString() + Environment.NewLine + "OriginalSource: " + e.OriginalSource);
    } //

  } // class
} // namespace

The next example adds a menu. The shortcut Ctrl+N is automatically shown. There is a slight change for the button as well. The object content (text) now binds to itself and uses the text from the command. The advantage is that you hardcode less and become more flexible on multi-language support later on.
You don’t have to change anything in the C# source code.

<Window x:Class="DemoApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="200">
    <Window.CommandBindings>
        <CommandBinding Command="{x:Static ApplicationCommands.New}" Executed="Button_Pressed" />
    </Window.CommandBindings>
    <StackPanel>
        <Menu>
            <MenuItem Header="_File">
                <MenuItem Command="{x:Static ApplicationCommands.New}" CommandParameter="NewProject_Y"/>
            </MenuItem>
        </Menu>
        <Separator/>
        <Button Command="{x:Static ApplicationCommands.New}" CommandParameter="NewProject_X" Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}" FontSize="20" />
    </StackPanel>
</Window>

Window3

Window4

Final note: Do not use the old school WinForms like approach anymore:

<Button Click="Button_Click" CommandParameter="NewProject_C" FontSize="20">Click</Button>
private void Button_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Button clicked"); } 

The next post will follow-up on custom commands.

Call Java from C#, IKVM

There are not many reasons why someone would want to call Java code from C#. This is like downgrading your code. It would make sense to use a service, but why directly call Java?
I can think of three reasons:
- You have access to the Java code and you do not want to program a service.
- You have access to a Java library. You have no access to its source code.
- You want to directly use the same code from Java and C#, because you are offering your software on several platforms.

There are many ways to get access to Java code. I am concentrating on the easiest one today, which is IKVM.
And just to have it mentioned as well. There is a lot of software in the market that supports the link between Java and C#. Eg. jni4net looks pretty awesome. It is worth checking the links on this page.

Let me give you an easy IKVM example now. This is the Java code:

package MyNameSpace;

public class Friend {
  public int friendSince; // value type
  public String name; // reference type
} // class
// ---------------------------------------------------------------------
package MyNameSpace;

interface IFriends {

  Friend[] getGetFriends();

  String ShowErrorMessage(String xMessage);
} // interface
// ---------------------------------------------------------------------
package MyNameSpace;

import javax.swing.*;

public class Friends implements IFriends {

  @Override
  public final String ShowErrorMessage(String xMessage) {
    System.out.println("Do you see the nice Swing MessgeBox?");
    int lButtons = JOptionPane.showConfirmDialog(null, "Let's use Swing.", xMessage, JOptionPane.YES_NO_CANCEL_OPTION);
    switch (lButtons) {
      case JOptionPane.CANCEL_OPTION:
        return "Cancel? Any other decision would have been better than that one!";
      case JOptionPane.NO_OPTION:
        return "No? What a pessimist you are!";
      case JOptionPane.YES_OPTION:
        return "Yes? PS:I lov ya!";
      default:
        return "impossible";
    }
  } //

  @Override
  public final Friend[] getGetFriends() {
    Friend[] lFriends = new Friend[6];
    for (int i = 0; i < 6; i++) lFriends[i] = new Friend(); 
    
    lFriends[0].name = "Michael Sylvester Gardenzio Stallone";
    lFriends[0].friendSince = 1946;

    lFriends[1].name = "Rocky Balboa";
    lFriends[1].friendSince = 1978;

    lFriends[2].name = "John Rambo";
    lFriends[2].friendSince = 1982;

    lFriends[3].name = "Ray Breslin";
    lFriends[3].friendSince = 2013;

    lFriends[4].name = "Gabe Walker";
    lFriends[4].friendSince = 1993;

    lFriends[5].name = "Ray Tango";
    lFriends[5].friendSince = 1989;

    return lFriends;
  } //
  
} // class

Compile above code into a jar file.
To keep things simple, copy the jar file (here: JavaLib.jar) to your IKVM folder, which is F:\Programming\ikvm-7.2.4630.5\bin in our example. Now convert the file into C# by entering the following command:

IKVM

It is important to use the right Java Version. I had Java 8 installed, but had to use JDK1.7 to avoid incompatibility. The 32/64 bit issue is also important. Use the right version in the -plattform: option. Simply type in IKVMC to see the usage of the IKVMC command.

Now add the reference IKVM.OpenJDK.Core to your C# project. You also need to reference your library, which is JavaLib.dll in our example.

References

It could not be easier. This was it!
Let’s run a test program:

using System;

namespace CallJava {
   class Program {
      
      static void Main(string[] args) {         
         MyNameSpace.Friends lFriendsObject = new MyNameSpace.Friends();
         string lFeedback = lFriendsObject.ShowErrorMessage("Hello Java from C#");
         Console.WriteLine("C# says that Java replied: " + lFeedback);
         MyNameSpace.Friend[] lFriends = lFriendsObject.getGetFriends();
         foreach (MyNameSpace.Friend lFriend in lFriends) {
            Console.WriteLine("since " + lFriend.friendSince + " " + lFriend.name + " is one of my best buddies");
         }
         Console.ReadKey();
      } //

   } // class
} // namespace

<a href="http://csharphardcoreprogramming.files.wordpress.com/2014/04/messagebox.jpg"><img src="http://csharphardcoreprogramming.files.wordpress.com/2014/04/messagebox.jpg" alt="messagebox" width="268" height="112" class="alignnone size-full wp-image-1499" /></a>

example output:
Do you see the nice Swing MessgeBox?
C# says that Java replied: Yes? PS:I lov ya!
since 1946 Michael Sylvester Gardenzio Stallone is one of my best buddies
since 1978 Rocky Balboa is one of my best buddies
since 1982 John Rambo is one of my best buddies
since 2013 Ray Breslin is one of my best buddies
since 1993 Gabe Walker is one of my best buddies
since 1989 Ray Tango is one of my best buddies

Inversion of Control and Dependency Injection (advanced, Part 1), Programming Patterns

I finally had some time and spent some hours on Inversion of Control (IoC) and Dependency Injection (DI). When I did the same a few weeks ago I did not understand a lot. I got lost on the concept of inversion. I tried to figure out, what the inversion was. This blocked all and I ended up pretty much blank despite nearly an hour of pumping information into my head. When you get lost then you should do it at least properly and at full steam ;)  Well, I finally understood the headline … and the world started making sense again.

 

Why the name “Inversion of Control”? (IoC)

An entirely hardcoded class controls the program execution path. All branches are predetermined. By using interfaces you can decouple theses flows, so that at the time of creation the class does not exactly know what instructions to call next.
Let’s say you are using events. The class, which is raising an event, hands the control over to another class. The subscribing class is in control of the program flow, not the class that raises the event. The subscribing class can subscribe or unsubscribe. The class, which is providing the event, should not have any active control over subscriptions. Hence it is an inversion of control.
By using IoC classes become more encapsulated. Let’s say a perfect class is blind and urgently needs a guide dog. The control can now be taken over by external factors. This inverts the control entirely.
Unit testing uses that mechanism. A container can be used to control classes and change the bindings.

 

What is a container?

The expression “container” is rarely used in C#. The C++ world calls containers what C# calls collections. We have come across containers in my C++ posts. Follow the link for a quick refresher.
To simplify the matter we can call a UnityContainer a dictionary of objects with some additional methods.
This container performs binding between components. For instance it replaces all specific interface declarations by fully instantiated classes without the need to explicitly call any initialization.

 

What is dependency?

The structure of a program is: Input, Calculations, Output. The same generally applies to classes. Let’s say you want to run an analysis of a text file. That analysis class can only function properly if the required text file does exist. The calculations depend on the input. The same applies to the output, which can only run if the calculation was successful.

The input class calls the calculation class, which in turn calls the output class. As we are discussing inversion, let’s decouple the classes and implement events. In this case the output class subscribes to the calculation result event and the calculator subscribes to the input event.

 

What Dependency Injection? (DI)

“Dependency Injection” is a subset of “Inversion of Control”. IoC is a principle, whereas DI is an actual implementation of the principle.
DI is a software design pattern that allows removing hard-coded dependencies. First of all you do not create objects directly; you just describe how they look like. To accomplish this, the pattern uses interfaces or base classes. As the dependency is not hardcoded, the actual object can vary each time. It just needs to fulfill the inheritable pattern of an interface or base class.

public class Car { }   // base class
public class Audi : Car { }
public class BMW : Car { }
public class Exhibition {
   Car StageObject { set; get; }  // assign Audi or BMW as the dependency object of class Exhibition
}

 

Interfaces

What are the benefits of interfaces besides multiple inheritance? Several people can work on different problems simultaneously by using interfaces. One person for instance writes the code for logging to text files and another person writes the code for logging to databases. If both use the same interface definition, then the underlying classes can be easily replaced by each other. Interfaces are like promises to provide predefined class patterns at runtime.
Thus we end up with component separation, which is very useful in unit testing. Interfaces can eliminate unfathomable dependencies if used wisely.

 

Dependency Injection and Unit Testing

When you run unit tests, then you will need input data. But it could be too complex to run the entire program just to test some methods. You would try to only instantiate the minimum requirements. Think of a syringe and inject the data into the test case to create an acceptable environment. This can be difficult in case the program was not structured well. You need to examine the code to find dependencies.

Inversion of Control

 

I will cover some IoC/DI basics today and will follow-up on this after some other posts, which were queuing up in the last weeks:

  • Calling Java from C#
  • Calling C# from Java
  • Implement all Java source code examples of the 15 day series C# to C++
  • WPF Datagrid formatting
  • Google Authenticator
  • create a post index for my blog

 

Dependency Injection

There are several ways to implement dependencies in a class. The easiest way is to have a field that holds a reference to the dependency, which is probably the worst approach you can have in terms of flexibility.

public class Report1 {
 private IDataBase _DB = new DataBase();
} 

Report1 r1 = new Report1(); // dependency DataBase must be figured out by examining the code

 

You can use methods or properties to tell your classes what dependency objects they should use. The best approach though is via constructors. You can hardly miss parameters when trying to call the constructor. Of course bad constructor overloading can jeopardize this concept.

public class Car { }  // base class (instead of an interface)
public class Audi : Car { }
public class BMW : Car { }
public class Exhibition {
   Car StageObject { set; get; }  // assign Audi or BMW as the dependency object of class Exhibition
}

public class Report2 {
   public IDataBase DB { get; private set; }
   public void SetDB(IDataBase xDB) { DB = xDB; }
} 

public class Report3 {
  public IDataBase DB { get; set; }
} 

public class Report4 {
   private IDataBase _DB;
   public Report4(IDataBase xDB) { _DB = xDB; }
} 

DataBase lDB = new DataBase();
Report2 r2 = new Report2(); r2.SetDB(lDB);
Report3 r3 = new Report3(); r3.DB = lDB;
Report4 r4 = new Report4(lDB); 

 
If the world was just like class Report4, then we could more or less end the post here. Unfortunately dependencies are often not that obvious. They are well hidden and you need to read the code thoroughly to build unit tests.
Dependency Injection goes further and the real take off takes place with Moq, which I will explain in the follow-up post.

The following code example was didactically compiled. You don’t need any further information, it should be self-explanatory. You can download unity by following this link or using NuGet.

using System;
using Microsoft.Practices.Unity;

public interface IDataBase {
   void QuerySomething();
} // interface

public interface ITextFile {
   void LoadSomething();
} // interface

public interface INetwork {
   string Text { set; get; }
   void ReceiveSomething();
} // interface

public class Network : INetwork {
   public void ReceiveSomething() { Console.WriteLine("Receiving TCP data ..."); }
   public string Text { set; get; }
} // class

public class DataBase : IDataBase {
   private string _Dummy = "I am doing something.";
   public void QuerySomething() { Console.WriteLine(_Dummy); }
} // class

public class TextFile1 : ITextFile {
   public void LoadSomething() { Console.WriteLine("TF1: Loading something..."); }
} // class

public class TextFile2 : ITextFile {
   public void LoadSomething() { Console.WriteLine("TF2: Loading something..."); }
} // class

public class TextFile3 : ITextFile {
   public void LoadSomething() { Console.WriteLine("TF3: Loading something..."); }
} // class

public class Report5 {
   public string Text = "#N/A";
   private IDataBase _DB;
   public readonly ITextFile TF;
   public IDataBase getDB() { return _DB; }
   public Report5(IDataBase xDB, ITextFile xTextFile) { _DB = xDB; TF = xTextFile; }
} // class

public class Report6 {
   public readonly string Text1;
   public readonly string Text2;
   private readonly ITextFile _TextFile;
   public readonly INetwork Network;
   public Report6(ITextFile xTextFile, INetwork xNetwork, string xText1, string xText2) {
      _TextFile = xTextFile;
      Network = xNetwork;
      Text1 = xText1;
      Text2 = xText2;
   } // constructor
} // class

class Program {

   static void Main(string[] args) {

      UnityContainer lContainer = new UnityContainer(); // using Microsoft.Practices.Unity;  

      Report5 r;

      // insufficient data
      Console.WriteLine("test: insufficient data");
      Console.WriteLine("Registering IDataBase");
      lContainer.RegisterType(typeof(IDataBase), typeof(DataBase)); // whenever someone asks for an IDataBase, then return a new DataBase instance    
      try {
         r = lContainer.Resolve<Report5>(); // throws an exception, because ITextFile is undefined
      }
      catch (Exception ex) { Console.WriteLine(ex.Message); }
      Console.WriteLine();

      // full data
      Console.WriteLine("test: sufficient data");
      Console.WriteLine("Registering ITextFile TF1");
      Console.WriteLine("IDataBase is still registered");
      lContainer.RegisterType(typeof(ITextFile), typeof(TextFile1));
      r = lContainer.Resolve<Report5>();
      Console.WriteLine("type of r.TF is " + r.TF.GetType()); // TextFile1
      r.getDB().QuerySomething();
      r.TF.LoadSomething(); // this is TextFile1
      Console.WriteLine();

      // override a previous type registration with another type
      Console.WriteLine("test: override a previous type registration with another type");
      Console.WriteLine("Registering ITextFile TF2");
      lContainer.RegisterType(typeof(ITextFile), typeof(TextFile2)); // override the first type registration    
      //lContainer.RegisterType<ITextFile, TextFile2>();   // same as lContainer.RegisterType(typeof(ITextFile), typeof(TextFile2));
      r = lContainer.Resolve<Report5>();
      Console.WriteLine("type of r.TF is " + r.TF.GetType()); // TextFile2
      r.getDB().QuerySomething();
      r.TF.LoadSomething(); // this is TextFile2 
      Console.WriteLine();

      // override a previous type registration with an instance
      Console.WriteLine("test: override a previous type registration with an instance");
      Console.WriteLine("Registering an instance of TextFile3");
      ITextFile lTextFile = new TextFile3();
      lContainer.RegisterInstance(lTextFile);
      r = lContainer.Resolve<Report5>();
      Console.WriteLine("type of r.TF is " + r.TF.GetType()); // TextFile3
      r.getDB().QuerySomething();
      r.TF.LoadSomething(); // this is TextFile3 
      Console.WriteLine();

      // using names to register instances
      Console.WriteLine("test: using names to register instances");
      lContainer.RegisterType<Report5, Report5>(); // creates a default class without any name
      Report5 a = new Report5(r.getDB(), r.TF); lContainer.RegisterInstance("A", a); a.Text = "Report A";
      Report5 b = new Report5(r.getDB(), r.TF); lContainer.RegisterInstance("B", b); b.Text = "Report B";

      r = lContainer.Resolve<Report5>("A"); Console.WriteLine("got " + r.Text);
      r = lContainer.Resolve<Report5>("B"); Console.WriteLine("got " + r.Text);
      r = lContainer.Resolve<Report5>(); Console.WriteLine("got " + r.Text); r.Text = "same instance?";
      r = lContainer.Resolve<Report5>("X"); Console.WriteLine("got " + r.Text);  // new instance
      r = lContainer.Resolve<Report5>(); Console.WriteLine("got " + r.Text); // new instance
      Console.WriteLine();

      // => HAVE A LOOK AT THE BELOW CONTAINER SNAPSHOT => there are 3 instances for Report5

      // using names to register instances
      Console.WriteLine("test: revision, using the same instance");
      Console.WriteLine("ContainerControlledLifetimeManager: re-use instances (singleton behaviour for objects)");
      lContainer.RegisterType<Report5, Report5>(new ContainerControlledLifetimeManager());
      r = lContainer.Resolve<Report5>(); Console.WriteLine("got " + r.Text); r.Text = "same instance?";
      r = lContainer.Resolve<Report5>("X"); Console.WriteLine("got " + r.Text);  // new instance
      r = lContainer.Resolve<Report5>(); Console.WriteLine("got " + r.Text); // same instance !!!!!
      Console.WriteLine();

      // constructors with parameters
      lContainer.RegisterType<INetwork, Network>();
      lContainer.RegisterType<ITextFile, TextFile2>();
      Console.WriteLine("test: constructors with parameters");
      ResolverOverride[] lParameters = new ResolverOverride[] { new ParameterOverride("xText1", "Hello "), new ParameterOverride("xText2", "world") };
      Report6 lReport6 = lContainer.Resolve<Report6>(lParameters);
      Console.WriteLine("Report6 text field values are: " + lReport6.Text1 + lReport6.Text2);

      Console.ReadLine();
   } //

} // class

 

instances
 

example output:
test: insufficient data
Registering IDataBase
Resolution of the dependency failed, type = “Report5″, name = “(none)”.
Exception occurred while: while resolving.
Exception is: InvalidOperationException – The type ITextFile does not have an ac
cessible constructor.
———————————————–
At the time of the exception, the container was:

Resolving Report5,(none)
Resolving parameter “xTextFile” of constructor Report5(IDataBase xDB, ITextFil
e xTextFile)
Resolving ITextFile,(none)

test: sufficient data
Registering ITextFile TF1
IDataBase is still registered
type of r.TF is TextFile1
I am doing something.
TF1: Loading something…

test: override a previous type registration with another type
Registering ITextFile TF2
type of r.TF is TextFile2
I am doing something.
TF2: Loading something…

test: override a previous type registration with an instance
Registering an instance of TextFile3
type of r.TF is TextFile3
I am doing something.
TF3: Loading something…

test: using names to register instances
got Report A
got Report B
got #N/A
got #N/A
got #N/A

test: revision, using the same instance
ContainerControlledLifetimeManager: re-use instances (singleton behaviour for ob
jects)
got #N/A
got #N/A
got same instance?

test: constructors with parameters
Report6 text field values are: Hello world

migration Java, C++ (day 15), professional), call C++ from Java, call Java from C++

logo

Guys, day15! I was not giving up. I haven’t found any example on the web that explains, how to return arrays of classes/structures when crossing language barriers. I was close to giving up. But after roughly six hours I had found the solution. And as usual: In hindsight it all looks simple.

Today is the last day I cover C++ in this series. There will be more, but not as a part of this 15 day bet. I have learnt a lot during these days. I proved someone else’s opinion wrong and can firmly support people with a similar attitude now. Well, so the conclusion and good news is: YES, you can learn C++ in 15 days and be on a good level afterwards. All you need is resilience.
Surely, 15 days are not enough to become an expert. But it was amazing to see how much someone can learn in such a short time.

EDIT 27 March:
I spoke to a friend yesterday. He asked me why I was not using SWIG. It is useful to learn driving a car with gears before you upgrade to automatic transmission. However, here is the link for further studies to Swig.

What settings do we need today?

In C++ add jvm.lib to Additional Dependencies of the Linker. Then enter C:\Program Files\Java\jdk1.8.0\lib in field Additional Library Directories.

Setting1

You also need additional include directories:
a) C:\Program Files\Java\jdk1.8.0\include\win32
b) C:\Program Files\Java\jdk1.8.0\include

Setting2

Google for javah for further research. (You don’t need it here as I provide all required code). You can use javah to generate header files for you. It simplifies your work a lot. Furthermore you may be interested in the memory management of the JNI. You don’t need to manage objects, which you generate via the JNI in C++, yourself. Great deal!

DOS

I created a temporary directory in C:\temp . It helped me to keep my environment neat and tidy. Some people prefer to store the files directly in the build directories. But this can cause problems when you clear all project data to rebuild your code from scratch.

JNI sometimes uses weird abbreviations for IDs like in lJNIEnv->GetMethodID(lTestClass, “getFriends”, “()[LFriend;"). They look worse than they are. In the brackets () you enter the input parameter types. Next to it, on the right side, you have the output parameter type. Do not add any space or separators. For instance (II)V would describe a method with two integer parameters and a void return type.

JvmTypeSignatures

Calling Java code from C++

import javax.swing.JOptionPane;

public class TestLib {

  double[]  DoubleArrayField  = { 1.1, 2.2, 3.3, 4.4, 5.5 };
  int       IntField           = 99;

  public TestLib() {
    System.out.println("Java: Executing constructor");
  } // constructor

  public static void main(String[] args) {
    System.out.println("Java: main()");
  } //

  public String ShowErrorMessage(String xMessage) {
    System.out.println("Java: Do you see the nice Java MessgeBox?");
    int dialogResult = JOptionPane.showConfirmDialog(null, "Therefore let’s use Javax Swing and do the stuff that would take too much time in C++.", xMessage, JOptionPane.YES_NO_CANCEL_OPTION);
    switch (dialogResult) {
      case JOptionPane.CANCEL_OPTION:
        return "Cancel? Any other decision would have been better than that one!";
      case JOptionPane.YES_OPTION:
        return "Yes? PS:I lov ya!";
      case JOptionPane.NO_OPTION:
        return "No? What a pessimist you are!";
      default:
    }

    return "impossible";
  } //

  public Friend[] getFriends() {
    Friend[] lFriends = new Friend[6];

    lFriends[0] = new Friend(1946, "Michael Sylvester Gardenzio Stallone");
    lFriends[1] = new Friend(1978, "Rocky Balboa");
    lFriends[2] = new Friend(1982, "John Rambo");
    lFriends[3] = new Friend(2013, "Ray Breslin");
    lFriends[4] = new Friend(1993, "Gabe Walker");
    lFriends[5] = new Friend(1989, "Ray Tango");

    return lFriends;
  } //

} // class
#include <iostream>
#include <jni.h>
#include <string>

using namespace std;


JNIEnv* GetJVM(JavaVM ** xJVM) {
  JavaVMOption lOptions;
  lOptions.optionString = "-Djava.class.path=C:\\Ohta\\cppin15days\\Day15\\bin"; // path to your java source code

  JavaVMInitArgs lInitArgs;
  lInitArgs.version = JNI_VERSION_1_6;
  lInitArgs.nOptions = 1;
  lInitArgs.options = &lOptions;
  lInitArgs.ignoreUnrecognized = 0;

  JNIEnv *lJNIEnv;
  int lResult = JNI_CreateJavaVM(xJVM, (void**)&lJNIEnv, &lInitArgs);
  if (lResult < 0)  cout << "Cannot launch JVM" << endl;

  return lJNIEnv;
} //


void test() {
  JavaVM *lJavaVM;
  JNIEnv *lJNIEnv = GetJVM(&lJavaVM);
  if (lJNIEnv == nullptr)  return;

  jclass lTestClass = lJNIEnv->FindClass("TestLib");
  if (!lTestClass) { std::cerr << "C++: TestLib class not found." << std::endl; return; }

  // call main()
  jmethodID lMain = lJNIEnv->GetStaticMethodID(lTestClass, "main", "([Ljava/lang/String;)V");
  if (!lMain) { std::cerr << "C++: Failed to get main()." << std::endl; return; }
  jobjectArray lArguments = lJNIEnv->NewObjectArray(1, lJNIEnv->FindClass("java/lang/String"), NULL);
  jstring lFirstArgument = lJNIEnv->NewStringUTF("dummy");
  lJNIEnv->SetObjectArrayElement(lArguments, 0, lFirstArgument);
  lJNIEnv->CallStaticVoidMethod(lTestClass, lMain, lArguments);

  // instantiate our TestClass
  jmethodID lConstructor = lJNIEnv->GetMethodID(lTestClass, "<init>", "()V"); // get the constructor by using <init>
  jobject lInstance = lJNIEnv->NewObject(lTestClass, lConstructor);

  // DoubleArrayField
  jobject lJArray = lJNIEnv->GetObjectField(lInstance, lJNIEnv->GetFieldID(lTestClass, "DoubleArrayField", "[D"));
  jdoubleArray *lJDoubles = reinterpret_cast<jdoubleArray*>(&lJArray);
  jsize lJSize = lJNIEnv->GetArrayLength(*lJDoubles);
  jboolean lFalse(false);
  double *lDoubles = lJNIEnv->GetDoubleArrayElements(*lJDoubles, &lFalse);
  cout << "DoubleArrayField: ";
  for (int i = 0; i < lJSize; i++) cout << " " << lDoubles[i];
  cout << endl;

  // IntField
  jint lInt = lJNIEnv->GetIntField(lInstance, lJNIEnv->GetFieldID(lTestClass, "IntField", "I"));
  cout << "IntField: " << (int)lInt << endl;

  // ShowErrorMessage()  
  jboolean lTrue(true);
  if (lJNIEnv->IsInstanceOf(lInstance, lTestClass) == JNI_TRUE) { // <= this code line is just for demo purposes
    jmethodID lMethod = lJNIEnv->GetMethodID(lTestClass, "ShowErrorMessage", "(Ljava/lang/String;)Ljava/lang/String;");
    lFirstArgument = lJNIEnv->NewStringUTF("A kiss from C++");
    jobject lResult = lJNIEnv->CallObjectMethod(lInstance, lMethod, lFirstArgument); // arguments in function call ,CallCharMethodA => arguments in a jvalues array, CallCharMethodV => arguments in a va_list   
    jstring lString = reinterpret_cast<jstring>(lResult);
    const char *s = lJNIEnv->GetStringUTFChars(lString, nullptr);
    cout << "C++: Java said => " << s << endl;   
    //lJNIEnv->ReleaseStringUTFChars(lString, s);
  }
  
  // getFriends() 
  jmethodID lMethod = lJNIEnv->GetMethodID(lTestClass, "getFriends", "()[LFriend;");
  jobject lResult = lJNIEnv->CallObjectMethod(lInstance, lMethod);  
  jobjectArray lArray = reinterpret_cast<jobjectArray>(lResult);
  jclass lFriendClass = lJNIEnv->FindClass("Friend");  
  
  int n = (int)lJNIEnv->GetArrayLength(lArray);
  for (int i = 0; i < n; i++)  {
    jobject lFriend = lJNIEnv->GetObjectArrayElement(lArray, jsize(i));
    jfieldID lFieldId0 = lJNIEnv->GetFieldID(lFriendClass, "friendSince", "I");
    int lFriendSince = lJNIEnv->GetIntField(lFriend, lFieldId0);
    jfieldID lFieldId1 = lJNIEnv->GetFieldID(lFriendClass, "name", "Ljava/lang/String;");
    jobject h = lJNIEnv->GetObjectField(lFriend, lFieldId1);   
    jstring lName = reinterpret_cast<jstring>(h);
    const char *s = lJNIEnv->GetStringUTFChars(lName, nullptr);  
    cout << s << " is my best buddy since " << lFriendSince << endl;
  }

  cin.get();
} //

example output:
Java: main()
Java: Executing constructor
DoubleArrayField: 1.1 2.2 3.3 4.4 5.5
IntField: 99
Java: Do you see the nice Java MessgeBox?
C++: Java said => No? What a pessimist you are!
Michael Sylvester Gardenzio Stallone is my best buddy since 1946
Rocky Balboa is my best buddy since 1978
John Rambo is my best buddy since 1982
Ray Breslin is my best buddy since 2013
Gabe Walker is my best buddy since 1993
Ray Tango is my best buddy since 1989

Calling C++ code from Java


// -------------------------------------------------------------------------------------------------------------
//   Friend.java 
// -------------------------------------------------------------------------------------------------------------

public class Friend {
  public int		friendSince;	// value type
  public String	name;				// reference type

  public Friend(int xFriendSince, String xName) {
    friendSince = xFriendSince;
    name = xName;
  }
} // class

// -------------------------------------------------------------------------------------------------------------
//   TestProgram.java file
// -------------------------------------------------------------------------------------------------------------

import java.io.IOException;

public class TestProgram {

  public native String ShowErrorMessage(String xMessage);
  public native Friend[] getFriends();

  public static void main(String[] args) throws IOException {
    System.load("c:\\temp\\Day15.dll"); 
    TestProgram lTestProgram = new TestProgram();
    String s = lTestProgram.ShowErrorMessage("Java: Hello C++");
    System.out.println(s);

    Friend[] lFriends = lTestProgram.getFriends();

    for (Friend lFriend : lFriends) {
      System.out.println(lFriend.name + " is my best buddy since " + lFriend.friendSince);
    }
    System.in.read();
  } //
} // class
// -------------------------------------------------------------------------------------------------------------
//   TestProgram.h  (generated with javah.exe)
// -------------------------------------------------------------------------------------------------------------

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class TestProgram */

#ifndef _Included_TestProgram
#define _Included_TestProgram
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     TestProgram
 * Method:    ShowErrorMessage
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_TestProgram_ShowErrorMessage (JNIEnv *, jobject, jstring);

/*
 * Class:     TestProgram
 * Method:    getFriends
 * Signature: ()[LFriend;
 */
JNIEXPORT jobjectArray JNICALL Java_TestProgram_getFriends (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

// -------------------------------------------------------------------------------------------------------------
//  Day15.cpp file
// -------------------------------------------------------------------------------------------------------------

#include <stdio.h>
#include <iostream>
#include <string>
#include <jni.h>
#include "C:\temp\TestProgram.h"

using namespace std;

jstring Alloc(JNIEnv *xJNIEnv, const char *xText){
  return xJNIEnv->NewStringUTF(xText);
} //

JNIEXPORT jstring JNICALL Java_TestProgram_ShowErrorMessage(JNIEnv *xJNIEnv, jobject xObject, jstring xMessage) {
  const char *lMessage = xJNIEnv->GetStringUTFChars(xMessage, nullptr);
  cout << "C++: I am too lazy for MessageBoxes." << endl;
  wcout << "C++: Your message was: " << lMessage << endl;
  return Alloc(xJNIEnv, "C++: Good night!");
} //

void AddFriend(JNIEnv *xJNIEnv, jclass xFriendClass, jobjectArray xArray, int xIndex, int xFriendSince, const char *xFriendName) {
  jobjectArray lArguments = xJNIEnv->NewObjectArray(2, xFriendClass, NULL);
  jint lFriendSince(xFriendSince);
  jstring lName = xJNIEnv->NewStringUTF(xFriendName);
  jmethodID lConstructor = xJNIEnv->GetMethodID(xFriendClass, "<init>", "(ILjava/lang/String;)V"); // get the constructor by using <init>
  jobject lInstance = xJNIEnv->NewObject(xFriendClass, lConstructor, lFriendSince, lName);
  xJNIEnv->SetObjectArrayElement(xArray, jsize(xIndex), lInstance);
} //

JNIEXPORT jobjectArray JNICALL Java_TestProgram_getFriends(JNIEnv *xJNIEnv, jobject xObject) {
  //jclass lObjectClass = xJNIEnv->GetObjectClass(xObject);      
  jclass lFriendClass = xJNIEnv->FindClass("Friend");
  jobjectArray lArray = xJNIEnv->NewObjectArray(6, lFriendClass, NULL);
  if (!lFriendClass) { std::cerr << "C++: Friend class not found." << std::endl; return lArray; }

  AddFriend(xJNIEnv, lFriendClass, lArray, 0, 1946, "Michael Sylvester Gardenzio Stallone");
  AddFriend(xJNIEnv, lFriendClass, lArray, 1, 1978, "Rocky Balboa");
  AddFriend(xJNIEnv, lFriendClass, lArray, 2, 1982, "John Rambo");
  AddFriend(xJNIEnv, lFriendClass, lArray, 3, 2013, "Ray Breslin");
  AddFriend(xJNIEnv, lFriendClass, lArray, 4, 1993, "Gabe Walker");
  AddFriend(xJNIEnv, lFriendClass, lArray, 5, 1989, "Ray Tango");

  return lArray;
} //

example output:
C++: I am too lazy for MessageBoxes.
C++: Your message was: Java: Hello C++
C++: Good night!
Michael Sylvester Gardenzio Stallone is my best buddy since 1946
Rocky Balboa is my best buddy since 1978
John Rambo is my best buddy since 1982
Ray Breslin is my best buddy since 2013
Gabe Walker is my best buddy since 1993
Ray Tango is my best buddy since 1989

migration C#, C++ (day 14), call C# from C++ (advanced), call C++ from C# (hardcore)

logo

Hardcore today.The second example is C# even though it looks like C++. So don’t get confused. Day 15 is nigh.

C++ is about speed and not comfort. Nevertheless, sometimes you want comfort. And it can be done. The C++ programmer can in fact call C# code from C++ to access the entire .Net Framework indirectly.
Usually you would use a TCP connection to achieve this. Unfortunately it does require work. And you sometimes do not have the source code of a C# library to quickly build in a network connection. And remoting is not a solution as well; the protocol needs to be the same. So you could end up in a lot of unnecessary programming. If you can, access available C# libraries directly. And today I show you how it can be done.

In case you need to write the library, make sure to amend the com-visibility in your AssemblyInfo.cs to [assembly: ComVisible(true)]. You also have to check the “Register for COM Interop” setting.

ComVisible

Oh, and before I forget this important detail. Start your Visual Studio in admin mode by right clicking it and then selecting “Run as administrator”. You won’t have enough user rights to register the library for com otherwise. In case you are not using Visual Studio, or you have to roll out the library on a different PC, then use RegAsm to register the library on that system. You may have a 32 bit and a 64 bit version of RegAsm on your PC. Use the right one to avoid nasty error messages.

Calling C# code from C++

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace TestLib {

  // struct is a value type
  [StructLayout(LayoutKind.Sequential)]
  public struct Friend {
    public int friendSince; // value type
    [MarshalAs(UnmanagedType.BStr)]
    public string name;  // reference type
  } // struct

  public interface IFriends {
    Friend[] GetFriends { get; }
    string ShowErrorMessage(string xMessage);
  } // interface

  public class Friends : IFriends {

    public string ShowErrorMessage(string xMessage) {
      Console.WriteLine("Do you see the nice .Net MessgeBox?");
      DialogResult lButtons = MessageBox.Show("Therefore let's use Windows Forms and do the stuff that would take too much time in C++.", xMessage, MessageBoxButtons.YesNoCancel);
      switch (lButtons) {
        case DialogResult.Cancel:
          return "Cancel? Any other decision would have been better than that one!";
        case DialogResult.No:
          return "No? What a pessimist you are!";
        case DialogResult.Yes:
          return "Yes? PS:I lov ya!";
        default:
          return "impossible";
      }
    } //


    public Friend[] GetFriends {
      get {
        Friend[] lFriends = new Friend[6];
        lFriends[0].name = "Michael Sylvester Gardenzio Stallone";
        lFriends[0].friendSince = 1946;

        lFriends[1].name = "Rocky Balboa";
        lFriends[1].friendSince = 1978;

        lFriends[2].name = "John Rambo";
        lFriends[2].friendSince = 1982;

        lFriends[3].name = "Ray Breslin";
        lFriends[3].friendSince = 2013;

        lFriends[4].name = "Gabe Walker";
        lFriends[4].friendSince = 1993;

        lFriends[5].name = "Ray Tango";
        lFriends[5].friendSince = 1989;

        return lFriends;
      }
    } //

  } // class
} // namespace
#include <windows.h>
#include <stdio.h>
#include <iostream>
#pragma warning (disable: 4278)
#import <mscorlib.tlb> // import the CLR
#import "..\TestLib\bin\Debug\TestLib.tlb"  // path to your C# library

using namespace std;
using namespace TestLib;

void test() {
  HRESULT lHResult;

  lHResult = CoInitialize(NULL); // Initializes the COM library on the current thread and identifies the concurrency model as single-thread apartment (STA).
  if (FAILED(lHResult)) { cout << "Cannot initialize com." << endl; return; }

  IFriends *lFriends = nullptr;
  lHResult = CoCreateInstance(__uuidof(Friends), NULL, CLSCTX_INPROC_SERVER, __uuidof(IFriends), (void**)&lFriends);
  if (FAILED(lHResult)) { cout << "Instance creation failed" << endl; return; }

  Friend HUGEP *lBSTR;
  SAFEARRAY *lSafeArray = lFriends->GetFriends;
  lHResult = SafeArrayAccessData(lSafeArray, (void HUGEP* FAR*)&lBSTR);
  if (FAILED(lHResult)) { cout << "Getting a property failed" << endl; return; }
  for (ULONG i = 0; i < lSafeArray->rgsabound->cElements; i++) {
    wcout << lBSTR[i].name << " is my best buddy since " << lBSTR[i].friendSince << endl;  // 64bit: lBSTR[0].name is wchar_t (Unicode)
  }
  SafeArrayUnaccessData(lSafeArray);

  _bstr_t lMessage("C++ is not happy enough with Rambo!");
  _bstr_t lReply = lFriends->ShowErrorMessage(lMessage);
  wcout << "C# replied: " << lReply << endl; // .GetBSTR()

  CoUninitialize();
  cin.get();
} //

example output:
Michael Sylvester Gardenzio Stallone is my best buddy since 1946
Rocky Balboa is my best buddy since 1978
John Rambo is my best buddy since 1982
Ray Breslin is my best buddy since 2013
Gabe Walker is my best buddy since 1993
Ray Tango is my best buddy since 1989
Do you see the nice .Net MessgeBox?
C# replied: Yes? PS:I lov ya!

MsgBox

Let’s do the opposite now. C# coders sometimes need to access mashine code (C++, Assembler, etc).
I decided to make it a bit more difficult today. As mentioned already: It is day 14. Therefore I thought about returning an array of a structure from C++ to C#. I was checking the internet and after more than an hour I still had not found anything that could be used. C# most likely does not support it.
After a while I got the idea to use pointers in C#. They are very unusual and only for professional people. Well, finally I found a practical example for something seemingly useless. You can really crash your PC if you do it wrong. The critical code is marked with the keyword unsafe:

unsafe {
  Friend* lFriend = (Friend*)lIntPtr;
  for (int i = 0, n = FriendsCount(); i < n; i++) {
    char* lChars = (char*)lFriend->name;
    string lWho = new string(lChars);
    Console.WriteLine("C#: since " + lFriend->friendSince + " my best buddy is " + lWho);
    lFriend++;
  }
}

I have to admit, in hindsight it does look easy. But it took a lot of time to get there. Check the internet. There is no solution out there on how to read returned arrays … at least I did not find it. Many people have failed it seems.
First of all you have to enable unsafe code to use pointers in C#. Go to your Build settings and check the Allow unsafe code option:

Unsafe

The unknown size with arrays of structures can be solved by using pointers in the structure rather than the content itself. This way the size is equidistant. Surely, you cannot solve the problem when you have no source code access to the library and the returned structure size is variable. I see no practical com-example for this. Indeed all programmers of all languages would face the same problem here. C++ does not tell you the size, because there is no meta-data. This is why I implemented a function to get the array size separately. I am sure you have used buffers in the past. You always have to oversize them. This is a similar problem, not the same though.

Calling C++ code from C#

This really is C#. It can use pointers.

using System;
using System.Runtime.InteropServices;

namespace Day14b {
  class Program {

    [StructLayout(LayoutKind.Sequential)]
    public struct Friend {
      public int friendSince;
      public IntPtr name;
    }; // struct

    private const string cLibrary = @"C:\Users\Username\Desktop\Day14b\Debug\TestLib.dll";

    [DllImport(cLibrary, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    [return: MarshalAs(UnmanagedType.BStr)]
    static extern string ShowErrorMessage(string xMessage);

    [DllImport(cLibrary, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    static extern IntPtr GetFriend();

    [DllImport(cLibrary)]
    static extern int FriendsCount();

    [DllImport(cLibrary)]
    static extern void ReleaseMemory();

    static void Main(string[] args) {
      string lFeedback = ShowErrorMessage("C#: Hello C++");
      Console.WriteLine("C#: C++ replied -> " + lFeedback + Environment.NewLine);

      Console.WriteLine("C#: Number of friends: " + FriendsCount());
      Console.WriteLine("C#: Fasten your seatbelts! This is hardcore C#");

      IntPtr lIntPtr = GetFriend();
      Console.WriteLine();
      Console.WriteLine("C#: Number of friends: " + FriendsCount());
      Console.WriteLine();
      unsafe {
        Friend* lFriend = (Friend*)lIntPtr;
        for (int i = 0, n = FriendsCount(); i < n; i++) {
          char* lChars = (char*)lFriend->name;
          string lWho = new string(lChars);
          Console.WriteLine("C#: since " + lFriend->friendSince + " my best buddy is " + lWho);
          lFriend++; // increment the pointer, it now points to the next structure in the array
        }
      }

      ReleaseMemory();
      Console.ReadKey();
    } //

  } // class
} // namespace
#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>

using namespace std;

extern "C" {
  struct Friend {
    int friendSince;
    const wchar_t *name;
  }; // struct

  vector<wchar_t *> _BStrings;
  Friend *_Friends = nullptr;

  const wchar_t *Alloc(const wchar_t *xText){
    wchar_t * lBSTR = SysAllocString(xText);
    _BStrings.push_back(lBSTR);
    return lBSTR;
  } //

  __declspec(dllexport) const wchar_t* ShowErrorMessage(BSTR xMessage) {
    cout << "C++: I am too lazy for MessageBoxes." << endl;
    wcout << "C++: Your message was: " << xMessage << endl;
    return Alloc(L"C++: Good night!");
  } //

  __declspec(dllexport) int FriendsCount() {
    if (_Friends == nullptr) return 0;
    return 6; // which is a constant value in our example
  } //

  __declspec(dllexport) Friend *GetFriend(int xIndexer) {
    if (_Friends != nullptr) return _Friends;

    _Friends = new Friend[6];
    _Friends[0].name = Alloc(L"Michael Sylvester Gardenzio Stallone");
    _Friends[0].friendSince = 1946;

    _Friends[1].name = Alloc(L"Rocky Balboa");
    _Friends[1].friendSince = 1978;

    _Friends[2].name = Alloc(L"John Rambo");
    _Friends[2].friendSince = 1982;

    _Friends[3].name = Alloc(L"Ray Breslin");
    _Friends[3].friendSince = 2013;

    _Friends[4].name = Alloc(L"Gabe Walker");
    _Friends[4].friendSince = 1993;

    _Friends[5].name = Alloc(L"Ray Tango");
    _Friends[5].friendSince = 1989;

    return _Friends;  // be aware of the possible memory leak, you have to free lFriend
  } //

  __declspec(dllexport) void ReleaseMemory()  {
    for (auto &lBSTR : _BStrings) SysFreeString(lBSTR);
    if (_Friends != nullptr) delete[] _Friends;
    cout << endl << "C++: Memory released." << endl;
  } //

} // extern

example output:
C++: I am too lazy for MessageBoxes.
C++: Your message was: C#: Hello C++
C#: C++ replied -> C++: Good night!

C#: Number of friends: 0
C#: Fasten your seatbelts! This is hardcore C#

C#: Number of friends: 6

C#: since 1946 my best buddy is Michael Sylvester Gardenzio Stallone
C#: since 1978 my best buddy is Rocky Balboa
C#: since 1982 my best buddy is John Rambo
C#: since 2013 my best buddy is Ray Breslin
C#: since 1993 my best buddy is Gabe Walker
C#: since 1989 my best buddy is Ray Tango

C++: Memory released.

migration C#, Java, C++ (day 13), HashTable

The one who has not used a Dictionary in C# is definitely not a programmer. You need Dictionaries to lookup values quickly. But how do they work?
Dictionaries use HashTables. These are, to simplify it here, large arrays of linked lists.

HashTable

To demonstrate the technique I chose small arrays of 5 elements in my example source codes. Otherwise it would be difficult to produce duplicate entries, because hash values are supposed to have as few duplicates as possible.

Let’s say you have 6 objects and an algorithm that produces equally distributed values between 0 and 7 (see picture) for each object. Now you do not have to walk through a list anymore to find the objects. Simply use that hash value (0 to 7) to check, which of the 8 lists you have to look at. The number of search steps would ideally be only 1/8 compared to a list. Unfortunately hash values are not unique. Therefore you can have many entries for one hash value. In my examples I use a simple linked list to store them.

The C# Dictionary class is obviously more complex and uses larger arrays and nested search algorithms. Well, the following simplified examples are easier to grasp.

HashTables

using System;

namespace Day13b {
  class Program {

    public class HashTable<K, V> {
      public class Entry {
        public K key;
        public V value;
        public Entry next = null;

        public Entry(K xKey, V xValue) { key = xKey; value = xValue; }
      }  // class

      private readonly uint _HashTableSize;
      private readonly Entry[] _HashTable;

      public HashTable(uint xHashTableSize) {
        _HashTableSize = xHashTableSize;
        _HashTable = new Entry[xHashTableSize];
        for (int i = 0; i < xHashTableSize; i++) _HashTable[i] = null;
      } // constructor

      public void Print() {
        for (int i = 0; i < _HashTableSize; i++) {
          if (_HashTable[i] == null) continue;
          Entry lEntry = _HashTable[i];
          while (lEntry != null) {
            Entry lNext = lEntry.next;
            Console.WriteLine("HashTable[" + i + "] has key " + lEntry.key);
            lEntry = lNext;
          }
        }
      } //

      public uint GetHashCode(string xKey) {
        uint lHash = 2166136261;  // initial FNV www.isthe.com/chongo/tech/comp/fnv
        for (int i = 0; i < xKey.Length; i++) {
          lHash = lHash ^ (xKey[i]);
          lHash = lHash * 16777619;  // FNVMultiple
        }
        return lHash % _HashTableSize;
      } //

      public uint GetHashCode(uint xKey) {
        return xKey % _HashTableSize;
      } //

      public uint GetHashCode(K xKey) {
        if (xKey is string) return GetHashCode(xKey as string);
        if (xKey is uint) return GetHashCode(Convert.ToUInt32(xKey));
        return (uint)xKey.GetHashCode() % _HashTableSize; // general approach         
      } //



      public V AddOrReplace(K xKey, V xValue) {
        uint lHash = GetHashCode(xKey);
        Entry lEntry = _HashTable[lHash];

        // new entry
        if (lEntry == null) {
          _HashTable[lHash] = new Entry(xKey, xValue);
          return default(V);
        }

        while (lEntry != null) {
          if (lEntry.key.Equals(xKey)) {
            // replace existing entry  
            V lRemove = lEntry.value;
            lEntry.value = xValue;
            Console.WriteLine("Replacing " + lRemove);
            return lRemove;
          }
          if (lEntry.next == null) {
            // end of linked list
            lEntry.next = new Entry(xKey, xValue);
            return default(V);
          }
          lEntry = lEntry.next;
        }

        // non reachable code:
        return default(V);
      } //

      public V TryGetValue(K xKey) {
        uint lHash = GetHashCode(xKey);
        if (_HashTable[lHash] == null) return default(V);

        Entry lEntry = _HashTable[lHash];
        while ((lEntry != null) && (!lEntry.key.Equals(xKey))) lEntry = lEntry.next;

        if (lEntry == null) return default(V);
        else return lEntry.value;
      } //

      public V Remove(K xKey) {
        uint lHash = GetHashCode(xKey);
        Entry lEntry = _HashTable[lHash];
        if (lEntry == null) return default(V);

        Entry lPrevious = null;
        while (true) {
          if (lEntry == null) return default(V); // end of linked list
          if (lEntry.key.Equals(xKey)) {
            // remove existing entry  
            V lRemove = lEntry.value;
            if (lPrevious != null) lPrevious.next = lEntry.next;
            else _HashTable[lHash] = null; // no previous element
            return lRemove;
          }
          lPrevious = lEntry;
          lEntry = lEntry.next;
        }

        // non reachable code
        //return default(V);  // the compiler complains properly :)
      } //

    }; // class


    public class Data {
      public int id;
      public string text;

      public override string ToString() {
        return "id: " + id + ", text: " + text;
      } //

      ~Data() {
        Console.WriteLine("good bye Data struct with id " + id + " and text " + text);
      } // destructor

    } // class


    static void Main(string[] args) {
      // test with KEY string and VALUE struct

      HashTable<string, Data> lHashTable = new HashTable<string, Data>(5);
      string[] lTestStrings = { "hello", "world", "hola", "mundo", "hallo", "Welt", "hej", "verden", "hello", "wereld" };
      int i = 0;
      foreach (string s in lTestStrings) {
        Console.WriteLine("HashCode example: " + s + " = " + lHashTable.GetHashCode(s));
        Data lData = new Data();
        lData.text = s;
        lData.id = i++;
        lHashTable.AddOrReplace(s, lData);
      }
      lHashTable.Print();
      Data lRemoved = lHashTable.Remove("hej");
      lRemoved = null;  // de-reference for garbage collector (just for demo purposes)
      lHashTable.Print();
      Data a = lHashTable.TryGetValue("hej");
      Data b = lHashTable.TryGetValue("hallo");
      if (a == null) Console.WriteLine("a is null");
      if (b != null) Console.WriteLine("b has been found");

      Console.WriteLine();
      Console.WriteLine();

      // test with KEY integer and VALUE integer

      HashTable<uint, uint> lHashTable2 = new HashTable<uint, uint>(5);
      uint[] lTestIntegers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
      foreach (uint x in lTestIntegers) {
        Console.WriteLine("HashCode example: " + x + " = " + lHashTable2.GetHashCode(x));
        lHashTable2.AddOrReplace(x, x + 100);
      }
      lHashTable2.Print();

      GC.Collect();   // calls destructors of de-referenced objects
      Console.ReadKey();
    } //

  } // class
} // namespace

example output:
HashCode example: hello = 3
HashCode example: world = 2
HashCode example: hola = 3
HashCode example: mundo = 0
HashCode example: hallo = 1
HashCode example: Welt = 2
HashCode example: hej = 0
HashCode example: verden = 0
HashCode example: hello = 3
Replacing id: 0, text: hello
HashCode example: wereld = 1
HashTable[0] has key mundo
HashTable[0] has key hej
HashTable[0] has key verden
HashTable[1] has key hallo
HashTable[1] has key wereld
HashTable[2] has key world
HashTable[2] has key Welt
HashTable[3] has key hello
HashTable[3] has key hola
HashTable[0] has key mundo
HashTable[0] has key verden
HashTable[1] has key hallo
HashTable[1] has key wereld
HashTable[2] has key world
HashTable[2] has key Welt
HashTable[3] has key hello
HashTable[3] has key hola
a is null
b has been found

HashCode example: 1 = 1
HashCode example: 2 = 2
HashCode example: 3 = 3
HashCode example: 4 = 4
HashCode example: 5 = 0
HashCode example: 6 = 1
HashCode example: 7 = 2
HashCode example: 8 = 3
HashCode example: 9 = 4
HashCode example: 10 = 0
HashCode example: 11 = 1
HashCode example: 12 = 2
HashTable[0] has key 5
HashTable[0] has key 10
HashTable[1] has key 1
HashTable[1] has key 6
HashTable[1] has key 11
HashTable[2] has key 2
HashTable[2] has key 7
HashTable[2] has key 12
HashTable[3] has key 3
HashTable[3] has key 8
HashTable[4] has key 4
HashTable[4] has key 9
good bye Data struct with id 0 and text hello
good bye Data struct with id 6 and text hej

One of the main differences between C# and C++ is the memory management. I call the garbage collector at the end with GC.Collect() to show that some objects were de-referenced during the runtime.

Let me also highlight one part of the C# code: GetHashCode(K xKey) {}.
Although there is a definition for string, the above method is called. In fact we have a duplicate overload as soon as we define K as string or unsigned integer. The reason is that the generic class is not specific enough. The type K is closer to K than string. It therefore has a higher priority.

public V AddOrReplace(K xKey, V xValue) {
  uint lHash = GetHashCode(xKey);
  ....

And now compare it with a clear type declaration.

foreach (uint x in lTestIntegers) {
  ....
  lHashTable2.AddOrReplace(x, x + 100);
}

C++ frees memory as soon as you call delete. Compare the output. The destructors are called immediately. You could also use a kind of smart memory management in C++ as well. But why would you then use C++ at all? Such memory management indirectly questions the need for pure C++. The garbage collector for C# is highly optimized. If you need memory management, then don’t program in C++.

#include <string>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstdlib>

using namespace std;

template <typename K, typename V>
class HashTable {
public:
  class Entry {
  public:
    K key;
    V value;
    Entry *next;

    Entry(K xKey, V xValue)  { key = xKey; value = xValue;    next = nullptr; }
  }; // class

private:
  int _HashTableSize;
  Entry **_HashTable;

public:

  HashTable(int xHashTableSize) : _HashTableSize(xHashTableSize) {
    _HashTable = new Entry*[xHashTableSize];
    for (int i = 0; i < xHashTableSize; i++)  _HashTable[i] = nullptr;
  } // constructor

  ~HashTable() {
    for (int i = 0; i < _HashTableSize; i++) {
      if (_HashTable[i] == nullptr) continue;
      Entry *lThis = _HashTable[i];
      while (lThis != nullptr) {
        if (lThis->next == nullptr) break;
        Entry *lNext = lThis->next;
        delete lThis;
        lThis = lNext;
      }
    }
    delete[] _HashTable;
  } // destructor

  void Print() {
    for (int i = 0; i < _HashTableSize; i++) {
      if (_HashTable[i] == nullptr) continue;
      Entry *lEntry = _HashTable[i];
      while (lEntry != nullptr) {
        Entry *lNext = lEntry->next;
        cout << "HashTable[" << i << "] has key " << lEntry->key << endl;
        lEntry = lNext;
      }
    }
  } //

  int GetHashCode(const string &xKey) {
    size_t lHash = 2166136261U; // initial FNV www.isthe.com/chongo/tech/comp/fnv
    for (size_t i = 0; i < xKey.length(); i++) {
      lHash = lHash ^ (xKey[i]);
      lHash = lHash * 16777619;  // FNVMultiple
    }
    return lHash % _HashTableSize;
  } //

  int GetHashCode(int xKey) {
    return xKey % _HashTableSize;
  } //



  V AddOrReplace(K xKey, V xValue)  {
    int lHash = GetHashCode(xKey);
    Entry *lEntry = _HashTable[lHash];

    // new entry
    if (lEntry == nullptr)  {
      _HashTable[lHash] = new Entry(xKey, xValue);
      return V();
    }

    while (lEntry != nullptr) {
      if (lEntry->key == xKey) {
        // replace existing entry  
        V lRemove = lEntry->value;
        lEntry->value = xValue;
        return lRemove;
      }
      if (lEntry->next == nullptr) {
        // end of linked list
        lEntry->next = new Entry(xKey, xValue);
        return V();
      }
      lEntry = lEntry->next;
    }

    // non reachable code:
    return V();
  } //

  V TryGetValue(K xKey) {
    int lHash = GetHashCode(xKey);
    if (_HashTable[lHash] == nullptr) return V();

    Entry *lEntry = _HashTable[lHash];
    while ((lEntry != nullptr) && (lEntry->key != xKey)) lEntry = lEntry->next;

    if (lEntry == nullptr) return V();
    else return lEntry->value;
  } //

  V Remove(K xKey) {
    int lHash = GetHashCode(xKey);
    Entry *lEntry = _HashTable[lHash];
    if (lEntry == nullptr) return V();

    Entry *lPrevious = nullptr;
    while (true) {
      if (lEntry == nullptr) return V(); // end of linked list
      if (lEntry->key == xKey) {
        // remove existing entry  
        V lRemove = lEntry->value;
        if (lPrevious != nullptr) lPrevious->next = lEntry->next;
        else _HashTable[lHash] = nullptr; // no previous element
        delete lEntry;
        return lRemove;
      }
      lPrevious = lEntry;
      lEntry = lEntry->next;
    }

    // non reachable code
    return V();
  } //

}; // class

struct Data {
  int id;
  string text;
  ~Data() {
    cout << "good bye Data struct with id " << id << " and text " << text << endl;
  }
}; // struct


void test() {

  // test with KEY string and VALUE struct

  HashTable<string, Data*> *lHashTable = new HashTable<string, Data*>(5);
  string lTestStrings[] = { "hello", "world", "hola", "mundo", "hallo", "Welt", "hej", "verden", "hello", "wereld" };
  int i = 0;
  for each (string s in lTestStrings) {
    cout << "HashCode example: " << s << " = " << lHashTable->GetHashCode(s) << endl;
    Data *lData = new Data();
    lData->text = s;
    lData->id = i++;
    Data *lReplaced = lHashTable->AddOrReplace(s, lData);
    if (lReplaced != nullptr) delete lReplaced;
  }
  lHashTable->Print();
  Data *lRemoved = lHashTable->Remove("hej");
  if (lRemoved != nullptr) delete lRemoved;
  lHashTable->Print();
  Data *a = lHashTable->TryGetValue("hej");
  Data *b = lHashTable->TryGetValue("hallo");
  if (a == nullptr) cout << "a is null" << endl;
  if (b != nullptr) cout << "b has been found" << endl;

  delete lHashTable;

  cout << endl << endl;

  // test with KEY integer and VALUE integer

  HashTable<int, int> *lHashTable2 = new HashTable<int, int>(5);
  int lTestIntegers[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
  for each (int x in lTestIntegers) {
    cout << "HashCode example: " << x << " = " << lHashTable2->GetHashCode(x) << endl;
    lHashTable2->AddOrReplace(x, x + 100);
  }
  lHashTable2->Print();
  delete lHashTable2;

  cin.get();
} //

example output:
HashCode example: hello = 3
HashCode example: world = 2
HashCode example: hola = 3
HashCode example: mundo = 0
HashCode example: hallo = 1
HashCode example: Welt = 2
HashCode example: hej = 0
HashCode example: verden = 0
HashCode example: hello = 3
good bye Data struct with id 0 and text hello
HashCode example: wereld = 1
HashTable[0] has key mundo
HashTable[0] has key hej
HashTable[0] has key verden
HashTable[1] has key hallo
HashTable[1] has key wereld
HashTable[2] has key world
HashTable[2] has key Welt
HashTable[3] has key hello
HashTable[3] has key hola
good bye Data struct with id 6 and text hej
HashTable[0] has key mundo
HashTable[0] has key verden
HashTable[1] has key hallo
HashTable[1] has key wereld
HashTable[2] has key world
HashTable[2] has key Welt
HashTable[3] has key hello
HashTable[3] has key hola
a is null
b has been found

HashCode example: 1 = 1
HashCode example: 2 = 2
HashCode example: 3 = 3
HashCode example: 4 = 4
HashCode example: 5 = 0
HashCode example: 6 = 1
HashCode example: 7 = 2
HashCode example: 8 = 3
HashCode example: 9 = 4
HashCode example: 10 = 0
HashCode example: 11 = 1
HashCode example: 12 = 2
HashTable[0] has key 5
HashTable[0] has key 10
HashTable[1] has key 1
HashTable[1] has key 6
HashTable[1] has key 11
HashTable[2] has key 2
HashTable[2] has key 7
HashTable[2] has key 12
HashTable[3] has key 3
HashTable[3] has key 8
HashTable[4] has key 4
HashTable[4] has key 9

  public class Data {

    public int id;
    public String text;

    @Override
    public String toString() {
      return "id: " + id + ", text: " + text;
    }

    @Override
    protected void finalize() throws Throwable {
      try {
        System.out.println("good bye Data struct with id " + id + " and text " + text);
      } finally {
        super.finalize();
      }
    } // destructor

  } // class
//--------------------------------------------------------------------------------------------
import java.util.ArrayList;

public class HashTable<K, V> {

  public class Entry {

    public K key;
    public V value;
    public Entry next = null;

    public Entry(K xKey, V xValue) {
      key = xKey;
      value = xValue;
    } // constructor
  } // class

  private final long _HashTableSize;
  private final ArrayList<Entry> _HashTable;

  public HashTable(int xHashTableSize) {
    _HashTableSize = xHashTableSize;
    _HashTable = new ArrayList<Entry>();
    //_HashTable = new Entry[xHashTableSize]; // Java generic array creation error
    for (int i = 0; i < xHashTableSize; i++) _HashTable.add(null);
  } // constructor

  public final void Print() {
    for (int i = 0; i < _HashTableSize; i++) {
      if (_HashTable.get(i) == null) continue;
      Entry lEntry = _HashTable.get(i);
      while (lEntry != null) {
        Entry lNext = lEntry.next;
        System.out.println("HashTable[" + i + "] has key " + lEntry.key);
        lEntry = lNext;
      }
    }
  } //

  public final long hashCode(long xKey) {
    return xKey % _HashTableSize;
  } //

  public final long hashCode(K xKey) { 
    if (xKey instanceof Long) return hashCode((Long) xKey);
    return Math.abs(xKey.hashCode() % _HashTableSize); // general approach
  } //

  public final V AddOrReplace(K xKey, V xValue) {
    int lHash = (int) hashCode(xKey);
    Entry lEntry = _HashTable.get(lHash);

    // new entry
    if (lEntry == null) {
      _HashTable.set(lHash, new Entry(xKey, xValue));
      return null;
    }

    while (lEntry != null) {
      if (lEntry.key.equals(xKey)) {
        // replace existing entry 
        V lRemove = lEntry.value;
        lEntry.value = xValue;
        System.out.println("Replacing " + lRemove);
        return lRemove;
      }
      if (lEntry.next == null) {
        // end of linked list
        lEntry.next = new Entry(xKey, xValue);
        return null;
      }
      lEntry = lEntry.next;
    }

    // non reachable code:
    return null;
  } //

  public final V TryGetValue(K xKey) {
    int lHash = (int) hashCode(xKey);
    if (_HashTable.get(lHash) == null) return null;

    Entry lEntry = _HashTable.get(lHash);
    while ((lEntry != null) && (!lEntry.key.equals(xKey)))
      lEntry = lEntry.next;

    if (lEntry == null) return null;
    else return lEntry.value;
  } //

  public final V Remove(K xKey) {
    int lHash = (int) hashCode(xKey);
    Entry lEntry = _HashTable.get(lHash);
    if (lEntry == null) return null;

    Entry lPrevious = null;
    while (true) {
      if (lEntry == null) return null; // end of linked list          
      if (lEntry.key.equals(xKey)) {
        // remove existing entry 
        V lRemove = lEntry.value;
        if (lPrevious != null)
          lPrevious.next = lEntry.next;
        else // no previous element
          _HashTable.set(lHash, null);
        return lRemove;
      }
      lPrevious = lEntry;
      lEntry = lEntry.next;
    }

      // non reachable code
    //return null;
  } //
} // class
//--------------------------------------------------------------------------------------------

import java.io.IOException;

public class Program {

  public static void main(String[] args) {
    try {
      HashTable<String, Data> lHashTable = new HashTable<>(5);
      //= new HashTable<>(5);
      String[] lTestStrings = {"hello", "world", "hola", "mundo", "hallo", "Welt", "hej", "verden", "hello", "wereld"};
      int i = 0;
      for (String s : lTestStrings) {
        System.out.println("HashCode example: " + s + " = " + lHashTable.hashCode(s));
        Data lData = new Data();
        lData.text = s;
        lData.id = i++;
        lHashTable.AddOrReplace(s, lData);
      }
      lHashTable.Print();
      Data lRemoved = lHashTable.Remove("hej");
      lRemoved = null; // de-reference for garbage collector (just for demo purposes)
      lHashTable.Print();
      Data a = lHashTable.TryGetValue("hej");
      Data b = lHashTable.TryGetValue("hallo");
      if (a == null) System.out.println("a is null");
      if (b != null) System.out.println("b has been found");

      System.out.println();
      System.out.println();

      // test with KEY integer and VALUE integer
      HashTable<Integer, Integer> lHashTable2 = new HashTable<>(5);
      int[] lTestIntegers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
      for (int x : lTestIntegers) {
        System.out.println("HashCode example: " + x + " = " + lHashTable2.hashCode(x));
        lHashTable2.AddOrReplace(x, x + 100);
      }
      lHashTable2.Print();

      System.gc(); // calls destructors of de-referenced objects
      System.in.read();
    } catch (IOException ex) {
      System.out.println("IOException: " + ex.getMessage());
    }
  } //
  
} // class

example output:
HashCode example: hello = 2
HashCode example: world = 2
HashCode example: hola = 0
HashCode example: mundo = 2
HashCode example: hallo = 3
HashCode example: Welt = 2
HashCode example: hej = 1
HashCode example: verden = 2
HashCode example: hello = 2
Replacing id: 0, text: hello
HashCode example: wereld = 3
HashTable[0] has key hola
HashTable[1] has key hej
HashTable[2] has key hello
HashTable[2] has key world
HashTable[2] has key mundo
HashTable[2] has key Welt
HashTable[2] has key verden
HashTable[3] has key hallo
HashTable[3] has key wereld
HashTable[0] has key hola
HashTable[2] has key hello
HashTable[2] has key world
HashTable[2] has key mundo
HashTable[2] has key Welt
HashTable[2] has key verden
HashTable[3] has key hallo
HashTable[3] has key wereld
a is null
b has been found

HashCode example: 1 = 1
HashCode example: 2 = 2
HashCode example: 3 = 3
HashCode example: 4 = 4
HashCode example: 5 = 0
HashCode example: 6 = 1
HashCode example: 7 = 2
HashCode example: 8 = 3
HashCode example: 9 = 4
HashCode example: 10 = 0
HashCode example: 11 = 1
HashCode example: 12 = 2
HashTable[0] has key 5
HashTable[0] has key 10
HashTable[1] has key 1
HashTable[1] has key 6
HashTable[1] has key 11
HashTable[2] has key 2
HashTable[2] has key 7
HashTable[2] has key 12
HashTable[3] has key 3
HashTable[3] has key 8
HashTable[4] has key 4
HashTable[4] has key 9
good bye Data struct with id 0 and text hello
good bye Data struct with id 6 and text hej

migration C#, Java, C++ (day 12), binary tree

Trees are not difficult. They just require a little bit of practice in recursion. Today’s code uses the minimum framework. You can easily enhance this code for your purposes. Inherit from class Node or implement an interface in your personalized tree.
You have probably realized that I do not add new C++ fundamentals to learn in the C# to C++ series. The reason is that I do want to stay platform independent and also not use any non-standard classes.
Thus the code can be seen as pure training of C# to C++ translations.

tree as tree can

using System;

namespace Day12 {
  class Program {

    public class Node {
      public int key;
      public string description;
      public Node up = null;
      public Node down = null;
      public Node same = null;

      public Node(int xKey, string xDescription) { key = xKey; description = xDescription; }
    } // class


    public class BinaryTree {
      Node root;

      private void remove(Node xLeaf) {
        if (xLeaf == null) return;
        remove(xLeaf.same);
        remove(xLeaf.down);
        remove(xLeaf.up);
      } //

      private void insert(Node xNewLeaf, Node xLeaf) {
        // down
        if (xNewLeaf.key < xLeaf.key) {
          if (xLeaf.down != null) {
            insert(xNewLeaf, xLeaf.down);
            return;
          }
          xLeaf.down = xNewLeaf;
          return;
        }

        // up
        if (xNewLeaf.key > xLeaf.key) {
          if (xLeaf.up != null) {
            insert(xNewLeaf, xLeaf.up);
            return;
          }
          xLeaf.up = xNewLeaf;
          return;
        }

        // same
        if (xLeaf.same != null) insert(xNewLeaf, xLeaf.same);
        else xLeaf.same = xNewLeaf;
      } //

      public Node search(int xKey, Node xLeaf) {
        if (xLeaf != null) {
          if (xKey == xLeaf.key) return xLeaf;
          if (xKey < xLeaf.key) return search(xKey, xLeaf.down);
          else return search(xKey, xLeaf.up);
        }
        else return null;
      } //

      public void insert(Node xNewLeaf) {
        if (root != null) insert(xNewLeaf, root);
        else root = xNewLeaf;
      } //

      public Node search(int xKey) {
        return search(xKey, root);
      } //

      private void removeAll() {
        remove(root);
      } //

      public static void print(Node xLeaf, int xLevel, string xDirection) {
        if (xLeaf == null) return;

        for (int i = 0; i < xLevel; i++) { Console.Write(" "); }
        Console.WriteLine(xDirection + xLeaf.key + " " + xLeaf.description);
        xLevel++;
        print(xLeaf.same, xLevel, ".");
        print(xLeaf.down, xLevel, "-");
        print(xLeaf.up, xLevel, "+");
      } //

    } // class


    static void Main(string[] args) {
      BinaryTree lTree = new BinaryTree();
      Node lRoot = new Node(1975, "Despicable Me");
      lTree.insert(lRoot);
      lTree.insert(new Node(1926, "Elisabeth"));
      lTree.insert(new Node(1948, "Charles"));
      lTree.insert(new Node(1982, "William"));
      lTree.insert(new Node(1984, "Harry"));
      lTree.insert(new Node(1961, "Diana"));
      lTree.insert(new Node(1947, "Camilla"));
      lTree.insert(new Node(1921, "Phillip"));
      lTree.insert(new Node(1983, "Pippa"));
      lTree.insert(new Node(1982, "Catherine"));
      lTree.insert(new Node(1984, "George Orwell"));

      Node lSearchResult = lTree.search(1984);
      Console.WriteLine("found some nice guys in 1984: " + lSearchResult.description + " & " + lSearchResult.same.description + Environment.NewLine + Environment.NewLine);

      BinaryTree.print(lRoot, 0, "*");

      lTree = null;     // lTree.removeAll(); called by the garbage collector  

      Console.ReadKey();
    } //

  } // class
} // namespace

import java.io.IOException;

public class Program {

  public static class Node {

    public int key;
    public String description;
    public Node up = null;
    public Node down = null;
    public Node same = null;

    public Node(int xKey, String xDescription) {
      key = xKey;
      description = xDescription;
    } // constructor
  } // class

  public static class BinaryTree {

    private Node root;

    private void remove(Node xLeaf) {
      if (xLeaf == null)
        return;
      remove(xLeaf.same);
      remove(xLeaf.down);
      remove(xLeaf.up);
    } //

    private void insert(Node xNewLeaf, Node xLeaf) {
      // down
      if (xNewLeaf.key < xLeaf.key) {
        if (xLeaf.down != null) {
          insert(xNewLeaf, xLeaf.down);
          return;
        }
        xLeaf.down = xNewLeaf;
        return;
      } //

      // up
      if (xNewLeaf.key > xLeaf.key) {
        if (xLeaf.up != null) {
          insert(xNewLeaf, xLeaf.up);
          return;
        }
        xLeaf.up = xNewLeaf;
        return;
      } //

      // same
      if (xLeaf.same != null) insert(xNewLeaf, xLeaf.same);
      else xLeaf.same = xNewLeaf;
    } //

    public final Node search(int xKey, Node xLeaf) {
      if (xLeaf != null) {
        if (xKey == xLeaf.key)
          return xLeaf;
        if (xKey < xLeaf.key)
          return search(xKey, xLeaf.down);
        else
          return search(xKey, xLeaf.up);
      } else
        return null;
    } //

    public final void insert(Node xNewLeaf) {
      if (root != null)
        insert(xNewLeaf, root);
      else
        root = xNewLeaf;
    } // 

    public final Node search(int xKey) {
      return search(xKey, root);
    } //

    private void removeAll() {
      remove(root);
    } //

    public static void print(Node xLeaf, int xLevel, String xDirection) {
      if (xLeaf == null) return;

      for (int i = 0; i < xLevel; i++)
        System.out.print(" ");
      System.out.println(xDirection + xLeaf.key + " " + xLeaf.description);
      xLevel++;
      print(xLeaf.same, xLevel, ".");
      print(xLeaf.down, xLevel, "-");
      print(xLeaf.up, xLevel, "+");
    } //

  } // class

  public static void main(String[] args) {
    try {
      BinaryTree lTree = new BinaryTree();
      Node lRoot = new Node(1975, "Despicable Me");
      lTree.insert(lRoot);
      lTree.insert(new Node(1926, "Elisabeth"));
      lTree.insert(new Node(1948, "Charles"));
      lTree.insert(new Node(1982, "William"));
      lTree.insert(new Node(1984, "Harry"));
      lTree.insert(new Node(1961, "Diana"));
      lTree.insert(new Node(1947, "Camilla"));
      lTree.insert(new Node(1921, "Phillip"));
      lTree.insert(new Node(1983, "Pippa"));
      lTree.insert(new Node(1982, "Catherine"));
      lTree.insert(new Node(1984, "George Orwell"));

      Node lSearchResult = lTree.search(1984);
      System.out.println("found some nice guys in 1984: " + lSearchResult.description + " & " + lSearchResult.same.description + "\n\n");

      BinaryTree.print(lRoot, 0, "*");

      lTree = null; // lTree.removeAll(); called by the garbage collector

      System.in.read();
    } catch (IOException ex) {
      System.out.println("IOException: " + ex.getMessage());
    }
  } //

} // class
#include <functional>
#include <string>
#include <iostream>

using namespace std;


class Node {
public:
  int key;
  string description;
  Node *up = nullptr;
  Node *down = nullptr;
  Node *same = nullptr;

  Node(int xKey, const string &xDescription) { key = xKey; description = xDescription; }
}; // class


class BinaryTree {
public:
  BinaryTree() { root = nullptr; }
  ~BinaryTree() { removeAll(); }

  void insert(Node *xNewLeaf);
  Node *search(int xKey);
  static void print(Node *xLeaf, int xLevel, const string &xDirection);
  void removeAll();

private:
  void remove(Node *xLeaf);
  void insert(Node *xNewLeaf, Node *xLeaf);
  Node *search(int key, Node *xLeaf);

  Node *root;
}; // class

void BinaryTree::remove(Node *xLeaf) {
  if (xLeaf == nullptr) return;
  remove(xLeaf->same);
  remove(xLeaf->down);
  remove(xLeaf->up);
  delete xLeaf;
} //

void BinaryTree::insert(Node *xNewLeaf, Node *xLeaf) {
  // down
  if (xNewLeaf->key < xLeaf->key) {
    if (xLeaf->down != nullptr) {
      insert(xNewLeaf, xLeaf->down);
      return;
    }

    xLeaf->down = xNewLeaf;
    return;
  }

  // up
  if (xNewLeaf->key > xLeaf->key)  {
    if (xLeaf->up != nullptr) {
      insert(xNewLeaf, xLeaf->up);
      return;
    }

    xLeaf->up = xNewLeaf;
    return;
  }

  // same
  if (xLeaf->same != nullptr) insert(xNewLeaf, xLeaf->same);
  else xLeaf->same = xNewLeaf;
} //

Node *BinaryTree::search(int xKey, Node *xLeaf) {
  if (xLeaf != nullptr) {
    if (xKey == xLeaf->key) return xLeaf;
    if (xKey < xLeaf->key) return search(xKey, xLeaf->down);
    else return search(xKey, xLeaf->up);
  }
  else return nullptr;
} //

void BinaryTree::insert(Node *xNewLeaf) {
  if (root != nullptr) insert(xNewLeaf, root);
  else root = xNewLeaf;
} //

Node *BinaryTree::search(int xKey) {
  return search(xKey, root);
} //

void BinaryTree::removeAll() {
  remove(root);
} //

void BinaryTree::print(Node *xLeaf, int xLevel, const string &xDirection) {
  if (xLeaf == nullptr) return;
  
  for (int i = 0; i < xLevel; i++)  { cout << " "; }
  cout << xDirection << xLeaf->key << " " << xLeaf->description << endl;
  xLevel++;
  print(xLeaf->same, xLevel, ".");
  print(xLeaf->down, xLevel, "-");
  print(xLeaf->up, xLevel, "+");  
} //

void test() {

  BinaryTree lTree;
  Node *lRoot = new Node(1975, "Despicable Me");
  lTree.insert(lRoot);
  lTree.insert(new Node(1926, "Elisabeth"));
  lTree.insert(new Node(1948, "Charles"));
  lTree.insert(new Node(1982, "William"));
  lTree.insert(new Node(1984, "Harry"));
  lTree.insert(new Node(1961, "Diana"));
  lTree.insert(new Node(1947, "Camilla"));
  lTree.insert(new Node(1921, "Phillip"));
  lTree.insert(new Node(1983, "Pippa"));
  lTree.insert(new Node(1982, "Catherine"));
  lTree.insert(new Node(1984, "George Orwell"));

  Node *lSearchResult = lTree.search(1984);
  cout << "found some nice guys in 1984: " << lSearchResult->description << " & " << lSearchResult->same->description << endl;
  cout << endl << endl;

  lTree.print(lRoot, 0, "*");

  // lTree.removeAll();  called by the deconstructor
  cin.get();
} //
found some nice guys in 1984: Harry & George Orwell


*1975 Despicable Me
 -1926 Elisabeth
  -1921 Phillip
  +1948 Charles
   -1947 Camilla
   +1961 Diana
 +1982 William
  .1982 Catherine
  +1984 Harry
   .1984 George Orwell
   -1983 Pippa

C# to C++ (day 11), future and promise

There is hardly anything directly to compare with in C#. Future and promise are C++ concepts, which are probably best compared to C# task concepts. The comparison was not easy today. Have a look at the outcome.

future and promise

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Program {
    public class Day11 {

        private class Params {
            public int Input;
            public int Result;
        }

        private void DoSomething() {
            Console.WriteLine("DoSomething()");
            Thread.Sleep(4000);
        }  //     

        private void Method1(object xObject) {
            Params lParams = xObject as Params;
            Console.WriteLine("Method1");
            Thread.Sleep(2000);
            lParams.Result = 2 * lParams.Input;
        } //

        private int Method2(int xInt1) {
            Console.WriteLine("Method2");
            Thread.Sleep(2000);
            return 2 * xInt1;
        } //

        private async Task<int> Method3(int xInt1) {
            await Task.Delay(0);
            Console.WriteLine("Method3");
            return 2 * xInt1;
        } //

        private void Method4(Params xParams, AutoResetEvent xEvent) {
            Console.WriteLine("Method4");
            Thread.Sleep(2000);
            xEvent.WaitOne();
            xParams.Result = 2 * xParams.Input;
        } //


        static void Main(string[] args) {
            Day11 lDay10 = new Day11();
            lDay10.test();
        } //

        public async void test() {
            int i;

            // use a thread to get an asynchronous result
            ParameterizedThreadStart lParams = new ParameterizedThreadStart(Method1);
            Thread thread1 = new Thread(lParams);
            Params p = new Params() { Input = 123 };
            thread1.Start(p);
            Console.WriteLine("Method1.join()");
            thread1.Join();
            Console.WriteLine("Method1 result is: " + p.Result);

            Func<int, int> t1 = new Func<int, int>(x => { return Method2(x); });
            i = t1(123); // synchronous
            IAsyncResult lResult = t1.BeginInvoke(123, null, null); // asynchronously
            lResult.AsyncWaitHandle.WaitOne();

            i = await Method3(123);
            Console.WriteLine("Method3 result is: " + i);

            p.Input = 123;
            p.Result = 0;
            AutoResetEvent lEvent = new AutoResetEvent(false);
            Task t2 = new Task(() => Method4(p, lEvent));
            t2.Start();
            lEvent.Set();
            t2.Wait();
            Console.WriteLine("Method4 result is: " + p.Result);

            Console.ReadLine();
        } //

    } // class
} // namespace

example output:
Method1.join()
Method1
Method1 result is: 246
Method2
Method2
Method3
Method3 result is: 246
Method4
Method4 result is: 246

#include <future>
#include <iostream>
#include <thread>

using namespace std;

void DoSomething() {
  cout << "DoSomething()" << endl;
  this_thread::sleep_for(chrono::seconds(4));
}  //

void Thread1(int xInt1, int &xInt2) {
  cout << "Thread1" << endl;
  this_thread::sleep_for(chrono::seconds(2));
  xInt2 = 2 * xInt1;
} //

int Thread2(int xInt1) {
  cout << "Thread2" << endl;
  this_thread::sleep_for(chrono::seconds(2));
  return 2 * xInt1;
} //

int Thread3(future<int> &xInt1) {
  cout << "Thread3" << endl;
  this_thread::sleep_for(chrono::seconds(2));
  return 2 * xInt1.get(); // .get() => waits until the promise is fullfilled
} //

int Thread4(shared_future<int> xInt1) {
  cout << "Thread4" << endl;
  this_thread::sleep_for(chrono::seconds(2));
  return 2 * xInt1.get(); // returns the same value to all waiting futures
} //

void test(){
  int i;

  // use a thread to get an asynchronous result
  thread t1(Thread1, 123, ref(i));
  cout << "Thread1.join()" << endl;
  t1.join();
  cout << "Thread1 result is: " << i << endl;

  // like a task, may be synchronous or asychronous  
  future<int> f1 = async(Thread2, 123);
  cout << "Thread2, f1.get()" << endl;
  i = f1.get(); // waits

  // like a synchronous task, which is running on the same thread
  // will be called when you get the value
  future<int> f2 = async(launch::deferred, Thread2, 123); 
  cout << "Thread2, f2.get()" << endl; 
  i = f2.get(); // waits
  cout << "Thread2 deferred result is: " << i << endl;

  // like an asynchronous task, which is running on a new thread
  future<int> f3 = async(launch::async, Thread2, 123); 
  cout << "Thread2, f3.get()" << endl; 
  i = f3.get(); // waits
  cout << "Thread2 async result is: " << i << endl;

  // same as f1, because this is the default value; the system decides what to do
  future<int> f4 = async(launch::async | launch::deferred, Thread2, 123);
  i = f4.get(); // waits

  promise<int> lPromise5; // promise to provide a value at a later time  
  future<int> f5 = lPromise5.get_future();
  future<int> f5b = async(launch::async, Thread3, ref(f5));
  DoSomething();
  cout << "lPromise5.set_value()" << endl;
  lPromise5.set_value(123); // fulfill our promise now
  cout << "f5b async result is: " << f5b.get() << endl;

  promise<int> lPromise6; // promise to provide a value at a later time
  future<int> f6 = lPromise6.get_future();
  DoSomething();
  // tell the parallel thread to stop waiting for the promise fulfillment
  lPromise6.set_exception(make_exception_ptr(runtime_error("sorry, I cannot fulfill my promise")));  

  //
  // SOME PRACTICAL ISSUES
  //
  promise<int> lPromise7; // promise to provide a value at a later time
  future<int> f7 = lPromise7.get_future();
  promise<int> lPromise8 = move(lPromise7); // you cannot assign a promise, you have to move it
  future<int> f8 = move(f7); // same with the future    

  // you cannot call future.get() more than once
  // to allow multiple consumers use:
  shared_future<int> f9 = f8.share();
  future<int> f10 = async(launch::async, Thread4, f9);
  future<int> f11 = async(launch::async, Thread4, f9);
  future<int> f12 = async(launch::async, Thread4, f9);
  future<int> f13 = async(launch::async, Thread4, f9);
  lPromise8.set_value(123);
  cout << "f10: " << f10.get() << ", f11:" << f11.get() << ", f12:" << f12.get() << ", f13:" << f13.get() << endl;

  // packaged_task
  auto t2 = bind(Thread2, 123);
  t2(); // synchronous

  packaged_task<int()> t3(bind(Thread2, 123)); // wrapper to make async calls
  t3(); // call the task  in a different context
  future<int> f14 = t3.get_future(); // getting a future is not possible with t2 
  int x = f14.get();
  cout << "f14: " << x << endl;

  cin.get();
} //

example output:
Thread1.join()
Thread1

Thread1 result is: 246
Thread2, f1.get()
Thread2

Thread2, f2.get()
Thread2
Thread2 deferred result is: 246
Thread2, f3.get()
Thread2

Thread2 async result is: 246
Thread2
DoSomething()
Thread3

lPromise5.set_value()
f5b async result is: 246
DoSomething()
Thread4
Thread4

Thread4
Thread4
f10: 246, f11:246, f12:246, f13:246
Thread2
Thread2
f14: 246

C# to C++ (day 10), chrono, time, exceptions

I have mentioned speed quite often. Let’s measure it now!

It is remarkable that C# is dealing with exceptions faster than C++. The code execution is amazing. Anyway, when it comes to thrown exceptions (rarely happens in practice), then C++ is more than 20x faster. I knew how to build in the exceptions to see a difference. I was astonished that C++ was beyond belief compared to C# thrown exceptions. For further study follow these links:
Exceptions part 1
Exceptions part 2
Exceptions part 3

Time, Benchmark and Co.

using System;
using System.Diagnostics;

namespace DemoApp {
   public class Benchmark {

      void Benchmark1() {
         for (int i = 0; i < 1000; i++) { Console.Write("*"); }
         Console.WriteLine();
      } //

      void Benchmark2() {
         for (int i = 0; i < 1000; i++) {
            try { Console.Write("*"); }
            catch (Exception ex) { Console.WriteLine(ex.Message); }
         }
         Console.WriteLine();
      } //

      void Benchmark3() {
         for (int i = 0; i < 1000; i++) {
            try { Console.Write("*"); throw new Exception("OMG"); }
            catch (Exception ex) { }
         }
         Console.WriteLine();
      } //

      void Benchmark4b() { Console.Write("*"); throw new Exception("OMG"); }
      void Benchmark4a() {
         for (int i = 0; i < 1000; i++) {
            try { Benchmark4b(); }
            catch (Exception ex) { }
         }
         Console.WriteLine();
      } //

      public class StopWatch {
         Stopwatch _Stopwatch = new Stopwatch();

         public void start() { _Stopwatch.Start(); }
         public void stop() {
            _Stopwatch.Stop();
            long lElapsedTicks = _Stopwatch.ElapsedTicks;
            long lTicksPerSecond = Stopwatch.Frequency;
            double lMilliseconds = 1000.0 * (double)lElapsedTicks / (double)lTicksPerSecond;
            Console.WriteLine(lMilliseconds + " ms ");
            _Stopwatch.Start();
         }
      };


      public void test() {
         DateTime lNow1 = DateTime.Now; // current time
         DateTime lNow2 = DateTime.Now.AddSeconds(2.0); // current time plus 2 seconds
         double lSince1970 = DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;  // Seconds since 1 Jan 1970  

         Console.WriteLine("Current local time and date: " + DateTime.Now.ToString("dd MMM yyyy, HH:mm:ss"));
         Console.WriteLine("1/" + Stopwatch.Frequency);  // eg. 1/1,000,000,000 == 1ns

         // Benchmark
         DateTime lStart = DateTime.Now;
         Benchmark1();
         DateTime lEnd = DateTime.Now;
         TimeSpan lDuration = lEnd - lStart;
         Console.WriteLine("Time passed ms: " + lDuration.TotalMilliseconds);

         // Benchmarks: let's get more precise now
         StopWatch lStopwatch = new StopWatch();
         lStopwatch.start();
         Console.Write("Benchmark1:"); Benchmark1(); lStopwatch.stop();
         Console.Write("Benchmark2:"); Benchmark2(); lStopwatch.stop();
         Console.Write("Benchmark3:"); Benchmark3(); lStopwatch.stop();
         Console.Write("Benchmark4:"); Benchmark4a(); lStopwatch.stop();

         Console.ReadKey();
      } //

   } // class
} // namespace

example output:
Current local time and date: 12 Mar 2014, 21:35:46
1/3122812
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
****************************************
Time passed ms: 62.0035
Benchmark1:*********************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
***************************************************
63.3714101265142 ms
Benchmark2:*********************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
***************************************************
133.177405492229 ms
Benchmark3:*********************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
***************************************************
6450.41872517462 ms
Benchmark4:*********************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
***************************************************
13223.9343899024 ms

#include <iostream>
#include <chrono>
#include <time.h>
#include <string>

using namespace std;
using namespace std::chrono;

void Benchmark1() {
  for (int i = 0; i < 1000; i++) { cout << "*"; }
  cout << endl;
} //

void Benchmark2() {
  for (int i = 0; i < 1000; i++) {
    try { cout << "*"; }
    catch (exception &ex) { cout << ex.what() << endl; }
  }
  cout << endl;
} //

void Benchmark3() {
  for (int i = 0; i < 1000; i++) {
    try { cout << "*"; throw exception("OMG"); }
    catch (exception &ex) {}
  }
  cout << endl;
} //

void Benchmark4b(){ cout << "*"; throw exception("OMG"); }
void Benchmark4a() {
  for (int i = 0; i < 1000; i++) {
    try { Benchmark4b(); }
    catch (exception &ex) {}
  }
  cout << endl;
} //

class Stopwatch {
  high_resolution_clock _Clock;
  high_resolution_clock::time_point _From;

public:
  void start() { _From = _Clock.now(); }
  void stop() {
    high_resolution_clock::time_point lNow = _Clock.now();
    high_resolution_clock::duration lDuration = lNow - _From;
    intmax_t lNum = high_resolution_clock::period::num;
    intmax_t lDen = high_resolution_clock::period::den;
    double lMilliseconds = 1000.0 * lDuration.count() * (double)lNum / (double)lDen;
    cout << lMilliseconds << " ms " << endl;
    _From = _Clock.now();
  }
};


int main() {
  system_clock c1;  // system clock changes will have an impact
  steady_clock c2;  // independent from system clock changes
  high_resolution_clock c3;

  system_clock::time_point lTimePoint = system_clock::now();
  cout << lTimePoint.time_since_epoch().count() << endl;
  lTimePoint = lTimePoint + seconds(2);
  cout << lTimePoint.time_since_epoch().count() << endl;
  
  time_t lRawTime;
  struct tm lLocalTime;
  const int lTimeStringLength = 50;
  char lTimeString[lTimeStringLength];
  bool b1 = (time(&lRawTime) != -1);                 // Seconds since 1 Jan 1970
  bool b2 = (localtime_s(&lLocalTime, &lRawTime) == 0); // Convert to local time
  bool b3 = (asctime_s(lTimeString, lTimeStringLength, &lLocalTime) == 0); // convert to string

  if (b1 && b2 && b3) cout << "Current local time and date: " << lTimeString << endl;
  else cerr << "Error, cannot get current time." << endl;
    
  ratio<1, 10> r1; // 1/10
  ratio<2, 10> r2; // 2/10
  cout << r1.num << "/" << r1.den << endl;  // 1/10
  cout << r2.num << "/" << r2.den << endl;  // 1/5
  cout << system_clock::period::num << "/" << system_clock::period::den << endl;  // eg. 1/1,000,000,000 == 1ns
  
  microseconds micros(1234);       // 1,234 microseconds
  cout << micros.count() << endl;  // 1,234
  nanoseconds ns = micros;         // 1,234,000 nanoseconds, no loss
  cout << ns.count() << endl;      // 1,234,000
  milliseconds ms = duration_cast<milliseconds>(micros); // 1 millisecond, precision loss => duration_cast required
  micros += ms;
  cout << micros.count() << endl;  // 2,234

  // Benchmark
  steady_clock::time_point lStart = steady_clock::now();
  Benchmark1();
  steady_clock::time_point lEnd = steady_clock::now();
  steady_clock::duration lDuration = lEnd - lStart;
  if (lDuration == steady_clock::duration::zero()) cout << "no time has passed" << endl;
  cout << duration_cast<milliseconds>(lDuration).count() << endl;

  // Benchmarks: let's get more precise now
  Stopwatch lStopwatch;
  lStopwatch.start();
  cout << "Benchmark1:"; Benchmark1(); lStopwatch.stop();
  cout << "Benchmark2:"; Benchmark2(); lStopwatch.stop();
  cout << "Benchmark3:"; Benchmark3(); lStopwatch.stop();
  cout << "Benchmark4:"; Benchmark4a(); lStopwatch.stop();

  cin.get();
  return 0;
} //

example output:
13946584250282411
13946584270282411
Current local time and date: Wed Mar 12 21:07:05 2014

1/10
1/5
1/10000000
1234
1234000
2234
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
****************************************
80
Benchmark1:*********************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
***************************************************
86.0049 ms
Benchmark2:*********************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
***************************************************
84.0048 ms
Benchmark3:*********************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
***************************************************
311.018 ms
Benchmark4:*********************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
***************************************************
306.017 ms

Follow

Get every new post delivered to your Inbox.