首页 新闻 会员 周边 捐助

WinForm设置ShowInTaskBar=false无法正常执行API

0
[已关闭问题]

程序只启动一个窗口,如果再次启动则激活以前运行的窗口,大部分功能我已经实现,但是如果设置ShowInTaskBar为false就运行不正常了,经过测试问题如下:

winForm中如果设置ShowInTaskBar为false,API函数为什么不能正常的执行?如果为true运行正常。

还有一个问题,

winForm中如果设置ShowInTaskBar为false,使用process.MainWindowHandle窗口句柄为0,如果设置为true,也就是显示任务栏按钮,可以得到窗口句柄。已经通过使用api得到窗口句柄了,但是其它的api函数还是运行不正常。

详细可以参考:

http://www.cnblogs.com/houleixx/archive/2008/04/15/StartOnly.html

 

侯垒的主页 侯垒 | 老鸟四级 | 园豆:3435
提问于:2009-08-20 10:33
< >
分享
其他回答(2)
0

没具体看,你那个参考link偶打不开~ >_<

不过大概应该是下面这样~

---------------------------------

.NET中,把调用调用放在UI线程里执行是通过Form类及其子类的Invoke()方法实现的(具体的过程请参考其他资料),可以这样做是因为Form对象保存了创建它的线程的信息,而且Form类有一个bool类型的属性InvokeRequired,可以通过它查看当前线程是否为创建该Form对象的线程(UI线程)——如果为true,则表示当前线程不是UI线程,反之则是。下面提供一个例子:

 

using System.Threading;

 

using System.Windows.Forms;

 

 

 

namespace csharpTest

 

{

 

     public class TestForm : Form

 

     {

 

         private Form form1;

 

         private Form form2;

 

 

 

         public static void Main()

 

         {

 

              TestForm tf = new TestForm();

 

              tf.Show();

 

              tf.UIThread();

 

              Application.Run();

 

         }

 

 

 

         public void UIThread()

 

         {

 

              form1 = new Form();

 

              form2 = new Form();

 

              form2.Show();//这里是关键

 

              form1.Show();

 

              Thread thread = new Thread(new ThreadStart(WorkerThread));

 

              thread.Start();

 

         }

 

 

 

         public void WorkerThread()

 

         {

 

              if (form2.InvokeRequired)

 

                   form2.Invoke(new MethodInvoker(WorkerThread));

 

              else

 

              {

 

                   form1.Text = "This is from WorkerThread.";

 

              }

 

         }

 

 

 

         protected override void OnClosing(System.ComponentModel.CancelEventArgs e)

 

         {

 

              base.OnClosing (e);

 

              Application.Exit();

 

         }

 

     }

 

}

 

TestForm里有两个需要注意的方法,UIThread——用来模拟UI线程,WorkerThread——用来模拟用户线程,UIThread中实例化了成员form1form2并调用了它们的Show方法,在WorkerThread中改变form1Text属性。请注意WorkerThread里有个技巧, if (form2.InvokeRequired) 即如果当前线程不是创建该form2的线程,则将方法通通过过Invoke方法放到UI线程里去执行。但就是这里问题出现了form1form2都是在UIThread里建立的,所以它们保存的线程的信息应该是一样的。所以form1.InvokeRquiredform2.InvokeRquired的值在任何线程里都是一样的,即在WorkerThreadInvokeRquire的值都应该是true(因为在不同的线程里)。但是如果注释掉form2.Show()的话form2.InvokeRquiredWorkerThread中的值却是false(在vs.net中调试看到),怎么会这样呢?而且如果不经过判断直接在WorkerThread里调用form2对象的Invoke的话…………居然会抛出异常——“在创建窗口句柄之前,不能在控件上调用 Invoke InvokeAsync (偶猜你就是这种问题吧~~~ hoho)

 

分析一下该异常的信息,在win32里每一个窗体都有一个窗体句柄,是该窗体在建立时系统分配的,但我们确实在UI线程里建立了form2对象的。这里有个误区.Net里的Form对象并不是和win32的窗体对象完全对应的。本人窃以为,产生一个Form类的实例时,只是产生了一个内存中的普通的对象,并不产生系统窗体(好像叫做User对象吧),只有它第一次呈现在屏幕上(或称作创建)时,才产生系统里表示窗体的User对象且分配句柄,对应的WIN32 APICreateWindow()方法大概也在这个时候执行(先声明:本人对WIN32 API 并不熟悉,虽然曾经在Microsoft里混过一段时间)

 

只有.NET里的form对象调用某种方法使系统产生真正的窗体时,form才会有创建它的线程的信息,且InvokeRquired才有效,即才能调用formInvoke方法。不过我还没弄清楚哪几个方法可以做到。据我所知Show, CreateGraphics可以产生系统真正的系统窗体。

在Window窗体程序开发的时候,如果使用多线程编程,在子线程中访问主线程窗体内的控件,就需要使用控件的Control.Invoke方法或者BeginInvoke方法。但是有时候因为Window执行速度太快,尤其是你写代码的时候在InitializeComponent();完成之前起了一个线程去执行某些操作,涉及到窗体控件的,当你在调用
Control.Invoke的时候,就可能出现 “在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke”错误。

解决的办法就是让线程等待,直到窗口句柄创建完毕:

               //防止在窗口句柄初始化之前就走到下面的代码
                while (!this.IsHandleCreated)
                {
                    ;
                }
                this.Invoke(new MethodWithoutParameter(LoadContactTemplate));

Gieno | 园豆:255 (菜鸟二级) | 2009-08-20 11:23
好像与我要的不太一样,我的现在是可以得到句柄,但是就是执行API的时候,如果ShowInTaskBar=false不能正常执行,执行没有结果。
支持(0) 反对(0) 侯垒 | 园豆:3435 (老鸟四级) | 2009-08-20 15:26
0

IntPtr handler = FindWindow(null, "Form1");

MainWindowHandle 是空,说前 MainWindow就是空了,MainWindowTitle当然就是空的,你用窗口标题名就OK,我测试了。

skyedge | 园豆:275 (菜鸟二级) | 2009-08-28 19:21
0

ShowInTaskBar=false;不能执行API,是转为 false时句柄发生了改变,变为true时又会发生改变。

只需要重新获取下 句柄就可以了。

小草旁的大树 | 园豆:199 (初学一级) | 2013-04-07 18:50
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册