Link to home
Start Free TrialLog in
Avatar of ndmiller
ndmiller

asked on

OLE Automation with Threads

My main thread calls this function when a menu is clicked on..Notice the last function call it a start of a thread.
The next section of code is the thread code...
void CYAGMeasurementSystemProjectDoc::OnBegintest()
{
      // TODO: Add your command handler code here
      if (!theMeasurementSession.GetOutputFileName())
            return;
      if (!theMeasurementSession.Verify())
            return;
      FrequencySetter.Initialize(&theMeasurementSession, &theJAG, &MeasurementTaker);
      MeasurementTaker.Initialize(&theJAG, &theMeasurementSession, &DataRecorder);
      DataRecorder.Initialize(&theMeasurementSession, FrequencySetter.NumberOfFrequencyPoints());
      MeasurementThreadHandle = AfxBeginThread(CMeasurementThread, nothing);
}


UINT CMeasurementThread ( LPVOID param )
{
      //const COleVariant vOpt((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
      
      if (!AfxOleInit())
      {
            AfxMessageBox(IDP_OLE_INIT_FAILED);
            return FALSE;
      }

      POSITION DocTemplatePosition = AfxGetApp()->GetFirstDocTemplatePosition();
      CSingleDocTemplate* m_pDocTemplate = (CSingleDocTemplate *) AfxGetApp()->GetNextDocTemplate(DocTemplatePosition);
      POSITION DocPosition = (*m_pDocTemplate).GetFirstDocPosition();
      CYAGMeasurementSystemProjectDoc* Doc = (CYAGMeasurementSystemProjectDoc *)(*m_pDocTemplate).GetNextDoc(DocPosition);
(*Doc).BeginMeasurements();      
}

Here is the BeginMeasurments code that is called
void CYAGMeasurementSystemProjectDoc::BeginMeasurements()
{
      FrequencySetter.BeginMeasurements();
}

This is the same Frequency Setter Objec that is Initialized before the Thread is called.  This FrequencySetter Object is a private data memeber of the CYAGMeasurementSystemProjectDoc class.  This FrequencySetter Object also has a pointer to the DataRecorder, which is also a private member of the CYAGMeasurementSystemProjectDoc class.  Notice in the new thread, the function BeginMeasurements is called.  This function accesses the DataRecorder which accesses an Excel _Application object..but it will not access the object from within the new thread.  All this code will work if I Initialize the DataRecorder (which contains the Excel Application) in the same thread that I access it from, but i can't do that?..
If there are any questions, please ask. thanks
Avatar of ndmiller
ndmiller

ASKER

Adjusted points from 200 to 300
First of all if you want COM support you have to call:

   ::CoInitialize (NULL);

from your thread before calling any other COM function.

In order to pass COM interface from one thread to the other you have to marshall it.

In your primary thread call:

   hr = ::CoMarshalInterThreadInterfaceInStream (IID, pHandler, &pStream);

It takes COM pointer and returns (last parameter) a pointer to newly create IStream interface.

You can use that IStream pointer in the other thread to get marshalled pointer:

   hr = ::CoGetInterfaceAndReleaseStream (pStream, IID, (void**)&pThreadHandler);

If you need further explanation let me know.



hr = ::CoGetInterfaceAndReleaseStream (m_pRegHandler->m_pStream, IID_IMsgHandler, (void**)&(m_pRegHandler->m_pDispatchHandler));

PMazur ..Please check back in 15 min or so..i will most likely have questions..i am going to try to read and understand a little before I ask..thanks
C:\NDM\JAG project\Archive\Step 8 YAGMeasurementSystemProject\YAGMeasurementSystemProject.cpp(69) : error C2065: 'hr' : undeclared identifier
C:\NDM\JAG project\Archive\Step 8 YAGMeasurementSystemProject\YAGMeasurementSystemProject.cpp(69) : error C2275: 'IID' : illegal use of this type as an expression
        c:\program files\microsoft visual studio\vc98\mfc\include\afxwin.h(1270) : see declaration of 'IID'
