1

好吧,谷歌今晚不是我的朋友......

我有一个屏幕保护程序CC.Votd(Codeplex 上的完整源代码),并且我刚刚开始实现运行正常的预览模式(/p 参数)。当它处于预览模式时,我将我的表单设置为小计算机监视器窗口的子窗口,然后它会在那里绘制。

这工作正常,如果显示属性对话框消失,我的应用程序将退出。

问题是,如果我从列表中选择我的屏幕保护程序,然后选择不同的屏幕保护程序,我的会继续运行并绘制新选择的屏幕保护程序的预览。

那么我怎么知道何时选择了不同的屏幕保护程序并且我的应该关闭?


编辑:对于 Anon,这是我用来使我的表单成为预览窗口的子窗体的代码:

P/调用:

[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);

[DllImport("user32.dll")]
static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect);

编码:

SetParent(Handle, _PreviewHandle);
SetWindowLong(Handle, -16, new IntPtr(GetWindowLong(Handle, -16) | 0x40000000));

Rectangle parentRectangle;
GetClientRect(_PreviewHandle, out parentRectangle);
Size = parentRectangle.Size;

Location = new Point(0, 0);

完整的表单代码:http ://ccvotd.codeplex.com/SourceControl/changeset/view/40085#862458


忘了提及我尝试使用IsWindowVisible()但没有工作,因为预览窗口仍然可见并且与选择我的屏幕保护程序时具有相同的句柄。

编辑:在我添加SetParent()和关联调用之前,我的应用程序将在显示对话框关闭后继续运行,所以我认为该部分正在工作,并且当用户选择不同的屏幕保护程序时会发生不同的事情。


正如 John K 建议的那样,我一直在使用 Spy++ 查看我的表单。我从来没有看到应用了 WS_CHILD 样式。然而,我所有的调试都表明它应该是。我将代码修改为:

long style = GetWindowLong(Handle, -16);
System.Diagnostics.Trace.WriteLine("Original Style: " + style);
style &= ~0x800000000;
style |= 0x40000000;
System.Diagnostics.Trace.WriteLine("Adjusted Style: " + style);

SetWindowLong(Handle, -16, new IntPtr(style));
System.Diagnostics.Trace.WriteLine("After Set Style: " + GetWindowLong(Handle, -16));
SetParent(Handle, _PreviewHandle);
System.Diagnostics.Trace.WriteLine("After Set Parent: " + GetWindowLong(Handle, -16));

最后三个跟踪的样式相同,其中两个应该是从表单本身获取值。去研究我的原生 API 调用并清理它们的声明,看看我能弄清楚什么。

感谢您迄今为止的所有帮助!


解决方案:问题最终是我设置了表单的几个属性,导致底层 .NET 控件覆盖了我的新样式。所以改变:

SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);

Capture = true;

if (!_IsPreview)
{
    // Removed ...
}
else
{
    SetWindowLong(Handle, -16, new IntPtr(GetWindowLong(Handle, -16) | 0x40000000));
    SetParent(Handle, _PreviewHandle);

    Rectangle parentRectangle;
    GetClientRect(_PreviewHandle, out parentRectangle);
    Size = parentRectangle.Size;

    Location = new Point(0, 0);
}

ShowInTaskbar = false;
DoubleBuffered = true;
BackgroundImageLayout = ImageLayout.Stretch;

至:

SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);

BackgroundImageLayout = ImageLayout.Stretch;
Capture = true;
DoubleBuffered = true;
ShowInTaskbar = false;

if (!_IsPreview)
{
    // Removed ...
}
else
{
    SetWindowLong(Handle, -16, new IntPtr(GetWindowLong(Handle, -16) | 0x40000000));
    SetParent(Handle, _PreviewHandle);

    Rectangle parentRectangle;
    GetClientRect(_PreviewHandle, out parentRectangle);
    Size = parentRectangle.Size;

    Location = new Point(0, 0);
}

修复了问题。简单的错误:-)


解决它的正确方法...覆盖 CreateParams:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams createParams = base.CreateParams;

        if (!DesignMode && _IsPreview)
        {
            createParams.Style |= 0x40000000;
        }

        return createParams;
    }
}
4

1 回答 1

1

曾经尝试在窗口创建后更改其 WS_CHILD 样式只会悄悄地失败。我认为他们在当前版本的窗口中改变了这一点,但可以肯定的是,你应该从一开始就将预览表单创建为子窗口。

我有一种预感,您的窗口不会成为预览的子窗口。你可以试试这个。

SetParent(Handle, _PreviewHandle);
SetWindowLong(Handle, -16, new IntPtr(GetWindowLong(Handle, -16) | 0x40000000));
SetParent(Handle, _PreviewHandle);

将窗口样式更改为 WS_CHILD的SetParent 。

此外,您的表单上可能没有 WS_POPUP 样式,但如果有,您希望将其删除。

int style = GetWindowLong(Handle, -16);
style &= ~0x800000000;
style |= 0x40000000;
SetWindowLong(Handle, -16, new IntPtr(style));

这里发生的是 SetParent 设置子窗口的父级,但它设置了WS_POPUP 和 WS_OVERLAPPED 窗口的所有者

于 2010-02-08T03:19:44.663 回答