-2

我对 C# 很陌生,但我一直在玩它来学习。到目前为止,我有一个不错的应用程序,它可以执行诸如启动屏幕保护程序和控制 Windows 系统音量之类的操作。

但是我遇到了一些麻烦,我不确定出了什么问题。我已经在网站上经历了一堆类似的问题,但我认为其中任何一个都不适用于我的具体案例。

所以我想从网络控制应用程序。我的计划是让应用程序每隔几秒钟检查一次我网站上的网页是否有命令。根据网站返回的内容,应用程序将执行不同的操作(静音、音量增大等)并将网站上的命令重置为空白。网站命令部分全部用PHP完成,非常简单,那部分没有问题。

我创建了一个按钮,该按钮调用一个检查页面并执行操作的函数。它工作得很好。但是当我试图让它自动检查网站时,我遇到了错误。我很确定这是因为我将检查和执行操作移到了一个新线程。所以让我们继续看代码。这些不是完整的文件,但我认为您需要知道以提供帮助。如果您需要更多信息,请告诉我。

Form1.cs

public Form1(Boolean init = true)
    {
        if (init)
        {
            InitializeComponent(); //initialize UI
            startWebMonitor(); //starts web monitor thread for remote web commands
        }
    }

private void startWebMonitor()
    {
        Thread t = new Thread(WebMonitor.doWork);
        t.Start();
    }

public IntPtr getWindowHandle()
    {
        return this.Handle;
    }

WebMonitor.cs

public static void doWork()
    {
        while(true)
        {
            checkForUpdate();
            Thread.Sleep(1000);
        }
    }

private static void checkForUpdate()
    {
        lastCommand = getLastCommand();

        if (lastCommand.Equals(""))
        {
            //No Update
        }
        else
        {
            processCommand(lastCommand);
        }
    }

public static void processCommand(String command)
    {
        if(command.Equals("mute"))
        {
            VolumeCtrl.mute(Program.form1.getWindowHandle());
        }

        HTTPGet req2 = new HTTPGet();
        req2.Request("http://mywebsite.com/commands.php?do=clearcommand");
    }

VolumeCtrl.cs

private static IntPtr getWindowHandle()
    {
        Form1 form1 = new Form1(false); //false = do not initialize UI again
        return form1.getWindowHandle();
    }

    public static void mute(IntPtr handle)
    {
        SendMessageW(getWindowHandle(), WM_APPCOMMAND, getWindowHandle(), (IntPtr)APPCOMMAND_VOLUME_MUTE);
    }

好吧,基本上静音功能需要窗口句柄才能工作。但是当我尝试从新线程获取窗口句柄时,它会抛出错误:

跨线程操作无效:控件“Form1”从创建它的线程以外的线程访问。

那么我该如何解决呢?我在这里阅读了其他答案,说您需要使用 Invoke 或 Delegate,但我不确定它们是如何工作的或在哪里使用它们。我试图遵循其中一个答案,但我遇到了更多错误。

4

2 回答 2

2

在这种情况下,在方法内部编写调用操作。然后您可以从控件的线程和其他线程访问。

delegate IntPtr GetWindowHandleDelegate();

private IntPtr GetWindowHandle() {

    if (this.InvokeRequired) {

        return (IntPtr)this.Invoke((GetWindowHandleDelegate)delegate() {

            return GetWindowHandle();

        });
    }

    return this.Handle;
}

或者,如果您想避免委托地狱,您可以使用内置委托和 lambda 编写更多代码。

private IntPtr GetWindowHandle() {
    if (this.InvokeRequired)
        return (IntPtr)this.Invoke((Func<IntPtr>)(GetWindowHandle));

    return this.Handle;
}
于 2013-04-16T16:10:42.360 回答
0

试试这个代码它肯定会帮助你

BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (s, e) => { };
bw.RunWorkerCompleted += (s, e) => 
 {
  //Call you windowsform method or anything which you want to do
 };
bw.RunWorkerAsync();
于 2015-04-10T09:39:48.633 回答