如何从已知应用程序的实例句柄推出它的App类实例?
小弟新来,请多关照
我知道从应用程序中取它的实例采用AfxGetInstanceHandle
现在我已经采用GetWindowLong(HWnd,GWL_HINSTANCE)得到了该应用程序的句柄,如何调用App类的函数呢?
谢谢!
问题点数:20、回复次数:31Top
1 楼fengqinggao(风清高)回复于 2005-02-01 01:19:41 得分 5
直接用AfxGetApp()函数就可以得到App类的指针,也就可以直接使用App类的函数了
另外一种方法是包含App类的头函数,声明外部变量theApp,就用theApp调用也一样Top
2 楼NewVC1978(新手学VC)回复于 2005-02-01 11:55:51 得分 0
我知道呀,这个问题是这样的,我在研究WORD2000的窗口形式,发现这样的问题:
WORD2000在进程中只启动一个实例,于是我想模仿这个行为.
我在应用程序主窗口中加入了 ::SetProp(m_hWnd, theApp.m_pszAppName, (HANDLE)1);
并且想在第二份实例启动的时刻,根据该Prop获得第一个实例的app指针,现在能获得的只是CMainFrame的句柄,并且该句柄也只能得到临时窗口对象,无法调用第一个实例的CWinApp::OnNewFile()函数.
我想通过GetWindowLong得到第一份实例的HINSTANCE,然后=>theApp对象,调用其中的方法,不知道是否可行?
这就是问题的所在,有空我把代码整理一下,发给你帮我看看行吗?
Top
3 楼fengqinggao(风清高)回复于 2005-02-01 13:02:07 得分 0
呵呵,根据帖子主题的内容,没有看出你要实现这么高级的功能,:)
如何获取App,先不说,假定能实现,用OnNewFile也只能新建文件,如果是MDI就是新建文档和视图,不能新建框架,所以也不能实现类似WORD的功能
不过可以研究研究,呵呵,网上应该有这样的资料,我的EMAIL是fqg76@163.com,可以发过来看看,呵呵,不过能否解决问题就难说了Top
4 楼xuzheng318(忧郁王子)回复于 2005-02-01 13:10:15 得分 3
// Print the application's executable filename.
TRACE("Executable filename = %s\n", AfxGetApp()->m_pszExeName);
Top
5 楼NewVC1978(新手学VC)回复于 2005-02-01 13:30:31 得分 0
fengqinggao的第二份回答,首先在这里表示感谢,当然你的第二段是正确的,不过我把CChildFrame的基类修改成为CFrameWnd,那么情况就不一样了,总之其它的基本都实现了,就是这个单一实例的模拟上出现了问题.
xuzheng318我没看出你的答案有什么意思.Top
6 楼shenailin(sal)回复于 2005-02-01 13:41:20 得分 2
我也想过这个问题, 可是没有去实现过, 希望楼主最后来个总结 !
然大家来学习学习 !Top
7 楼fengqinggao(风清高)回复于 2005-02-01 14:13:55 得分 0
那就弄个偷懒的方法,在CMainFrame类里建一个函数,调用App类的函数吧,可以试一试Top
8 楼dandycheung(珠穆朗玛)回复于 2005-02-01 14:28:44 得分 6
先说一下一些基本概念。Office 系列软件的后期版本以及 IE 的后期版本,采用了一种称为 MSDI 的界面,而不是使用传统的 SDI 和 MDI。这种界面的特点是一个应用程序有平级的多个主窗口,在最后一个主窗口被关闭时程序退出,而且,通常每个主窗口都在一个单独的线程中。
以下的讨论基于楼主想达到同样的效果的前提。
首先,楼主有一点认识上的错误,导致你的解决思路不正确。
假设你的应用已经有一个实例在运行,当第二个实例运行时,这时它们之间的交互属于进程间交互,也就是说,你希望在第二个实例中根据第一个进程的实例句柄构建一个可供操作的 App 对象是很困难的,况且,HINSTANCE 值在进程之间的传递几乎没有任何意义,通常两个进程的 HINSTANCE 数值是相等的,这一点的根源由来已久,并非三言两语可以说清楚。所以,解决办法应该是第二个进程一旦发现有第一个进程存在,则通过某种通知行为使第一个进程自己产生新的主窗口。在 Windows 的世界里,这种通知机制,无疑应该选用最便捷的消息机制。
简而言之,流程如下:
1、a.exe 运行,创建了主窗口 A,约定以下称此进程为 a.exe(1)
2、再次运行 a.exe,约定以下称此进程为 a.exe(2);该进程发现已经有一个 a.exe(1) 存在,而且找到了 a.exe(1) 的主窗口 A
3、a.exe(2) 向窗口 A 发送一条消息,例如消息名为 WM_MY_CREATEWND,a.exe(2) 退出
4、a.exe(1) 的主窗口 A 在收到 WM_MY_CREATEWND 消息后,生成新的主窗口 B。
Top
9 楼dandycheung(珠穆朗玛)回复于 2005-02-01 14:30:31 得分 0
另外补充一下,如果你用 WTL,则可以直接生成 MSDI 类型的应用程序,和你的要求略有不同的是默认并没有限制只启动一个实例。Top
10 楼fengqinggao(风清高)回复于 2005-02-01 14:48:19 得分 0
总体来讲,楼上的思路和楼主的还是很类似的,只是一个是想调用函数,一个是发消息,应该都可以实现,后者当然更灵活些
不过楼上说的,很有水准,学习!Top
11 楼dandycheung(珠穆朗玛)回复于 2005-02-01 15:30:18 得分 0
楼上说的很对,思路的确类似,但是落在实际中却有很大的差别。其根本的差异在于以下事实:无论是调用函数,还是发送消息,我们其实都已经承认一个隐含的前提,那就是最终任务的执行是有一个实体的,如果调用函数,那么实体就是一个对象,或者是对象封装的句柄;使用消息,则实体是一个窗口。不幸的是,在 Windows 里,HINSTANCE 本身并没有任何可以激活的行为功能,而 CWinApp 其实又不是 HINSTANCE 的封装物,况且在不同的进程中传递是没有意义的,由此导致无从操纵前一个程序,窗口不存在这一问题。
难道我真的老了吗?好像越来越喜欢唠叨了!:-)Top
12 楼NewVC1978(新手学VC)回复于 2005-02-01 18:26:59 得分 0
dangdycheung大虾的发言很有水平,功底不错,不过被fengqinggao前辈一语道破,
事实上很难讲发消息与调函数哪个更加具有灵活性,这里存在的问题在于:
"现在能获得的只是CMainFrame的句柄,并且该句柄也只能得到临时窗口对象,无法调用第一个实例的CWinApp::OnNewFile()函数."
在操作的过程中,我试着向得到的窗口句柄发送自定义消息(进程间通讯),但出现了错误,也许我这种调用方式没有跨越进程的权限,接下来请问哪个高手告诉我如何正确地向第一个进程发送消息?
或许问题就可以迎刃而解了.
Top
13 楼dandycheung(珠穆朗玛)回复于 2005-02-01 19:37:33 得分 0
TO 楼主:你是(新手学VC) ,还没有达到透过现象看本质的地步。呵呵。Top
14 楼NewVC1978(新手学VC)回复于 2005-02-01 23:39:59 得分 0
dangdycheung大虾有时间给上上课吧,小弟不才,临时申请了一个帐号而已,让你见笑了.
等会儿我给风大虾发个邮件,看看他能否解决吧.Top
15 楼fengqinggao(风清高)回复于 2005-02-02 00:03:03 得分 0
呵呵,回复我早就看了,一直在考虑,想来我也一直处于只看到了现象的阶段,感觉的确有些麻烦:
1、对于调用函数:
用CWnd::FromHandle()获取主窗口的CWnd的指针,然后用CMainFrame强制转换,不知道行不行;
2、对于发送消息:
那就是用常用的发送消息的方法了,具体如何操作,不是很清楚;
3、新想法:上两者的结合:
获取CMainFrame的指针后,获取它的菜单,然后给菜单发送消息,执行那个函数;
对于第三种方法,原来做过,对Notepad是成功的,对WORD是不成功的,可能就是如dangdycheung兄所说的采用的机制不一样,你的不知道属于哪一种,呵呵Top
16 楼dandycheung(珠穆朗玛)回复于 2005-02-02 09:01:49 得分 0
如果有时间,我可以试着做一个演示程序。不过预先说明,程序会是用 SDK 写的,如果不需要,还请提前通知我。我的 MSN messenger:dandycheung@hotmail.com,请在添加联系人成功后自我介绍一下先。Top
17 楼NewVC1978(新手学VC)回复于 2005-02-02 11:43:48 得分 0
dangdycheung兄台厉害,如果你真的拿SDK写出来,那真是厉害了
基本上采用MFC我已经完成了,不过有个小bug,
就是在全部窗口最小化时候,我的第二份窗口在打开后只在任务栏显示焦点,桌面上并没有显示
请教两位如何发送系统消息,让桌面取消全部最小化,
也就是Win+M键的功能.
Top
18 楼NewVC1978(新手学VC)回复于 2005-02-02 11:45:03 得分 0
刚才错了,全部最小化时 Win+D 快捷键Top
19 楼dandycheung(珠穆朗玛)回复于 2005-02-02 12:29:43 得分 0
广播消息也是用 SendMessage 发出,但目标窗口是 HWND_BROADCASTTop
20 楼NewVC1978(新手学VC)回复于 2005-02-02 12:34:51 得分 0
哦,我知道广播消息,但是不知道如何发送类似 Win+D 按键消息啊!Top
21 楼NewVC1978(新手学VC)回复于 2005-02-02 12:57:04 得分 0
// 以下函数在已存在一个实例的情况下触发
void CMainFrame::OpenChildFrame()
{
POSITION ps = theApp.GetFirstDocTemplatePosition();
ASSERT(ps != NULL);
CDocTemplate * pDocTemplate = theApp.GetNextDocTemplate(ps);
CDocument *pDoc = pDocTemplate->OpenDocumentFile(NULL); // good this can open null
ps = pDoc->GetFirstViewPosition();
CView *pView = pDoc->GetNextView(ps);
/*
* 存在问题:当桌面最小化时,无法将新建窗口显示在最前面
* 现象:任务栏当前打开窗口有焦点,但是桌面没有显示
*/
GetActiveFrame()->BringWindowToTop(); // <===>::BringWindowToTop(m_hWnd);
// pView->GetParentFrame()->ShowWindow(SW_SHOW);
// pView->GetParentFrame()->UpdateWindow();
// GetActiveFrame()->BringWindowToTop();
// pView->GetParentFrame()->BringWindowToTop();
//-MDIActivate(pView->GetParentFrame());
//-pView->GetParentFrame()->SetForegroundWindow();
//-GetActiveFrame()->SetForegroundWindow();
//-::SetForegroundWindow(m_hWnd);
}
Top
22 楼dandycheung(珠穆朗玛)回复于 2005-02-02 12:59:07 得分 0
消息就是让他们全部最小化。WM_SYSCOMMAND/SC_MINIMIZE。Top
23 楼llihua(Hill)回复于 2005-02-02 13:34:32 得分 3
研究这种新的文档界面挺有意义的,从《Microsoft Visual C++ .NET 技术内幕(第6版)》一书中摘些话来,大家来讨论讨论吧:
“Windows 2000又引入了第三种应用程序类型:多顶级文档界面(MTI, Multiple Top-Level Interface)应用程序。这也正是被Office 2000和Office XP应用程序率先采用的界面类型。MTI应用程序与SDI应用程序很相似,但是,SDI应用程序以独立的窗口来运行,每个打开的窗口都有一个应用程序实例,而MTI应用程序对于所有打开的窗口都共享同一个实例。当用户创建一个新的文件的时候,应用程序打开一个新的独立的顶级窗口,以及与之相关联的新文档,但是它们都与同一个正在运行的应用程序实例关联。”
“与MDI和SDI应用程序不同的是,MTI应用程序的File菜单中包含了一个New Frame命令,该命令告诉应用程序打开一个新的顶级窗口。下面的代码说明了New Frame命令的处理过程:(略)”
我用VC++ .NET 2003创建了一个MFC MTI应用程序。运行该程序后,可以从菜单中再新建出一个平级的主窗口。不过它并没有自然而然的解决这个问题:当再次运行程序时,检测到原进程,然后仅创建一个新主窗口(象Word2000那样)。而是简单地生成一个新程序进程,就象Excel2000那样。
大家再仔细研究Word2000和Excel2000,就会发现它们的行为其实是不同的!Word2000和Excel2000虽然都是多顶级文档(MTI),但Word2000在再次运行时仍然仅有一个进程,而Excel2000在再次运行时会新建一个进程。
Top
24 楼dandycheung(珠穆朗玛)回复于 2005-02-02 14:38:33 得分 0
Excel 2000 和 IE 的行为是一样,手动运行程序,则每次创建新的进程;如果用菜单创建新文档(或者新窗口),则创建一个新线程。WORD 只不过在第二个进程启动的时候把创建新文档的工作移交给了已有的进程而已。这已经不算是新的界面模式了,出现很久了。Top
25 楼NewVC1978(新手学VC)回复于 2005-02-02 15:31:08 得分 0
llihua(Hill) good多谢指明出处,
可惜手头只有第五版的垃圾书.Top
26 楼llihua(Hill)回复于 2005-02-03 10:30:12 得分 0
嗯,大家说得都有道理,这里其实是有两个问题。我说的文档界面问题已经是跑题了。
觉得“dandycheung(珠穆朗玛)”还是强人Top
27 楼JasonHeung(拥有一切不过就这样笑着哭)回复于 2005-02-03 10:59:35 得分 0
我知道呀,这个问题是这样的,我在研究WORD2000的窗口形式,发现这样的问题:
WORD2000在进程中只启动一个实例,于是我想模仿这个行为.
我在应用程序主窗口中加入了 ::SetProp(m_hWnd, theApp.m_pszAppName, (HANDLE)1);
并且想在第二份实例启动的时刻,根据该Prop获得第一个实例的app指针,现在能获得的只是CMainFrame的句柄,并且该句柄也只能得到临时窗口对象,无法调用第一个实例的CWinApp::OnNewFile()函数.
关于启动一个实例的办法很多。
例如:
声明如下:
//实例句柄,保证在一台机器上启动单一进程
static HANDLE m_hOneInstance;
在InitInstance()里最前面加入:
m_hOneInstance = CreateMutex(NULL, FALSE,str );
if (GetLastError() == ERROR_ALREADY_EXISTS )
{
AfxMessageBox("Another application is running!");
return FALSE;
}
在ExitInstance()里加入:
if (m_hOneInstance != NULL) CloseHandle(m_hOneInstance);Top
28 楼cadinfo(无语清风)回复于 2005-02-03 15:18:35 得分 1
谢谢大家,问题已经解决了,是app类中gdi+初始化类出导致的问题
尚存在的问题是全部窗口最小化时候,使用Win+R运行我的程序不能将子窗口显示出来.Top
29 楼dandycheung(珠穆朗玛)回复于 2005-02-03 16:02:46 得分 0
我的代码也已经结束,有望今天晚上放到我的 blog 上,欢迎大家捧场。Top
30 楼cadinfo(无语清风)回复于 2005-02-04 04:43:28 得分 0
哦,真厉害,我去你的blog看看.Top
31 楼dandycheung(珠穆朗玛)回复于 2005-02-04 10:09:33 得分 0
http://spaces.msn.com/members/sluttery/Blog/cns!1pT-_vAfaYbpcFEI23XZlwLg!175.entryTop




