You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

动态IL生成的WndProc重载未触发的WinForms单实例应用问题

解决动态生成Form子类的WndProc未被调用问题

核心问题分析

  1. 方法属性错误:基类Form.WndProc是protected virtual,但你定义的动态方法用了private修饰符,导致无法正确覆盖基类方法,WinForms消息循环只会调用类型的虚方法实现。
  2. 未明确标记方法覆盖:动态生成方法后,未调用DefineMethodOverride告诉CLR该方法是对基类WndProc的覆盖,CLR无法识别这是一个重写方法。
  3. IL指令错误:调用静态方法MessageHandler时错误传递了实例参数(Ldarg_0),且多传了一个不存在的Ldarg_2参数(WndProc仅包含实例和ref Message两个参数)。

修正后的关键代码

修正CreateSingleInstanceFormRunner方法

private static void CreateSingleInstanceFormRunner() {
    string methodName = "WndProc";
    Type type = typeof(T);
    MethodInfo? methodInfo = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic);
    if (null == methodInfo) {
        methodInfo = typeof(Form).GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic);
    }
    if (methodInfo == null) throw new InvalidOperationException("无法获取WndProc方法");

    AssemblyName assemblyName = new AssemblyName("SingleInstanceAssembly");
    AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
    ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("SingleInstanceModule");
    TypeBuilder typeBuilder = moduleBuilder.DefineType("SingleInstanceFormRunner", TypeAttributes.Public, type);

    // 定义匹配基类的protected virtual方法
    MethodBuilder methodBuilder = typeBuilder.DefineMethod(
        methodName,
        MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig,
        methodInfo.ReturnType,
        new Type[] { typeof(Message).MakeByRefType() });

    RefAction newWndProc = MessageHandler;
    ILGenerator il = methodBuilder.GetILGenerator();

    // 调用静态MessageHandler,仅传递ref Message参数
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Call, newWndProc.Method);

    // 调用基类WndProc方法
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Call, methodInfo);

    il.Emit(OpCodes.Ret);

    // 关键:标记该方法覆盖基类的WndProc
    typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);

    Type dynamicType = typeBuilder.CreateType();
    _instanceForm = (T)Activator.CreateInstance(dynamicType);
}

额外注意事项

  • 确保MessageHandler中的逻辑正确:因为已经在IL中调用了基类WndProc,不需要在MessageHandler中再调用base.WndProc。
  • WM_SHOW_RUNNING_INSTANCE的注册是全局的,RegisterWindowMessage会为相同的字符串返回唯一值,多实例调用不会有冲突。
  • Mutex的使用正确:第一个实例获取所有权,退出时释放Mutex,确保单实例逻辑正常。

内容的提问来源于stack exchange,提问作者Sam Axe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 03:05:48