开发者

Avoiding cross process calls when doing Word automation via VB.net

开发者 https://www.devze.com 2023-01-19 07:18 出处:网络
The short version I\'ve got a Word Addin in VB.net and VSTO that exposes a COM compatible object via Word.COMAddins.Object, so that the addin functionality can be called External to Word, without acce

The short version I've got a Word Addin in VB.net and VSTO that exposes a COM compatible object via Word.COMAddins.Object, so that the addin functionality can be called External to Word, without accesses to Word itself being cross-process.

The technique worked in VB6, but with VB.net, it still works, but it's much slower than the same code running directly from the addin via a task pane, as if the calls are all cross process when they shouldn't be. x

The Long version This addin essentially does tons of processing on Word Documents. The addin can be run in two ways.

  1. from within Word, using a taskpane
  2. externally, via a set of classes exposed to COM (because I have to provide access to the functionality to VB6 client apps.

BUT, here's the rub. Anyone who's ever done Word automation knows that code that runs perfectly acceptably INPROC with Word (in this case the instance of the ADDI开发者_如何学运维N that Word itself loads), will generally run unacceptably slowly out of process (or cross process).

This app is no different.

Ages ago, I made use of a handy trick to circumvent this issue.

  1. Create a Word Addin as usual
  2. Expose an object via the Word.COMAddin.Object property that will let external code access your addin.
  3. In your external project, instead of manipulating Word directly, Use the Application.COMAddins collection, find your addin, retrieve the exposed COMAddin.Object property from it and then call a method on that object that does the work.

Of course, the call to your COMAddin.Object object will still be cross process, BUT, once execution is in the addin that is IN PROCESS with Word, your addin can now perform all the Word object manipulations it wants and it's fast because they're all in-process calls at that point.

That worked in the VB6 COM days.

But, I put together this VB.net vsto addin, and expose my addin object via the RequestComAddInAutomationService function of VSTO's Connect object

I can make calls into my addin externally and they all work exactly as I would expect them to, except they're all +slow+, very much like the calls into Word are still being performed cross process even though the code making those calls to Word is part of the addin dll that was loaded in-process by Word!

And slow as in a factor of about 10 to 1; what takes 3 seconds to run when run directly from the ADDIN via the task pane, takes ~30seconds to run when called from external code through the COMADDIN.object object.

I'm guessing that I'm running into some sort of issue with .net APPDOMAINS or something and what +really+ constitutes cross proc calls in .net, but I've found nothing so far that would even hint about this sort of thing.

My next step, barring some mystical insight, will be to code up a repro, which could get tricky because of the shear number of elements in play.

Any thoughts?


I've made the same observations with my VSTO Word add in. What I'd like to add here: When you add your procedure as a click handler to a button:

`this.testButton.Click += new Office._CommandBarButtonEvents_ClickEventHandler(YourProcedure);´

and implement your expensive procedure in "YourProcedure", you can call into Word's UI thread using

this.testButton.Execute();

This is not an elegant solution either, but maybe useful if you happen to have buttons ready in a CommandBar.


Unfortunately, the Event hook technique Thorben mentions wouldn't work for my particular situation.

So I'm closing this question out with the workaround that I mentioned in comments and I'll repeat here...

Well, not a perfect solution, but I have found +a+ solution. It involved a timer, so it's definitely suboptimal Essentially, when the addin is loaded by Word, (ie during the STARTUP event), initialize a timer (a WINFORMS timer, not a threading timer), and set it's interval to 500. When External code connects to the addin via the COMADDIN.OBject property, and makes a call into the addin, set a variable flag, which is being polled by the timer. When the timer sees it set, it resets the flag and performs the action.

It's not the clean solution I'd have preferred, but it's fairly easy to implement, moderately easy to understand after the fact, and it definitely avoids the slowdown of xprocess COM calls into Word.

0

精彩评论

暂无评论...
验证码 换一张
取 消