Blog Archives

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

Advertisements

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.

Reflection (part 6, professional), Emit

Reflection can discover information about objects at runtime and execute against those objects. The namespace System.Reflection.Emit also allows you to build assemblies and create types at runtime. Only a few programmers will come across Emit. You have to be a kind of Rambo sewing yourself while fighting … and definitely not Alice in Wonderland.

Emit generates IL code in memory. The source code for such is quite complex and difficult. We are nearly back to Assembler style. And if you remember well, crashes and difficult debugging were the order of the day. There are tools like the EmitHelper class out there to make Emit easier. I am going to show the fundamentals today, this does not cover tools.

Today’s word list:

Domain
Application domains aid security, separating applications from each other and each other’s data. A single process can run several application domains, with the same level of isolation that would exist in separate processes. Running multiple applications within a single process increases server scalability.
Faults in one application domain cannot affect other code running in another application domain.

Module
A module is a portable executable file, such as type.dll or application.exe, consisting of one or more classes and interfaces. There may be multiple namespaces contained in a single module, and a namespace may span multiple modules.
One or more modules deployed as a unit compose an assembly.

The hierarchy is: domain => assemblies => modules => classes => functions


Ildasm.exe

A disassembler for MSIL code.

The first step is to create an executable file from:

using System;
using System.Reflection;

namespace HelloWorld {
    public class Program {
        static void Main(string[] args) {
        } //
        

        public string Test() {
            return string.Format("DateTime is {0:dd MMM yyyy  HH:mm:ss}", DateTime.Now);
        } //

        public string Test2() {
            return DateTime.UtcNow.ToString();
        } //
        
        public string Test3() {
            return Assembly.GetExecutingAssembly().ToString();
        } //

        public void Test4() {
            Console.WriteLine("hello world !");
        } //

    } // class
} // namespace

On the windows taskbar, click Start, click All Programs, click Visual Studio, click Visual Studio Tools, and then click Visual Studio Command Prompt.
-or-
If you have the Windows SDK installed on your computer: On the taskbar, click Start, click All Programs, click the folder for the Windows SDK, and then click Command Prompt (or CMD Shell).

Change to the right folder and enter “ildasm HelloWorld.exe /output:HelloWorld.il”.

ILDASM

In your folder you should see something like this:

SnapShot

Open the HelloWorld.il file in a text editor and delve into the following sections:

method Test()

  .method public hidebysig instance string 
          Test() cil managed
  {
    // Code size       21 (0x15)
    .maxstack  8
    IL_0000:  ldstr      "DateTime is {0:dd MMM yyyy  HH:mm:ss}"
    IL_0005:  call       valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now()
    IL_000a:  box        [mscorlib]System.DateTime
    IL_000f:  call       string [mscorlib]System.String::Format(string,
                                                                object)
    IL_0014:  ret
  } // end of method Program::Test

method Test3()

  .method public hidebysig instance string 
          Test2() cil managed
  {
    // Code size       20 (0x14)
    .maxstack  1
    .locals init ([0] valuetype [mscorlib]System.DateTime CS$0$0000)
    IL_0000:  call       valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_UtcNow()
    IL_0005:  stloc.0
    IL_0006:  ldloca.s   CS$0$0000
    IL_0008:  constrained. [mscorlib]System.DateTime
    IL_000e:  callvirt   instance string [mscorlib]System.Object::ToString()
    IL_0013:  ret
  } // end of method Program::Test2

method Test3()

  .method public hidebysig instance string 
          Test3() cil managed
  {
    // Code size       11 (0xb)
    .maxstack  8
    IL_0000:  call       class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::GetExecutingAssembly()
    IL_0005:  callvirt   instance string [mscorlib]System.Object::ToString()
    IL_000a:  ret
  } // end of method Program::Test3

method Test4()

  .method public hidebysig instance void 
          Test4() cil managed
  {
    // Code size       11 (0xb)
    .maxstack  8
    IL_0000:  ldstr      "hello world !"
    IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000a:  ret
  } // end of method Program::Test4

