I have a simple program that I am having trouble debugging.
It contains two different problems.

1. If I run a MessageBox in this program after the program is
up and running, the program crashes. I have to call the
Task Manager to shut down the program.

2. SetTimer will not work unless I put other code in the
funtion containing it. I've pinned down what happens using
a debugger but don't know how to cure it. I'm popping BPX
with a bad momory position after SetTimer completes.

The program is in working order now by fudging and the
"points of failure" are documented in the program.
I tried to eliminate compiler problems by compiling
using two different compilers. "cl" and Borland BCC.
Both act the same.

I run an AMD with SP1.

Attachments
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>

#define ID_FILE_EXIT         408
#define ID_FILE_LOAD	     409

//***** START Prototypes

int WINAPI WinMain (HINSTANCE hInstance , HINSTANCE hPrevInstance , LPSTR lpCmdLine , int nCmdShow);
LRESULT CALLBACK MainWndProc(HWND hwndMainFrame, UINT uMsg , WPARAM wParam , LPARAM lParam);
HWND DoMenu(HWND hwndMainFrame);
HWND MyTimerFunc(HWND hwndMainFrame);
VOID CALLBACK TimerProc(HWND hwndMainFrame,UINT uMsg,UINT idEvent,DWORD dwTime);

//*******END Prototypes

   HWND hwndMainFrame;
   WPARAM wParam;
   LPARAM lParam;
   HINSTANCE hInstance;
   WNDCLASSEX wc;
   UINT uMsg;
   MSG msg;
   MSG message;
   PAINTSTRUCT paintStruct;
   HDC  hDC;

   HMENU hMyMenu;
   HWND Menubar;
   HMENU hFileMenu;
   MENUITEMINFO mii;

 TIMERPROC lpTimerFunc;
 UINT idEvent;
 DWORD dwTime;

  int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow)
{
    (void)UNREFERENCED_PARAMETER(hPrevInstance);
    (void)UNREFERENCED_PARAMETER(lpCmdLine);
    (void)UNREFERENCED_PARAMETER(nCmdShow);

	wc.cbSize=sizeof(WNDCLASSEX);
	wc.style=CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = MainWndProc;
	wc.cbClsExtra=0;
	wc.cbWndExtra=0;
	wc.hInstance=hInstance;
	wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	wc.hCursor=LoadCursor(NULL,IDC_ARROW);
        wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName=NULL;
	wc.lpszClassName="MyClass";
	wc.hIconSm=LoadIcon(NULL,IDI_WINLOGO);

	if(!RegisterClassEx(&wc))
		return 0;
        
	hwndMainFrame = CreateWindowEx(NULL,"MyClass","MAINFRAME",WS_OVERLAPPEDWINDOW |
                        WS_VSCROLL | WS_VISIBLE | WS_CLIPCHILDREN,0,0,1024,740,
                        NULL,NULL,hInstance,NULL);

            if (!hwndMainFrame)
		return 0;
               
        ShowWindow(hwndMainFrame, nCmdShow);
	UpdateWindow(hwndMainFrame);
        
	while (GetMessage(&message,NULL,0,0)>0)

	{
	  TranslateMessage(&message);
	  DispatchMessage(&message);
	}
          return msg.wParam;
} 

   LRESULT CALLBACK MainWndProc(HWND hwndMainFrame, UINT uMsg, WPARAM wParam, LPARAM lParam)

{                               // ****************************** START MAIN WIND PROCEDURE

	 switch(uMsg)
	{                               // ********************** START SWITCH

	      case WM_CREATE:
                        DoMenu(hwndMainFrame); 
  		        break;
 
              case WM_PAINT:
  		        break;
 
		case WM_SIZE:
 		        break;

		 case WM_CLOSE: 
			PostQuitMessage(0);
			DestroyWindow(hwndMainFrame);
		        break;

		case WM_DESTROY:
                        KillTimer(hwndMainFrame,idEvent);
			PostQuitMessage(0);
			DestroyWindow(hwndMainFrame);
		        break;

	     case WM_COMMAND:
		switch(wParam)
       	            {                 // ***************** START MAIN WM_COMMAND

                case ID_FILE_LOAD:

                    MyTimerFunc(hwndMainFrame);
                    break;

	        case ID_FILE_EXIT:

                    SendMessage(hwndMainFrame,WM_DESTROY,0,0);
		    break;

                    }  // ********************************* END MAIN WM_COMMAND
	       	 break;

		           default:

	             return DefWindowProc(hwndMainFrame,uMsg, wParam, lParam);

         }                               // ********************** END SWITCH
        	return 0; 
}                                         // **************************** END MAIN WIND PROCEDURE

                  HWND DoMenu(HWND hwndMainFrame)

             {                                // ****************** START MAIN MENU
                HMENU hMyMenu = CreateMenu();
                IsMenu(hMyMenu);
               if(hMyMenu == NULL)
                   MessageBox(hwndMainFrame,"No Menu","MBOX3",MB_OK);

                   AppendMenu(hMyMenu,MF_STRING,ID_FILE_LOAD,"LOAD");
                   AppendMenu(hMyMenu,MF_STRING,ID_FILE_EXIT,"EXIT");
                   SetMenu(hwndMainFrame,hMyMenu);
                   DrawMenuBar(hwndMainFrame);
                   UpdateWindow(hwndMainFrame);

                return 0;
             }                                // ****************** END MAIN MENU

                   HWND MyTimerFunc(HWND hwndMainFrame)

              {          // *************************************** START TIMER

            SetTimer(hwndMainFrame,idEvent,1000,(TIMERPROC)TimerProc);

// ----- Remove below and the function fails --------------------------- TEST INFO

            hDC = GetDC(hwndMainFrame);
            BeginPaint(hwndMainFrame, &paintStruct);
            TextOut(hDC,1,20,"MyTimerFunc has been called.",28);
            EndPaint(hwndMainFrame, &paintStruct);
            ReleaseDC(hwndMainFrame, hDC);

// ----- Keep above and fuction works ---------------------------------- TEST INFO

            return 0;
              }          // *************************************** END TIMER

        VOID CALLBACK TimerProc(HWND hwndMainFrame,UINT uMsg,UINT idEvent,DWORD dwTime)

          {          // *************************************** START CALLBACK

            hDC = GetDC(hwndMainFrame);
            BeginPaint(hwndMainFrame, &paintStruct);
            TextOut(hDC,1,90,"This indicates that TimerProc timed out.",40);
            EndPaint(hwndMainFrame, &paintStruct);
            ReleaseDC(hwndMainFrame, hDC);

// ----- Allowing below to run causes crash --------------------------- TEST INFO

//  MessageBox(hwndMainFrame,"Worked","MBOXTEST",MB_OK); 

// ----- Allowing above to run causes crash --------------------------- TEST INFO

          }          // *************************************** END CALLBACK 