C:\NDM\JAG project\Archive\Step 8 YAGMeasurementSystemProject\YAGMeasurementSystemProject.cpp(69) : error C2065: 'pHandler' : undeclared identifier
C:\NDM\JAG project\Archive\Step 8 YAGMeasurementSystemProject\YAGMeasurementSystemProject.cpp(69) : error C2065: 'pStream' : undeclared identifier
Error executing cl.exe.

These are the errors that I get...I put the first line in the InitInstance of my CYAGMeasurementSystemProjectApp which has public Inheritance from CWinApp...I am going to see if i can read the MSDN online documentation on this function...if you care to explain more that would be cool...Namely..everything i guess..like...what is the stream object and do i have to have it as a data member to a class so that it is not destroyed out of the InitIntance scope?...
Thanks a lot for your time...
Also, how do i get a pointer to my interface that I need marshalled?....Is the interface the excel9.h classes?...sorry about these stupid questions, but i feel like i am swimming around trying to grasp on to something...thanks :)
Just to give you more information about my project...it might or might not help..
I am createing the following objects like so:
_Application ExcelApp;                  //Excel application object
      Workbooks ExcelWorkbooks;            //Excel workbooks object
      _Workbook ExcelWorkbook;            //Excel workbook object
      Worksheets ExcelWorksheets;            //Excel worksheets object
      _Worksheet ExcelWorksheet;            //Excel worksheet object
      Range ExcelRange;                        //Excel range object
      _Chart ExcelChart;                        //Excel chart object

I don't know if have to use a class derived from COleDocObjectItem or not...maybe my problem doesn't have anything to do with this but i thought you might want to know how this is working so far..

Then in the DataRecorder Initialize function which is called before the second thread spawns off..this code is called...
      ExcelApp.SetVisible(true);
      ExcelWorkbooks = ExcelApp.GetWorkbooks();
      ExcelWorkbook      =      ExcelWorkbooks.Add(vOpt);
      ExcelWorksheets = ExcelWorkbook.GetWorksheets();
      ExcelWorksheet = ExcelWorksheets.GetItem(COleVariant((short)1));


Thanks again for your help..I can't really seem to find anyone here at work that knows how to do this..(i have been working on it for a week)..
ExcelApp.CreateDispatch("Excel.Application");      
      if (!ExcelApp)  
    {
         AfxMessageBox("Cannot start Excel.");          
             return;    
      }

This is the code that I am useing to create the excel Application.. I don't have anything about a COleClientItem yet..do i need that?
Adjusted points from 300 to 400
Sorry, I was offline. I will get back to you within couple minutes.
I will try to be more specific.

You use class wizard to import those classes (_Application, etc.) from typelib, don't you?

In that case your imported classes are derived from COleDisptachDriver, and original IDispatch pointer is kept in public member variable: m_lpDispatch. This pointer should be passed as a second parameter to ::CoMarshall...

When you call CreateDispatch you use ProgId of "Excel.Application". Youhave to obtain its CLSID:

IID iidExcel;

::CLSIDfromProgID ("Excel.Application", &iidExcel);

And the last thing you need to declare

IStream* pStream;

That pointer must be accessible from your both threads.

Now you can call:

HRESULT hr;
hr = ::CoMarshalInterThreadInterfaceInStream (iidExcel, ExcelApp.m_lpDispatch, &pStream);

Now about the other part of marshalling which is going to happen in a newly created thread.

I assume that pStream pointer and iidExcel are accessible in this thread.

First thing, COM initialization:
::CoInitialize (NULL);

Now ww will need two variables. lpDispatch will receive marshalled pointer to IDispatch from a stream and hr for error checking.

LPDISPATCH lpDispatch;
HRESULT    hr;

To retrieve the pointer you have to call:

hr = ::CoGetInterfaceAndReleaseStream (pStream, iidExcel, (void**)lpDispatch);
if ( hr != S_OK )
   ;  // ERROR

The last step. Declare variable of _Application type and attach the IDispatch pointer.

_Application appMarshalled (lpDispatch);

