Undocumented Matlab
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT

Fixing Matlab's actxserver

December 19, 2012 8 Comments

Matlab’s built-in actxserver function provides access to COM/DCOM server applications on Microsoft Windows platforms. This enables us, for example, to open a Microsoft Office document programmatically, and modify it from within Matlab. This in turn can be used, for example, to prepare professional PDF reports, relying on Office’s ability to save documents in PDF format. Alternately, we could programmatically update cell formatting (colors, fonts, borders etc.) and embed images and graphs in an Excel workbook – something that the standard xlswrite cannot do (my officedoc utility does this, using the same COM interface).
Note: For some reason, COM servers are called an ActiveX server in Matlab, although the term ActiveX is normally used for clients (i.e., controls), for which we have the actxcontrol* set of built-in functions.
Today I will focus on two changes that I made to Matlab’s built-in actxserver function:

Reusing an active server (no pun intended…)

By default, actxserver starts a new instance of the specified COM server whenever it is called. Sometimes this is indeed useful. However, I find that in the vast majority of cases, I actually want to reuse an existing server instance if it is currently running. For example, it is much faster and more memory-efficient to open an Excel workbook file in an existing Excel process, than to open it in a new dedicated process.
In R2007a, Matlab introduced the actxGetRunningServer function. Unfortunately, it did not see fit to set it as the default behavior for actxserver, nor even as an optional additional parameter (although MathWorks *did* change the actxserver function in that very same release, to accept a custom interface parameter). Users need to change their programs to first call actxGetRunningServer, check whether it works or fails, and then call actxserver if it fails (meaning that a server process is not currently running and a new one needs to be started):

% Try to reuse an existing COM server instance if possible
try
    hServer = actxGetRunningServer('excel.application');
    % no crash so probably succeeded to connect to a running server
catch
    % Never mind - continue normally to start the COM server and connect to it
    hServer = actxserver('excel.application');
end

% Try to reuse an existing COM server instance if possible try hServer = actxGetRunningServer('excel.application'); % no crash so probably succeeded to connect to a running server catch % Never mind - continue normally to start the COM server and connect to it hServer = actxserver('excel.application'); end

This is downright silly, I must say.

Moreover, all the existing user and Matlab code that uses actxserver will continue to start a new server instance rather than reuse existing ones. For example, the widely-used xlsread and xlswrite functions.
Instead of fixing Matlab’s installed actxserver.m file, which could be problematic when deploying applications to end-users, I created a copy of actxserver.m somewhere in my user folders that is high on the Matlab path. This way I can modify the file and bundle it with any application that I send to clients. The change to this file is simply to add a variant of the code above at the very top of the actxserver.m file, as follows (the new lines are highlighted):

function h = actxserver(progID, varargin)
%ACTXSERVER Creates a COM Automation server.
...
% Copyright 2006-2007 The MathWorks, Inc.
% $Revision: 1.8.6.12 $ $Date: 2011/08/13 17:30:50 $
error(nargchk(1, 5, nargin, 'struct'));
% Yair 17/5/2009: Try to reuse an existing COM server instance if possible
try
    h = actxGetRunningServer(progID);    return;  % no crash so probably succeeded - returncatch    % Never mind - continue normally to start the COM server and connect to itendmachinename = '';interface = 'IDispatch';...

function h = actxserver(progID, varargin) %ACTXSERVER Creates a COM Automation server. ... % Copyright 2006-2007 The MathWorks, Inc. % $Revision: 1.8.6.12 $ $Date: 2011/08/13 17:30:50 $ error(nargchk(1, 5, nargin, 'struct')); % Yair 17/5/2009: Try to reuse an existing COM server instance if possible try h = actxGetRunningServer(progID); return; % no crash so probably succeeded - return catch % Never mind - continue normally to start the COM server and connect to it end machinename = ''; interface = 'IDispatch'; ...

This simple change means that all exiting code, including Matlab’s built-in xlsread and xlswrite functions, now try to reuse a running COM server process if possible, starting a new one only if this fails. The code is fault-tolerant in that it also works on old Matlab releases where the actxGetRunningServer is not available.

Fix of the progID