// ********************** END OF PROGRAM ***********************************

Hint: If the code in the timer proc TimerProc() takes more time to execute than the amount of time specified in the SetTimer() function call (1 second) then TimerProc() needs to kill the timer and restart it before leaving. Don't leave the timer running or the os will call TimerProc() again before it has finished processing the previous call. That can be disasterous.

I blocked off the print text code in the time function and then raised the time to 10 seconds. Thaat failed. Then I killed the timer in the procedure as you suggested. That failed. Maybe I am not understanding what you suggest correctly. Please clarify.

I've been doing some experiments while waiting for further replies.

If I move the two timer functions above the "DoMenu" function, then MessageBox will work. I don't know why but you can't beat success.

If I block off the TextOut portion inside the SetTimer it still does not work even with both functions above the DoMenu.

I have compiled and run your program several times and I can't get SetTimer() to work either. I even started a whole new simple win32 api program that the compiler generated, and SetTimer() doesn't work there either. Finally tried google search for the problem -- other people have had the same problem but I didn't see any solutions!

The only way I could make it work is like this, which is almost the same as you originally posted. And I think I would just leave it like that.

HWND MyTimerFunc(HWND hwndMainFrame)
{          // *************************************** START TIMER
   HDC  hDC;
   PAINTSTRUCT paintStruct;

   hDC = GetDC(hwndMainFrame);
    BeginPaint(hwndMainFrame, &paintStruct);
    SetTimer(NULL,0,1000,(TIMERPROC)TimerProc);
// ----- Remove below and the function fails --------------------------- TEST INFO
    //TextOut(hDC,1,20,"MyTimerFunc has been called.",28);
    EndPaint(hwndMainFrame, &paintStruct);
    ReleaseDC(hwndMainFrame, hDC);
// ----- Keep above and fuction works ---------------------------- TEST INFO

    return 0;
}          // ********************************* END TIMER

Using BeginPaint() ad-hoc like this isn't recommended. Works sometimes, but isn't reliable. You should only use it in response to WM_PAINT messages.
Your WM_PAINT handler does nothing, so I suggest you add something like this to MainWndProc():-

case WM_PAINT:
{
 	PAINTSTRUCT ps;
	HDC hdc;
	hdc = BeginPaint(hwndMainFrame, &ps); 
        // Do your painting
	EndPaint(hwndMainFrame, &ps); 
        return 0L; 
}

Even if you don't want to paint anything right now, put in the Begin and EndPaint() calls.
With that in place, remove all the painting code from MyTimerFunc() and TimerProc() and just use message boxes where necessary.
If you want to use TextOut(), do it in response to WM_PAINT rather than when the fancy takes you.

After these changes I think your timer will behave normally.

To Ancient Dragon:

I appreciate all the work you did. I've been working on it too. Without the paint sequence, the stack loads differently. It seems the compiler leaves out one line of code "POP EBX". This causes the stack to get one less line.

I hate to have a program with a fudge like this. I use this little program as a blank to compile various api's so I can see them in assembly.

If you've given up, I will too and just keep the fudge in.

toolmanx@ij.net

The timer doesn't work without the paint code in MyTimerFunc() because you don't handle WM_PAINT, so the window is not validated and the high frequency (and priority) of WM_PAINT messages blocks the low priority WM_TIMER message.
Just handle WM_PAINT as suggested and your timer will work without the misplaced painting.
I don't understand why you were getting crashes when calling MessageBox() however.

This article has been dead for over six months. Start a new discussion instead.