Ken Atwell in the MATLAB product management group is guest blogging this week about his recent experiences using Microsoft .NET® and how it can used to expand the breadth of capabilities in MATLAB, especially in situations where you need a facility that MATLAB does not directly supply.
Microsoft .NET is a software framework for developing applications on Microsoft Windows. Notably, it includes a comprehensive library for all kinds of general-purpose programming tasks, from networking and security, to file parsing. Since R2009a, MATLAB has been able to call into the .NET library, but personally being a newbie to .NET, it was only very recently that I had enough motivation to invest it learning about it. It was a very positive experience, so I thought I’d share my story in this blog post.
The other day, I was experimenting with the MATLAB function REGMATLABSERVER. It registers MATLAB as an Automation server, so that it can be controlled by other applications. For instance, this is used by Spreadsheet Link EX to enable live data transfer from Microsoft Excel to MATLAB (Even if you don’t know or care about what these things are, bear with me, as much of what we’re discussing is generally applicable). Under Windows 7 or Windows Vista, registering is an Administrator-level operation that will cause User Account Control (UAC) to bring up a dialog box prompting the user to confirm the action. As it turns out, REGMATLABSERVER in its current form does not invoke UAC and will simply fail to register MATLAB. The work-around is easy enough -- run MATLAB as an Administrator (right-click on the MATLAB Start Menu icon) and register from within that privileged MATLAB. But, it got me wondering, is there a way to invoke UAC from within MATLAB, avoiding the need to run MATLAB as a whole as an Administrator?
Examining the implementation of REGMATLABSERVER shows that it works by simply invoking a second instance of MATLAB with a special command line switch. These are the relevant commands in REGMATLABSERVER:
command = sprintf('"%s" /wait /regserver /r quit', ... fullfile(matlabroot,'bin','matlab')); [s,msg] = system(command);
So, all I really needed to figure out was how to invoke a process as an Administrator. I knew of no way to do this in MATLAB, so like anyone, I used Google to find programmatic ways to start a process as an Administrator. I quickly learned that .NET provides facilities to do this, and found source code in C#/.NET (on the English-language Wikipedia page for UAC, of all places) that demonstrates how to do it. At first, this gave me some pause, as I’d never used C# or .NET in any meaningful way. But, the code was very readable, so I decided to drop the code into MATLAB and see if I could make it work. The C# code from Wikipedia was:
System.Diagnostics.Process proc = new System.Diagnostics.Process(); proc.StartInfo.FileName = "C:\\Windows\\system32\\notepad.exe"; proc.StartInfo.Verb = "runas"; // Elevate the application proc.Start();
The first thing I needed to do was make some small syntax changes to turn this C# program into a MATLAB program. With the help of the MATLAB Code Analyzer (those wavy red and orange lines in the editor), I was able to get to valid MATLAB code in maybe a minute. I needed to do three things:
This resulted in the following MATLAB code:
proc = System.Diagnostics.Process(); proc.StartInfo.FileName = 'C:\\Windows\\system32\\notepad.exe'; proc.StartInfo.Verb = 'runas'; % Elevate the application proc.Start();
Neat! With very little effort, I had a script which launches the Notepad application as an Administrator, triggering UAC prompts as necessary. My next step was to use this as a starting point for what I actually want to do, namely start MATLAB as an Administrator with extra command-line arguments (as we saw in the implementation of REGMATLABSERVER above). Given that I now knew the name of the .NET class I needed (System.Diagnostics.Process), I was able to get to the MSDN reference page (again, Google is your friend). Between this reference page and tab completion in MATLAB (type proc. , then press the Tab key), I was able to poke around and specify the bits I needed:
proc = System.Diagnostics.Process; % EXE to run proc.StartInfo.FileName = fullfile(matlabroot,'bin','matlab'); % Arguments to the EXE proc.StartInfo.Arguments = '/wait /regserver /r quit'; % Run-as admin proc.StartInfo.Verb = 'runas'; proc.Start(); % Start
It was now working, but there were two things I didn’t like:
Another several more minutes of experimentation and iteration, and I got to a more satisfying implementation:
proc = System.Diagnostics.Process; % EXE to run proc.StartInfo.FileName = fullfile(matlabroot,'bin','matlab'); % Arguments to the EXE proc.StartInfo.Arguments = '/wait /regserver /r quit'; % Run-as admin proc.StartInfo.Verb = 'runas'; proc.StartInfo.WindowStyle = ... System.Diagnostics.ProcessWindowStyle.Hidden; proc.Start(); % Start proc.WaitForExit(); % Wait for the process to end proc.ExitCode %Display exit code
Not bad! Knowing next-to-nothing about .NET, it took me about a half-hour to create my first MATLAB script that leverages .NET. Granted, this is a trivial program, but it does something new and useful. I know this sounds corny, but it was something of a revelatory moment for me and I won’t hesitate to leverage .NET when the situation next arises.
For a second experiment, I recalled hearing somewhere that .NET includes a speech synthesizer. I thought this might be a “fun” example, so I Google searched “.NET speech synthesis” and found a nice article on the subject, with code in C++, C#, and VB. Reading through the short article, it said something about needing to “reference the System.Speech assembly”. I was not quite sure what that meant, so I moved on. The C# code looked closest to MATLAB code, so I started with it:
using System.Speech.Synthesis; SpeechSynthesizer speaker = new SpeechSynthesizer(); speaker.Rate = 1; speaker.Volume = 100; speaker.Speak("Hello world.");
As before, I tweaked things a tiny bit to make the syntax agreeable to MATLAB:
using System.Speech.Synthesis; speaker = SpeechSynthesizer(); speaker.Rate = 1; speaker.Volume = 100; speaker.Speak('Hello world.');
Here, MATLAB (perhaps unsurprisingly) generated an error on the using keyword. Being a past C++ programmer, I recognized the using statement as a way to bring a namespace into scope; stated more pragmatically, it is a mechanism to save keystrokes later in your code. I could avoid the need for a using statement by simply specifying the full “path” to SpeechSynthesizer instead:
speaker = System.Speech.Synthesis.SpeechSynthesizer(); speaker.Rate = 1; speaker.Volume = 100; speaker.Speak('Hello world.');
But, that still didn’t work, as I triggered an error about an undefined variable or class. Hmm… guess I needed to pay attention earlier when the article advised me to add a reference to the System.Speech assembly. I did not know how to do this in MATLAB, so I Google searched “MATLAB add reference to .NET assembly”. For me, the first couple of results were from mathworks.com. The first result was an index of functions; the second was the topic Getting Started with .NET. Reading through the first few paragraphs of the introduction, I learned that in MATLAB I need to use NET.addAssembly to load an assembly. It is analogous to using JAVAADDPATH to make Java classes visible to MATLAB. As it turns out, a few particularly useful assemblies are loaded by default, which explains why I did not need to bother with this in the first example (basically, I got lucky!).
Armed with this information, I inserted a line of code to add the assembly before using its classes:
NET.addAssembly('System.Speech'); speaker = System.Speech.Synthesis.SpeechSynthesizer(); speaker.Rate = 1; speaker.Volume = 100; speaker.Speak('Hello world.');
And voilà! My computer was now saying “Hello world” to me. Since I was having fun, I changed the message to tell me the day of the week:
NET.addAssembly('System.Speech'); speaker = System.Speech.Synthesis.SpeechSynthesizer(); speaker.Rate = 1; speaker.Volume = 100; [~,S]=weekday(date, 'long'); speaker.Speak(['Today is ' S]);
I now had my second MATLAB program using .NET. This one was a touch more complex, as I need to understand NET.addAssembly, but that was a hurdle I was able to get over with little fuss.
Bottom line: When you’re looking to solve a problem that is outside the normal purview of MATLAB, don’t underestimate the power of the .NET Framework you have at your fingertips (or, on the off chance .NET is not already installed, it is freely available for download from Microsoft). Further, don’t be daunted by .NET if you’ve never used it, as starting points (code fragments) are easy to come by and C# and other languages can often easily be ported into MATLAB.
I’m curious to hear if any readers have had experiences with .NET in MATLAB. What kinds of problems do you solve? Chime in below!
댓글을 남기려면 링크 를 클릭하여 MathWorks 계정에 로그인하거나 계정을 새로 만드십시오.