2009-08-19 7 views
5

Ich habe eine WinForms-Anwendung, die ich irgendwann bei Mono ausführen möchte. Es verwendet jedoch einige P/Invoke gegen user32.dll, was zu offensichtlichen Problemen führen wird."Ignorieren" P/Invoke bei laufendem Mono

Dies ist jedoch keine kritische Funktionalität, nur einige Geschmacksstoffe. Daher möchte ich es ignorieren, wenn ich Mono starte.

Ich weiß, ich könnte nur eine #if-Anweisung verwenden, aber dann muss ich zwei verschiedene Baugruppen anbieten, was schlecht ist. Ich weiß, dass ich Runtime überprüfen kann, wenn ich in Mono laufe, aber das hilft mir nicht, die Deklarationen zu den Funktionen zu entfernen.

Also frage ich mich: Gibt es einen Weg, wo ich sagen kann "Wenn Mono läuft, ignoriere das komplett"? Wenn es hilft: Das P/Invoke-Zeug befindet sich in einer separaten CS-Datei und wird als Teilklasse implementiert.

Der Quellcode in Frage ist hier: http://pastie.org/588940
Es ist Teil meines Hauptformulars ist, das Überschreiben der WndProc Nachricht ein Element in das Systemmenü hinzuzufügen. (Einige andere Sachen wurden abgeschnitten). Mein Problem ist, dass, während der WndProc-Kram einfach ist, ich nicht weiß, was ich mit den beiden privaten externen Deklarationen machen soll - kann ich sie in eine andere (statische) Klasse einfügen, die ich einfach nie bei Mono anrufe? Oder wäre das russisches Roulette?

+1

Btw, Sie wissen, dass Swiki bereits der Name der Wiki-Software ist, richtig? Http://en.wikipedia.org/wiki/Swiki –

+0

Nur nach der Registrierung bereits, und jetzt wird es einige Treffer bekommen. Ich denke, dass ich es für 1.0 im Moment umbenennen. –

Antwort

8

Warum nicht die Plattform-abhängigen Sachen in einer Schnittstelle kapseln, dann haben Sie eine Möglichkeit, die "richtige" Implementierung für die aktuelle Plattform zu bekommen. Dann kann der aufrufende Code sie munter benutzen, und Sie können nach und nach Bits einfügen, um auf Mono zu laufen, wann Sie wollen. Ich würde zumindest Hoffnung, dass, wenn Sie noch nie die Klasse laden die P/Invoke Bits enthält, sollten Sie in Ordnung sein ...

EDIT:

Ich verstehe nicht, warum dieser Ansatz sollte nicht arbeiten, obwohl Sie vielleicht nicht einmal die Fabrik brauchen. Hier ist, was ich tun würde:

MainForm.cs:

PlatformServicesFacade.InitializeSystemMenu(); 

IPlatformServices.cs:

public interface IPlatformServices 
{ 
    void InitializeSystemMenu(); 
} 

MonoPlatformServices.cs:

public class MonoPlatformServices : IPlatformServices 
{ 
    // Prevent early type initialization 
    static WindowsPlatformServices() {} 

    public void InitializeSystemMenu() 
    { 
     // Maybe log what you would have done? 
    } 
} 

WindowsPlatformServices.cs:

public class WindowsPlatformServices : IPlatformServices 
{ 
    // Prevent early type initialization 
    static WindowsPlatformServices() {} 

    public const Int32 SystemMenuAboutSWikiId = 1000; 
    [DllImport("user32.dll")] 
    private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); 
    [DllImport("user32.dll")] 
    private static extern bool InsertMenu(IntPtr hMenu, Int32 wPosition, 
              Int32 wFlags, Int32 wIDNewItem, 
              string lpNewItem); 

    public void InitializeSystemMenu() 
    { 
     const Int32 MF_SEPARATOR = 0x800; 
     const Int32 MF_BYPOSITION = 0x400; 

     IntPtr systemMenuPtr = GetSystemMenu(Handle, false); 
     InsertMenu(systemMenuPtr, 5, MF_BYPOSITION | MF_SEPARATOR, 0, ""); 
     InsertMenu(systemMenuPtr, 6, MF_BYPOSITION, SystemMenuAboutSWikiId, 
        "About SWiki..."); 
    } 
} 

PlatformServicesFacade.cs:

public class PlatformServicesFacade 
{ 
    private static readonly IPlatformServices services; 

    static PlatformServiceFacade() 
    { 
     services = RunningOnWindows() ? new WindowsPlatformServices() 
      : (IPlatformServices) new MonoPlatformServices(); 
    } 

    public static void InitializeSystemMenu() 
    { 
     services.InitializeSystemMenu(); 
    } 
} 

ich denken, die funktionieren sollte ... wenn es nicht der Fall ist, sagen Sie uns bitte, was falsch läuft :)

2

die Laufzeit Überprüfung scheint wie eine tragfähige Lösung . Gibt es einen Grund, warum Sie die P/Invoke-Funktionsdeklarationen entfernen möchten, wenn sie unter Mono ausgeführt werden, selbst wenn sie niemals verwendet werden?

+0

Ich will nur sicher sein, dass sie nicht aufgerufen werden und stürzen meine Anwendung zufällig –

+0

Machen Sie sie nicht nur public - wickeln Sie sie in eine Funktion, die die plattformspezifische Variante überprüft sollte heißen: – skolima

4

Einige Umgebungseigenschaften haben wahrscheinlich diese Informationen, z. B. System.Environment.OSVersion.Platform. Oder verwenden Sie if (Type.GetType ("Mono.Runtime")! = Null)

Siehe "Wie kann die Ausführungsplattform erkannt werden?" und "Wie kann ich erkennen, wenn ich in Mono laufe?": http://www.mono-project.com/FAQ:_Technical

+0

Danke, mein Problem war mehr über "wie ich die _declaration_ einer externen Methode in einen bedingten Block, der zur Laufzeit ausgeführt wird?" –

2

Ich denke, Ihre beste Wette wird M/Invoke von den Mono-Jungs sein. Es ist immer noch ziemlich neu (nur in Mono SVN). Aber ich bin sicher, sie würden lieben helfen, es in eine Mono Distribution :)

+0

Ich denke schon :) Aber P/Invoke ist eines der Dinge, die ich nur verwenden möchte, wenn es wirklich ist kein anderer Weg, und selbst dann nur in sehr geringem Umfang. –

Verwandte Themen