Python for .NET 调用 System.Windows.Forms.Form 构造函数时无声失败

3 投票
2 回答
929 浏览
提问于 2025-04-17 19:57

C# 代码

我有一段 C# 代码,它被编译成一个叫做 "MinimalFormsApp.dll" 的库。

using System;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsTest
{
    public static class CreateACoolWindow
    {
        public static void Main(string[] args)
        {
            CreateWindow();
        }

        public static void CreateWindow()
        {
            Thread winFormsThread = new Thread(new ThreadStart(StartFormApplication));
            winFormsThread.SetApartmentState(ApartmentState.STA);
            winFormsThread.Start();
            Console.WriteLine("Started thread");
        }

        private static void StartFormApplication()
        {
            Application.EnableVisualStyles();
            Console.WriteLine("EnableVisualStyles");
            Application.SetCompatibleTextRenderingDefault(false);
            Console.WriteLine("SetCompatibleTextRenderingDefault");
            FormSubClass dmw = new FormSubClass();
            Console.WriteLine("Created window object");
            Application.Run(dmw);
        }
    }

    public class FormSubClass : Form
    {
        public FormSubClass()
        {
            Console.WriteLine("FormSubClass Constructor called");
            InitializeComponent();
        }

        private void InitializeComponent()
        {
            Console.WriteLine("Starting component init......");
            this.SuspendLayout();
            this.AutoScaleDimensions = new SizeF(6F, 13F);
            this.AutoScaleMode = AutoScaleMode.Font;
            this.ClientSize = new Size(300, 500);
            this.Name = "FormSubClass";
            this.Text = "FormSubClass";
            this.ResumeLayout(false);
            this.PerformLayout();

        }
    }
}

Python 代码

我使用 Python for .NET 和 Python 2.7(适用于 x86)来尝试调用这个 C# 库中的 CreateWindow() 方法。

我的 Python 代码如下:

import clr
clr.AddReference("MinimalFormsApp")

from WindowsFormsTest import CreateACoolWindow
CreateACoolWindow.CreateWindow()

#Print some output
print "Mary had a little lamb,"
print "it's fleece was white as snow;"
print "and everywhere that Mary went",
print "her lamb was sure to go."

控制台输出

这是 Python 在控制台上打印的内容:

启动线程
玛丽有一只小羊,启用视觉样式
设置兼容文本渲染默认值

它的毛像雪一样白;
玛丽走到哪里,她的小羊就跟到哪里。
FormSubClass 构造函数被调用

可以看到,它没有打印 "开始组件初始化......" 也没有打印 "创建窗口对象",实际上也没有创建窗口。Python 程序结束时没有产生任何错误信息,说明窗口没有被创建的原因。

如果我从另一个 C# 程序调用同样的 C# 库,所有内容都会如预期那样打印出来,并且窗口会被创建。

有没有人知道为什么 Python for .NET 在 Forms 构造函数上会静默失败?

2 个回答

3

我在找其他问题的时候偶然发现了这个问题。虽然我来得有点晚,但我觉得我可以给遇到类似问题的人提供一些见解。

当CPython解释器管理线程时,会把它们分成三类。

  • 正常线程
  • 守护线程
  • 外部线程

正常线程是通过线程模块启动的普通Python线程。只要这些线程或者主线程还在运行,解释器就不会退出。

守护线程也是通过线程模块启动的,但它们被标记为守护线程。在这种情况下,解释器在退出之前不会等这些线程结束。

最后,外部线程是指在与CPython相同的进程中启动的线程,但不是通过任何Python代码启动的。解释器知道这些线程的存在,但不知道如何等待它们,所以把它们当作守护线程处理,也就是说在退出时不会等它们结束。

如果你想在Windows上更好地处理线程(而且没有全局解释器锁),可以看看IronPython。虽然可能会慢一些,但它在处理.NET交互方面表现得更好,因为它是作为本地.NET运行的。

1

当Python的主线程结束时,.NET中的所有东西也会随之结束。

在上面的例子中,窗口还没来得及显示出来,Python的主线程就已经在终端打印完文本后结束了。

如果在一个新的Python线程中启动.NET的调用,就可以避免这种情况发生。

撰写回答