I hope that now it is clear. Let me know if you have encounter any problems.
PMazur, that helps a lot. Thanks. I have just a few more questions.  I hope that you will check this :).  I also did a lot of reading over the weekend so I understood a little more of what you are talking about.  My question is this:  When you say that I need to have my IStream object and my IDD object accessable to both threads, how do i go about making that happen.  Thanks for the follow up.  It looks like i might get this working after all.
Another question, would it be possible to have a _Application object that is able to write from two threads?  In other words, above you declared an appMarshalled object with a lpDispatch that was Marshalled to write.  Would it be possible to have a _Application object create in another thread and marshall it?
Also is there something that i have to do in order to undo this process?
Another question, sorry about this. :)
So each excel object is derived from the COleDispatchDriver class.  And each COleDispatchDriver derived object has a m_lpDispatch pointer that points to the IDispatch Interface.  Lets say that I just want to write to the a _WorkSheet object, does that mean that I have to Marshall the _Application though the _Worksheet object or just the _Worksheet object?
Thanks
>>When you say that I need to have my IStream object and my IDD object
>>accessable to both threads, how do i go about making that happen.  

Plenty of possibilities:
1. global variables (very bad)
2. Declaring a struct
   struct ThreadParams
   {
      IStream* pStream;
      IID      iidExcel;
   };

Create an instance on a heap:
ThreadParams* pThreadParams = new ThreadParams;

Initialize it and pass that pointer to AfxBeginThread as a second argument.

You will receive that pointer as an argument in your thread function:

ThreadParams* pParams = (ThreadParams*)param;

When you done you have to delete that pointer:

delete pParams;

3. You can declare those variables as members in one of the classes used in both threads, say CYAGMeasurementSystemProjectDoc or FrequencySetter.
In fact after marshalling you can access the object from both threads.

It means that you can call _Application using your original pointer from main thread. And also from your worker thread using appMarshaled.

C:\NDM\JAG project\Archive\Step 8 YAGMeasurementSystemProject\CDataRecorder.cpp(132) : error C2039: 'CLSIDfromProgID' : is not a member of '`global namespace''
C:\NDM\JAG project\Archive\Step 8 YAGMeasurementSystemProject\CDataRecorder.cpp(132) : error C2065: 'CLSIDfromProgID' : undeclared identifier

I am getting these errors with the CLSIDfromProgID function.I have tried including Ole.dll as a resource and #include "objbase.h" any ideas that might help?
>>So each excel object is derived from the COleDispatchDriver class.

COleDispatchDriver is MFC-specific. It is the way MFC simplifies creating and accessing IDispatch interface.

>> And each COleDispatchDriver derived object has a m_lpDispatch pointer that points to the IDispatch Interface.  

Yes.

>> Lets say that I just want to write to the a _WorkSheet object, does that mean that
>>I have to Marshall the _Application though the _Worksheet
>>object or just the _Worksheet object?

You have the choice.
1. Get the _Worksheet pointer in main thread and marshall it to the worker thread.
2. Marshall _Application pointer and get _Worksheet pointer in the worker thread.

Whatever you prefer.
Ok I got the error fixed..i am trying the solution right now. The function should be
CLSIDFromProgID not
CLSIDfromProgID :)
Should be CLSIDFomProgID.
Oops, I made a mistake again.
The lines of code
ExcelWorksheet = ExcelWorksheets.GetItem(COleVariant((short)1));
HRESULT hr = ::CLSIDFromProgID
//this returns hr = 0 so i think it works
hr = ::CoMarshalInterThreadInterfaceInStream (iidExcel, ExcelWorksheet.m_lpDispatch, &pStream);
//this returns hr = -2147467262 so i think that i might not be working

any ideas?
The pStream object is declared like IStream* pStream;
Thanks for sticking this out...This is going to be sooo great if this works..I have been trying to get this for the past week...Thank you very much
Sorry, I think I was wrong. You have to marshall _Application.

By the way, you can get a description of an error by using Error Lookup from menu Tools of VC. However, sometimes it doesn't tell anything interesting.
No such interface supported
that was the error message that I got from the big neagtive value returned by the hr = ::CoMarshalInterThreadInterfaceInStream (iidExcel, ExcelApp.m_lpDispatch, &pStream);  line of code....
Try this:

