Using Pascal Libraries with .NET and Mono/it: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: Using Pascal Libraries with .NET and Mono/it
| Old | New | Line | |
|---|---|---|---|
| 1 | + | ## Introduzione | |
| 2 | + | ||
| 3 | + | 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](http://www.mono-project.com/Main_Page) comprende un analogo supporto per le librerie native di Linux e macOS. Questo significa che si possono compilare librerie con Free Pascal e usarle con applicazioni .NET in Windows e con applicazioni Mono in Linux e macOS. | |
| 4 | + | ||
| 5 | + | ## Una semplice libreria Pascal | |
| 6 | + | ||
| 7 | + | Copiare e salvare il seguente codice Pascal nel file SimpleLib.pas: | |
| 8 | + | ||
| 9 | + | ``` pascal | |
| 10 | + | library SimpleLib; | |
| 11 | + | ||
| 12 | + | function MySucc(AVal : Int64) : Int64; stdcall; | |
| 13 | + | begin | |
| 14 | + | Result := System.Succ(AVal); | |
| 15 | + | end; | |
| 16 | + | ||
| 17 | + | function MyPred(AVal : Int64) : Int64; stdcall; | |
| 18 | + | begin | |
| 19 | + | Result := System.Pred(AVal); | |
| 20 | + | end; | |
| 21 | + | ||
| 22 | + | exports | |
| 23 | + | {$IFDEF DARWIN} {macOS entry points} | |
| 24 | + | MySucc name '_MySucc', | |
| 25 | + | MyPred name '_MyPred', | |
| 26 | + | {$ENDIF} | |
| 27 | + | MySucc, | |
| 28 | + | MyPred; | |
| 29 | + | ||
| 30 | + | end. | |
| 31 | + | ``` | |
| 32 | + | ||
| 33 | + | Notare la direttiva condizionale per compilazione su macOS (Darwin). Apparentemente il linker dinamico di macOS cerca un punto d'ingresso alla libreria che inizi con un underscore. | |
| 34 | + | ||
| 35 | + | Ora compilare la libreria con Free Pascal: | |
| 36 | + | ||
| 37 | + | fpc -Sd SimpleLib.pas | |
| 38 | + | ||
| 39 | + | In Windows, verrà creato il file simplelib.dll. In macOS, verrà creato il file libsimplelib.dylib. In Linux, this will create file simplelib.so. On macOS and Linux, rename the compiled library file to simplelib.dll: | |
| 40 | + | ||
| 41 | + | mv libsimplelib.dylib simplelib.dll | |
| 42 | + | ||
| 43 | + | ## Una semplice app VB.NET | |
| 44 | + | ||
| 45 | + | Copiare e salvare questo codice VB.NET nel file TestLib.vb: | |
| 46 | + | ||
| 47 | + | ``` vb | |
| 48 | + | Imports System | |
| 49 | + | Imports System.Runtime.InteropServices | |
| 50 | + | ||
| 51 | + | Public Class TestLib | |
| 52 | + | ||
| 53 | + | Const SimpLibName = "simplelib.dll" | |
| 54 | + | ||
| 55 | + | 'Declare external functions using the DllImport attribute. | |
| 56 | + | <DllImport(SimpLibName, EntryPoint:="MySucc", _ | |
| 57 | + | CallingConvention:=CallingConvention.StdCall)> _ | |
| 58 | + | Public Shared Function Succ(ByVal AVal As Long) As Long | |
| 59 | + | End Function | |
| 60 | + | ||
| 61 | + | <DllImport(SimpLibName, EntryPoint:="MyPred", _ | |
| 62 | + | CallingConvention:=CallingConvention.StdCall)> _ | |
| 63 | + | Public Shared Function Pred(ByVal AVal As Long) As Long | |
| 64 | + | End Function | |
| 65 | + | ||
| 66 | + | Public Shared Sub Main() | |
| 67 | + | ||
| 68 | + | Dim TestVal As Long | |
| 69 | + | ||
| 70 | + | Try | |
| 71 | + | TestVal = 123 | |
| 72 | + | Console.WriteLine("Value is " & TestVal) | |
| 73 | + | Console.WriteLine("Successor is " & Succ(TestVal)) | |
| 74 | + | Console.WriteLine("Predecessor is " & Pred(TestVal)) | |
| 75 | + | Catch e As Exception | |
| 76 | + | Console.WriteLine(e) | |
| 77 | + | End Try | |
| 78 | + | ||
| 79 | + | End Sub 'Main | |
| 80 | + | ||
| 81 | + | End Class 'TestLib | |
| 82 | + | ``` | |
| 83 | + | ||
| 84 | + | Se .NET framework è installato in Windows, si può compilare il codice così: | |
| 85 | + | ||
| 86 | + | [pathto]vbc TestLib.vb | |
| 87 | + | ||
| 88 | + | 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. | |
| 89 | + | ||
| 90 | + | Se Mono è installato, si può anche provare a compilare il codice così: | |
| 91 | + | ||
| 92 | + | vbnc TestLib.vb | |
| 93 | + | ||
| 94 | + | Si può anche provare a compilare la versione C#: | |
| 95 | + | ||
| 96 | + | ## Una semplice app C# | |
| 97 | + | ||
| 98 | + | Questo è l'equivalente codice per C#. Copiarlo e salvarlo nel file TestLib.cs. | |
| 99 | + | ||
| 100 | + | ``` c# | |
| 101 | + | using System; | |
| 102 | + | using System.Runtime.InteropServices; | |
| 103 | + | ||
| 104 | + | public class TestLib { | |
| 105 | + | ||
| 106 | + | const string SimpLibName = "simplelib.dll"; | |
| 107 | + | ||
| 108 | + | //Declare external functions using the DllImport attribute. | |
| 109 | + | [DllImport(SimpLibName, EntryPoint="MySucc", | |
| 110 | + | CallingConvention=CallingConvention.StdCall)] | |
| 111 | + | public static extern long Succ(long AVal); | |
| 112 | + | ||
| 113 | + | [DllImport(SimpLibName, EntryPoint="MyPred", | |
| 114 | + | CallingConvention=CallingConvention.StdCall)] | |
| 115 | + | public static extern long Pred(long AVal); | |
| 116 | + | ||
| 117 | + | public static void Main() | |
| 118 | + | { | |
| 119 | + | long TestVal; | |
| 120 | + | ||
| 121 | + | try | |
| 122 | + | { | |
| 123 | + | TestVal = 123; | |
| 124 | + | Console.WriteLine("Value is " + TestVal); | |
| 125 | + | Console.WriteLine("Successor is " + Succ(TestVal)); | |
| 126 | + | Console.WriteLine("Predecessor is " + Pred(TestVal)); | |
| 127 | + | } | |
| 128 | + | catch(Exception e) | |
| 129 | + | { | |
| 130 | + | Console.WriteLine(e); | |
| 131 | + | } | |
| 132 | + | } | |
| 133 | + | } | |
| 134 | + | ``` | |
| 135 | + | ||
| 136 | + | Con .NET, si può compilarlo così: | |
| 137 | + | ||
| 138 | + | [pathto]csc TestLib.cs | |
| 139 | + | ||
| 140 | + | Con Mono, si può compilarlo così: | |
| 141 | + | ||
| 142 | + | mcs TestLib.cs | |
| 143 | + | ||
| 144 | + | Con .NET e Mono, la compilazione creerà il file TestLib.exe. | |
| 145 | + | ||
| 146 | + | ## Una semplice app Pascal utilizzando Oxygene | |
| 147 | + | ||
| 148 | + | Copiare e salvare il seguente codice Pascal nel file TestLib.pas: | |
| 149 | + | ||
| 150 | + | ``` pascal | |
| 151 | + | namespace TestLib; | |
| 152 | + | ||
| 153 | + | interface | |
| 154 | + | ||
| 155 | + | uses | |
| 156 | + | System.Runtime.InteropServices; | |
| 157 | + | ||
| 158 | + | const | |
| 159 | + | SimpleLibName = 'simplelib.dll'; | |
| 160 | + | ||
| 161 | + | type | |
| 162 | + | TestLib = class | |
| 163 | + | private | |
| 164 | + | [DllImportAttribute(SimpleLibName, EntryPoint:='MySucc', | |
| 165 | + | CallingConvention:=CallingConvention.StdCall)] | |
| 166 | + | class method Succ(AVal : Int64) : Int64; external; | |
| 167 | + | ||
| 168 | + | [DllImportAttribute(SimpleLibName, EntryPoint:='MyPred', | |
| 169 | + | CallingConvention:=CallingConvention.StdCall)] | |
| 170 | + | class method Pred(AVal : Int64) : Int64; external; | |
| 171 | + | public | |
| 172 | + | class method Main; | |
| 173 | + | end; | |
| 174 | + | ||
| 175 | + | implementation | |
| 176 | + | ||
| 177 | + | class method TestLib.Main; | |
| 178 | + | var | |
| 179 | + | TestVal : Int64; | |
| 180 | + | begin | |
| 181 | + | try | |
| 182 | + | TestVal := 123; | |
| 183 | + | Console.WriteLine('Value is ' + TestVal); | |
| 184 | + | Console.WriteLine('Successor is ' + Succ(TestVal)); | |
| 185 | + | Console.WriteLine('Predecessor is ' + Pred(TestVal)); | |
| 186 | + | except | |
| 187 | + | on E: Exception do | |
| 188 | + | Console.WriteLine(E.Message); | |
| 189 | + | end; | |
| 190 | + | end; | |
| 191 | + | ||
| 192 | + | end. | |
| 193 | + | ``` | |
| 194 | + | ||
| 195 | + | Il compilatore free Oxygene Object Pascal è disponbile qui [RemObjects Software](http://www.remobjects.com). | |
| 196 | + | ||
| 197 | + | Con .NET e Mono, si può compilare TestLib.pas così: | |
| 198 | + | ||
| 199 | + | [pathto]oxygene TestLib.pas | |
| 200 | + | ||
| 201 | + | Con .NET e Mono, verrà creato il file testlib.exe. | |
| 202 | + | ||
| 203 | + | ## Eseguire la semplice app | |
| 204 | + | ||
| 205 | + | Con .NET, eseguire la app compilata così: | |
| 206 | + | ||
| 207 | + | testlib | |
| 208 | + | ||
| 209 | + | Se .NET trova simplelib.dll, l'output nella console sarà: | |
| 210 | + | ||
| 211 | + | Value is 123 | |
| 212 | + | Successor is 124 | |
| 213 | + | Predecessor is 122 | |
| 214 | + | ||
| 215 | + | Con Mono, eseguire la app compilata così: | |
| 216 | + | ||
| 217 | + | mono TestLib.exe | |
| 218 | + | ||
| 219 | + | Mono cercherà anche il file simplelib.dll -- e questo è il motivo per cui è stata rinominata la libreria compilata in Linux e macOS. | |
| 220 | + | ||
| 221 | + | 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 macOS e Linux (e viceversa) senza ricompilarlo. Si dovrà ricompilare le librerie Pascal su ogni piattforma che si vuole supportare. | |
| 222 | + | ||
| 223 | + | ## Quando usare librerie native con .NET/Mono | |
| 224 | + | ||
| 225 | + | Perché non scrivere semplicemente tutto il codice in VB.NET o C#? Ci sono diverse situazioni in cui questa può non essere una buona idea: | |
| 226 | + | ||
| 227 | + | - quando si ha un lungo o complesso codice Pascal che non si vuole riscrivere (e ricorreggere) in C#; | |
| 228 | + | - quando si hanno librerie native che devono essere utilizzate da apps sia native, sia .NET/Mono; | |
| 229 | + | - quando ci sono motivi di prestazioni (presumilmente codice compilato in FPC o Delphi è più veloce di quello equivalente compilato sotto .NET/Mono); | |
| 230 | + | - quando è necessario un accesso a basso livello al sistema operativo, non facilmente disponibile con .NET/Mono; | |
| 231 | + | - quando è necessario sviluppare codice velocemente in un linguaggio che you're more proficient in for a multi-developer .NET/Mono project. | |
| 232 | + | ||
| 233 | + | ## Appunti Mono | |
| 234 | + | ||
| 235 | + | **1.** Poiché Visual Basic è un perfetto sconosciuto a Linux e macOS, probabilmente si vorrà sviluppare apps .NET e Mono utilizzando C#, che è simile a C++ (e Object Pascal). O usare il compilatore Oxygene e sviluppare apps .NET e Mono con un Object Pascal familiare. | |
| 236 | + | ||
| 237 | + | **2.** Mono in macOS comprende uno script per la disinstallazione. E' bene eseguire questo script prima di installare una nuova versione di Mono: | |
| 238 | + | ||
| 239 | + | - In Finder, navigare fino a /Library/Receipts. | |
| 240 | + | - Ctrl+click su MonoFramework.pkg e scegliere Show Package Contents dal menu popup. | |
| 241 | + | - Doppio-click su Contents folder. | |
| 242 | + | - Doppio-click su Resources folder. | |
| 243 | + | - Trascinare una copia di uninstallMono.sh sul desktop. | |
| 244 | + | - Aprire una finestra Terminal. | |
| 245 | + | - cd desktop | |
| 246 | + | - sudo ./uninstallMono.sh e inserire la password. | |
| 247 | + | ||
| 248 | + | **3**. In generale, non utilizzare units Lazarus nelle librerie. Le librerie generalmente non hanno una interfaccia utente. Confine your use to Free Pascal units like System, SysUtils, StrUtils, DateUtils, Classes, Variants and Math. | |
| 249 | + | ||
| 250 | + | **4.** Se si ha bisogno di una interfaccia utente per operare con le librerie, si programmi come un'applicazione Windows Forms. Si riporta di seguito un semplice esempio di form. Copiare e salvare questo codice nel file MyForm.cs. | |
| 251 | + | ||
| 252 | + | ``` vb | |
| 253 | + | using System; | |
| 254 | + | using System.Windows.Forms; | |
| 255 | + | ||
| 256 | + | public class MyForm: Form | |
| 257 | + | { | |
| 258 | + | public MyForm () | |
| 259 | + | { | |
| 260 | + | this.Text = "A .NET/Mono Windows Forms App"; | |
| 261 | + | this.Width = 400; | |
| 262 | + | ||
| 263 | + | Button b = new Button(); | |
| 264 | + | b.Left = 15; | |
| 265 | + | b.Top = 20; | |
| 266 | + | b.Width = this.Width-30; | |
| 267 | + | b.Height = 30; | |
| 268 | + | b.Text = "Click Me"; | |
| 269 | + | b.Click += new EventHandler(button_Click); | |
| 270 | + | this.Controls.Add(b); | |
| 271 | + | } | |
| 272 | + | void button_Click(object sender, EventArgs e) | |
| 273 | + | { | |
| 274 | + | MessageBox.Show("Hello"); | |
| 275 | + | } | |
| 276 | + | } | |
| 277 | + | ||
| 278 | + | public class MyApp | |
| 279 | + | { | |
| 280 | + | public static void Main() | |
| 281 | + | { | |
| 282 | + | MyForm aForm = new MyForm(); | |
| 283 | + | Application.Run(aForm); | |
| 284 | + | } | |
| 285 | + | } | |
| 286 | + | ``` | |
| 287 | + | ||
| 288 | + | Compilare questo codice con Mono così: | |
| 289 | + | ||
| 290 | + | mcs -r:System.Windows.Forms MyForm.cs | |
| 291 | + | ||
| 292 | + | Run the app as follows: | |
| 293 | + | ||
| 294 | + | mono MyForm.exe | |
| 295 | + | ||
| 296 | + | In macOS, si può anche creare una normale app bundle utilizzando l'utility macpack: | |
| 297 | + | ||
| 298 | + | macpack -n MyForm -m winforms MyForm.exe | |
| 299 | + | ||
| 300 | + | che crea MyForm.app bundle, che può essere double-clicked, dropped onto the Dock, etc. | |
| 301 | + | ||
| 302 | + | **5.** Su Linux e macOS, Mono ora comprende MonoDevelop, una semplice IDE per l'editing e la compilazione del codice. | |
| 303 | + | ||
| 304 | + | **6.** If you have any questions or comments about using Pascal libraries with .NET or Mono, please post them to the Lazarus forum. | |
| 305 | + | ||
| 306 | + | --- | |
| 307 | + | *From the Free Pascal wiki, page "Using Pascal Libraries with .NET and Mono/it", as it stood on 2020-03-04 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
