Hi,
We are having code in which we start a new thread and set it as STA. This new thread initializes IHTMLWindow2 object and then starts another thread. But, in that second thread if we try to access the IHTMLWindow2 which is initialized in the first thread we are getting this exception "COM object that has been separated from its underlying RCW cannot be used". If we do not set the first thread to STA, we coudn't access the windows in that thread itself, so it needs to be in STA. So how can we access the window initialized in the first thread Please give any suggestions.
I am giving the code here.
Class1.java:
import
com.ms.wfc.html.*;import
com.ms.wfc.core.*;import
com.ms.wfc.ui.*;import
com.ms.wfc.html.om.*;public
class Class1 extends DhDocument{
DhText createdText;
DhText boundText;
public IHTMLWindow2 bottomwin; public IHTMLWindow2 leftwin;Helper helperobj;
public Class1(){
// Required for Visual J++ Form Designer supportinitForm();
// TODO: Add any constructor code after initForm call}
/*** Class1 overrides dispose so it can clean up the
* component list.
*/
public void dispose(){
super.dispose();}
private void initForm(){
createdText =
new DhText();createdText.setText("Created Text");
boundText =
new DhText();boundText.setID("bindText");
boundText.setBackColor(Color.LIGHTGRAY);
/*** setBoundElements() will take a list of elements that already are present
* in the HTML document, and binds them to the DhElement list.
*/
setBoundElements(
new DhElement[] {boundText}); /*** setNewElements() takes a list of DhElements and adds them to the HTML document.
*/
setNewElements(
new DhElement[] {createdText});}
protected void onDocumentLoad(Object sender, Event e){
bottomwin=
this.getWindowPeer().getParent().getParent(); // MessageBox.show("href::"+ bottomwin.getLocation().getHref()); // MessageBox.show("length::"+bottomwin.getLength());ThreadOne obj1=
new ThreadOne(this);Thread thr1=
new Thread(obj1);thr1.setApartmentState(System.Threading.ApartmentState.STA);
thr1.start();
}
//initDcontroller is called from ThreadOne public void initDController(){
leftwin=
this.getWindowPeer().getParent();helperobj=
new Helper(leftwin,this);helperobj.helperfun();
ThreadTwo obj2=
new ThreadTwo(helperobj,this);Thread thr2=
new Thread(obj2);thr2.setApartmentState(System.Threading.ApartmentState.STA);
thr2.start();
}
}
ThreadOne.java:
public
class ThreadOne implements Runnable{
public Class1 clsobj; public ThreadOne(Class1 obj){
clsobj=obj;
}
public synchronized void run(){
try{
clsobj.initDController();
}
catch(Exception ex){
MessageBox.show("exception in thread1::"+ex.toString());
}
}
}
ThreadTwo.java:
public
class ThreadTwo implements Runnable{
public Class1 clsobj; public Helper helperobj; public ThreadTwo(Helper hobj,Class1 obj){
helperobj=hobj;
clsobj=obj;
}
public synchronized void run(){
try{
//this line tries to access the bottomwin which is initialized by main thread //it works fine without exceptionMessageBox.show("bottomwin length in thread2::"+clsobj.bottomwin.getLength());
//next two lines access the leftwin which is initialized by thr1 //and thr1 is also set to STA //these lines give the exception COM object that has been separated from its underlying RCW cannot be usedhelperobj.helperfun();
//String href=clsobj.leftwin.getLocation().getHref();}
catch(Exception ex){
MessageBox.show("exception in thread2::"+ex.toString());
}
}
}
Helper.java:
public
class Helper{
public Class1 clsobj; public IHTMLWindow2 leftwin; public Helper(IHTMLWindow2 lwin,Class1 obj){
leftwin=lwin;
clsobj=obj;
}
public void helperfun(){
MessageBox.show("leftwin href::"+leftwin.getLocation().getHref());
}
}
Regards,
Sumathi

COM object that has been separated from its underlying RCW cannot be used exception within threads
Yaroslav58211
Hi Sumathi,
We are investigating this issue. we will keep you Updated. You can try to assign IHTMLWindow without getting it's parent and You can get its Parent in Thread Two.
Thread one:
clsobj.leftwin = (IHTMLWindow2)win.getPeer();
Thread Two:
MessageBox.show(clsobj.leftwin.getParent().getLocation().getHref());
Thanks,
Noorul Ameen.
Brad Peterson
Morten Hvidberg-Knudsen
Hi Sumathi,
I got the same error while running your code. I am investigating the cause of error. Meanwhile you can try the following code if this suits your application needs. I have changed the initDController function slightly and put it in ThreadOne. InitDcontroller function in ThreadOne will initialize the leftwindow object. Now you can access leftwindow in ThreadTwo which is initialized in ThreadOne.
import com.ms.wfc.html.*;
import com.ms.wfc.core.*;
import com.ms.wfc.ui.*;
import com.ms.wfc.html.om.*;
public class Class1 extends DhDocument
{
public IHTMLWindow2 bottomwin;
public IHTMLWindow2 leftwin;
public Helper helperobj;
public Class1()
{
initForm();
}
public void dispose()
{
super.dispose();
}
private void initForm()
{
}
protected void onDocumentLoad(Object sender, Event e)
{
try
{
bottomwin = this.getWindowPeer().getParent().getParent();
MessageBox.show("Main Thread:href::" + bottomwin.getLocation().getHref());
ThreadOne obj1 = new ThreadOne(this);
Thread thr1 = new Thread(obj1);
thr1.setApartmentState(System.Threading.ApartmentState.STA);
thr1.start();
}
catch (Exception e1)
{
}
}
}
public class ThreadOne implements Runnable
{
public Class1 clsobj;
public ThreadOne(Class1 obj)
{
clsobj = obj;
}
public void initDController()
{
DhWindow win = clsobj.getDocument().getWindow();
clsobj.leftwin = (IHTMLWindow2)win.getPeer();
clsobj.helperobj = new Helper(clsobj.leftwin, clsobj);
ThreadTwo obj2 = new ThreadTwo(clsobj.helperobj, clsobj);
Thread thr2 = new Thread(obj2);
thr2.setApartmentState(System.Threading.ApartmentState.STA);
thr2.start();
}
public synchronized void run()
{
try
{
initDController();
}
catch (Exception ex)
{
MessageBox.show("exception in thread1::" + ex.toString());
}
}
}
public class ThreadTwo implements Runnable
{
public Class1 clsobj;
public Helper helperobj;
public ThreadTwo(Helper hobj, Class1 obj)
{
helperobj = hobj;
clsobj = obj;
}
public synchronized void run()
{
try
{
//this line tries to access the bottomwin which is initialized by main thread
//it works fine without exception
MessageBox.show("bottomwin length in thread2::" + clsobj.bottomwin.getLength());
//next two lines access the leftwin which is initialized by thr1
//and thr1 is also set to STA
//these lines give the exception COM object that has been separated from its underlying RCW cannot be used
helperobj.helperfun();
MessageBox.show(clsobj.leftwin.getLocation().getHref());
}
catch (Exception ex)
{
MessageBox.show("exception in thread2::" + ex.toString());
}
}
}
public class Helper
{
public Class1 clsobj;
public IHTMLWindow2 leftwin;
public Helper(IHTMLWindow2 lwin, Class1 obj)
{
leftwin = lwin;
clsobj = obj;
}
public void helperfun()
{
MessageBox.show("leftwin href::" + leftwin.getLocation().getHref());
}
}
Please post back if this does not solve your issue.
Thanks,
Noorul Ameen.
rhoule
RoMoVi
Hi,
We are getting that exception in our product and i reproduced that with the sample code here. Actually we need to find a particular frame dynamically in thread1 and assign it to a variable and then we access that in second thread. As i said before, that exception happens when we access the frame in the second thread. I assigned the parent window to leftwin just for simplicity and to reproduce the error. So please let us know if there is anyother way to solve this.
Regards,
Sumathi
Gabriele38
Hi mumato,
I met the same problem when using COM object as static field in my test fixture.
It seems that the object was automatically disposed after each testmethod's running. By the way,this problem won't happen if I use NUnit instead.
darwind
Hi!
I have quite the same problem but without even using threads directly.
I wrote a library to automate Office Applications (namely Word, Excel, Outlook and PowerPoint) and some unit tests with it. When running these tests piece by piece, they all work well. But when running them whole, there are always some tests that fail with the message "COM object that has been separated from its underlying RCW cannot be used", and the tests that fail are not always the same ones.
Could it be that there is a timing problem I also realized that that the COM component gets disposed of way immediately after its retrieval...
CU
Q
Mike Houglum
Hi,
Our Team is investigating this issue. We will keep you updated.Thanks for reporting this issue.
Thanks,
Noorul Ameen.
bkjuice
I found the answer here: http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=175181&SiteID=1
Basically you need to switch the unit test to MTA since each unit test runs in its own thread. To do this change the0 to 1 in .testrunconfig so you end up with:
<apartmentState type="System.Threading.ApartmentState">
<value__ type="System.Int32">1</value__>
</apartmentState>
cisco0407
saint nik
I saw this link:
FIX: "COM Object Can Not Be Used" Error Message When You Use an STA COM Object That You Created by Using Server.CreateObject and Stored in Session Scope in a Different Web Page
http://support.microsoft.com/kb/818612/
on this thread:
http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=493227&SiteID=1
Have you tried that
Nick Foster
Hi Qanuc, got a solution
Stepped into the same trap - each test runs for itself but running them all won't work - calling the Tests from a single [TestMethod] (and remove the TestMethod attributes of the tests, keeping it only in the one that calls the 'Tests'), everything works fine...
What i'm doing is to create a COM Instance of a RealTime Processdata SDK and keeping it in some kind of Singleton (it's a Monostate) - the first Test runs perfectly, in the second test (without calling Marshal.ReleaseComObject(...)) the COM instance is no longer valid.
Doing the same stuff in NUnit it works fine, no "COM object that has been separated from its underlying RCW cannot be used" only within VS2005 it appears to be a problem.
Is it possible the Tests in VS 2005 / .NET 2.0 run in separate Threads (whatever that means to a COM Object)
cu, mumato
JainMohit
Hi,
Thanks for your help. I tried that as you said, but you seemed to assign the peer element of the window to leftwin,
DhWindow win = clsobj.getDocument().getWindow();
clsobj.leftwin = (IHTMLWindow2)win.getPeer();
but we need to assign parent of the window peer to leftwin,
leftwin=this.getWindowPeer().getParent();
It's working if we just assign the peer element of the window without getting parent, in such case it seems to work without modifying the initDController() and having that in Class1.java itself, but the problem happens when we try to access the parent.
Here i give the order of our frames starting from bottom.html
bottom.html:
<BODY topmargin=0 bottommargin=0 leftmargin=0 rightmargin=0 scroll=no>
<IFRAME name="dleftframe" src="left.html" height="50%" width="50%" APPLICATION="yes" frameborder=0>
</IFRAME>
<IFRAME name="webwindows" src="blank.html" height="50%" width="50%" APPLICATION="yes" frameborder=0 >
</IFRAME>
</BODY>
left.html:
<BODY>
<IFRAME name="dcontrolframe" src="Page1.htm" height="30%" width="100%" scrolling="yes" APPLICATION="yes">
</IFRAME>
</BODY>
Page1.htm:
<BODY>
<OBJECT CLASSID="CLSID:CF83EA5E-0FFD-4476-9BF7-6C15F7F8BDCF" height=0 width=0 … VIEWASTEXT ID="Object1">
<PARAM NAME=CODECLASS VALUE="DemoThread.dll#Class1">
<PARAM NAME=VJSVERSION VALUE= 1.0.3710>
</OBJECT>
<!-- Insert HTML here -->
<SPAN id="bindText">This is bound text.</SPAN>
</BODY>
So how can we solve this Please reply if you find any solution.
Regards,
Sumathi