hr = ::CoMarshalInterThreadInterfaceInStream (IID_IDispatch, ExcelApp.m_lpDispatch, &pStream);  

And you don't need to call CLSIDFromProgID.

IID_IDispatch should be already included in your project by other headers, but just in case it is declared in oaidl.h.

And one more thing. Probably you can marshall also Worksheet (passing IID_IDispatch as a first argument to ::CoMarshall...).

Sorry for all that mess. I usually don't use COleDispatchDriver. I prefer #import directive instead. It is more flexible.
That worked..now :)..this

When does the _Worksheet object have the ability to cross threads?

Does this call..
HRESULT hr = ::CoMarshalInterThreadInterfaceInStream (IID_IDispatch, ExcelWorksheet.m_lpDispatch, &pStream);  
...make the ExcelWorksheet be able to be used across threads?

OR do i have to use the call..
   hr = ::CoGetInterfaceAndReleaseStream (pStream, IID, (void**)&pThreadHandler);
and create a new _Worksheet object with the Marshalled Interface in the new thread?
I guess i am trying to figure out what is Marshalled.
With the first call..do i marshall the interface of the ExcelWorksheet object so that it can be used across threads...or do i marshall a new Interface pointer that i have to load into a new _Worksheet object?
In fact, every interface is able to cross threads. The problem in our first attempts was that we passed wrong interface id.

You can use both approaches I described earlier.
Humm...now i don't get it again :)
hehe..here is the line that is being used..
HRESULT hr = ::CoMarshalInterThreadInterfaceInStream (IID_IDispatch, ExcelWorksheet.m_lpDispatch, &pStream);  

It returns a 0 in hr so i think that it is "working"..however...what do you mean when you say that every interface in able to cross threads?...I thought the purpose of this was to make interfaces able to cross threads..i didn't think that they could without Marshalling them?..
It seems to me that we are marshalling the interfaces not the threads..is that right?
hr = ::CoGetInterfaceAndReleaseStream(pStream, IID_IDispatch, (void**)lpDispatch);
This line returns an error...just in case you see something wrong with it :)
Please don't give up on this...it almost works
Here are the calls that I am useing but I get a OLEAUT32.dll exception access error.


ExcelApp.CreateDispatch("Excel.Application");      
      if (!ExcelApp)  
    {
         AfxMessageBox("Cannot start Excel.");          
             return;    
      }
ExcelApp.SetVisible(true);
HRESULT hr = ::CoMarshalInterThreadInterfaceInStream (IID_IDispatch, ExcelApp.m_lpDispatch, &pStream);

Then in the other thread...
LPDISPATCH* lpDispatch;
      HRESULT    hr;
      hr = ::CoGetInterfaceAndReleaseStream(pStream, IID_IDispatch, (void**)&lpDispatch);
      _Application NEWApp((*lpDispatch));
      NEWApp.SetVisible(0);


All the results from the Marshalling functions return 0 for ok
Any ideas?
The hr returns a 0 but the SetVisible call does this
I am back from lunch. I need a minute.
No problem..I'm so glad your back :)
It seems to be working but not quite..i pasted some code for you..please ask questions...
Declare lpDispatch as LPDISPATCH:

   LPDISPATCH lpDispatch;

And then use it without dereferencing:
   
   _Application NEWApp(lpDispatch);


>>It returns a 0 in hr so i think that it is "working"..however...
>>what do you mean when you say that every interface in able
>> to cross threads?...I thought the purpose of this was to make interfaces able to
>> cross threads..i didn't think that they could without Marshalling them?..
>>It seems to me that we are marshalling the interfaces not the
>> threads..is that right?


It is like travelling on bus or train.
Everyone is able to travel, but must enter the bus before travelling and leave it at the end of trip.
Unhandled exception in program.exe (OLEAUT32.DLL): 0xC0000005: Access Violation
That is the error that i am getting....
It is the same error that i got when I just had my last line to be ExcelApp.SetVisible(false); from the other thread without Marshalling the interface...
YAH.YAYAYAYAYAYAHHHAYAYHH..that did it....
Just a min..lemme see if the rest of the program works...
Why couldn't i declare a pointer and dereference it??
Can I take this new LPDISPATCH object and attach it to my old Application object?  Therefore I would just have a new _Appllication object that could write from either thread....would that work...or would the _Application object only then be able to write from the new thread and not the old one?
Try following code:

