VASmalltalk – Embedding Mono – more examples …

In this posting I would like to document some added possibilities with the latest version – and actually it has reached a state, where the software may be tested in our projects.

Starting with the following CSharp code we can show how the whole stuff works. The code has several classes, constructors, attributes and static and instance methods.

using System;

namespace TestMe
{
  public class MainClass
  {
    public static int Main (string[] args)
      { return ((args.Length == 1) ? args[0].Length : -100); }
		
    public static int SendMeAnInteger ()
      { return 2 * 2; }

    public static int SendMeASquaredResult (int pValue)
      {	return pValue * pValue;	}
		
    public static string SendMeAString ()
      {	return "Hallo Marten"; }
		
    public static string SendMeADuplicatedString (string pString)
      {	return pString + pString; }		
  }

  public class TestClass
  {
    public TestClass(int pAge)
    { Age = pAge; }
		
     public int Age {
      get; 
      set;
     }		
   }	
}

Calling a Main() method
As shown in the first posting special support is available in Mono to call an available Main() method – and to retrieve the returned value.
Due to the fact, that with an embedded Mon you may only have one Domain instance this one is held in a global variable MoDomain and this one is used several times in some methods.

| aMonoAssembly rc |
"windowsPath contains the path to the executable"
(aMonoAssembly := MoDomain openAssembly: self windowsPath) isNull
  ifTrue: [^self error: 'Error: No Assembly found!'].

"two parameters, but Mono sees only parameters starting at index 1"
rc := aMonoAssembly execMainWithArgs: (Array with: self windowsPath with: 'Marten Feldtmann').

Calling a static method of a class

| monoAssembly monoMethod|

(MoDomain openAssembly: self windowsPath) isNull
  ifTrue: [^self error: 'Error: No Assembly found!'].

"Search in Mono for a specific method"
(monoMethod := MoThread methodName: 'SendMeAnInteger' className: 'MainClass' namespace: 'TestMe') isNil
  ifTrue:[ ^self error: 'No method found !' ].

"... and call this method amd retrieve the result"		
(MoThread methodInvoke: monoMethod receiver: nil args: nil exception: nil) asInteger inspect

actually “asInteger” in the last line does a little bit more: it has to unbox the returned objects and interpret the result pointer in a way I expect the result (here as an 32bit integer):

MonoObject>>asInteger
  "^ Mono Integer Values are boxed objects ..."

  ^(OSInt32 address: (MoThread unbox: self)) at: 0

Calling a static method and retrieve a string value
The source code is of coursce similar to the one above:

...
(monoMethod := MoThread methodName: 'SendMeAString' className: 'MainClass' namespace: 'TestMe') isNil
  ifTrue:[ ^self error: 'No method found !' ].

(MoThread methodInvoke: monoMethod receiver: nil args: nil exception: nil) asString

but string are special handled under Mono and asString looks like:

MonoObject>>asString
  ^(MoThread asUTF8: self) asString

Calling a method with parameters
In the next example we call a static method with parameters:

...
(monoMethod := MoThread methodName: 'SendMeASquaredResult' className: 'MainClass' namespace: 'TestMe') isNil
  ifTrue:[ ^self error: 'No method found !' ].

"building the parameter list for the call"		
argv := MonoArgumentList newAsync addArgument: 2 ; yourself.
		
(MoThread methodInvoke: monoMethod receiver: nil args: argv monoArgs exception: nil) asInteger inspect.
	
argv freeMonoArgs.

Creating a new instance of a class
In the next example we create a new instance of a Mono class in Mono space and execute a special constructor with arguments and then we query the attribute if the value has been set correctly:

| monoMethod argv aMonoClass aMonoObject aValue|

...
"First we create the space needed for the instance"
(aMonoObject := MoDomain newInstanceOfClassNamed: 'TestClass' namespace: 'TestMe') isNil
  ifTrue:[ ^self error: 'Object cold not be created !' ].

"then we look for the special constructor"
(monoMethod := MoThread methodName: '.ctor(int)' className: 'TestClass' namespace: 'TestMe') isNil
  ifTrue:[ ^self error: 'No method found !' ].

"build the argument list for this constructor"		
argv := MonoArgumentList newAsync addArgument: 8 ; yourself.		

"call the constructor"
MoThread methodInvoke: monoMethod receiver: aMonoObject args: argv monoArgs exception: nil.	
argv freeMonoArgs.	

"get the method of the value accessor of the attribute changed in the constructor"
(monoMethod := MoThread methodName: 'get_Age' className: 'TestClass' namespace: 'TestMe') isNil
  ifTrue:[ ^self error: 'No method found !' ].

"now we query the value of the attribute, which should be set by the constructor method above"	
aValue := (MoThread methodInvoke: monoMethod receiver: aMonoObject args: nil exception: nil) asInteger 

Default Constructor ….
Now the same as above, but with the default empty-parameter constructor (which is not in the CSharp source code shown at beginning of the posting):

...
(aMonoObject := MoDomain newDefaultInstanceOfClassNamed: 'TestClass' namespace: 'TestMe') isNil
  ifTrue:[ ^self error: 'Object cold not be created !' ].
...

Documentation of Software version 0.54 of MSKMonoInterfaceApp.

This entry was posted in .NET, Smalltalk and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s