Monthly Archives: April 2006

Running .NET applications on Debian GNU/Linux with Mono

Today i noticed Running .Net applications on Linux with Mono and the author wrote the following:

I found that on Debian at this stage I got an error: The assembly mscorlib.dll was not found or could not be loaded. It should have been installed in the ‘/usr/lib/mono/2.0/mscorlib.dll’ directory. I cured that by executing:
$ cd /usr/lib/mono
$ sudo ln -s 1.0 2.0

There is only one error, and it’s in the PEBKAC category. I can understand that the author couldn’t find the TargetFrameworkVersion tag in his project file and generated 2.0 code. What i don’t understand is that he didn’t notice the Other Downloads section and that there are Debian packages available with support for the 2.0 runtime. Ok, apt-get might complain about the packages and you would have to add a key to your keyring as following before you can install the packages:

gpg –recv-keys 7127E5ABEEF946C8
gpg –armor –export 7127E5ABEEF946C8 | apt-key add -

How hard is that? :P

Using .Net assemblies in your WIN32 application

Imagine that you’ve got an extensive codebase using WIN32/MFC and don’t want to give that up but on the other hand you’d like to take advantage of DOTNET classes then here’s a simple solution: First we write an Interface and an Implementation with C# as following:

public interface IQuoteClient {
  String getQuote();
  Boolean setQuote(String quote);
}

public class QuoteClient : IQuoteClient {
  // COM requires a parameterless constructor
  public QuoteClient() { ; }
  public string getQuote() { return String.Format"quote";}
  public bool setQuote(string quote) { return true; }
}

Go the project Properties and check the “Make assembly COM-Visible” box which you find in the Application tab, Assembly Information. Then you go to the Build tab and check “Register for COM interop” box and at the Signing tab you check the “Sign the assembly” box and assign a key. Build the project.

Now we have to extract a typelibrary, register the typelibrary and install it in the global assembly cache. Open a Visual Studio 2005 Command Prompt and go to your project\bin\Debug directory. Type the following commands:

tlbexp QuoteClient.dll
regasm QuoteClient.dll /tlb:QuoteClient.tlb
gacutil /i QuoteClient.dll

Now you can import the classes in this assembly from your WIN32 application as following:

#import "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorlib.tlb"
#import "D:\projects\Test\QuoteClient\bin\Debug\ClientLibrary.tlb" no_namespace named_guids

And you can use them just like any other COM component:

CoInitialize(NULL);

IQuoteClient *qc = NULL;
HRESULT hr = CoCreateInstance(
  CLSID_QuoteClient,
  NULL,
  CLSCTX_INPROC_SERVER,
  IID_IQuoteClient,
  reinterpret_cast<void**>(&qc)
);

if (SUCCEEDED(hr)) {
  cout << "Quote: " << qc->getQuote() << endl;
  qc->Release();
  qc = NULL;
}

CoUninitialize();

Simple serialization and deserialization of public class members

Here is a simple generic class that allows you to serialize classes (well, their public members) into XML and deserialize the XML to objects again. Make sure the class (or struct) has a parameterless constructor and that all the members that you want to serialize are public. Here is the code:

public class SimpleSerializer<t>
{
 public String Serialize(T o)
 {
  using(MemoryStream m = new MemoryStream())
  {
   XmlSerializer s = new XmlSerializer(o.GetType());
   s.Serialize(m, o);
   return Encoding.UTF8.GetString(m.ToArray());
  }
 }

 public T Deserialize(String xml)
 {
  using (MemoryStream m = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
  {
   XmlSerializer s = new XmlSerializer(typeof(T));
   return (T)s.Deserialize(m);
  }
 }
}

Here is a simple example of a class that will be serialized:

public struct Person {
  public String firstname;
  public String lastname;

  public Person(String firstname, String lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
  }
}

And finally, a simple console application that demonstrates how it works:

class Program {
  static void Main(string[] args) {
    Person p1 = new Person("Tim", "Van Wassenhove");
    SimpleSerializer<person> ss = new SimpleSerializer<person>();

    String xml = ss.Serialize(p1);
    Console.WriteLine("serialized:\n" + xml);

    Person p2 = ss.Deserialize(xml);
    Console.WriteLine("unserialized name: " + p2.firstname);

    Console.WriteLine("Press any key to continue...");
    Console.ReadKey();
  }
}

Building apache-win32 with Visual Studio 2005

Today i decided to build apache-win32. Here’s how i did it:

