C# 怎么使用API设置按钮visible和Enable属性?

我现在有俩个程序,一个是客户端程序,就是用户使用的;还有一个是客户端的自动升级程序。在客户端启动的同时,自动升级程序会自动启动。自动启动程序中有一个按钮btnChange... 我现在有俩个程序,一个是客户端程序,就是用户使用的;还有一个是客户端的自动升级程序。在客户端启动的同时,自动升级程序会自动启动。
自动启动程序中有一个按钮btnChange,但是它的visible属性设为了false,并且Enable属性也设为了false(这是那个程序的需要,必须这样设置,而且这个程序的代码我没有);
自动升级程序的这个按钮,需要通过客户端的操作,来判断是否执行...如果需要执行了,也就是模拟点击那个按钮。( 注意,这完全是俩个不同的进程,不是同一个项目。) ,所以我认为要用到API...我想我只有通过API才能找到那个按钮的handle,然后再触发它的事件.事实上,我已经通过API找到了那个按钮,但是它是visible=false,并且Enable=false的。这样子,我用API就不能直接点击了,必须先设置它的visible和enable属性。

我应该怎样才能用API设置它的visible为true,并且Enable也为true呢?

应该使用哪几个API函数?

希望高手指点迷经...
-- 草剃在: Control.FormHandle我试过了 没用啊

-- pythonercn:我这不是多线程的问题,而是不同进程之间的通信.. 同时也谢谢你拷贝了这么多过来,呵呵

-- lily_blues:自动升级的程序,是C++写的...所以...
我最开始就是使用这俩个函数的,但是没有效果,所以我很困惑...
ShowWindow(hWnd, 1);
EnableWindow(hWnd, true);
展开
 我来答
pythonercn
2010-07-09 · TA获得超过146个赞
知道小有建树答主
回答量:102
采纳率:0%
帮助的人:137万
展开全部
.net 2.0以后加强了安全机制,不允许在winform中直接跨线程访问控件的属性。那么怎么解决这个问题呢,下面提供几种方案。

第一种方案,我们在Form1_Load()方法中加一句代码:

private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
Thread thread = new Thread(ThreadFuntion);
thread.IsBackground = true;
thread.Start();
}
加入这句代码以后发现程序可以正常运行了。这句代码就是说在这个类中我们不检查跨线程的调用是否合法(如果没有加这句话运行也没有异常,那么说明系统以及默认的采用了不检查的方式)。然而,这种方法不可取。我们查看CheckForIllegalCrossThreadCalls 这个属性的定义,就会发现它是一个static的,也就是说无论我们在项目的什么地方修改了这个值,他就会在全局起作用。而且像这种跨线程访问是否存在异常,我们通常都会去检查。如果项目中其他人修改了这个属性,那么我们的方案就失败了,我们要采取另外的方案。

下面来看第二种方案,就是使用delegate和invoke来从其他线程中控制控件信息。网上有很多人写了这种控制方式,然而我看了很多这种帖子,表明上看来是没有什么问题的,但是实际上并没有解决这个问题,首先来看网络上的那种不完善的方式:

public partial class Form1 : Form
{
private delegate void FlushClient();//代理
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(CrossThreadFlush);

thread.IsBackground=true;
thread.Start();
}

private void CrossThreadFlush()
{
//将代理绑定到方法
FlushClient fc = new FlushClient(ThreadFuntion);
this.BeginInvoke(fc);//调用代理
}
private void ThreadFuntion()
{
while (true)
{
this.textBox1.Text = DateTime.Now.ToString();
Thread.Sleep(1000);
}
}
}

使用这种方式我们可以看到跨线程访问的异常没有了。但是新问题出现了,界面没有响应了。为什么会出现这个问题,我们只是让新开的线程无限循环刷新,理论上应该不会对主线程产生影响的。其实不然,这种方式其实相当于把这个新开的线程“注入”到了主控制线程中,它取得了主线程的控制。只要这个线程不返回,那么主线程将永远都无法响应。就算新开的线程中不使用无限循环,使可以返回了。这种方式的使用多线程也失去了它本来的意义。

现在来让我们看看推荐的解决方案:

public partial class Form1 : Form
{
private delegate void FlushClient();//代理
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(CrossThreadFlush);
thread.IsBackground = true;
thread.Start();
}

private void CrossThreadFlush()
{
while (true)
{
//将sleep和无限循环放在等待异步的外面
Thread.Sleep(1000);
ThreadFunction();
}
}
private void ThreadFunction()
{
if (this.textBox1.InvokeRequired)//等待异步
{
FlushClient fc = new FlushClient(ThreadFunction);
this.Invoke(fc);//通过代理调用刷新方法
}
else
{
this.textBox1.Text = DateTime.Now.ToString();
}
}
}

运行上述代码,我们可以看到问题已经被解决了,通过等待异步,我们就不会总是持有主线程的控制,这样就可以在不发生跨线程调用异常的情况下完成多线程对winform多线程控件的控制了。

对于深山老林提出的问题,我最近找到了更优的解决方案,利用了delegate的异步调用,大家可以看看:

public partial class Form1 : Form
{
private delegate void FlushClient();//代理
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(CrossThreadFlush);
thread.IsBackground = true;
thread.Start();
}

