0

我正在编写一个在本机 Windows 应用程序中运行的 .Net COM DLL。

我正在尝试在此应用程序的状态栏中注入一个额外的窗格,并且它没有任何特定的实现可以这样做,因此我正在尝试自己对应用程序的状态栏进行子类化。

我正在使用 Win32 API SetParent() 将标签控件的父级从 .Net 表单切换到 msctls_statusbar32 实例。我使用标签是因为它是最接近原生“静态”类控件的实现,无需编写自己的控件即可找到。

不知何故,我什至设法让 NativeWindow 成功连接到状态栏和标签的消息(尽管目前它只是将它们全部传递给下一个 WndProc),并且我已经为标签的窗口分配了匹配的样式和 styleExs ,并且我可以将我的标签视为子标签,并将 msctls_statusbar32 作为其父标签。一切看起来都应该正常工作,但事实并非如此。我的控件未显示在父应用的状态栏中。

我不明白为什么它没有出现。几乎我能想到的所有内容都正确匹配——当然,我的标签类是“WindowsForms10.STATIC.app.0.378734a”而不是“静态”,但除了它在正确的进程和线程上之外,还有匹配的窗口样式(至少是十六进制值...... Spy++ 似乎以不同的方式枚举它们),并且出于所有目的几乎与其余控件融为一体。有人知道还需要做什么才能使其可见吗?

(我最初选择了 CreateWindowEx 并设置 WNDPROC 回调,但我无法让应用程序工作......它会冻结一分钟左右然后解冻,我会注意到我的窗口从窗口树中消失了)

谢谢!

4

3 回答 3

2

您可以尝试使用现有的状态栏控件;您可以做的是将文本重置为现有部分或添加新部分;您也可能需要为状态栏的现有部分设置新的宽度。您可以在此处找到有关如何使用状态栏控件的详细信息:msdn 状态栏

请在下面找到如何执行此操作的示例。我实际上使用 win32 应用程序使用的 c# com 对象进行了尝试,它对我来说似乎工作正常。

    [ComVisible(true)]
    [Guid("CC5B405F-F3CD-417E-AA00-4638A12A2E94"),
    ClassInterface(ClassInterfaceType.None)]
    public class TestInterface : ITestInterface // see declaration of the interface below
    {
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, IntPtr lParam);

        public const int SB_SETTEXT = 1035;
        public const int SB_SETPARTS = 1028;
        public const int SB_GETPARTS = 1030;

        public unsafe void Test()
        {
            IntPtr mainWindowHandle = Process.GetCurrentProcess().MainWindowHandle;
            // find status bar control on the main window of the application
            IntPtr statusBarHandle = FindWindowEx(mainWindowHandle, IntPtr.Zero, "msctls_statusbar32", IntPtr.Zero);
            if (statusBarHandle != IntPtr.Zero)
            {
                // set text for the existing part with index 0
                IntPtr text = Marshal.StringToHGlobalAuto("test text 0");
                SendMessage(statusBarHandle, SB_SETTEXT, 0, text);
                Marshal.FreeHGlobal(text);

                // create new parts width array
                int nParts = SendMessage(statusBarHandle, SB_GETPARTS, 0, IntPtr.Zero).ToInt32();
                nParts++;
                IntPtr memPtr = Marshal.AllocHGlobal(sizeof(int) * nParts);
                int partWidth = 100; // set parts width according to the form size
                for (int i = 0; i < nParts; i++)
                {
                    Marshal.WriteInt32(memPtr, i*sizeof(int), partWidth);
                    partWidth += partWidth;
                }
                SendMessage(statusBarHandle, SB_SETPARTS, nParts, memPtr);
                Marshal.FreeHGlobal(memPtr);

                // set text for the new part
                IntPtr text0 = Marshal.StringToHGlobalAuto("new section text 1");
                SendMessage(statusBarHandle, SB_SETTEXT, nParts-1, text0);
                Marshal.FreeHGlobal(text0);
            }
        }
    }

    [ComVisible(true)]
    [Guid("694C1820-04B6-4988-928F-FD858B95C880")]
    public interface ITestInterface
    {
       [DispId(1)]
       void Test();
    }

希望这会有所帮助,问候

于 2009-12-08T07:02:43.827 回答
0

很多可能的原因:

  1. .Net Label 控件在发现它没有 WinForms 父级时会爆炸。
  2. 由于不正确的 Z 顺序,本机状态栏正在绘制标签控件。
  3. 标签控件不可见。
于 2009-12-08T04:34:21.707 回答
0

事实证明,答案非常简单……标签的 X 和 Y 坐标超出了状态栏父级的显示区域。将它们移动到 (0, 0),它就会出现在那里!当然,现在问题已经转移到:.Net COM Server 中的 C# WinForms 控件不会重绘

于 2009-12-21T21:34:21.990 回答