Message Loop in Windows Forms
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 9 of 9

Thread: Message Loop in Windows Forms

  1. #1
    Join Date
    May 2010
    Location
    .Net 4.0
    Posts
    58

    Message Loop in Windows Forms

    Hello,

    First, I hope this is the right forum. I thought that this should go into Managed C++ but someone else just posted a Windows Forms question there and was told that was the wrong place (but the right place wasn't specified). Please move me if necessary.

    I'm trying to port a Win32 application over to Windows Forms so that I can have better graphical control over the interface. The program itself is pretty simple; in the main message loop it listens for a WM_CopyData containing a certain char array, and occasionally sends WM_CopyData itself after the user clicks a certain sequence of buttons.

    I found a couple of pages discussing how to completely override the Windows Forms WndProc, but I rather like having the framework do all of the control and would prefer to only latch onto it, rather than replace it. So, what would be the best way to have a Win Forms application listen for Windows Messages continuously and execute a function upon receiving them?

    Edit: If I do need to override WndProc, what is the syntax? I found the following code:

    Code:
    
    protected override void WndProc(ref Message m)
    {
     base.WndProc (ref m);
     if (m.Msg==0x4a) // WM_COPYDATA
     {
      // do your stuff here...
     }
    }
    But when I stick that into my main.cpp file right after int main function, "protected" gets highlighted as a syntax error with the message " IntelliSense: expected a declaration". What am I doing wrong?


    Thanks,

    Dan
    Last edited by Danja91; May 13th, 2014 at 09:18 PM.

  2. #2
    Join Date
    Jul 2002
    Posts
    2,505

    Re: Message Loop in Windows Forms

    The first thing is to understand whether you work in C# or C++/CLI.

  3. #3
    Join Date
    May 2010
    Location
    .Net 4.0
    Posts
    58

    Re: Message Loop in Windows Forms

    Quote Originally Posted by Alex F View Post
    The first thing is to understand whether you work in C# or C++/CLI.
    I'm working in C++. I briefly tried porting all of my code to C#, my native language, but there are too many Win32 API calls and I'm not nearly enough of an expert to figure out how to port them (I'm a biologist, not a computer scientist).

    I figured out where the event handler override should go... I wish MSDN would make clear what goes in the header file vs. the cpp file.

    I have a new question about the event handler. In my original Win32 C++ code, I had the following lines:

    Code:
    :
    case WM_TIMER: // Timer has ticked!
    		{
    			switch (wParam) 
    			{ 
    			case IDT_CHECKSTATUS: 
    				{
    					CheckStatus(main_hwnd);
    					HWND SMhwnd = FindWindow("SOFTMaxProMainWnd", NULL);
    					std::string previous_status = ProgramStatus;
    					bool noSMPro = (SMhwnd == 0 || SMhwnd == NULL);
    					if (noSMPro) { ProgramStatus = "SoftMax Pro not responding!";}
    					else if (previous_status == "" || previous_status == "SoftMax Pro not responding!") { ProgramStatus = "Idle";}
    					break;
    				}
    This worked fine. I ported it as follows:

    Code:
    switch ( m.Msg )
             { 
    
    		 case WM_TIMER: // Timer has ticked!
    		{
    			switch (m.WParam) 
    			{ 
    			case IDT_CHECKSTATUS: 
    				{
    					CheckStatus(main_hwnd);
    					HWND SMhwnd = FindWindow("SOFTMaxProMainWnd", NULL);
    					std::string previous_status = ProgramStatus;
    					bool noSMPro = (SMhwnd == 0 || SMhwnd == NULL);
    					if (noSMPro) { ProgramStatus = "SoftMax Pro not responding!";}
    					else if (previous_status == "" || previous_status == "SoftMax Pro not responding!") { ProgramStatus = "Idle";}
    					break;
    				}
    			}
    			
             }
    
             Form::WndProc( m );
          }
    However, Visual Studio reports an error in the inner switch statement: switch (m.WParam). It says that the expression must have an integral or enum type. Why was this ok in Win32, but not in a Windows Forms project?

  4. #4
    Join Date
    Jul 2002
    Posts
    2,505

    Re: Message Loop in Windows Forms

    So, what is m? How it is defined? And post exact error message.

  5. #5
    Join Date
    May 2010
    Location
    .Net 4.0
    Posts
    58

    Re: Message Loop in Windows Forms

    Quote Originally Posted by Alex F View Post
    So, what is m? How it is defined? And post exact error message.

    m is a System::Windows::Forms::Message%. The whole function appears as follows:

    Code:
    virtual void WndProc( Message% m ) override
          {
    
             // Listen for operating system messages. 
             switch ( m.Msg )
             { 
    
    		 case WM_TIMER: // Timer has ticked!
    		{
    			switch (m.WParam) 
    			{ 
    			}
    		}
             }
    
             Form::WndProc( m );
          }
    The initial error is at switch (m.WParam). As soon as I include that line, leaving all of the internal code commented, I get 204 errors. When I mouse over the m, which is underlined, it says "Error: expression must have an integral or enum type". Further down in the error list, I get "error C2450: switch expression of type 'System::IntPtr' is illegal". I checked the structure of Message and WParam is indeed an IntPtr. I checked the definition in the original Win32 code and WPARAM is typedef'd as a uIntPtr. I tried casting Wparam to a UIntPtr as follows:

    Code:
    virtual void WndProc( Message% m ) override
          {
    		  UIntPtr temp = (UIntPtr)m.WParam.ToPointer();
             // Listen for operating system messages. 
             switch ( m.Msg )
             { 
    
    		 case WM_TIMER: // Timer has ticked!
    		{
    			switch (temp) 
    			{			
    			}
    			
             }
    
             Form::WndProc( m );
    }
    but I again get the error at switch(temp), saying that "switch expression of type System::UIntPtr is illegal." What is the correct course of action to reconstruct the Win32 code?

    Edit: to clarify, the whole message handler in the Win32 code (stripped of irrelevant case statements) looks as follows:

    Code:
    LRESULT CALLBACK WndProc(HWND main_hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	switch(msg)
    	{
    case WM_TIMER: // Timer has ticked!
    		{
    			switch (wParam) 
    			{ 
    			case IDT_CHECKSTATUS: 
    				{
    					CheckStatus(main_hwnd);
    					HWND SMhwnd = FindWindow("SOFTMaxProMainWnd", NULL);
    					std::string previous_status = ProgramStatus;
    					bool noSMPro = (SMhwnd == 0 || SMhwnd == NULL);
    					if (noSMPro) { ProgramStatus = "SoftMax Pro not responding!";}
    					else if (previous_status == "" || previous_status == "SoftMax Pro not responding!") { ProgramStatus = "Idle";}
    					
    				}break;
                         }
    		break;
              }
              return 0;
    }
    Last edited by Danja91; May 14th, 2014 at 12:06 PM.

  6. #6
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Wallisellen (ZH), Switzerland
    Posts
    17,276

    Re: Message Loop in Windows Forms

    Quote Originally Posted by Danja91 View Post
    ...
    but I again get the error at switch(temp), saying that "switch expression of type System::UIntPtr is illegal." What is the correct course of action to reconstruct the Win32 code?
    I guess it is because both System::IntPtr and System::UIntPtr are the structures: http://msdn.microsoft.com/en-us/libr...code-snippet-1, http://msdn.microsoft.com/en-us/libr...v=vs.100).aspx
    Last edited by VictorN; May 14th, 2014 at 12:05 PM.
    Victor Nijegorodov

  7. #7
    Join Date
    May 2010
    Location
    .Net 4.0
    Posts
    58

    Re: Message Loop in Windows Forms

    Quote Originally Posted by VictorN View Post
    I guess it is because both System::IntPtr and System::UIntPtr are the structures: http://msdn.microsoft.com/en-us/libr...code-snippet-1, http://msdn.microsoft.com/en-us/libr...v=vs.100).aspx
    Ah! Thanks for that catch. I was able to extract the pointer from it and now everything is running.

    If I may ask one more question about my program... I have a Form1.h which contains many objects, including a textbox called "textBox_SpecStatus". So, the organization of my Form1.h looks as follows:

    Code:
    #pragma once
    
    #include "stdafx.h"
    ...
    
    namespace SpecControl2 {
    
    	using namespace System;
    	using namespace System::ComponentModel;
    	using namespace System::Collections;
    	using namespace System::Windows::Forms;
    	using namespace System::Data;
    	using namespace System::Drawing;
    	using namespace System::Security::Permissions;
    
    ...
    
    public ref class Form1 : public System::Windows::Forms::Form
    	{
    	public:
    		Form1(void)
    		{
    			InitializeComponent();
    
    ...
    		}
    
    	protected:
    
    		// OVERRIDE WndProc
    		[SecurityPermission(SecurityAction::Demand, Flags=SecurityPermissionFlag::UnmanagedCode)]
    		virtual void WndProc( Message% m ) override
    		{ ... }
    ...
    
    /// <summary>
    		/// Clean up any resources being used.
    		/// </summary>
    
    		~Form1()
    		{
    			if (components)
    			{
    				delete components;
    			}
    		}
    
    ...
    
    	protected:  
    	private: System::Windows::Forms::TextBox^  textBox_SpecStatus;
    
    ...
    
    
    private:
    		/// <summary>
    		/// Required designer variable.
    		/// </summary>
    		System::ComponentModel::Container ^components;
    
    #pragma region Windows Form Designer generated code
    		/// <summary>
    		/// Required method for Designer support - do not modify
    		/// the contents of this method with the code editor.
    		/// </summary>
    		void InitializeComponent(void)
    		{
    			System::ComponentModel::ComponentResourceManager^  resources = (gcnew System::ComponentModel::ComponentResourceManager(Form1::typeid));
    ...
    			this->textBox_SpecStatus = (gcnew System::Windows::Forms::TextBox());
    ...
    
    			// textBox_SpecStatus
    			// 
    			this->textBox_SpecStatus->Location = System::Drawing::Point(284, 38);
    			this->textBox_SpecStatus->Name = L"textBox_SpecStatus";
    			this->textBox_SpecStatus->Size = System::Drawing::Size(272, 26);
    			this->textBox_SpecStatus->TabIndex = 6;
    			this->textBox_SpecStatus->TextChanged += gcnew System::EventHandler(this, &Form1::textBox_SpecStatus_TextChanged);
    			// 
    ...
    		}
    #pragma endregion
    
    ...
    			 }
    };
    }
    I have another .cpp file containing a function MyFunc() which gets called from main. I would like this function to send text to the textBox_SpecStatus object. However, I cannot figure out how to access this textbox. I searched and found methods like myTextBox->Text = "mytext" but I can't access textBox_SpecStatus from any other file, even if I #include Form1.h. How would I go about sending text to this box?
    Last edited by Danja91; May 14th, 2014 at 05:55 PM.

  8. #8
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,583

    Re: Message Loop in Windows Forms

    Quote Originally Posted by Danja91 View Post
    I have another .cpp file containing a function MyFunc() which gets called from main. I would like this function to send text to the textBox_SpecStatus object. However, I cannot figure out how to access this textbox. I searched and found methods like myTextBox->Text = "mytext" but I can't access textBox_SpecStatus from any other file, even if I #include Form1.h. How would I go about sending text to this box?
    This way of accessing the text box should work if MyFunc() were a class member of Form1. In order to make it one, declare the function like this in the Form1 class body in Form1.h:

    Code:
    private:  // Or any of the other member visibility keywords, depending on your demands
      void MyFunc();
    void may or may not be the correct return type, and the function may or may not take parameters, depending on what it's defined like now.

    In the .cpp file, define the function specifying the class it's a member of:

    Code:
    void Form1::MyFunc()
    {
      // Function code goes here
    }
    And, BTW, regarding the timer, as you already have a Windows Forms app, why don't you simply use a System::Windows::Forms::Timer?
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  9. #9
    Join Date
    May 2010
    Location
    .Net 4.0
    Posts
    58

    Re: Message Loop in Windows Forms

    Thanks! Got it working. Regarding the timer, it's a bit of a dumb reason. I'm porting a Win32 application which used a WM_Timer, and since I had to override the WndProc anyway to catch Windows Messages containing WM_CopyData, I decided to keep the old WM_Timer code as well. Laziness, if you will. I am looking into the Timer class for some new functionality though, so I may end up replacing the Windows Message-based timer.

    I have another question, if people can bear with me.

    In my original Win32 program, I had the following (trimmed) code:

    DataStructs.h:
    Code:
    #ifndef DataStructs_H
    #define DataStructs_H
    
    #include "stdafx.h"
    #include <string>
    
    struct proc_cmd
    {
    	std::string type;
    	std::string command;
    
    	proc_cmd()
    	{
    		type = "";
    		command = "";
    	}
    };
    
    extern std::vector<proc_cmd> parsed_Commands;
    #endif
    WinMain.cpp:
    Code:
    #include "stdafx.h"
    #include "DataStructs.h"
    
    std::vector<proc_cmd> parsed_Commands;
    
    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow);
    
    {
    	// Windows code, launch event handler, etc
    	return 0;
    }
    This worked just fine and if I put a breakpoint right before launching the WndProc function, and put parsed_Commands into my watch list, Visual Studio debugger showed a vector containing zero objects. However, when I ported this into my Windows Forms code using the same strategy, the debugger shows a vector with over a million objects. Even if I put a breakpoint right after parsed_Commands.Clear(), the result doesn't change. If I define parsed_Commands within Main (or any other function) rather than outside of a function, it correctly initializes with no objects but then as soon as I access it from a different function in a different .cpp file it reverts to having a million contained objects. Could someone explain what is going on?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Azure Activities Information Page

Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center