From: Joseph M. Newcomer on 11 May 2008 17:08 If you need a DLL that is called from matlab itself, and it is supposed to represent an application, I'd be inclined to do one of the following: * Have the DLL SendMessage(WM_COPYDATA) to an instance of an application. * Have the DLL use a shared memory segment to send data to the application, probably using a semaphore to indicate something has been enqueued. The application will wait for this semaphore in a separate thread and notify the app when the data arrives. * Same as above, using a memory-mapped file to do the sharing. * Use a simple message to send small quantities of data across using PostMessage (or PostThreadMessage if sent to a non-GUI UI thread of the other app) Partly, it depends on the amount of data. For very small amounts of data, a simple PostMessage to the app will suffice (it can send a pair of floats, two integers, etc. in one message). This does not scale up to massive data arrays. Shared memory should be treated with respect, in that you should not be doing much locking. I prefer the "positive handoff" protocol where you fill something up, and put it in an "inbox" for the other app. The only locking you need to do is in manipulating the allocation of the shared data values within the shared data segment, which is easier and safer to do than trying to lock entire data areas for long periods of time. Once a data block is allocated, it is either used by the "producer" that writes into it, or by the "consumer" that reads from it, but there is NEVER concurrent access to the data, under any circumstances. The only concurrent access is protecting the allocator. joe On Sun, 11 May 2008 11:50:57 -0700, "David Ching" <dc(a)remove-this.dcsoft.com> wrote: >"Scott McPhillips [MVP]" <org-dot-mvps-at-scottmcp> wrote in message >news:%23V3juM5sIHA.5832(a)TK2MSFTNGP02.phx.gbl... >> Here's a suggestion you might want to try, either as a permanent solution >> or perhaps as an experiment to see what you can learn about the OnClose >> problem. You could create a new (MFC) thread in the call from Matlab. >> That's done by deriving a class from CWinThread and calling AfxBeginThread >> with the class name. >> >> The thread has an InitInstance, just like your original application did, >> and all of your windows etc. would run in the new thread if you put your >> original InitInstance code there. The call from Matlab would merely sit >> suspended in a WaitForSingleObject until the thread exits. The advantage >> is that this would get you out of undocumented territory, and it would >> start your thread and message pump (the Run function) using the normal MFC >> initialization code. >> > >It's a good idea to start the secondary thread to wait for the window to >close. But I don't think it's proper behavior to call CWinApp::Run() from >the 'hook' function. That seems plain wrong. It's already been called when >the DLL was loaded and I've never seen it called again. So I would ditch >the idea of calling CWinApp::Run(). > >But everything else sounds good. Just move everything that was in the >CWinApp::InitInstance() to the CMyWinThread::InitInstance(), then start it >in the hook function using AfxBeginThread(), then WaitForSingleObject() of >that thread. > >The reason I suggested just executing the .exe was because there was no sign >of any data passing anywhere. I guess that is done through other exported >functions that haven't been shown. > >-- David > Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: JRGlide on 11 May 2008 17:18 David, Scott, Ajay, Thank you very much for your help. I will try your suggestion for the WinThread and see how it works. That sounds like that may be what I need. Scott, you said “The advantage is that this would get you out of undocumented territory”. I was surprised to read that. I thought what I was trying to do was pretty normal and done all the time. Is this not the case? I am really in uncharted territory? > The reason I suggested just executing the .exe was because there was no sign > of any data passing anywhere. I guess that is done through other exported > functions that haven't been shown. Sorry about that, David. I tried to trim it down so I didn't include a lot of unnecessary code, but maybe I cut it down too much. Here is a more complete version of the calling routine (but still some cut out some). typedef struct { float x; float y; float z; float intensity; unsigned char clipped; } IMAGE_DATA; extern "C" { __declspec(dllimport) IMAGE_DATA *point_cloud; __declspec(dllimport) int num_points; __declspec(dllimport) int ViewPointCloud (void); } int main (int argc, char* argv[]) { IMAGE_DATA *point_cloud; // Read data here. This would normally be passed in by MATLAB. point_cloud = (IMAGE_DATA*) malloc (sizeof (IMAGE_DATA)*100000); num_points = 100000; ViewPointCloud(); free (point_cloud); return 0; } Thanks again and I'll let you know how this works. Jim
From: JRGlide on 11 May 2008 17:58 Joe, The purpose of the viewer is to provide another tool for MATLAB (and LabView) users for viewing data, just as plot2d, plot3d and surf allow the user to view data in different ways. This is a research facility so the MATLAB programs are always changing. This is why the user needs to call my viewer and not the other way around. Actually, MATLAB has the ability to view and rotate 3D data, but it is dirt slow, which is why I came up with this idea. I already had a standalone program and I thought it would be easy to convert it to a dll, and call it from a MATLAB mex function. The sequence was suppose to be that the MATLAB user would call a mex function I wrote called “mxViewPointCloud” which in turn called “ViewPointCloud” within the MFC app, which was suppose to pass the data to the viewer. At least that was the theory… I will try the ideas you suggested and also the WinThread idea. The data passing is indeed one-way as you cautioned, since it is strictly for display. However, it is a large amount of data. It can be anywhere from a few hundred thousand to millions of points. A million points requires 40 Meg of data be passed along. Thank you for your help. Jim "Joseph M. Newcomer" wrote: > A DLL is a DLL. A .exe is a .exe. You can't magically convert one to the other. > > Generally, since matlab output can be made into a subroutine, I'd be more likely to write > an MFC app that called a matlab subroutine, rather than a matlab application that called > an MFC DLL that pretended to be an entire app. I have two clients right now who use > matlab, one for signal processing and one for signal conditioning, and what they send me > is matlab code in a DLL, which seems a lot more sensible as an approach. The advantage of > doing the DLL is that if they tweak the algorithms, we can distribute new DLLs and > everyone gets the tweak without any changes to the interface. > > It sounds to me like you are approaching the problem from the wrong direction. > joe
From: Joseph M. Newcomer on 11 May 2008 22:03 Yes. It is extremely uncommon to try to build an application and its message loop into a DLL. There are three components here that are invovled, as I've understood it: MATLAB mathematics Rendering an image Window management The question is, why do you need to incorporate window management with your rendering algorithm? Doesn't MATLAB already provide a window management capability? So all you should need to do is pass a window handle (HWND) into your DLL (and MATLAB probably wraps this in some higher-level graphical object so it can be platform-independent, but when running on Windows, there should be a way to extract the base graphical object). So you pass this window-representative into your DLL, which immediately subclasses WM_PAINT and WM_NCDESTROY. For WM_PAINT, you do your rendering, which is based on whatever information you passed into your DLL as a data call. For WM_NCDESTROY you unsubclass the window. The message loop of MATLAB should be dispatching. The alternative, to use a UI thread, is not unreasonable. But what it represents is a thread with a GUI interface, *NOT* a full-scale application. It is more self-contained but it in no way resembles a full app. On Sun, 11 May 2008 14:18:00 -0700, JRGlide <JRGlide(a)discussions.microsoft.com> wrote: > >David, Scott, Ajay, > >Thank you very much for your help. I will try your suggestion for the >WinThread and see how it works. That sounds like that may be what I need. > >Scott, you said �The advantage is that this would get you out of >undocumented territory�. I was surprised to read that. I thought what I was >trying to do was pretty normal and done all the time. Is this not the case? >I am really in uncharted territory? > >> The reason I suggested just executing the .exe was because there was no sign >> of any data passing anywhere. I guess that is done through other exported >> functions that haven't been shown. > >Sorry about that, David. I tried to trim it down so I didn�t include a lot >of unnecessary code, but maybe I cut it down too much. Here is a more >complete version of the calling routine (but still some cut out some). > > >typedef struct { > float x; > float y; > float z; > float intensity; > unsigned char clipped; > } IMAGE_DATA; > >extern "C" { > >__declspec(dllimport) IMAGE_DATA *point_cloud; >__declspec(dllimport) int num_points; >__declspec(dllimport) int ViewPointCloud (void); > >} > > >int main (int argc, char* argv[]) **** This is where I have problems. You would not be calling 'main', you would be calling a function in your DLL, whose name would almost certainly NOT be 'main'. It would have no argc, no argv; it would be a function, and nothing more. **** >{ > IMAGE_DATA *point_cloud; > >// Read data here. This would normally be passed in by MATLAB. > > point_cloud = (IMAGE_DATA*) malloc (sizeof (IMAGE_DATA)*100000); > num_points = 100000; **** Numbers like this, which are hardwired, scare me. It's not the 2MB, it's the fact that it is fixed at compile time and isn't even a #define/static const (U)INT. Forget 'main' or 'winMain' entirely, pretend you never heard of them. Then start working forward from there. joe **** > > ViewPointCloud(); > > free (point_cloud); > return 0; >} > >Thanks again and I'll let you know how this works. > >Jim > Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: JRGlide on 12 May 2008 22:17
Today I tried using the CWinThread as David and Scott suggested, but I had some problems. When I created my own CWinThread and moved my InitInstance over from my CWinApp, I got undefines on all the Doc/View type calls, such as: AddDocTemplate(pDocTemplate); ParseCommandLine(cmdInfo); ProcessShellCommand(cmdInfo) I think this is because they are only defined in CWinApp and not in CWinThread. So then I started thinking that since CWinApp is derived from CWinThread, that maybe I could just call AfxBeginThread and pass it the original application instead, like this: CViewPointCloudApp *pointCloudThread = (CViewPointCloudApp*) AfxBeginThread (RUNTIME_CLASS (CViewPointCloudApp)); It sounds good in theory anyway, but I got undefines. The RUNTIME_CLASS macro didn't like me passing an CWinApp instead of a CWinThread. Did I understand you right, is this how I should be doing it? Otherwise, my next idea is to either convert the program and get rid of the Doc/View and go straight to a Frame and child window (I don't really need Doc/View anyway). Or I will try Joes idea of passing the data in a global memory structure and just using the viewer as an application rather than a dll. As for Joe's concerns about using a main function and hard-coding array sizes. This is just another case of me making things more complicated by trying to simplify things. The normal calling routine would be a MATLAB mex (MATLAB Executable) function which is a non-MFC dll. But if I had included the code for that, it would just clutter things up with all the MATLAB calls I have to make to extract the called data. A simple main program shows the basic calling sequence and are the exact same calls I would make from the mex function. Thank you again for your help, Jim |