0

タイトルの実際の問題について何らかの指示を出したはずですが、それが何であるかわかりません。私が言えることは、アプリバーを実装するときに、変数に値を代入しようとするとフォームが応答しなくなるため、デスクトップの作業領域を取り戻すためにデバッグを停止してマシンを再起動する必要があるということだけです。エラーの場所は以下のコードに記載されています。エラーの発生箇所までのコードのみを記載しています。ここで私が見ていない露骨に明白なものはありますか?

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

public partial class Form1 : AppBar
{
    public Form1() : base()
    {
        InitializeComponent();
    }

    //This is a button on the test form.
    //When clicked, the form should become a desktop application bar
    //docked to the top of the desktop.
    private void t_Click(object sender, EventArgs e)
    {
        base.SET_APPBAR();
    }
}

public class AppBar : Form
{
    protected internal Size appbarSize;
    protected internal Point appbarLocation;
    protected internal bool appbarMode;
    private EDGES appbarEdge;
    private RECT appbarRect;

    private uint ID { get; private set; }
    private IntPtr HANDLE { get; private set; }

    //constructor
    public AppBar() : base () //no issues here
    {
        appbarEdge = EDGES.ABE_TOP;
        appbarRect = new RECT();
        ID = 0;
        HANDLE = this.Handle;
        appbarMode = false;
    }

    protected internal void SET_APPBAR()
    {
        if (IS_NEW())
        {
            QUERY_AND_SET_POSITION(ref appbarRect); //Never get to here
        }
    }

    private bool IS_NEW()
    {
        if (appbarMode) //so far, so good
        {
            return false;
        }
        while (ID == 0) 
        {
            CREATE_ID(); //ID is created, I have verified this.
        }
        this.FormBorderStyle = FormBorderStyle.FixedToolWindow; //BorderStyle does change
        appbarSize = this.Size; //Size is correct
        appbarLocation = this.Location; //still no issues
        NEW(); //this is where the error begins (see code further down)
        return appbarMode; //Never get here
    }

    private void CREATE_ID()
    {
        ID = Hooks.RegisterWindowMessage(Guid.NewGuid().ToString());
    }

    private void QUERY_AND_SET_POSITION(ref RECT appbarRect)
    {
        SET_APPBAR_SIZE(ref appbarRect);
        QUERY_POS(ref appbarRect);
        APPBAR_RESIZE(ref appbarRect);
        SET_POS(ref appbarRect);
        this.Location = new Point(appbarRect.left, appbarRect.top);
        appbarSize = new Size(appbarRect.right - appbarRect.left, appbarRect.bottom - appbarRect.top);
        this.Size = appbarSize;
    }

    private void SET_APPBAR_SIZE(ref RECT appbarRect)
    {
        switch (appbarEdge)
        {
            case (EDGES.ABE_BOTTOM):
                appbarRect.left = 0;
                appbarRect.right = SystemInformation.PrimaryMonitorSize.Width;
                appbarRect.top = SystemInformation.PrimaryMonitorSize.Height - appbarSize.Height;
                appbarRect.bottom = SystemInformation.PrimaryMonitorSize.Height;
                break;
            case (EDGES.ABE_LEFT):
                appbarRect.left = 0;
                appbarRect.right = appbarSize.Width;
                appbarRect.top = 0;
                appbarRect.bottom = SystemInformation.PrimaryMonitorSize.Height;
                break;
            case (EDGES.ABE_RIGHT):
                appbarRect.left = SystemInformation.PrimaryMonitorSize.Width - appbarSize.Width;
                appbarRect.right = SystemInformation.PrimaryMonitorSize.Width;
                appbarRect.top = 0;
                appbarRect.bottom = SystemInformation.PrimaryMonitorSize.Height;
                break;
            default:
                appbarRect.left = 0;
                appbarRect.right = SystemInformation.PrimaryMonitorSize.Width;
                appbarRect.top = SystemInformation.WorkingArea.Top;
                appbarRect.bottom = appbarSize.Height;
                break;
        }
    }

    private void APPBAR_RESIZE(ref RECT appbarRect)
    {
        switch (appbarEdge)
        {
            case (EDGES.ABE_TOP):
                appbarRect.bottom = appbarRect.top + appbarSize.Height;
                break;
            case (EDGES.ABE_BOTTOM):
                appbarRect.top = appbarRect.bottom - appbarSize.Height;
                break;
            case (EDGES.ABE_LEFT):
                appbarRect.right = appbarRect.left + appbarSize.Width;
                break;
            case (EDGES.ABE_RIGHT):
                appbarRect.left = appbarRect.right - appbarSize.Width;
                break;
        }
    }

