Accessing a Word or Excel document through a proxy causes deadlock

Hi,

I have an Office add-in that tracks documents open in various instances
of Word and Excel. This "tracker" object is a Singleton Well-Known
object registered with .Net remoting.

I use a MarshalByRefObject-derived proxy class that has an internal
reference to the document object. This proxy is used to "send" the
document over remoting. The problem appears when the "tracker" calls a
method on the proxy which in turn accesses a property (FileName or
something) on the document object. What happens is that it simply locks.

I tried creating a separate STA thread for this, with no effect. What
should I do? Colud it be that the document object gets confused when
called inside a remoting context? Maybe this call should have been
dispatched to the UI's primary thread (no idea how to do this with
office)? Any ideas?

Thanks in advance!
pedja11Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

eekjCommented:
>>What happens is that it simply locks.
please post the code that accessed the document object
0
pedja11Author Commented:
Server:

IDictionary h_Table;
h_Table = new Hashtable();
h_Table["port"] = 9932;
BinaryServerFormatterSinkProvider obj_FormatProvider = new BinaryServerFormatterSinkProvider();
obj_FormatProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
ServChannel = new TcpServerChannel(h_Table, obj_FormatProvider);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(GlobalData) , "GlobalData" , WellKnownObjectMode.Singleton);

Client:

TcpClientChannel tc = new TcpClientChannel();
ChannelServices.RegisterChannel(tc);
GlobData = (GlobalData)Activator.GetObject(typeof(GlobalData) , "tcp://localhost:9932/GlobalData");

******************************************************

Microsoft.Office.Interop.Excel.Workbook wbb = (Microsoft.Office.Interop.Excel.Application)app.ActiveWorkbook;
GlobalData gd = new GlobalData();
gd.SetExcelDoc(wbb);
GlobData.SetExcelDocWithGlobalData(gd);                  
GlobData.DoSomething();
*******************************************************
public class GlobalData:System.MarshalByRefObject
{
   public Microsoft.Office.Interop.Excel.Workbook ExcelDoc;
   public void SetExcelDocWithGlobalData(GlobalData gd)
   {
       ExcelDoc = gd.ExcelDoc;
   }
   public void SetExcelDoc(Microsoft.Office.Interop.Excel.Workbook wb)
   {
     ExcelDoc = wb;
   }

   public void DoSomething()
   {
      Thread wt = new Thread(new ThreadStart(Something));
      wt.ApartmentState = ApartmentState.STA;
      wt.Start();
      wt.Join();
   }

   public Something()
   {
    //Some code that uses ExcelDoc
   }

   public GlobalData()
   {
   }
}

0
eekjCommented:
So the client is opening a document and your remoting service is tracking that. What I dont get is why you're doing this on the client side:

GlobalData gd = new GlobalData();
gd.SetExcelDoc(wbb);
GlobData.SetExcelDocWithGlobalData(gd);              

it looks like you've created a proxy already using this code on the client:
GlobData = (GlobalData)Activator.GetObject(typeof(GlobalData) , "tcp://localhost:9932/GlobalData");

but then the client creates another remoting service on the client using:
GlobalData gd = new GlobalData();
... and then passes this back to the proxy.

If you want to activate the object from the client you should use:
RemotingConfiguration.RegisterWellKnownClientType(typeof(GlobalData), "tcp://localhost:9932/GlobalData");
GlobalData gd = new GlobalData();
gd.SetExcelDoc(wbb);

But also I don't understand what this is doing:
GlobData.SetExcelDocWithGlobalData(gd);              

Just one more thing Im confused about - should this be Singleton? Singleton creates a single server-side instance for everybody that accesses your service, for all calls.

0
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

pedja11Author Commented:
That is all because I wanted to send an object not inherited from MarshalByRefObject. I want server to work something with ExcelDocument.

It should be singleton.
0
eekjCommented:
ok cool but what does this do?

   public void SetExcelDocWithGlobalData(GlobalData gd)
   {
       ExcelDoc = gd.ExcelDoc;
   }
0
pedja11Author Commented:
I'm using MarshalByRefObject to send Excel Document object which is not MarshalByRefObject.
0
eekjCommented:
A MarshalByRefObject is a remote object that runs on the server and accepts method calls from the client. You cant really use it like that. You probably need to serialise the excel document to xml then pass it to the MarshalByRefObject and deserialize it on the server then process it (in your thread or wherever)
0
pedja11Author Commented:
If I use some other object, instance of the class I created and which is not MarshalByRefObject, not the excel document, I don't have a problem.
And I am doing all this to avoid serialization.
0
eekjCommented:
Its never going to work like that. When you create an excel "document" in code youre only creating an instance of a class that interfaces with Microsoft Excel (the program itself), not the actual excel document or anything like that. When you do anything with Excel - creating a new workbook or whatever - what happens is the ExcelDoc object would send a command to the copy of Microsoft Office installed on your local machine telling it to do that task for you.

The only project I know of that reads and writes excel documents directly and bypasses the Microsoft Office API is Jakarta POI, but thats in java. You won't be able to 'send' your file to the server to process it the way you've tried. I would suggest doing your processing client-side, its going to be much easier.

If you HAVE to pass the excel document to the server to do some processing on it you'll need to convert it to XML and send the document itself (not ExcelDoc) that way. Otherwise you could send the file as a byte stream then save it on the server and then send it back when you've finished ... but thats the hard way. Do it client side and save yourself the trouble.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.