These code sections give you a rough idea of what we are going to code in runtime.
Start a new console project. You have to edit the file “AssemblyInfo.cs”. Add the assembly attribute AllowPartiallyTrustedCallersAttribute. The program won’t run otherwise. We are on a low coding level and Microsoft obviously tries to protect code especially on that level.

AssemblyInfo.cs

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("oink")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("blablabla")]
[assembly: AssemblyCopyright("Copyright ©  2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AllowPartiallyTrustedCallersAttribute]

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("0bf893aa-f3da-49ef-a2dc-a63d8ffc9ead")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

The Print() method is not big, nevertheless you find something unusual here. The keyword __arglist is not official. It has been implemented by Microsoft, but is not documented at all. It is also not well supported in C#. For instance you cannot use a foreach loop. __arglist takes any number of optional arguments like object[]. In our example it does make a big difference to use __arglist. We do not have to create an array and fill it in. This would be much more code in Emit. On the contrary the __arglist algorithm is quite short and comfortable. Follow the link for more __arglist documentation.

public static void Print(string xHeader, __arglist) {
    ArgIterator lIterator = new ArgIterator(__arglist);

    Console.WriteLine(xHeader);
    while (lIterator.GetRemainingCount() > 0) {
        TypedReference r = lIterator.GetNextArg();
        object o = TypedReference.ToObject(r);
        Console.Write(o);
    }
    Console.WriteLine();
    Console.WriteLine();
} //

EmitCode() is the actual code generation part. Let’s call the remaining source code “administration” to simplify the situation.
There are two ways to get the MethodInfo for a property. One is used for DateTime.Now, the other one is used for DateTime.UtcNow .
They can be used equally. I used both ways for demonstration purposes only.
I tried to keep the example simple. You don’t have to study the MSIL to understand the code. Some information about MSIL OpCodes can be found here.

static void EmitCode(ILGenerator xILGenerator) {
    MethodInfo lMethodInfo_Print = typeof(EmitDemo).GetMethod("Print");
    MethodInfo lDateTime_Now = typeof(DateTime).GetProperty("Now").GetGetMethod();
    MethodInfo lFormat = typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object) });

    xILGenerator.Emit(OpCodes.Ldstr, "DateTime is {0:dd MMM yyyy  HH:mm:ss}");
    xILGenerator.Emit(OpCodes.Call, lDateTime_Now);
    xILGenerator.Emit(OpCodes.Box, typeof(DateTime));
    xILGenerator.Emit(OpCodes.Call, lFormat);
    xILGenerator.EmitCall(OpCodes.Call, lMethodInfo_Print, new Type[] { });

    xILGenerator.Emit(OpCodes.Ldstr, "This equals UTC: ");
    xILGenerator.Emit(OpCodes.Call, typeof(DateTime).GetMethod("get_UtcNow"));  // compare this with lDateTime_Now (== same, just another demo approach)
    xILGenerator.EmitCall(OpCodes.Call, lMethodInfo_Print, new Type[] { typeof(DateTime) });

    xILGenerator.Emit(OpCodes.Ldstr, "The assembly is: ");
    xILGenerator.Emit(OpCodes.Call, typeof(Assembly).GetMethod("GetExecutingAssembly"));
    xILGenerator.EmitCall(OpCodes.Call, lMethodInfo_Print, new Type[] { typeof(Assembly) });

    xILGenerator.Emit(OpCodes.Ldstr, "Console.WriteLine() is old school.");
    xILGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) }));

    xILGenerator.EmitWriteLine("EmitWriteLine() is for lazy programmers.");

    xILGenerator.Emit(OpCodes.Ret);
} //

Test1_ViaFullAssembly() shows you how to properly initialize and use an assembly. Remember the hierarchy from above: domain => assemblies => modules => classes => functions
The method is build like a chain. Each statement uses the result of the previous one.

