MFC Activex OCX Javascript 互相访问问题,线程回调javascript
2012-12-12 17:37
405 查看
//比较好的教程
ocx 在 win7 系统会出现注册需要管理员权限的问题,这时候需要用管理员身份运行 cmd,然后运行 regsvr32注册。
很麻烦
尝试使用 nsis 做成安装包, 采用 regdll 注册 ocx, 成功。
ocx和外面的程序交互主要通过提供方法属性 + 事件
方法属性可以提供给js调用,
事件可以给js 通过下面的方式进行回调注入
<object id="xxx"></object>
<script language="JavaScript" for="xx" Event="eventFunction(x)">
alert(x);
</script>
或者
document.getElementByIdx_x(xx).attachEvent("eventFunction",function(x,y){
alert(x);
});
这两种功能都可以在类视图里面选择 XXXCtrl,右键选择 add ,会出现 方法属性事件
按照wizard进行添加就好。
主要记录一下如果ocx创建了线程,想通过事件回调js的话,会出现问题。
这时候解决方法就是通过 PostMessage(WM_THREADFIREEVENT,(WPARAM)NULL,(LPARAM)NULL); 下面的看看应该懂了
//-------------------------
SAMPLE: Firing Events From a Second Thread
---------------------------------------------------------------------
The information in this article applies to:
- Microsoft Visual C++, 32-bit Edition versions 4.0, 4.1, 4.2
---------------------------------------------------------------------
SUMMARY
=======
MFC based ActiveX controls typically fire their events from the same thread
that implements the sink interface of the container that the events are
being fired to.
Sometimes, it is desirable to start a second thread in an ActiveX control
which will fire events to the container. Since MFC ActiveX controls
use the Apartment threading model, special consideration must be taken
into account when firing events from a secondary thread.
MORE INFORMATION
================
An MFC based ActiveX control supports events by implementing the
IConnectionPointContainer and IConnectionPoint interfaces, as well as
supplying information about it's event interface in it's type information.
When an MFC based ActiveX control is embedded in a container that supports
events, that container will dynamically construct a sink interface that has
all of the methods specified in the control's type information for it's
event interface. Once the container constructs it's sink interface, it
will pass a pointer to that interface to the ActiveX control. The ActiveX
control will use it's implementation of IConnectionPoint to communicate
through the now hooked up sink interface that was constructed by the
container. This sample will demonstrate how to call methods of the
container's sink interface from a second thread.
The two most important things to consider when starting a new thread to
fire events from in an ActiveX control are:
1. MFC based ActiveX controls are in-process objects (implemented in a
DLL).
2. MFC based ActiveX controls use the Apartment threading model.
The Apartment threading model specifies that all threads that want to use
OLE services must initialize OLE in their thread prior to using OLE
services. Also, if a thread wants to use a pointer to an interface that is
either implemented by a different thread of the same process or has been
previously marshaled to a different thread of the same process, that
pointer must be marshaled to the requesting thread. In the Apartment
threading model, hidden windows are created to synchronize requests from
other threads to the thread being called. This means that all
communication between threads will be done by using hidden windows and
Windows messages in the Apartment model.
There are two possible ways to fire events from a second thread in an
ActiveX control (or any other in-proc server that implements connection
points) under the Apartment threading model. The first is to make the
interface call from the second thread by calling the event sink's method
from the second thread. The second is to have the second thread post a
message to the first thread when it is ready to fire the event, and have
the first thread fire the event.
The first method mentioned above is not the optimal way to fire an event
from a second thread. This is because for the second thread to fire the
event, it must make a call on an interface pointer that is held by the
thread that initialized the control. This means that the interface pointer
that will be used to fire the event must be marshaled to the second thread
which will cause OLE to set up hidden windows to communicate between the
threads. Windows messages will be used to communicate between the threads.
The MFC ActiveX control framework is not set up to easily fire events from
a second thread. It is possible to override the default MFC code to marshal
the sink interface pointers to the second thread, but this is not
recommended. The reason this is not recommended is that since Windows is
going to create hidden windows and use PostMessage to send messages between
threads anyway, it makes more sense for the second thread to post it's own
messages to the first thread and have that thread fire the event. This code
can be easily set up in an MFC ActiveX control. Take the following steps to
add a second thread which fires events to the container in an MFC ActiveX
control.
1. Create your control project.
2. Using ClassWizard, add a method that will start a second thread and
return. The code for a method that starts a second thread and returns
immediatly in an MFC ActiveX control is shown below. A global function
to serve as the second thread's work function is also declared:
LONG ThreadProc(LPVOID pParam);
void CFireeventCtrl::StartLengthyProcess()
{
DWORD dwID;
HANDLE threadHandle = CreateThread(NULL,NULL,
(LPTHREAD_START_ROUTINE)ThreadProc,
(LPVOID)this, NULL, &dwID);
TRACE("Started the thread %x/n",dwID);
}
3. Add any events you wish to fire from the second thread using
ClassWizard.
4. Define a custom message to be sent from the second thread. Also, add a
message map entry to the control's message map which will call the
message handling function when the custom message is received. This
message handler will fire the desired event. A sample of how to do this
in an MFC ActiveX control is shown below:
//define a custom message:
#define WM_THREADFIREEVENT WM_USER+101
//add an entry for the message to the message map of the control
BEGIN_MESSAGE_MAP(CFireeventCtrl, COleControl)
//{{AFX_MSG_MAP(CFireeventCtrl)
//}}AFX_MSG_MAP
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
ON_MESSAGE(WM_THREADFIREEVENT,OnFireEventForThread) //custom handler
END_MESSAGE_MAP()
//add a handler for the custom message that will fire our event
LRESULT CFireeventCtrl::OnFireEventForThread(WPARAM wParam,
LPARAM lParam)
{
FireLengthyProcessDone();
return TRUE;
}
5. In the thread procedure for the second thread, when it's time for the
second thread to fire the event, post the custom message defined in step
3 back to the main thread. The event will be fired. The following code
demonstrates this:
LONG ThreadProc(LPVOID pParam)
{
Sleep(2000); //simulate lengthy processing
CFireeventCtrl *pCtrl = (CFireeventCtrl*)pParam;
PostMessage(pCtrl->m_hWnd,
WM_THREADFIREEVENT,
(WPARAM)NULL,
(LPARAM)NULL);
return TRUE;
}
Notice in the sample code above that the window handle of the ActiveX
control is used as the target to which the message from the second thread
will be posted. In most cases, an MFC based ActiveX control will be in-
place active when it's methods are called and will have a window handle.
It is possible, however for an ActiveX control to not have a window handle,
such as in the case of a windowless control. One way to work around this
is to create a hidden window that could be used to communicate between
threads. That window could then be destroyed when the thread terminated.
The FIREEV sample has code which is commented out in it's
StartLengthyProcess method and ThreadProc thread work function which
demonstrates creating a window which is wrapped by the CMyWindow class that
serves this purpose. Also notice that PostMessage is used instead of
PostThreadMessage. MFC's message maps are set up to intercept thread
messages in CWinThread derived classes only. Since MFC ActiveX controls
are derived from CWnd, they will not have messages sent with
PostThreadMessage routed to them. Messages sent with PostThreadMessage will
have a NULL hWnd.
----------------------------------//
里面提到的 hWnd,如果在IE使用空间,这个窗口句柄是空的,会导致回调照样失败,
这时候需要重载OnSetClientSite
参考 http://hi.baidu.com/cr0_3/blog/item/471113c1d5fadd3ae5dd3b88.html
void CMyControl::OnSetClientSite()
{
// It doesn't matter who the parent window is or what the size of
// the window is because the control's window will be reparented
// and resized correctly later when it's in-place activated.
if (m_pClientSite)
VERIFY (CreateControlWindow (::GetDesktopWindow(), CRect(0,0,0,0), CRect(0,0,0,0)));
COleControl::OnSetClientSite();
}
这样,整个流程就走通了。
js调用 ocx, ocx回调js 全部走通。
在Windows XP中,可以在任务栏上看到控件的窗口
解决的方法是尽可能用GetForegroundWindow替代GetDesktopWindow(GetForegroundWindow有时返回NULL)
//参考
http://bbs.51cmm.com/user1/224/archives/2008/29315.html
ocx 在 win7 系统会出现注册需要管理员权限的问题,这时候需要用管理员身份运行 cmd,然后运行 regsvr32注册。
很麻烦
尝试使用 nsis 做成安装包, 采用 regdll 注册 ocx, 成功。
ocx和外面的程序交互主要通过提供方法属性 + 事件
方法属性可以提供给js调用,
事件可以给js 通过下面的方式进行回调注入
<object id="xxx"></object>
<script language="JavaScript" for="xx" Event="eventFunction(x)">
alert(x);
</script>
或者
document.getElementByIdx_x(xx).attachEvent("eventFunction",function(x,y){
alert(x);
});
这两种功能都可以在类视图里面选择 XXXCtrl,右键选择 add ,会出现 方法属性事件
按照wizard进行添加就好。
主要记录一下如果ocx创建了线程,想通过事件回调js的话,会出现问题。
这时候解决方法就是通过 PostMessage(WM_THREADFIREEVENT,(WPARAM)NULL,(LPARAM)NULL); 下面的看看应该懂了
//-------------------------
SAMPLE: Firing Events From a Second Thread
---------------------------------------------------------------------
The information in this article applies to:
- Microsoft Visual C++, 32-bit Edition versions 4.0, 4.1, 4.2
---------------------------------------------------------------------
SUMMARY
=======
MFC based ActiveX controls typically fire their events from the same thread
that implements the sink interface of the container that the events are
being fired to.
Sometimes, it is desirable to start a second thread in an ActiveX control
which will fire events to the container. Since MFC ActiveX controls
use the Apartment threading model, special consideration must be taken
into account when firing events from a secondary thread.
MORE INFORMATION
================
An MFC based ActiveX control supports events by implementing the
IConnectionPointContainer and IConnectionPoint interfaces, as well as
supplying information about it's event interface in it's type information.
When an MFC based ActiveX control is embedded in a container that supports
events, that container will dynamically construct a sink interface that has
all of the methods specified in the control's type information for it's
event interface. Once the container constructs it's sink interface, it
will pass a pointer to that interface to the ActiveX control. The ActiveX
control will use it's implementation of IConnectionPoint to communicate
through the now hooked up sink interface that was constructed by the
container. This sample will demonstrate how to call methods of the
container's sink interface from a second thread.
The two most important things to consider when starting a new thread to
fire events from in an ActiveX control are:
1. MFC based ActiveX controls are in-process objects (implemented in a
DLL).
2. MFC based ActiveX controls use the Apartment threading model.
The Apartment threading model specifies that all threads that want to use
OLE services must initialize OLE in their thread prior to using OLE
services. Also, if a thread wants to use a pointer to an interface that is
either implemented by a different thread of the same process or has been
previously marshaled to a different thread of the same process, that
pointer must be marshaled to the requesting thread. In the Apartment
threading model, hidden windows are created to synchronize requests from
other threads to the thread being called. This means that all
communication between threads will be done by using hidden windows and
Windows messages in the Apartment model.
There are two possible ways to fire events from a second thread in an
ActiveX control (or any other in-proc server that implements connection
points) under the Apartment threading model. The first is to make the
interface call from the second thread by calling the event sink's method
from the second thread. The second is to have the second thread post a
message to the first thread when it is ready to fire the event, and have
the first thread fire the event.
The first method mentioned above is not the optimal way to fire an event
from a second thread. This is because for the second thread to fire the
event, it must make a call on an interface pointer that is held by the
thread that initialized the control. This means that the interface pointer
that will be used to fire the event must be marshaled to the second thread
which will cause OLE to set up hidden windows to communicate between the
threads. Windows messages will be used to communicate between the threads.
The MFC ActiveX control framework is not set up to easily fire events from
a second thread. It is possible to override the default MFC code to marshal
the sink interface pointers to the second thread, but this is not
recommended. The reason this is not recommended is that since Windows is
going to create hidden windows and use PostMessage to send messages between
threads anyway, it makes more sense for the second thread to post it's own
messages to the first thread and have that thread fire the event. This code
can be easily set up in an MFC ActiveX control. Take the following steps to
add a second thread which fires events to the container in an MFC ActiveX
control.
1. Create your control project.
2. Using ClassWizard, add a method that will start a second thread and
return. The code for a method that starts a second thread and returns
immediatly in an MFC ActiveX control is shown below. A global function
to serve as the second thread's work function is also declared:
LONG ThreadProc(LPVOID pParam);
void CFireeventCtrl::StartLengthyProcess()
{
DWORD dwID;
HANDLE threadHandle = CreateThread(NULL,NULL,
(LPTHREAD_START_ROUTINE)ThreadProc,
(LPVOID)this, NULL, &dwID);
TRACE("Started the thread %x/n",dwID);
}
3. Add any events you wish to fire from the second thread using
ClassWizard.
4. Define a custom message to be sent from the second thread. Also, add a
message map entry to the control's message map which will call the
message handling function when the custom message is received. This
message handler will fire the desired event. A sample of how to do this
in an MFC ActiveX control is shown below:
//define a custom message:
#define WM_THREADFIREEVENT WM_USER+101
//add an entry for the message to the message map of the control
BEGIN_MESSAGE_MAP(CFireeventCtrl, COleControl)
//{{AFX_MSG_MAP(CFireeventCtrl)
//}}AFX_MSG_MAP
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
ON_MESSAGE(WM_THREADFIREEVENT,OnFireEventForThread) //custom handler
END_MESSAGE_MAP()
//add a handler for the custom message that will fire our event
LRESULT CFireeventCtrl::OnFireEventForThread(WPARAM wParam,
LPARAM lParam)
{
FireLengthyProcessDone();
return TRUE;
}
5. In the thread procedure for the second thread, when it's time for the
second thread to fire the event, post the custom message defined in step
3 back to the main thread. The event will be fired. The following code
demonstrates this:
LONG ThreadProc(LPVOID pParam)
{
Sleep(2000); //simulate lengthy processing
CFireeventCtrl *pCtrl = (CFireeventCtrl*)pParam;
PostMessage(pCtrl->m_hWnd,
WM_THREADFIREEVENT,
(WPARAM)NULL,
(LPARAM)NULL);
return TRUE;
}
Notice in the sample code above that the window handle of the ActiveX
control is used as the target to which the message from the second thread
will be posted. In most cases, an MFC based ActiveX control will be in-
place active when it's methods are called and will have a window handle.
It is possible, however for an ActiveX control to not have a window handle,
such as in the case of a windowless control. One way to work around this
is to create a hidden window that could be used to communicate between
threads. That window could then be destroyed when the thread terminated.
The FIREEV sample has code which is commented out in it's
StartLengthyProcess method and ThreadProc thread work function which
demonstrates creating a window which is wrapped by the CMyWindow class that
serves this purpose. Also notice that PostMessage is used instead of
PostThreadMessage. MFC's message maps are set up to intercept thread
messages in CWinThread derived classes only. Since MFC ActiveX controls
are derived from CWnd, they will not have messages sent with
PostThreadMessage routed to them. Messages sent with PostThreadMessage will
have a NULL hWnd.
----------------------------------//
里面提到的 hWnd,如果在IE使用空间,这个窗口句柄是空的,会导致回调照样失败,
这时候需要重载OnSetClientSite
参考 http://hi.baidu.com/cr0_3/blog/item/471113c1d5fadd3ae5dd3b88.html
void CMyControl::OnSetClientSite()
{
// It doesn't matter who the parent window is or what the size of
// the window is because the control's window will be reparented
// and resized correctly later when it's in-place activated.
if (m_pClientSite)
VERIFY (CreateControlWindow (::GetDesktopWindow(), CRect(0,0,0,0), CRect(0,0,0,0)));
COleControl::OnSetClientSite();
}
这样,整个流程就走通了。
js调用 ocx, ocx回调js 全部走通。
在Windows XP中,可以在任务栏上看到控件的窗口
解决的方法是尽可能用GetForegroundWindow替代GetDesktopWindow(GetForegroundWindow有时返回NULL)
//参考
http://bbs.51cmm.com/user1/224/archives/2008/29315.html
相关文章推荐
- 页面调用OCX(ActiveX)控件,自动下载、注册及 javascript对ActiveX的访问、控制和事件调用等。
- 关于java多线程中同步的问题(两个线程访问同一个实例类的两个同步方法,会不会互相影响)
- MFC + 线程访问窗口资源的问题(规则DLL)
- Java线程:线程的同步与锁 一、同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。 例如:两个线程ThreadA、ThreadB都操作同一个对象Foo对
- ASP.NET中javascript与c#互相访问
- ActiveX异步回调JavaScript(通过事件方式)
- 线程访问临界区的问题 实例,需解决
- VC2005从开发MFC ActiveX ocx控件到发布到.net网站的全部过程
- Spring并发访问的线程安全性问题
- VC2005从开发MFC ActiveX ocx控件到发布到.net网站的全部过程
- 关于线程并发访问全局变量问题
- MFC 线程内延时问题
- JavaScript 跨域访问的问题和解决过程
- 使用JavaScript生成器解决回调问题的研究
- 线程间操作无效: 从不是创建控件“Control Name'”的线程访问它问题的解决方案及原理分析
- Spring MVC并发访问的线程安全性问题
- 用线程控制访问请求URL超时问题
- javascript与cs代码互相调用 asp.net中前台javascript与后台C#交互 这里主要包括了javascipt与后台CS代码四种方法互调(其中包括函数与变量的访问)
- MFC中使用线程创建窗口的问题
- 关于Win32 API(VC作为程序设计语言)的创建线程,解决互斥访问临界资源问题