Difference between revisions of "Using Pascal Libraries with .NET and Mono/it"

From Lazarus wiki
Jump to navigationJump to search
Line 227: Line 227:
 
== Quando usare librerie native con .NET/Mono ==
 
== Quando usare librerie native con .NET/Mono ==
  
Why not just code everything in VB.NET or C#? There are several situations where this might not be a  good idea:
+
Perché non scrivere semplicemente tutto il codice in VB.NET o C#? There are several situations where this might not be a  good idea:
  
 
* When you have a large or complicated Pascal codebase that you don't want to rewrite (and re-debug) in C#.
 
* When you have a large or complicated Pascal codebase that you don't want to rewrite (and re-debug) in C#.

Revision as of 21:21, 4 April 2010

English (en) | italiano (it) | 日本語 (ja)

Introduzione

Con .NET framework, Microsoft ha fornito una eccellente compatibilità per il codice "unmanaged" (non gestito). Se il termine "codice non gestito" sembra evocare qualcosa di selvaggio e pericoloso, esso rappresenta solo il cosiddetto codice "legacy" nella forma delle lbrerie native di Windows. Il progetto Mono comprende un analogo supporto per le librerie native di Linux e OS X. Questo significa che si possono compilare librerie con Free Pascal e usarle con applicazioni .NET in Windows e con applicazioni Mono in Linux e OS X.

Una semplice libreria Pascal

Copiare e salvare il seguente codice Pascal nel file SimpleLib.pas:

library SimpleLib;

function MySucc(AVal : Int64) : Int64; stdcall;
begin
  Result := System.Succ(AVal);
end;

function MyPred(AVal : Int64) : Int64; stdcall;
begin
  Result := System.Pred(AVal);
end;

exports
{$IFDEF DARWIN}  {OS X entry points}
  MySucc name '_MySucc',
  MyPred name '_MyPred',
{$ENDIF}
  MySucc,
  MyPred;

end.

Notare la direttiva condizionale per compilazione su OS X (DARWIN). Apparentemente il linker dinamico di OS X cerca un punto d'ingresso alla libreria che inizi con un underscore.

Ora compilare la libreria con Free Pascal:

 fpc -Sd SimpleLib.pas

In Windows, verrà creato il file simplelib.dll. In OS X, verrà creato il file libsimplelib.dylib. In Linux, this will create file simplelib.so. On OS X and Linux, rename the compiled library file to simplelib.dll:

 mv libsimplelib.dylib simplelib.dll

Una semplice app VB.NET

Copare e salvare questo codice VB.NET nel file TestLib.vb:

Imports System
Imports System.Runtime.InteropServices

Public Class TestLib

  Const SimpLibName = "simplelib.dll"

   'Declare external functions using the DllImport attribute.
  <DllImport(SimpLibName, EntryPoint:="MySucc", _
             CallingConvention:=CallingConvention.StdCall)> _
             Public Shared Function Succ(ByVal AVal As Long) As Long
    End Function

  <DllImport(SimpLibName, EntryPoint:="MyPred", _
             CallingConvention:=CallingConvention.StdCall)> _
             Public Shared Function Pred(ByVal AVal As Long) As Long
    End Function

  Public Shared Sub Main()
  
    Dim TestVal As Long

    Try
      TestVal = 123
      Console.WriteLine("Value is " & TestVal)
      Console.WriteLine("Successor is " & Succ(TestVal))
      Console.WriteLine("Predecessor is " & Pred(TestVal))
    Catch e As Exception
      Console.WriteLine(e)
    End Try

  End Sub  'Main

End Class  'TestLib

Se .NET framework è installato in Windows, si può compilare il codice così:

 [pathto]vbc TestLib.vb

dove [pathto] è il percorso di .NET framework (example: c:\windows\microsoft.net\framework\v1.1.4322\ with .NET 1.1). Verrà creato il file TestLib.exe.

Se Mono è installato, si può anche provare a compilare il codice così:

 vbnc TestLib.vb

Si può anche provare a compilare la versione C#:

Una semplice app C#

Questo è l'equivalente codice per C#. Copiarlo e salvarlo nel file TestLib.cs.

using System;
using System.Runtime.InteropServices;

public class TestLib {
  
  const string SimpLibName = "simplelib.dll";

   //Declare external functions using the DllImport attribute.
  [DllImport(SimpLibName, EntryPoint="MySucc",
             CallingConvention=CallingConvention.StdCall)]
             public static extern long Succ(long AVal);

  [DllImport(SimpLibName, EntryPoint="MyPred", 
             CallingConvention=CallingConvention.StdCall)] 
             public static extern long Pred(long AVal);

  public static void Main()
  {
    long TestVal;

    try
    {
      TestVal = 123;
      Console.WriteLine("Value is " + TestVal);
      Console.WriteLine("Successor is " + Succ(TestVal));
      Console.WriteLine("Predecessor is " + Pred(TestVal));
    }
    catch(Exception e)
    {
      Console.WriteLine(e);
    }
  }
}

Con .NET, si può compilarlo così:

 [pathto]csc TestLib.cs

Con Mono, si può compilarlo così:

 mcs TestLib.cs

Con .NET e Mono, la compilazione creerà il file TestLib.exe.

