.net - Excel file operations using interop in multithreaded C# application fails -
i've application automates file related jobs. every job executed inside separate threads. 1 kind of job exporting excel file html format. use microsoft.office.interop.excel
namespace purpose. application working fine under windows server 2008 environment upgraded our server windows server 2012 , started following error :
the message filter indicated application busy. (exception hresult: 0x8001010a (rpc_e_servercall_retrylater))
the thing first call export function exports excel file html successive calls fails above error. make sure close , finalize excel related objects , check task manager excel.exe not working no luck.
i use following code retry if error occurs keeps getting exception , fails after 5 retries
while (!success) { try { exportexcel(); success = true; system.threading.thread.sleep(2000); } catch (system.runtime.interopservices.comexception loe) { trycount++; if (loe.hresult.tostring("x") == "80010001" || loe.hresult.tostring("x") == "8001010a" && trycount<5) { system.threading.thread.sleep(2000); } else { throw; } } }
i suspect might related threading error can't come answer. insight helpful.
thank joe pointing out right way:
i ended using solution mixture of following links: http://blogs.artinsoft.net/mrojas/archive/2012/09/28/office-interop-and-call-was-rejected-by-callee.aspx
http://blogs.msdn.com/b/pfxteam/archive/2010/04/07/9990421.aspx
so used following:
stataskscheduler cts=new stataskscheduler(1); taskfactory factory; factory = new taskfactory(cts); task jobruntask = factory.startnew(() => { messagefilter.register(); excelinteropfunction(); messagefilter.revove(); });
i believe excel object model apartment threaded, calls multiple threads marshaled same thread in excel process - may busy if there several client threads.
you can implement imessagefilter (ole message filter, not confused system.windows.forms.imessagefilter
) provide custom retry logic.
your server upgrade might have changed timing characteristics problem occurs more frequently.
update
here sample basic implementation of ole message filter:
// definition of imessagefilter interface need implement , // register coregistermessagefilter api. [comimport(), guid("00000016-0000-0000-c000-000000000046"), interfacetypeattribute(cominterfacetype.interfaceisiunknown)] interface iolemessagefilter // renamed avoid confusion w/ system.windows.forms.imessagefilter { [preservesig] int handleincomingcall(int dwcalltype, intptr htaskcaller, int dwtickcount, intptr lpinterfaceinfo); [preservesig] int retryrejectedcall(intptr htaskcallee, int dwtickcount, int dwrejecttype); [preservesig] int messagepending(intptr htaskcallee, int dwtickcount, int dwpendingtype); } internal sealed class olemessagefilter : iolemessagefilter, idisposable { [dllimport("ole32.dll")] private static extern int coregistermessagefilter(iolemessagefilter newfilter, out iolemessagefilter oldfilter); private bool _isregistered; private iolemessagefilter _oldfilter; public olemessagefilter() { register(); } private void register() { // coregistermessagefilter supported on sta thread. throw exception // if can't switch sta thread.currentthread.setapartmentstate(apartmentstate.sta); int result = coregistermessagefilter(this, out _oldfilter); if (result != 0) { throw new comexception("coregistermessagefilter failed", result); } _isregistered = true; } private void revoke() { if (_isregistered) { iolemessagefilter revokedfilter; coregistermessagefilter(_oldfilter, out revokedfilter); _oldfilter = null; _isregistered = false; } } #region idisposable members private void dispose(bool disposing) { if (disposing) { // dispose managed resources } // dispose unmanaged resources revoke(); } void idisposable.dispose() { gc.suppressfinalize(this); dispose(true); } ~olemessagefilter() { dispose(false); } #endregion #region iolemessagefilter members int iolemessagefilter.handleincomingcall(int dwcalltype, intptr htaskcaller, int dwtickcount, intptr lpinterfaceinfo) { return 0; //servercall_ishandled } int iolemessagefilter.retryrejectedcall(intptr htaskcallee, int dwtickcount, int dwrejecttype) { if (dwrejecttype == 2) // servercall_retrylater { return 200; // wait 200ms , try again } return -1; // cancel call } int iolemessagefilter.messagepending(intptr htaskcallee, int dwtickcount, int dwpendingtype) { return 2; //pendingmsg_waitdefprocess } #endregion }
you can @ this sample, though displays prompt asking user if want retry, not appropriate if client multithreaded , server-based.
Comments
Post a Comment