1

さて、Googleは今夜私の友達ではありません...

スクリーンセーバー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));

そして、スタイルは最後の3つのトレースで同じであり、そのうちの2つはフォーム自体から値を取得する必要があります。私のネイティブ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 に答える