We started using MATLAB 64 bits in our system and some of our legacy M code uses a custom version of the MSFlexGrid ActiveX component so we decided to write a .Net 64 bit version of it.
The ActiveX is exposed via a Windows Forms host.
[ProgId("FlexiGrid")]
[Guid("88888888-4444-4444-4444-CCCCCCCCCCCC")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public partial class GridWinFormsHost : UserControl
{
}
The Windows Form User Control embeds a WPF UserControl via ElementHost.
private IGrid grid;
private void GridWinFormsHostLoad(object sender, System.EventArgs e)
{
var host = new ElementHost { Dock = DockStyle.Fill };
this.grid = new GridView();
host.Child = (GridView)this.grid;
this.Controls.Add(host);
}
The control is successfully registered, visible to MATLAB, and can be instantiated via
actxcontrol('FlexiGrid', Position, Fig, CallBack);
Methods and properties exposed in the GridWinForms are visible and can be get/set/invoked.
However after instantiating the ActiveX we eventually need to call into .Net - in the MATLAB process - via a MEX DLL. The call executes successfully in .Net but the MATLAB process freezes when control returns from .Net. Running the same code without instantiating the ActiveX control succeeds and MATLAB doesn't freeze, which means that instantiating the .Net ActiveX control is probably the cause of MATLAB freezing.
When searching for solutions I came across this MSDN thread in which it is stated: "This problem occurs because the message loop that the Windows Form uses and the message loop that the COM client application provides are different." The original poster concludes that he solved the issue with WPF + MFC but doesn't detail the solution.
I also found this MSDN article which states that: "To make a Windows Form work correctly from a COM client application, you must run the form on a Windows Forms message loop." This is also promising except that the solution focus on creating new Windows Form windows but I need to run a Windows Forms user control embedded in a MATLAB window.
So the issue seems to be related to hosting a managed ActiveX control on an unmanaged application - any ideas?
Not a real "solution" to your issue, but maybe a (imho good) alternative for the activeX stuff:
Starting from some MATLAB version (I think ~2009 or so, others might correct me if not) you can use .NET libraries directly from MATLAB, without the need for the COM-interface:
http://www.mathworks.de/de/help/matlab/getting-started.html
Syntax-wise you can use .NET classes almost as good as java-classes.
Particularly, this should be much more comfortable than talking to .NET via MEX - I assume.
Related
I've been asked to create a little tool to help automate a basic 3rd party WinForms application.
So far I've managed to overcome many hurdles but this one is by far one of the most frustrating of them all (And spending 8 hours researching only to find out LVM_GETITEMTEXT was returning an LVITEM struct with 64-bit pointers was very frustrating) - I can't seem to find any way at all to get any kind of reference to a ToolStrupStatusLabel in the third party application's StatusStrip.
The only indication I have that the application has finished it's assigned task is when the StatusStrip is updated to show it has been finished. I can't reliably automate it's operation if I can't find out when it finishes one job and proceeds to another.
Is there any message I can SendMessage() to the application? Any function I can call? Anything that will help me locate the text on this label so I can gain some insight into the application's status?
The automation tool is programmed in C#/Winforms with pInvoke for various Windows functions. I've also created my own DLL in C++ to assist with obtaining data from the LVITEM struct, so C++ workarounds are possible too.
This isn't going to work. The ToolStripItem derived classes are special, they do not derive from Control. They don't have their own window handle, they use the window of their host to draw themselves. Where the host is a Control, like ToolStrip or StatusStrip in your case.
This makes them unusable from traditional UI automation tools that require a window handle. The only way to commandeer them is by injecting a DLL that uses reflection to get a ToolStripItem reference. This exists, the Managed Spy++ tool uses this technique. Source code is provided so you can put your own together, you'll want to leverage the ManagedSpyLib which does the heavy lifting.
I am writing a plugin for a C# application and would like to add a dialog window. I have no control over the application, rather, the application loads plugins dynamically using reflection. I am a newbie with windows forms (this is a forms application) but would like to have a dialog window come up to control my plugin. How can I accomplish this?
If I just add a windows form to my application via visual studio no form appears. Application.Run has presumably already been called by the main application. I am almost completely new to forms.
How can I start the form with with my plugin (the plugin has a method that is called when it is started) and make it active?
Edit: I should clarify, the main application application window will not respond (even to minimize or maximize the window) when a plugin is running, so presumably whatever thread is devoted to handling windows messages is used to run the plugin and is, temporarily, not handling any windows messages. Thus my form needs its own thread handling windows messages.
You will need to initialize your code from whatever method the plugin architecture defined as the entry point (where the application will call your plugin).
To show a form, you can call the Show method on it.
// In a method that the plugin framework calls
myPluginForm.Show();
The application that loads your plugin should have some facility to load a window. Check the API documentation. Also, do you know if there are other plugins that can create arbitrary new windows? Usually, the host application can allow the plugin to create certain predefined (by the host) types of windows (such as config, load a file, etc...).
It might also be possible to programmaticaly create a new form and then load it. See here for an example: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.aspx and look for the "examples" section.
I have a managed application TestApplication.exe in C# and Application.EnableVisualStyles() is allready called.
I have a Class Library MySharedCode.dll also in C# which uses [DLLImport()] to import some External dialogs out of an unmanaged dll.
Well, now I am using (add reference) MySharedCode.dll in my TestApplication.exe and call a function MyTestConfigDlg() out of it. TestClass.MyTestConfigDlg();
OK, everything works fine and I get my dialog, but the dialog has NO XP style/themes?
I just wanted to see if it's general problem with managed/unmanged modules, so I used the [DLLImport()] to call the same MyTestConfigDlg() dialog but this time directly in my TestApplication.exe! WOW! Worked as I expected. The Dialog was in XP Style/Themes!
so, anybody here who can help me out?
FYI: I also tried (just for test) to call MessageBoxA() API call in my Class Library Dll which later called by my TestApplication.exe and the MessageBoxA() had also no Style/Themes!
Thanks in advance!
Usage of the Application.EnableVisualStyles() applies to certain windows controls such as ListBox, ListView, Menu, Buttons, to make it in line with the XP themes control from the start, if it was running on Vista and later, it would conform the controls to that style also. In short I do not know how do you mean the dialog has no XP/Themes support when invoked directly via the References, yet when you used DllImport keyword to import the function it worked, that is unusual. Usually the usage of DllImport is for unmanaged code API, but somehow it picked it up...I do recall that there was a bug with the .NET 1.1 framework in that if you called Application.EnableVisualStyles(), it failed to work, unless a call to Application.DoEvents() was invoked between enabling the Visual styles and instantiating a winforms, maybe in your case, when instantiating a dialog, perhaps that could solve it by calling Application.DoEvents(), other than that, I am out of ideas...
Hope this helps,
Best regards,
Tom.
I've read a few topics about programs that combine Windows Forms and console applications, but it seems my question hasn't been solved yet. Is it possible to run a program from cmd-line and to be able to control the application via forms and via cmd-line commands? It means:
for ordinary users of the application to control the application via (Windows Forms) forms,
for debugging and advanced users to control the application via the console (and optionally see what's happening in Windows Forms))
I know that what I want is quite a big deal, and it will probably mean a lot of work, but still I would like to know how to do it properly.
It isn't difficult, just P/Invoke the AllocConsole() API function to create your own console. For example, make your Program.cs source code file look like this:
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
#if DEBUG
CreateConsole();
#endif
Application.Run(new Form1());
}
static void CreateConsole() {
var t = new System.Threading.Thread(() => {
AllocConsole();
for (; ; ) {
var cmd = Console.ReadLine();
if (cmd.ToLower() == "quit") break;
// Etc...
}
FreeConsole();
});
t.IsBackground = true;
t.Start();
}
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool AllocConsole();
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool FreeConsole();
}
You just need to start your Windows Forms application with an ApplicationContext instead of a form itself. You are then not depending on the main form to be shown and can act like an console application.
You could also just create a command-line executable and link with the Windows Forms libraries yourself to use them.
Another way would be to use some kind of starter, that fires up the Windows Forms application, and a command line tool that communicates with the Windows Forms application over local networking, or some other inter-process communication, D-Bus or similiar systems - many ways lead to Rome...
Yes, what you want is very possible. You have options. Some I can think of...:
Use UI Automation to write a controller application that can connect to the Windows Forms application and control it. This is new in Windows Vista. There are managed classes packaged in the System.Windows.Automation namespace, which first shipped in WPF, which arrived in .NET 3.0. (Now that I think about it, I'm not sure "new in Windows Vista" is true. It may be "new in .NET 3.0" which implies it also works on Windows XP. Hmmm....) UI Automation requires no code change to the Windows Forms application, but it can be sort of low-level, because you need to program each mouse click or cut/paste. See the answer to Stack Overflow question Is there a way to control a third-party EXE file from VB.NET?.
Modify your Windows Forms application to expose its function via a WM_COPYDATA interface. Then your client application can communicate with it. Again, the model here is two distinct applications, one of which can control or interrogate the other. The .NET Reflector tool is a good example of this approach. There's a ReflectorController, available as part of the ReflectorAddins project on CodePlex. The controller is a command-line tool, that can send WM_COPYDATA messages to Reflector, to tell it to open a new assembly, navigate to a particular class, and so on.
The code for the controller:
http://reflectoraddins.codeplex.com/sourcecontrol/network/Show?projectName=reflectoraddins&changeSetId=29526#19979
This approach will work for any Windows Forms application. You will need to override the WndProc method. To see how, check The Code Project article Use WM_COPYDATA to send data to/from C++ and C# Windows processes.
I also used this approach to build a Windows Forms-based progress monitor that can visually display the progress of long-running tests.
Within your application, expose a COM server object that can be programmed. This is exactly how Microsoft exposes Office function to applications. Office Automation allows any COM-capable program (C#, VBScript, PowerShell, Perl, PHP, etc.) to "drive" Office applications. The Office application is visible while that is happening. This approach would also require additional code in your Windows Forms application; specifically you have to host a COM object and hook it up to your UI layer. This may be preferable if you want maximum flexibility for superusers - they can write their own scripts to drive that component.
I'm sure there are other options.
I remember seeing IronPython being used in a demo controlling Windows Forms from Python's command line interface (IDLE).
Edit:
I could not find the original video but this one should show what is possible without too much effort. See this video and jump to 19:00.
This would be possible. You will have to look into threading the Windows Forms form, possibly with the use of a separate application domain within the same process. You might look into creating a proxy object (a kind of message class inheriting MarshalByRefObject).
Normally when looking at your application, you have an UI layer and a business layer (and a data layer, and who knows many more layers). You can think of the console client as an UI layer (with simple command inputs) and the Windows Forms client as another one.
Simply check at application startup for command-line arguments. If there are arguments specified, instantiate the simple console classes, otherwise instantiate the (probably more complex) Windows Forms classes.
If you want your changes to reflect in the Windows Forms application (while controlling it from the console application) setup your applications as much as you can with databinding. Let your business layer reflect what's actually going on in your application.
I'm currently developing an application for Windows platform that will be able to play Quick Time videos.
The targeted OS versions are Windows XP, Windows Vista and Windows 7.
I successfully used the Apple ActiveX QuickTime Control 2.0 (in C#) and everything works well on Windows XP.
However, on Vista and Windows 7 I'm facing problems with properly disposing the control.
Here are the "steps to reproduce" :
- I create the Quick Time control dynamically at runtime and I place it on a panel;
I successfully play videos with it;
At some point I close the application main form; the application windows is destroyed and the application will continue to run in the background (doing operations like syncing videos); at this point the control is disposed using IDisposable pattern; I can't explicitly dispose the Movie object (from the ActiveX control) because I get an exception like: "COM object that has been separated from its underlying RCW cannot be used."; I just use (AxQTOControlLib.AxQTControl) player.Dispose(); On Windows XP this is fine but not on Vista and 7
I restore my application (from tool bar where it was running in background) and try to open the video again; At this point an AccessViolationException "Attempted to read/write protected memory" is thrown;
My questions are:
Why is this happening only on Vista and Windows 7 ?
On XP is a hidden leak ?
What is the recommended way to dispose the control (with its movie object) when it is created at runtime ?
I'm now using an explicit Movie.Disconnect() call (although I don't now what this disconnect means because I could not find proper documentation) fallowed by a QuickTimeTerminate() call before the form is closed.
While my method is working it is kind of design breaking so I would like to know a better way of doing this.
Thank you,
Mosu'
Update:
I just discovered that my method is not workink. I use to players: QuickTime control and Windows Media player control (both ActiveX) and when one fails to play a file the other one is used. I was seeing the output of WindowsMedia player and thinking the methos IS working.
So my fix is not working at all.
Lots of people seem to be having this error.
This page offers an interesting approach: http://www.theusenetarchive.com/usenet-message-how-to-properly-destroy-quicktime-activex-object-10384503.htm
The crash occurs because of file handles still being open. I was
'unloading' movies from the Quicktime control by wiring a null string
to the FileName or URL property. Quicktime doesn't handle this
correctly and leaves the original file open. So instead I wired
a path to an actual image file (Quicktime does images too) that was
all black. Eveything seems fine now.