    private void APPBAR_CALLBACK(ref Message apiMessage)
    {
        switch ((NOTIFICATIONS)(uint)apiMessage.WParam)//? on int vs uint here
        {
            case (NOTIFICATIONS.ABN_STATECHANGE):
                STATE_CHANGE();
                break;
            case (NOTIFICATIONS.ABN_POSCHANGED):
                QUERY_AND_SET_POSITION(ref appbarRect);
                break;
            case (NOTIFICATIONS.ABN_FULLSCREENAPP):
                if ((int)apiMessage.LParam != 0)
                {
                    this.SendToBack();
                    this.TopMost = false;
                }
                else
                {
                    STATE_CHANGE();
                }
                break;
            case (NOTIFICATIONS.ABN_WINDOWARRANGE):
                //first call
                if ((int)apiMessage.LParam != 0)
                {
                    this.Visible = false;
                }
                //second call
                else
                {
                    this.Visible = true;
                }
                break;
        }
    }

    protected override void WndProc(ref Message apiMessage)
    {
        if (appbarMode)
        {
            if (HANDLE == apiMessage.HWnd)
            {
                APPBAR_CALLBACK(ref apiMessage);
            }
            else if (apiMessage.Msg == (int)API_MESSAGES.WM_ACTIVATE)
            {
                ACTIVATE();
            }
            else if (apiMessage.Msg == (int)API_MESSAGES.WM_WINDOWPOSCHANGED)
            {
                WINDOW_POS_CHANGED();
            }
        }
        base.WndProc(ref apiMessage);
    }

    private void NEW()
    {
        APPBARDATA data = new APPBARDATA(); //no apparent issue
        data.cbSize = (uint)Marshal.SizeOf(data); //no apparent issue
        data.hWnd = HANDLE; //no apparent issue
        data.uCallbackMessage = ID; //no apparent issue
        if (Hooks.SHAppBarMessage((uint)DWORD.ABM_NEW, ref data) != 0) //SHAppBar returns 1 (true)
        {
            //no issue if I were to place a MessageBox here
            appbarMode = true; // why in the world is this causing an issue?????
            //can't do anything from this point
        }
    }
}

public static class Hooks
{
    [DllImport("shell32.dll", EntryPoint = "SHAppBarMessage")]
    public static extern uint SHAppBarMessage(uint dwMessage, ref APPBARDATA pData);

    [DllImport("user32.dll", EntryPoint = "RegisterWindowMessage")]
    public static extern uint RegisterWindowMessage(
        [MarshalAs(UnmanagedType.LPTStr)]
        string lpString);
}

問題が発生した後、ボタンをクリックしたり、フォームを閉じたりすることはできません。デスクトップの作業領域は常に適切にサイズ変更されます。うまくいけば、これらすべてが誰かにとって意味のあるものになるでしょう。事前にご覧いただきありがとうございます。

4

1 に答える 1

3

問題は、UI スレッドで実行時間の長い操作を実行していることです。これにより、UI スレッドがブロックされ、他の処理 (ペイントの変更、ボタン クリックまたはマウス移動イベントへの応答など) が妨げられます。

バックグラウンド スレッドで実行時間の長い操作を実行する必要があります。これは手動で行うこともできますがBackgroundWorker、まさにこのアプリケーション向けに設計されているため、 を使用することをお勧めします。バックグラウンド スレッドを作成/構成するだけでなく、バ​​ックグラウンド タスクが完了したときに UI を更新するためのシンプルで使いやすいメカニズムを提供し、タスクの実行中に進行状況に応じて UI を更新します。

バックグラウンド スレッドでは、UI 要素にアクセスできないことに注意してください。UI スレッドからアクセスする必要があります。バックグラウンド タスクを開始する前に、UI から情報を取得するすべてのコードを移動し (後でローカル変数またはフィールドに保存する)、結果に基づいて UI を更新するすべてのコードを最後に移動する必要があります (RunWorkerCompletedを使用している場合はイベントBackgroundWorker)。DoWork以外のすべてのイベントBackgroundWorkerはすべて UI スレッドで実行されるため、UI コントロールにアクセスできます。

于 2012-12-07T18:35:29.037 に答える