Una semplice app Pascal utilizzando Oxygene

Copiae e salvare il seguente codice Pascal nel file TestLib.pas:

namespace TestLib;

interface

uses
  System.Runtime.InteropServices;
  
const
  SimpleLibName = 'simplelib.dll';

type
  TestLib = class
  private
    [DllImportAttribute(SimpleLibName, EntryPoint:='MySucc',
                        CallingConvention:=CallingConvention.StdCall)]
    class method Succ(AVal : Int64) : Int64; external;  

    [DllImportAttribute(SimpleLibName, EntryPoint:='MyPred',
                        CallingConvention:=CallingConvention.StdCall)]
    class method Pred(AVal : Int64) : Int64; external;  
  public
    class method Main;
  end;
    
implementation

class method TestLib.Main;
var
  TestVal : Int64;
begin
  try
    TestVal := 123;
    Console.WriteLine('Value is ' + TestVal);
    Console.WriteLine('Successor is ' + Succ(TestVal));
    Console.WriteLine('Predecessor is ' + Pred(TestVal));
  except
    on E: Exception do
      Console.WriteLine(E.Message);
  end;
end;

end.

Il compilatore free Oxygene Object Pascal è disponbile qui RemObjects Software.

Con .NET e Mono, si può compilare TestLib.pas così:

 [pathto]oxygene TestLib.pas

Con .NET e Mono, verrà creato il file testlib.exe.

Eseguire la semplice app

Con .NET, eseguire la app compilata così:

 testlib

Se .NET trova simplelib.dll, l'output nella console sarà:

 Value is 123
 Successor is 124
 Predecessor is 122

Con Mono, eseguire la app compilata così:

 mono TestLib.exe

Mono cercherà anche il file simplelib.dll -- e questo è il motivo per cui è stata rinominata la libreria compilata in Linux e OS X.

Notare che i files ".exe" di .NET/Mono non contengono codice compilato nativo. Invece, contengono bytecode eseguito da .NET/Mono a runtime. Come risultato, si può prendere un file .NET .exe creato in Windows ed eseguirlo con Mono su OS X e Linux (e viceversa) senza ricompilarlo. Si dovrà ricompilare le librerie Pascal su ogni piattforma che si vuole supportare.

Quando usare librerie native con .NET/Mono

Perché non scrivere semplicemente tutto il codice in VB.NET o C#? There are several situations where this might not be a good idea:

  • When you have a large or complicated Pascal codebase that you don't want to rewrite (and re-debug) in C#.
  • When you have native libraries that need to be used by both native and .NET/Mono apps.
  • When there are performance reasons (presumably compiled FPC or Delphi native code is faster than the equivalent compiled bytecode run under .NET/Mono).
  • When you need low-level operating system access not available easily with .NET/Mono.
  • When you need to quickly develop code in a language you're more proficient in for a multi-developer .NET/Mono project.

Mono tips

1. Since Visual Basic is pretty foreign to Linux and OS X, you'll probably want to develop .NET and Mono apps using C#, which is similar to C++ (and Object Pascal). Or use the Oxygene compiler and develop your .NET and Mono apps with familiar Object Pascal.

2. Mono on OS X includes a script for uninstalling it. You can run this script before installing a newer version of Mono:

  • In Finder, navigate to /Library/Receipts.
  • Ctrl+click on MonoFramework.pkg and choose Show Package Contents from the popup menu.
  • Double-click the Contents folder.
  • Double-click the Resources folder.
  • Drag a copy of uninstallMono.sh to the desktop.
  • Open a Terminal window.
  • cd desktop
  • sudo ./uninstallMono.sh and enter your password.

3. In general, don't use any Lazarus units in your libraries. Libraries usually don't have a user interface. Confine your use to Free Pascal units like System, SysUtils, StrUtils, DateUtils, Classes, Variants and Math.

4. If you need a user interface to go with your library, program it as a Windows Forms application. Here's a simple form example. Copy and save this code to file MyForm.cs.

using System;
using System.Windows.Forms;

public class MyForm: Form
{
  public MyForm ()
  {
    this.Text = "A .NET/Mono Windows Forms App";
    this.Width = 400;

    Button b = new Button();
    b.Left = 15;
    b.Top = 20;
    b.Width = this.Width-30;
    b.Height = 30;
    b.Text = "Click Me";
    b.Click += new EventHandler(button_Click);
    this.Controls.Add(b);
  }
  void button_Click(object sender, EventArgs e)
  {
    MessageBox.Show("Hello");
  }
}

public class MyApp
{
  public static void Main()
  {
    MyForm aForm = new MyForm();
    Application.Run(aForm);
  }
}

Compile this code on Mono as follows:

 mcs -r:System.Windows.Forms MyForm.cs

Run the app as follows:

 mono MyForm.exe

On OS X, you can also create a normal app bundle using the macpack utility:

 macpack -n MyForm -m winforms MyForm.exe

This creates the MyForm.app bundle, which can be double-clicked, dropped onto the Dock, etc.

5. On Linux and OS X, Mono now includes MonoDevelop, a simple IDE for editing and compiling code.

6. If you have any questions or comments about using Pascal libraries with .NET or Mono, please post them to the Lazarus forum.