“忽略” 在 Mono 上运行时的 P/Invoke

发布于 2024-08-02 03:58:12 字数 602 浏览 1 评论 0原文

我有一个 WinForms 应用程序,我想在某个时候在 Mono 上运行。 然而,它正在对 user32.dll 使用一些 P/Invoke,这会导致明显的问题。

然而,这不是一个关键的功能,只是一些风味的东西。 所以我想在运行 Mono 时忽略它。

我知道我可以只使用 #if 指令,但随后我必须提供两个不同的程序集,这很糟糕。 我知道如果我在 Mono 中运行,我可以检查运行时,但这无助于我删除函数的声明。

所以我想知道:有没有一种方法可以让我说“如果运行 Mono,完全忽略它”? 如果有帮助:P/Invoke 内容位于单独的 .cs 文件中,并作为部分类实现。

有问题的源代码在这里:http://pastie.org/588940
它是我的主窗体的一部分,覆盖 WndProc 消息以将项目添加到系统菜单。 (其他一些东西被剪掉了)。 我的问题是,虽然 WndProc 的东西很简单,但我不知道如何处理两个私有 extern 声明 - 我可以将它们放入另一个我从未在 Mono 上调用的(静态)类中吗? 或者那是俄罗斯轮盘赌?

I have a WinForms Application that I want to run at Mono at some point. However, it is using some P/Invoke against user32.dll, which will cause an obvious problems.

However, this is not a critical functionality, just some flavor stuff. So I would like to ignore it when running Mono.

I know I could just use an #if directive, but then I have to offer two different assemblies, which is bad. I know I can check on Runtime if I am running in Mono, but that won't help me removing the declarations to the functions.

So I wonder: Is there a way where I can say "If running Mono, ignore this completely"? If it helps: The P/Invoke stuff is in a separate .cs file and implemented as a Partial Class.

The source code in question is here: http://pastie.org/588940
It is part of my Main Form, overriding the WndProc message to add an item to the system menu. (Some other stuff snipped). My problem is that while the WndProc stuff is easy, I do not know what to do with the two private extern declarations - can I put them into another (static) class that I just never call on Mono? Or would that be russian roulette?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

从来不烧饼 2024-08-09 03:58:12

为什么不将依赖于平台的东西封装在一个接口中,然后通过某种方式获得当前平台的“正确”实现。 然后调用代码就可以轻松地使用它,并且您可以逐渐填充位以在需要时在 Mono 上运行。 我至少希望如果你从来没有加载包含 P/Invoke 位的类,你应该没问题......

编辑:

我不明白为什么这种方法不应该工作,尽管你甚至可能不需要工厂。 这就是我要做的:

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();
    }
}

我认为应该可行...如果不行,请告诉我们出了什么问题:)

Why not encapsulate the platform-dependent stuff in an interface, then have some way of getting the "right" implementation for the current platform. Then the calling code can use it blithely, and you can gradually fill in bits to run on Mono as and when you want. I would at least hope that if you never even load the class containing the P/Invoke bits, you should be okay...

EDIT:

I don't see why this approach shouldn't work, although you may not even need the factory. Here's what I'd do:

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();
    }
}

I think that should work... if it doesn't, please tell us what's going wrong :)

暖伴 2024-08-09 03:58:12

某些环境属性可能具有此信息,例如 System.Environment.OSVersion.Platform。 或者使用 if (Type.GetType("Mono.Runtime") != null)

参见《如何检测执行平台?》 和“如何检测是否在 Mono 中运行?”: http://www.mono- project.com/FAQ:_技术

Some Environment property probably has this info, for example System.Environment.OSVersion.Platform. Or use if (Type.GetType("Mono.Runtime") != null)

See "How to detect the execution platform?" and "How can I detect if am running in Mono?": http://www.mono-project.com/FAQ:_Technical

回忆那么伤 2024-08-09 03:58:12

检查运行时似乎是一个可行的解决方案。 如果在 Mono 下运行,您是否有任何理由想要删除 P/Invoke 函数声明,即使它们从未使用过?

Checking the runtime seems like a viable solution. Is there any reason you would like to remove the P/Invoke function declarations if running under Mono even if they are never used?

浮生未歇 2024-08-09 03:58:12

我认为你最好的选择是 M/Invoke 来自莫诺人。 它仍然很新(仅在 Mono SVN 中)。 但我确信他们很乐意帮助将其纳入 Mono 发行版:)

I think your best bet will be M/Invoke from the Mono guys. It is still pretty new (only in Mono SVN). But I'm sure they'd love help getting it into a Mono Distribution :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文