public static void Test1_ViaFullAssembly() {
    AssemblyName lAssemblyName = new AssemblyName("MyAssembly");
    AssemblyBuilder lAssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(lAssemblyName, AssemblyBuilderAccess.Run);
    ModuleBuilder lModuleBuilder = lAssemblyBuilder.DefineDynamicModule("MyModule");
    TypeBuilder lTypeBuilder = lModuleBuilder.DefineType("MyType");
    MethodBuilder lMethodBuilder = lTypeBuilder.DefineMethod("DoSomething", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(void), Type.EmptyTypes);
    EmitCode(lMethodBuilder.GetILGenerator());

    Type lType = lTypeBuilder.CreateType();
    lType.GetMethod("DoSomething").Invoke(null, null);

    Console.ReadLine();
} //

example output:
DateTime is 15 Jan 2014 23:17:30

This equals UTC:
15/01/2014 23:17:30

The assembly is:
MyAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

Console.WriteLine() is old school.
EmitWriteLine() is for lazy programmers.

You can avoid building a full assembly. DynamicMethod simplifies the dynamic creation of methods. Of course you won’t have any class structure. The method is super-public, it reminds me of VBA modules.

public static void ViaDynamicMethod() {
    DynamicMethod lDynamicMethod = new DynamicMethod("DoSomething", typeof(void), Type.EmptyTypes, typeof(object));
    EmitCode(lDynamicMethod.GetILGenerator());
    lDynamicMethod.Invoke(null, null);
    Console.ReadLine();
} //

example output:
DateTime is 15 Jan 2014 23:17:58

This equals UTC:
15/01/2014 23:17:58

The assembly is:
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

Console.WriteLine() is old school.
EmitWriteLine() is for lazy programmers.

Good Practice (Part 2)

Today a quick follow-up on code legibility.
As usual all should be self-explanatory.

static void BadPractice5() {
    string a = null;
    string b = "hello";
    string c = string.Empty;

    string s;
    if (a != null) s = a;
    else if (b != null) s = b;
    else s = c;
} //

static void GoodPractice5() {
    string a = null;
    string b = "hello";
    string c = string.Empty;

    string s = a ?? b ?? c;
} //
static void BadPractice6() {
    string s = "12345";
    // s.Length is called multiple times
    for (int i = 0; i < s.Length; i++) {
        Console.WriteLine(s[i]);
        //s = "a";   // uncomment to see that "i < s.Length" is evaluated over and over again
    }
} //

static void GoodPractice6() {            
    string s = "12345";
    for (int i = 0, n = s.Length; i < n; i++)
        Console.WriteLine(s[i]); // s.Length is only called once
} //
static void BadPractice7() {
    string s = string.Empty;

    for (int i = 0; i < 100; i++) s += i.ToString() + " ";
    Console.WriteLine(s);
    Console.ReadLine();
} //

static void GoodPractice7() {
    // Use the StringBuilder class for multiple string concatenations!
    // Strings are immutable, concatenations are very slow.
    string s = string.Empty;
    StringBuilder lStringBuilder = new StringBuilder();

    for (int i = 0; i < 100; i++) {
        lStringBuilder.Append(i);
        lStringBuilder.Append(" ");
    }
    s = lStringBuilder.ToString();
    Console.WriteLine(s);
    Console.ReadLine();
} //
static void BadPractice8() {
    string s = string.Empty;

    do {
        s = Console.ReadLine();
        if (s == string.Empty) break;
    } while (true);
} //

static void GoodPractice8() {
    string s = string.Empty;

    while (true) {
        s = Console.ReadLine();
        if (string.IsNullOrEmpty(s)) break;
    }
} //
static void BadPractice9() {
    var lList = Enumerable.Range(1, 10); // imagine it is a grow only list

    // bad
    foreach (var i in lList) {
        Console.WriteLine(i);
    }
    Console.ReadLine();


    // also bad
    for (int i = 0, n = lList.Count(); i < n; i++) {
        Console.WriteLine(lList.ElementAt(i));
    }
    Console.ReadLine();
} //

static void GoodPractice9() {
    var lList = Enumerable.Range(1, 10); // imagine it is a grow only list

    // This is for real hardcore multithreading coders:
    // If poosibe walk through the list backwards and you can add elements
    // to the list concurrently without the need to synchronize anything.
    // No lock() required in a multithreading environment!
    for (int i = lList.Count() - 1; i > -1; i--) {
        Console.WriteLine(lList.ElementAt(i));
    }   
  Console.ReadLine();
} //