  • Download Apache httpd-2.2.0-win32-src-rev2.zip.
  • Unzip and read README.TXT, INSTALL.TXT and docs/manual/platform/win_compiling.html.en
  • Save awk95.exe as awk.exe in a directory that’s in your %PATH%.
  • Open Apache.dsw with VS2005 and choose “Yes To All” to convert the project.
  • Uncheck abs, mod_deflate and mod_ssl in the the configuration form via Build -> Configuration Manager.
  • Choose InstallBin, click right and Set as StartUp Project.
  • Open InstallBin/Makefile.win and remove the lines 129, 130, 131, 133, 134, 135 and 136.
  • Start debugging (F5). Stop debugging and end the httpd.exe process via your Task Manager.
  • Download and extract zlib-1.2.3.tar.bz2 into srclib/zlib.
  • Prepend “dword ptr” to the second argument of the movd instructions on lines647, 649, 663 and 720 in srclib/zlib/contrib/masmx86/inffas32.asm
  • Open srclib/zlib/projects/visualc6/zlib.dsp, choose the zlib project in the solution explorer. Choose “LIB ASM Release” in the configuration explorer and build zlib.
  • Copy srclib/zlib/projects/visualc6/Win32_LIB_ASM_Release/zlib.lib to srclib/zlib.
  • Check the mod_deflate in the configuration form via Build -> Configuration Manager.
  • Choose the mod_deflate project in the solution explorer and build it.
  • The original openssl-0.9.8a.tar.gz doesn’t compile with Visual Studio 2005 but someone has already made a patch. Download openssl-0.9.8a-vc2005.zip and extract it into srclib/openssl.
  • Open a Visual Studio 2005 Command Prompt and cd to the openssl directory and run: “perl Configure VC-WIN32″ (don’t close this prompt yet).
  • Insert before line 61 in srclib/openssl/ms/do_masm.bat the following line: “perl util\mk1mf.pl debug dll VC-WIN32 > ms\ntdll-dbg.mak”. Now run: “ms\do_masm” and “nmake -f ms\ntdll-dbg.mak”.
  • Check the abs and mod_ssl project in the configuration from via Build -> Configuration Manager.
  • Build the two projects.
  • Done!

Select best 3 laptimes for each player

Imagine that you have a schema where you store all the times a player needed to complete a parcours. A possible schema could be (postgresql):

CREATE TABLE laptimes (
 lap_id SERIAL NOT NULL,
 player_id INT NOT NULL,
 laptime INT NOT NULL,
 PRIMARY KEY (lap_id)
);

INSERT INTO laptimes (player_id, laptime) VALUES (1, 250);
INSERT INTO laptimes (player_id, laptime) VALUES (1, 450);
INSERT INTO laptimes (player_id, laptime) VALUES (1, 350);
INSERT INTO laptimes (player_id, laptime) VALUES (1, 300);
INSERT INTO laptimes (player_id, laptime) VALUES (1, 327);

INSERT INTO laptimes (player_id, laptime) VALUES (2, 327);
INSERT INTO laptimes (player_id, laptime) VALUES (2, 249);
INSERT INTO laptimes (player_id, laptime) VALUES (2, 123);
INSERT INTO laptimes (player_id, laptime) VALUES (2, 489);
INSERT INTO laptimes (player_id, laptime) VALUES (2, 158);

INSERT INTO laptimes (player_id, laptime) VALUES (3, 158);
INSERT INTO laptimes (player_id, laptime) VALUES (3, 120);
INSERT INTO laptimes (player_id, laptime) VALUES (3, 190);

INSERT INTO laptimes (player_id, laptime) VALUES (4, 600);

Now imagine that you want to display the best 3 results for each player. Here’s how:

SELECT *
FROM laptimes AS l1
WHERE lap_id IN (
 SELECT lap_id
 FROM laptimes AS l2
 WHERE l1.player_id = l2.player_id
 ORDER BY laptime ASC
 LIMIT 3
)
ORDER BY player_id ASC, laptime ASC;

Using a function with parameters as parameter

Imagine that you have a function that expects a reference to a function. Here is an example of such a function:

function bar(fn) { fn(); }

Now imagine that the function that you want to pass to bar accepts a parameter. Here is an example of such a function:

function foo(arg) { alert(arg); }

With the help of a closure this is no problem:

bar(function e() { foo('hello'); });

PS: Kudos go to Weirdan for providing the solution to this problem.

JSpace

I wrote a simple shoot-em-up game: JSpace.zip.

Allow a form to be posted only once

People can fill in a form and submit it. Then they can hit their back button, and choose to submit it again. Usually the second time this form is being posted, the values in that form aren’t valid anymore and thus corrupt the database.
Most developpers i know try to work around this problem by using the header function or the html meta tags to set the expiration date. However, this solution does not only limit the usability of a site, it simply does not work for visitors that have a browser that ignores the expiration date.

My solution for this problem is quite easy. For each entity in the database that can be updated by a form, we should add an attribute lastupdate. Now every time we build a form that contains data of that entity, we should also add an input of type hidden with the value of that lastupdate attribute. If the value of the lastupdate attribute in the database is more recent than the value of the posted lastupdate in the recieving script, then the posted values are invalid and this script should tell the user about this error. Offcourse, every time such an entity is updated, the lastupdate attribute of this entity should be updated too.

Using cmd.exe

Earlier someone asked me how he could use windows cmd.exe with PHP. People run into trouble as soon as there are quotes needed because there are special characters (>/&()[]{}^=;!’+,`~ and <space>) in the command. I do it like this:

<?php
$result = `""c:\\my path\\prog.exe" "filename""`;
?>

In case you have to do it often you might want to wrap it into a little function like this:

<?php
function cmd($command, $arguments = null)
{
        $commandline = '';
        foreach(func_get_args() as $word) {
                $commandline .= '"' . $word . '" ';
        }
        $commandline = rtrim($commandline, ' ');
        $commandline = '"' . $commandline . '"';
        return `$commandline`;
}

// run blah.exe
cmd('blah.exe');

// run c:\my path\blah.exe with the arguments "foo" and "bar bar"
cmd('c:\\my path\\blah.exe', 'foo', 'bar bar');
?>