The %matlabroot%/toolbox/matlab/winfun/private/newprogid.m function, a private function used by actxserver, normalizes COM program identifiers (progIDs), which is the string used to locate the COM server. Unfortunately, until R2011a (or specifically, when this was fixed by some MathWorker on June 10, 2010), this function had a bug that caused the normalization to fail. In order to correct this, I simply added the fixed function to the bottom of my modified actxserver.m file:

% Taken from: [matlabroot '\toolbox\matlab\winfun\private\newprogid.m']
function convertedProgID = newprogid(progID)
% Copyright 1984-2004 The MathWorks, Inc.
% $Revision: 1.1.8.5 $ $Date: 2004/04/15 00:07:00 $
convertedProgID = lower(progID);  % Yair: in the new version (after 2010/06/10) this line is missing i.e. case-sensitive progID
convertedProgID = regexprep(convertedProgID, '_', '__');  % Yair 17/5/2009: was progId - probably a bug
convertedProgID = regexprep(convertedProgID, '-', '___');
convertedProgID = regexprep(convertedProgID, '\.', '_');
convertedProgID = regexprep(convertedProgID, ' ', '____');
convertedProgID = regexprep(convertedProgID, '&', '_____');

% Taken from: [matlabroot '\toolbox\matlab\winfun\private\newprogid.m'] function convertedProgID = newprogid(progID) % Copyright 1984-2004 The MathWorks, Inc. % $Revision: 1.1.8.5 $ $Date: 2004/04/15 00:07:00 $ convertedProgID = lower(progID); % Yair: in the new version (after 2010/06/10) this line is missing i.e. case-sensitive progID convertedProgID = regexprep(convertedProgID, '_', '__'); % Yair 17/5/2009: was progId - probably a bug convertedProgID = regexprep(convertedProgID, '-', '___'); convertedProgID = regexprep(convertedProgID, '\.', '_'); convertedProgID = regexprep(convertedProgID, ' ', '____'); convertedProgID = regexprep(convertedProgID, '&', '_____');

Note that when MathWorks fixed %matlabroot%/toolbox/matlab/winfun/private/newprogid.m in 2010, they removed the conversion of progID to lower-case, making it case-sensitive. In my modified version above, I have kept the older conversion to lowercase for case-insensitivity.

Public-service announcements

Matlab open training day (Israel) - click for details
Matlab open training day (Israel) - click for details

Readers in Israel are invited to attend a free training seminar that I will present on advanced Matlab topics in Herzliya, on Tuesday Jan 8, 2013. The seminar is free, but requires registration. Additional details here. I will speak in Hebrew, but the presentation will be in English and I will be happy to answer questions in English.
I wish to point readers’ attentions to the recent announcement by AccelerEyes and MathWorks, that they will now merge their parallel-processing solutions into Matlab’s product line. I assume this also means an out-of-court settlement of MathWorks’ patent-infringement lawsuit. On the one hand, this is bad news for competition, removing Matlab PCT’s major competitor from the market. On the other hand, it could mean improved PCT/DCS products, merging Jacket’s superior performance and functionality directly within Matlab. If I may venture a guess, 2013 will herald a better, faster, more integrated parallel computing solution for Matlab, but we should probably (and quite sadly) say goodbye to Jacket’s price levels. Such collaborations, generally portrayed as exciting for consumers, are typically much more exciting for the respective shareholders…
This blog will now take a short winter break, and will return following the New-Year. Happy Holidays/New-Year everyone! Let this upcoming year be another year filled with discoveries, innovation and success!
 