LPDISPATCH lpDispatch;
HRESULT    hr;

hr = ::CoGetInterfaceAndReleaseStream(pStream, IID_IDispatch, (void**)&lpDispatch);
_Application NEWApp(lpDispatch);
TRY
{
   NEWApp.SetVisible(0);
}
CATCH (COleDispatchException, e)
{
   e->ReportError ();
}
AND_CATCH (COleException, e)
{
   e->ReportError ();
}
END_CATCH

In case that OLE exception was thrown it will display a message.

>>Can I take this new LPDISPATCH object and attach it to my old Application object?

Yes, you can.

>> Therefore I would just have a new _Appllication object that could write
>>from either thread....would that work...

No.

>>or would the _Application object only then be able to write from the new
>>thread and not the old one?

Yes.
>>Why couldn't i declare a pointer and dereference it??

You can. But, in this case you will not get what you expect since LPDISPATCH is already declared as a pointer to IDispatch, hence LPDISPATCH* is like IDispatch**.
Is there a way to make a _Application object that would write from either thread?
No, as far as I know not.
Thanks for the help....
I have one more question...if you have time...
Right now the Excel Application is in its own window...is it possible to make the view come up in my window..and if so are there many complications..i just want the _Worksheet object to be in my view and its embeded chart object...is that very hard to do?
It is completely different.
In order to embed an Excel chart you have to create your application as an OLE container.

You may want to read a little bit about it from MSDN:

http://msdn.microsoft.com/library/default.asp?URL=/library/devprods/vs6/visualc/vccore/_core_containers.htm

You will also find there a link to a tutorial teaching about OLE containers.

if I have a HANDLE to a thread, how can i tell if that thread is complete?
You can call GetExitCodeThread. If the specified thread has not terminated the return status is STILL_ACTIVE.

DWORD dwExitCode;
if ( !GetExitCodeThread (hYourThread, &dwExitCode) )
{
  // ERROR: use GetLastError to get specific error code.
}

if ( dwExitCode == STILL_ALIVE )
{
   // Thread is still working.
}

You can also call WaitForSingleObject.
That function can wait for a specified time for the thread to finish or simply check if the thread is still working if you pass a timeout =0.

if ( WaitForSingleObject (hYourThread, 0) == WAIT_OBJECT_0 )
{
   // Thread has finished.
}


For the SuspendThread function
does it only pause between controling function calls or does it also pause the child function calls?..I hope that makes sense
I am not sure if I know what you mean, but SuspendThread should be able to suspend your thread when in application code. That says documentation. Although it doesn't explain precisely what it means, my understanding is that you can suspent the thread inside a system function.
Another guess: if you issue a call to SuspendThread when a tread is inside system function the thread will be suspended after return from that function.

Is that what you wanted to know?
You don't have to answer any of these questions...so just let me know when you want to stop :) and get your points...If I use PostThreadMessage i just read that I can not send it a message because ...
Messages sent by PostThreadMessage are not associated with a window. Messages that are not associated with a window cannot be dispatched by the DispatchMessage function. Therefore, if the recipient thread is in a modal loop (as used by MessageBox or DialogBox), the messages will be lost. To intercept thread messages while in a modal loop, use a thread-specific hook.
.....
However, if i use AfxBeginThread....how do I make it so that the thread will process my message that i send to it...
I want the thread to pause when i tell it but the SuspendThread doesn't work..i think it is because the controlling function look something like this
UINT ThreadFunction (LPVOID Param)
{
..
..
..
object.function
..
..
..
}

and there is a big loop in the function..so i am going to have a message passed in to do a WaitForSingleObject in the message handler...would that work?
Yea..i tried the SuspendThread..but i think that it only will work after it returns from a function call...
I took the fragment below from documentation.

The function fails if the specified thread does not have a message queue. The system creates a thread's message queue when the thread makes its first call to one of the Win32 User or GDI functions.