private void CrossThreadFlush()
{

FlushClient=new FlushClient(ThreadFunction);

FlushClient.BeginInvoke(null,null);
}
private void ThreadFunction()
{

while (true)
{
this.textBox1.Text = DateTime.Now.ToString();
Thread.Sleep(1000);
}

}
}

这种方法也可以直接简化为(因为delegate的异步就是开了一个异步线程):

public partial class Form1 : Form
{
private delegate void FlushClient();//代理
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(CrossThreadFlush);
FlushClient=new FlushClient(ThreadFunction);

FlushClient.BeginInvoke(null,null);
}

private void ThreadFunction()
{

while (true)
{
this.textBox1.Text = DateTime.Now.ToString();
Thread.Sleep(1000);
}

}
}
lily_blues
2010-07-10 · TA获得超过6468个赞
知道大有可为答主
回答量:1279
采纳率:0%
帮助的人:1732万
展开全部
如果自动升级程序也是C#写的,并且你没法修改它代码的话……

MSDN Magazine 2006 四月刊上曾经发表过一篇关于 .NET 下的Spy++工具ManagedSpy,其中就涉及到了跨进程修改其他WinForm应用程序控件属性的的技术,并且有完整源码下载。但是比较复杂,还需要一个C++写的库ManagedSpyLib(也有源码)来配合——主要是因为还需要使用钩子来注入代码到目标应用程序中去等。

我下载编译调试通过了,的确可以修改其它进程WinForm控件的属性(比如设置按钮的Visible及Enabled属性)。

最关键的是引用那个C++写的ManagedSpyLib库之后,使用类似下面的代码即可修改其它进程控件的属性了:

namespace ManagedSpyTester
{
using System.Diagnostics;
using Microsoft.ManagedSpy;

class Program
{
static void Main()
{
Process[] p = Process.GetProcessesByName("MyAutoUpdate");

if (p.Length == 0)
{
return;
}

ControlProxy proxy = ControlProxy.FromHandle(p[0].MainWindowHandle);
foreach (ControlProxy child in proxy.Children)
{
if (child.GetComponentName() == "btnChange")
{
child.SetValue("Enabled", true);
child.SetValue("Visible", true);
break;
}
}
}
}
}

不过ManagedSpyLib的代码如果想要在Vista/Win7(打开了UAC的情况下)正常运行,需要稍作修改(很小);而且要确保自动升级程序和客户端主程序是在同一个权限级别下运行(比如都是管理员身份或者都是非管理员身份),否则无法存取在另一个权限级别下运行进程的控件属性。此外,如果系统的.NET版本是3.5/4.0以上,也需要稍作改动(很小),因为它原来的代码假定的是2.0版本。

楼主可以先自己把代码下载下来试试用用看,如果不行可以再找我。

相关网址:http://msdn.microsoft.com/en-us/magazine/cc163617.aspx

___________________________
补充:

唉,是我想太多了,把问题弄复杂了。因为Visible和Enabled都是最基本的窗口属性,所以实际上用基本的Windows API就可以搞定了。

先添加下面几句话:
[DllImport("user32.dll")]
static extern bool EnableWindow(IntPtr hWnd, bool bEnable);

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

然后在你拿到按钮的窗口句柄hWnd之后,加入如下代码:

ShowWindow(hWnd, 1);
EnableWindow(hWnd, true);

所以这样的说的话,应该是采纳“坂井悠二の阴谋”这位朋友的答案,是他先提出了使用这两个API的主意。

————————————
补充:
会不会是hWnd找错了?要不你用Spy++抓一下那个按钮看看……
我这边做了一个简单的试验,是可行的。

哦,也有可能是这个原因:
你用的Windows是什么版本?如果是Vista、Win7或者Win2008,而且UAC默认是开启的话,那么如果自动升级程序是“以管理员身份运行”而你的客户端程序不是(或者正好相反的情形),那此时EnableWindow和ShowWindow是没有效果的。也就是两个程序必须运行在同一个安全级别下面。这应该是Vista和Win7上UAC的User Interface Privilege Isolation(UIPI)保护的结果,防止低安全级别的恶意应用篡改高安全级别应用的状态。

不过,也只是我的猜想罢了,楼主可以自己试验一下看看。
本回答被提问者采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
草薙在
2010-07-09 · TA获得超过4795个赞
知道大有可为答主
回答量:6187
采纳率:50%
帮助的人:6328万
展开全部
这么高的分都没人回答

你既然能找到Handle,那你可以用Control.FormHandle获取控件看看,然后转换成Button再设置,我不确保可以

不过你最好做进程通信,通过Process类或者用.Net Remoting AppDomain会比较好,当然你用windows窗体消息交互也可以

补充:
那你要用一些进程间通信的手段了,最好不要直接操作控件
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
荔菲彭泽07
2010-07-10 · TA获得超过725个赞
知道小有建树答主
回答量:505
采纳率:0%
帮助的人:694万
展开全部
用这两个API
EnableWindow---设置窗口是否可用
ShowWindowAsync----隐藏或显示窗口
使用方法可以去网上查,很简单的两个函数。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
mwtcz
2010-07-10 · TA获得超过1322个赞
知道小有建树答主
回答量:1367
采纳率:50%
帮助的人:1034万
展开全部
继续研究,如果你先有结果也请交流一下,我对这个问题也挺感兴趣地。

顺便问一句,那个带按钮的程序,是c#的吗?
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 更多回答(3)
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式