Related posts:

  1. Fixing a Java focus problem – Java components added to Matlab GUIs do not participate in the standard focus cycle - this article explains how to fix this problem....
  2. Speeding up compiled apps startup – The MCR_CACHE_ROOT environment variable can reportedly help to speed-up deployed Matlab executables....
  3. Explicit multi-threading in Matlab part 2 – Matlab performance can be improved by employing .Net (C#, VB, F# or C++) threads. ...
  4. Creating a simple UDD class – This article explains how to create and test custom UDD packages, classes and objects...
  5. Running VB code in Matlab – Matlab does not natively enable running VB code, but a nice trick enables us to do just that...
  6. Class object creation performance – Performance aspects of Matlab class object creation are discussed, with specific suggestions. ...
ActiveX COM Performance Pure Matlab Undocumented feature
Print Print
« Previous
Next »
8 Responses
  1. liam July 17, 2014 at 08:44 Reply

    Is there a way to force actxserver to create two separate instances.

    I have been trying to launch to separate COM instance of CQG COM object by calling actxserver(‘CQG.CQGCEL.4’) twice. This will only return one instance of the actxserver.

    Is there a way to force 2 instances?

    Tks

    • Yair Altman July 18, 2014 at 01:15 Reply

      @Liam – I’m not aware of a way to do this.

  2. duke April 5, 2016 at 21:26 Reply

    doesn’t work, crashes out.

  3. Sarunas January 3, 2018 at 09:38 Reply

    I had a program that reads two excel files (== two tables) and returns an excel with 10 sheets, 2 – 3 tables each sheet. I used WRITETABLE, I had to use that for every table, making the program a bit slow.

    Even more, when I had to calculate hundreds of input file variation combinations, the run-time started slowing down progressively. This was due to the fact, that EXCEL instances were opened for each call to read/write EXCEL files, and they, not closing before the following loop, started stacking up. I solved this by closing all EXCEL instances after each reference to EXCEL files, side effect being not being able to use EXCEL while running the program (which I was too lazy to solve).

    After implementing the try/catch posted here into actxserver.m, the program runs twice as fast without the side effect. Thank you kind sir.

    • Sarunas January 3, 2018 at 11:16 Reply

      Or maybe I was too joyful too quickly.

      Apparently if there is an excel window open, I get an error and/or the window is closed.

    • Sarunas January 11, 2018 at 16:55 Reply

      Update:

      Since “the one” used instance of EXCEL is closed inside other called functions (like xlsread/xlswrite), I had to hide some of the code there to prevent the programs from closing. I use readtable, which works good with this xlsread correction, but writetable has another Excel.Quit line, which I managed to find in write.m file. I disabled a few lines in writeXLSFile (which is called from within write.m), but not sure if they are of any significance, because my problem was fixed eventually after editing the write.m file. This however means that I will have to manually control the behaviour of how EXCEL workbooks are displayed, but this way my run-time was reduced from ~90 s to ~20 s.

      HOWEVER, once compiled to an .exe, program seems to have a problem using actxGetRunningServer.m, which is the core to this ‘fix’. This meant that I had to change back all the functions to compile a version that’s usable with MCR.

      At least I learnt something in the process. And even though my users get no merits from this, I will definitely use those fixes if I happen read/write hundreds of excel files again.

  4. Ren April 3, 2022 at 18:38 Reply

    I noticed that xlsread will create a hidden and never-dying special server that always has priority when actxGetRunningServer is called.
    So this cause a problem that no matter how many servers I re-create, the actxGetRunningServer is always connected to the hidden xlsread-generated server, which never dies even when I change the raw code by adding a Excel.Quit() to the private file of Matlab.

    • Yair Altman May 27, 2022 at 12:28 Reply

      Ren – This is usually the expected behavior, which avoids unnecessary duplications of the Excel process in CPU/memory. If you want to kill the process you can always run system('taskkill /im excel.exe 2> NUL') or hExcel.Quit; delete(hExcel). (the delete(hExcel) part is important – without it the process will not actually quit).

Leave a Reply
HTML tags such as <b> or <i> are accepted.
Wrap code fragments inside <pre lang="matlab"> tags, like this:
<pre lang="matlab">
a = magic(3);
disp(sum(a))
</pre>
I reserve the right to edit/delete comments (read the site policies).
Not all comments will be answered. You can always email me (altmany at gmail) for private consulting.

Click here to cancel reply.

Useful links
  •  Email Yair Altman
  •  Subscribe to new posts (email)
  •  Subscribe to new posts (feed)
  •  Subscribe to new posts (reader)
  •  Subscribe to comments (feed)
 
Accelerating MATLAB Performance book
Recent Posts

Speeding-up builtin Matlab functions – part 3

Improving graphics interactivity

Interesting Matlab puzzle – analysis

Interesting Matlab puzzle

Undocumented plot marker types

Matlab toolstrip – part 9 (popup figures)

Matlab toolstrip – part 8 (galleries)

Matlab toolstrip – part 7 (selection controls)

Matlab toolstrip – part 6 (complex controls)

Matlab toolstrip – part 5 (icons)

Matlab toolstrip – part 4 (control customization)

Reverting axes controls in figure toolbar

Matlab toolstrip – part 3 (basic customization)

Matlab toolstrip – part 2 (ToolGroup App)

Matlab toolstrip – part 1

Categories
  • Desktop (45)
  • Figure window (59)
  • Guest bloggers (65)
  • GUI (165)
  • Handle graphics (84)
  • Hidden property (42)
  • Icons (15)
  • Java (174)
  • Listeners (22)
  • Memory (16)
  • Mex (13)
  • Presumed future risk (394)
    • High risk of breaking in future versions (100)
    • Low risk of breaking in future versions (160)
    • Medium risk of breaking in future versions (136)
  • Public presentation (6)
  • Semi-documented feature (10)
  • Semi-documented function (35)
  • Stock Matlab function (140)
  • Toolbox (10)
  • UI controls (52)
  • Uncategorized (13)
  • Undocumented feature (217)
  • Undocumented function (37)
Tags
ActiveX (6) AppDesigner (9) Callbacks (31) Compiler (10) Desktop (38) Donn Shull (10) Editor (8) Figure (19) FindJObj (27) GUI (141) GUIDE (8) Handle graphics (78) HG2 (34) Hidden property (51) HTML (26) Icons (9) Internal component (39) Java (178) JavaFrame (20) JIDE (19) JMI (8) Listener (17) Malcolm Lidierth (8) MCOS (11) Memory (13) Menubar (9) Mex (14) Optical illusion (11) Performance (78) Profiler (9) Pure Matlab (187) schema (7) schema.class (8) schema.prop (18) Semi-documented feature (6) Semi-documented function (33) Toolbar (14) Toolstrip (13) uicontrol (37) uifigure (8) UIInspect (12) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
  • Iñigo (2 days 14 hours ago): Thanks Yair. I didn’t realize it was posted just above. It would be great to know about a solution soon
  • Yair Altman (3 days 21 hours ago): @Iñigo – your query is related to Seth’s question above. We can access the currently-browsed URL in JavaScript (for example: jBrowserPanel.executeScript...
  • Iñigo (5 days 13 hours ago): I am looking for setting a UI that allows following process: opening a web site, navigate inside this web site and at some specific moments (i.e. when the figure is closed or a button...
  • Nicholas (12 days 19 hours ago): Yair, this works wonderfully! I can’t thank you enough!
  • Collin (14 days 22 hours ago): Seth Good point, I am using 2022b, mathworks seems to have started using CEF browsers from 2019a, best I can tell. take a look at the package com.mathworks.toolbox.matla...
  • Seth (15 days 14 hours ago): Collin, What version of MATLAB are you using?
  • Collin (20 days 20 hours ago): Seth, I have had some success executing javascript that requires no return value by executing it directly (sort of) on the org.cef.browser.CefBrowser that a...
  • Coo Coo (22 days 16 hours ago): FFT-based convolution is circular whereas MATLAB’s conv functions have several options (‘valid’, ‘same’, ‘full’) but unfortunately not...
  • Seth (22 days 18 hours ago): No luck with removing the space.
  • Seth (22 days 20 hours ago): The javascript code works fine running the application from the 2019b desktop version and the 2016b deployed version.
  • Seth (22 days 20 hours ago): I have been using this browser functionality in 2016b because it works fully in deployed applications in that version. However, because of Java 7 being flagged as a security risk, I...
  • Yair Altman (22 days 20 hours ago): I’ve never tested javascript callbacks, but perhaps you should try removing the extra space after the “matlab:” protocol specifier. Does it make any difference?
  • Seth (22 days 21 hours ago): I have been using this functionality in 2016b since it works in deployed applications and have not had a reason to need to upgrade but with java 7 being flagged as a security risk I am...
  • KEVIN (42 days 21 hours ago): I apologize, I intended my response to fall under ‘T’ but did not seem to work. I was referring to the bit of code posted by ‘T’ regarding the toolgroup and...
  • Yair Altman (42 days 22 hours ago): It is not clear from your comment which code exactly you are referring to and what you see differently in 19b vs. 20b, so I cannot assist with your specific query. In general I...
Contact us
Undocumented Matlab © 2009 - Yair Altman
This website and Octahedron Ltd. are not affiliated with The MathWorks Inc.; MATLAB® is a registered trademark of The MathWorks Inc.
Scroll to top