It looks like a message queue is create "on demand". I suggest you to call PeekMessage right after you start your thread.

And then somewhere in your thread function you have to periodically call PeekMessage to retrieve posted messages.

You can also use events to comunicate with your thread.
that sucks..the reason that i went away from the peekMessage is so that my program would respond quicker.....
if you find a way to make the AfxBeginThread command to take its Message Queue from somewhere please let me know
Thanks
Could i just create a object that has public inheritance from a CWinThread object?
class myThread: public CWinThread
myThread CMeasurementThread;
AxfBeginThread(CMeasurementThread);
Is it so big delay when you call PeekMessage?

If you don't want messages you can use events.

If the event is reset the function WaitForSingleObject till it is set or timeout expires.

You can set and reset event from your main thread to stop and start your worker thread.


you can derive  your thread from CWinThread, but it installs message loop and dispatches messages.
It is rather designed for showing some kinfd of UI and respond to the event that come from the user.

And if your thread is working all the time and you never returns control to CWinThread then messages are never dispatched.

ok..I guess that will work..the worker thread that i am running it search feed-back loop from a system...and it has a few nested loops...but i guess that i could a WaitForSingleObject in the loops....and the main thread could set and reset the flag...
One thing that i wanted to do was to have a abort....i wanted the nested loops to finish upon an event..is that a possiblity?
So you need two event. One for pause/start and the other to terminate.

You can use WaitForMultipleObjects to wait for two handles, and take the action for each of them.
ASKER CERTIFIED SOLUTION
Avatar of PMazur
PMazur

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Answer accepted
PMazur..I need to take action when the child thread is complete..however..I don't know how to do that...i tried the sample code that you gave me..here is what i am useing

int ExitCode = 0;
SetEvent(HandleArray[0]);
SetDlgItemText(IDC_STATIC, "Please wait while system shuts down");

GetExitCodeThread(AfxGetThread(), (unsigned long *)&ExitCode);
//while (WaitForSingleObject (MeasurementThread, 0) != WAIT_OBJECT_0)
while (ExitCode == STILL_ACTIVE)
{
GetExitCodeThread(MeasurementThread, (unsigned long *)&ExitCode);
}


The problem is that GetExitCodeThread does not update ExitCode varible...
MeasurementThread is the return value from AfxBeginThread...
Couple things:

All those thread functions require thread handle. AfxGetThread, however, returns pointer to CWinThread.

When you create a new thread you receive also the pointer to MFC'c CWinThread:
   MeasurementThreadHandle = AfxBeginThread(CMeasurementThread, nothing);

If you call GetExitCodeThread in a loop utilization of processor can go high.

You may want to rewrite your code as follows:

SetDlgItemText(IDC_STATIC, "Please wait while system shuts down");

while ( WaitForSingleObject (MeasurementThread->m_hThread, 5000) != WAIT_OBJECT_0)
{
   // five seconds elapsed, and the thread is still alive
   // Some feedback to user?
}





PMazur,
while ( WaitForSingleObject (MeasurementThread->m_hThread, 5000) != WAIT_OBJECT_0)
{
   // five seconds elapsed, and the thread is still alive
   // Some feedback to user?
}
In the feed back from user, I want to check a dialog box and see it something has been clicked and if so, I want to take the correct action. here is what i think it should/would look like in psudeo code...

MeasurementThreadHandle = AfxBeginThread(CMeasurementThread, HandleArray)->m_hThread;
      CControlDialog dlg(HandleArray, MeasurementThreadHandle);
      dlg.Create(IDD_CONTROL, this);
      dlg.ShowWindow(SW_SHOW);
      while (WaitForSingleObject(MeasurementThreadHandle, 0))
{
      while (PeekMessage(&msg, NULL, 0, 0, 0))
      {
            GetMessage(&msg, 0, 0,0);
            TranslateMessage(&msg);
            DispatchMessage(&msg);
      }
//This is to process any clicks in the Dialog box
}
dlg.KillTheBoxSomeHow();
does that make sense?


Yes, it does.

