Link to home
Start Free TrialLog in
Avatar of jaldu
jaldu

asked on

Assertion errors

Hi,

I have an mfc client application that has a display that shows the list of alarms in a system.  This list of alarms is updated by sending requests to a server.  For optimization all the alarms are not sent to the client application by the server.  As the user scrolls down the display, messages are being sent to the server and the server sends the alarms for that portion of the display.  

Now I want to add a feature for printing.  Since all the alarms are not on the display the client application will send a print request to the server.  The server spawns a thread and from that thread, this time sends all the alarms that were supposed to be there on the display in the first place to the mfc application.  

But since the client application shouldnt be held up for doing this job it also spawns a thread to receive these alarms and send them to the printer.  So now the server thread and the client thread are communicating.  

The client's main thread creates a window of type CView and its pointer is passed to the spawned thread.  After receiving all the alarms the secondary thread of the client is calling functions of the CView to do the printing.  

This is where my application fails.  The AfxGetApp() function is being called in DoPreparePrinting() which is being called from the secondary thread.

I tried to pass a handle to the MyCView from the client's primary thread to the secondary thread and then recreate the object in the secondary thread by using FromHandle()  but it doesnt help.

Help----- The secondary thread that I spawned in the client is a worker thread.  Should I be using a User Interface thread?  But I have read at many places that it may still not work.  Any help would be appreciated.

Thanks in advance.

RJ
ASKER CERTIFIED SOLUTION
Avatar of Crius
Crius

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
Avatar of jaldu
jaldu

ASKER

Thanks Crius.

>>>My question is, why pass all the alarms to the client? Why not just have the server receive the print
queue, and print the list itself?

Because the client could be a remote client so the server cannot get to the printer that is configured on the machine that the remote client is running on.

>>>Anyway, assuming you do have to pass it all back to the client, just make the worker thread wait until
it has received all the data, and populate a structure of some sort, or memory somewhere, then SendMessage
or PostMessage to the main thread for processing

Yes I thought about doing that but that would put the load on the client's main thread which is what I was trying to get away with in the first place.  Because the print job could be 40 to 100 pages.

RJ
Ok, well, the root problem is passing the CView to the newly spawned thread. One way to avoid this problem:

Don't use the functions in CView to print. Q162609 in the MSDN can show you how to create a printer DC, and from there you just draw into the DC the way you would in a CView. Let me know if you have any questions on this method.

A second idea is to not draw all 40-100 pages at the same time. Once you have all the data, it's just text data, and so is fairly small. You can generate a page at a time in a worker thread and send them individually to the printer.