You can use dlg.DestroyWindow to kill dlgbox.
     MeasurementThreadHandle = AfxBeginThread(CMeasurementThread, HandleArray)->m_hThread;
      CControlDialog dlg(HandleArray, MeasurementThreadHandle);
      dlg->Create(IDD_CONTROL, this);
      dlg.ShowWindow(SW_SHOW);
      while (WaitForSingleObject(MeasurementThreadHandle, INFINITE))
      {
            while (PeekMessage(&msg, NULL, 0, 0, 0))
            {
                  GetMessage(&msg, 0, 0,0);
                  TranslateMessage(&msg);
                  DispatchMessage(&msg);
            }
      }
      dlg.EndDialog(0);

This is what I am trying
and this is the error that I am getting

C:\NDM\JAG project\Archive\Step 10 YAGMeasurementSystemProject\YAGMeasurementSystemProjectDoc.cpp(162) : error C2819: type 'CControlDialog' does not have an overloaded member 'operator ->'
        c:\ndm\jag project\archive\step 10 yagmeasurementsystemproject\ccontroldialog.h(13) : see declaration of 'CControlDialog'
C:\NDM\JAG project\Archive\Step 10 YAGMeasurementSystemProject\YAGMeasurementSystemProjectDoc.cpp(162) : error C2227: left of '->Create' must point to class/struct/union

If you have any idea or thoughts..that woudl be great
thanks :)
Change:
   >> dlg->Create(IDD_CONTROL, this);
to
   dlg.Create(IDD_CONTROL, this);

Use DestroyWindow instead of EndDialog. The latter is designed to destroy modal dialogs.


     MeasurementThreadHandle = AfxBeginThread(CMeasurementThread, HandleArray)->m_hThread;
      CControlDialog dlg(HandleArray, MeasurementThreadHandle);
      int check = dlg.Create(IDD_CONTROL, NULL);
      check = dlg.ShowWindow(SW_SHOW);
      while (WaitForSingleObject(MeasurementThreadHandle, 0) == WAIT_OBJECT_0)
      {
            while (PeekMessage(&msg, NULL, 0, 0, 0))
            {
                  GetMessage(&msg, 0, 0,0);
                  TranslateMessage(&msg);
                  DispatchMessage(&msg);
            }
      }
      dlg.EndDialog(0);

This is the new code that i am useing ..
there are no errer upon compile but the
check = dlg.ShowWindow(SW_SHOW);
returns 0 and doesn't work
C:\NDM\JAG project\Archive\Step 10 YAGMeasurementSystemProject\YAGMeasurementSystemProjectDoc.cpp(160) : error C2664: 'int __thiscall CDialog::Create(const char *,class CWnd *)' : cannot convert parameter 1 from 'const int' to 'const char *'
        Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast

This is the error that i get when i change NULL to this
int check = dlg.Create(IDD_CONTROL, this);
Post the declaration of CControlDialog.
class CControlDialog : public CDialog
{
// Construction
public:
      CControlDialog(HANDLE init_HandleArray[3], HANDLE init_MeasurementThread, CWnd* pParent = NULL);   // standard constructor

// Dialog Data
      //{{AFX_DATA(CControlDialog)
      enum { IDD = IDD_CONTROL };
            // NOTE: the ClassWizard will add data members here
      //}}AFX_DATA


// Overrides
      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CControlDialog)
      protected:
      virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
      //}}AFX_VIRTUAL

// Implementation
protected:

      // Generated message map functions
      //{{AFX_MSG(CControlDialog)
      afx_msg void OnPauseResume();
      afx_msg void OnAbort();
      //}}AFX_MSG
      DECLARE_MESSAGE_MAP()
private:
      HANDLE HandleArray[2];
      HANDLE MeasurementThread;
};
I don't know why compiler picks up wrong Create method.

You can try following:

int check = dlg.Create((UINT)IDD_CONTROL, this);

Yu said that nothing happens after calling ShowWindow. In fact, when you set WS_VISIBLE style in dialog editor, the window should be automatically shown during creation.

What is this pointing to in call to dlg.Create?

What is this pointing to in call to dlg.Create?
What do you mean by this?....
Do you mean what is IID_CONTROL?
I think that it is calling the wrong function because "this" is of type
class CYAGMeasurementSystemProjectDoc : public COleDocument.

and Create wants Wind*
could that be?
Yap. You have to pass a pointer to a window which will be a parent for your dialog. You can use AfxGetMainWnd to get app window.
BOOL check = dlg.Create((UINT)IDD_CONTROL, AfxGetMainWnd());
Now the window pops up for a small amount of time and then goes away...
and it is in the upper left part of the screen...
Ok i made it centered with the centered check mark in the dialog editor under properties....
but it still just flashs up and then disapears...any ideas why?
it is like the thing is being painted over or something..i just don't get it
Do you see dialog when you set the breakpoint after dlg.Create returned?
yea..the dialog will pop up and then go away
But if you are stopped in a debugger does it remain?
In other words, I want to know if the dialog box stays visible after Create mathod finishes. If not that the problem is in creation. If it stays then your thread is very fast.
The dialog box will not stay there for a long time....as soon as the screen is redrawn it will dissappear...
if i set a break point right after the create line..i see a gray box where it should be...but the whole screen not quite drawn properly..but then when I go past the break point....it will go away..
i don't think that it stays visible after the create method finishes...
because I put a break point on the destroy line and I don't even get to it..so i don't see where the dialog box would be getting destroyed from my line
Let me do small experiment and I will get back to you within couple minutes.
Do you have any visible window in you application?

What do you mean be visible window...I have the window that MFC exe wizard creates for me....
so "yes"..maybe :)..
What kind of application did you create (SDI, MDI or Dialog)?

If dialog is CControlDialog your main window?

Did you select any styles in dialog editor?

It is very weird that your dialog disappears immediately.
ok..hehe..sorry about the wait..but i just figured it out..

      MeasurementThreadHandle = AfxBeginThread(CMeasurementThread, HandleArray)->m_hThread;
      CControlDialog dlg(HandleArray, MeasurementThreadHandle);
      BOOL check = dlg.Create((UINT)IDD_CONTROL, AfxGetMainWnd());
      //check = dlg.ShowWindow(SW_SHOW);
      while (WaitForSingleObject(MeasurementThreadHandle, 0) == WAIT_OBJECT_0)
      {
            while (PeekMessage(&msg, NULL, 0, 0, 0))
            {
                  GetMessage(&msg, 0, 0,0);
                  TranslateMessage(&msg);
                  DispatchMessage(&msg);
            }
      }
      dlg.DestroyWindow();
The destroy window is called...i don't even go into the while loop..any ideas??
Condition!!!

while (WaitForSingleObject(MeasurementThreadHandle, 0) != WAIT_OBJECT_0)

if WaitForSingleObject returns WAIT_OBJECT_0 it means that the object was in signaled state (i.e. thread finished). So, you want your loop running till you get WAIT_OBJECT_0.


OK...I tried that..but after I call AfxThreadExit(0) on the other thread...it still doesn't work...It is never signaled
OK..i got it..i had been autodeleteing the thread...so it didn't signal...how do i delete a thread...with a handle to it???
also...how do i make the dialog box the only thing that can be clicked on..
i don't want the user to be able to interact with the rest of the program..
It all works...just a few more things..
1) Thank you VERY much for helping
2) The dialog box will not move when i move the main window.  I can make it move with the window, but when i move the main window the smaller window does not get back the focus.
3) Is there a way to make the rest of my program not "work" like in a modal dialog box.  I only want the user to be able to click on the dialog box not anything else.
Thanks once again
To end the thread simply quit your thread function.

You can disable application main window by calling:

AfxGetMainWnd ()->EnableWindow (FALSE);

and enable it by calling:

AfxGetMainWnd ()->EnableWindow (TRUE);
PMazur..Thank you for the help...I don't think that i have any more questions....but i might later on...You just helped me complete my first MFC program..wow..three months ago i didn't know there was a thing called MFC..now i know there is a whole bunch of MFC stuff i don't know :)...thanks for helping me finish off my project...
How did you get to know MFC?
I am glad to hear that.

>>How did you get to know MFC?
It was a long time ago. Basically from Microsoft's documentation and from MFC's source code and samples. And of course from using it, that's the best way.