A third way is to write all the text data into a file, or a memory file, and start a new program that does little more than read the file, and using its own main thread, run it through CView and print it. You can create the program to run completely invisibly fairly easily, and your main thread won't be tied down with the print data.
    SHELLEXECUTEINFO WorkShellExecuteOptions;

         WorkShellExecuteOptions.cbSize = sizeof(SHELLEXECUTEINFO);
         WorkShellExecuteOptions.fMask = SEE_MASK_NOCLOSEPROCESS|SEE_MASK_FLAG_DDEWAIT;
         WorkShellExecuteOptions.hwnd = WorkDocument->mMainFrm->m_hWnd;
         WorkShellExecuteOptions.lpVerb = "open";
         WorkShellExecuteOptions.lpFile = WorkFileName.ReturnCharPtr();
         WorkShellExecuteOptions.lpParameters = WorkParameters.ReturnCharPtr();
         WorkShellExecuteOptions.lpDirectory = NULL;
         WorkShellExecuteOptions.nShow = SW_HIDE; //Hides the main window

         fp = fopen(WorkFileName, "wb");
         if(fp)
         {
          fprintf(fp, "All the data you want to write out");
          fclose(fp);
          if(ShellExecuteEx(&WorkShellExecuteOptions))
          {
              WaitForSingleObject(WorkShellExecuteOptions.hProcess, INFINITE);
.....
Avatar of jaldu

ASKER

Thanks Crius.

>>>My question is, why pass all the alarms to the client? Why not just have the server receive the print
queue, and print the list itself?

Because the client could be a remote client so the server cannot get to the printer that is configured on the machine that the remote client is running on.

>>>Anyway, assuming you do have to pass it all back to the client, just make the worker thread wait until
it has received all the data, and populate a structure of some sort, or memory somewhere, then SendMessage
or PostMessage to the main thread for processing

Yes I thought about doing that but that would put the load on the client's main thread which is what I was trying to get away with in the first place.  Because the print job could be 40 to 100 pages.

RJ
Avatar of jaldu

ASKER

>>>A second idea is to not draw all 40-100 pages at the same time. Once you have all the data, it's just
text data, and so is fairly small. You can generate a page at a time in a worker thread and send them
individually to the printer.

But using the framework wont help to do this.  It will be the same problem of Asserts.  

------------------
I have been thinking more about this.  So I wanted to ask you a question about the following idea.

I was thinking that what if I created another window similar to the window that is created in the client's main thread, in the client's spawned thread.  Will the AfxGetWinApp() work or fail?  By this design I was thinking that the spawned thread will get all the alarms from the server and update the window that it created and once updated send it to the printer.  The window that is created in the spawned thread will be created hidden.

The AfxGetWinApp() is being called in the DoPreparePrinting() function of the framework.  I need to call this for opening up the dialog box.

Also the project that I am working on has all the code for formating the output for the printer and everything.  It was being done for other kinds of displays from the client's main thread because it had all the information.  Now I am working on a feature that will allow printing from a display that doesnt have all the information with it when the print command is issued.

Do you think that I can without using the framework create my own dialogbox and keep track of which page to print and then send that particular page for printing?  Is that what your first solution is about?

Thanks in advance

RJ
AfxGetApp() should work fine from what I know, but immediately grab its HWND and use that instead. You'll really want to only send/post messages to it. Don't call functions in the returned CWinApp. This, unfortunately, does prevent you from creating a CView within the thread.

You can, without using the framework, create your own dialog box and keep track of which page to print. Yes, this was my second idea was about.

As far as I can tell, the best suggestion I can give is:
Use the worker thread to receive the information from the server, and post or send a message to the main window.

I know, I know. :( This is the first solution I talked about. Granted, you may have 40, 100, or even 1000 pages of data, but it's just text data, and the memory in machines these days, I mean, assuming 80 characters per line, 40 lines per page, times 1000 pages (80*40*1000) is still only a bit over 3Megs of memory, which should be easily handled by today's computers.

No matter how you handle getting the data, you're still going to have to store it somewhere before you actually print it, aren't you? Or do you plan to have the server only send a page at a time or something?

It all comes back to the main Application thread. It must be the only one to interact with your CWinApp object, your CDocument, your CView. Calling any modifying functions of any CObject class inside another thread is asking for trouble. You could use Get functions - most people wouldn't recommend it, but if you don't *modify* the CObject's variables in *any* way in another thread, you don't require mutexs, critical sections, semaphores, or all the other fun stuff that makes multi-threaded applications a pain. That's why I suggest SendMessage or PostMessage.

You can still use your CView to generate all the stuff to be printed, like how you want to. Just SendMessage all the data you want to print as one of the arguments, and print it immediately. Yes, it'll take a bit of time from Main thread, you won't get redraws, and the user won't be able to interact, but when you're preparing to print, you are using all the CPU time to format and prepare anyway, and how many applications can you think of that don't stop you from working while it formats/prepares the data to be printed?

Anyway, if you don't want to be doing it this way, well, there are other ways, maybe some even better, but I can't think of any off the top of my head..
Avatar of jaldu

ASKER

>>>A second idea is to not draw all 40-100 pages at the same time. Once you have all the data, it's just
text data, and so is fairly small. You can generate a page at a time in a worker thread and send them
individually to the printer.

But using the framework wont help to do this.  It will be the same problem of Asserts.  

------------------
I have been thinking more about this.  So I wanted to ask you a question about the following idea.

I was thinking that what if I created another window similar to the window that is created in the client's main thread, in the client's spawned thread.  Will the AfxGetWinApp() work or fail?  By this design I was thinking that the spawned thread will get all the alarms from the server and update the window that it created and once updated send it to the printer.  The window that is created in the spawned thread will be created hidden.

The AfxGetWinApp() is being called in the DoPreparePrinting() function of the framework.  I need to call this for opening up the dialog box.

Also the project that I am working on has all the code for formating the output for the printer and everything.  It was being done for other kinds of displays from the client's main thread because it had all the information.  Now I am working on a feature that will allow printing from a display that doesnt have all the information with it when the print command is issued.

Do you think that I can without using the framework create my own dialogbox and keep track of which page to print and then send that particular page for printing?  Is that what your first solution is about?

Thanks in advance

RJ
Just one other note:

To prevent using up the main thread to handle any of the processing is possible, but it involves, for the most part, manually handling all the printing. I have written applications that do this, but it is time consuming. Days. You can also, of course, spawn a second program to handle the printing, as I mentioned before.

Whether or not you use these solutions depends a lot on how you want the data to look, how you are printing the data. I don't know how you are using the framework to help you print. Maybe you're still filling the Printer HDC manually with data. In that case, the solutions here will work great.

Sorry that I can not be of more help..
Avatar of jaldu

ASKER

>>>A second idea is to not draw all 40-100 pages at the same time. Once you have all the data, it's just
text data, and so is fairly small. You can generate a page at a time in a worker thread and send them
individually to the printer.

But using the framework wont help to do this.  It will be the same problem of Asserts.  

------------------
I have been thinking more about this.  So I wanted to ask you a question about the following idea.

I was thinking that what if I created another window similar to the window that is created in the client's main thread, in the client's spawned thread.  Will the AfxGetWinApp() work or fail?  By this design I was thinking that the spawned thread will get all the alarms from the server and update the window that it created and once updated send it to the printer.  The window that is created in the spawned thread will be created hidden.

The AfxGetWinApp() is being called in the DoPreparePrinting() function of the framework.  I need to call this for opening up the dialog box.

Also the project that I am working on has all the code for formating the output for the printer and everything.  It was being done for other kinds of displays from the client's main thread because it had all the information.  Now I am working on a feature that will allow printing from a display that doesnt have all the information with it when the print command is issued.

Do you think that I can without using the framework create my own dialogbox and keep track of which page to print and then send that particular page for printing?  Is that what your first solution is about?

Thanks in advance

RJ
Dear jaldu

I think you forgot this question. I will ask Community Support to close it unless you finalize it within 7 days. You can always request to keep this question open. But remember, experts can only help you if you provide feedback to their questions.
Unless there is objection or further activity,  I will suggest to accept

     "Crius"

comment(s) as an answer.
     "refund the points and delete this question"
since nobody had a satisfying answer for you.
since you never gave more feedback.
PAQ at zero points.

If you think your question was not answered at all, you can explain here why you want to do this and post a request in Community support (please include this link) to refund your points. The link to the Community Support area is: https://www.experts-exchange.com/commspt/


PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
======
Werner
Force accepted

** Mindphaser - Community Support Moderator **