Thread: Creating an Edit Box (Subclassing)

  1. #1
    Registered User
    Join Date
    Apr 2008
    Posts
    610

    Creating an Edit Box (Subclassing)

    The code below is my first attempt to create an edit box, i've used three files "SubClassedEditProc.cpp", "subclassing.cpp", and "SubclassedEditProc.h"

    BTW these should be .c files, yet struggling to compile C files in VS 2005, get lots of errors.

    Subclassing.cpp..
    Code:
    #include "stdafx.h"
    #include <windows.h>
    
    #include "SubclassedEditProc.h"		// we need the 'oldEditProcedure' variable
    
    LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	switch (message)                 
    	{
    	case WM_CREATE:
    		{
    			/*
    			First we create an edit control...
    			*/
    			HWND edit = CreateWindowEx (
    				WS_EX_ACCEPTFILES,	//	Either set the flag here or call DragAcceptFiles (edit, TRUE); after creating the edit
    				TEXT("EDIT"),
    				TEXT("You can drag and drop a file here..."),
    				WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | ES_LEFT,
    				10, 10,		//	position
    				300, 22,	//	size
    				hwnd,
    				0,			//	no control ID (we don't need it in this example)
    				(HINSTANCE)GetModuleHandle (0),
    				0
    				);
    
    			oldEditProcedure = (WNDPROC)GetWindowLongPtr (edit, GWLP_WNDPROC);			
    
    			SetWindowLongPtr (edit, GWLP_WNDPROC, (LONG_PTR)newEditProcedure);
    			break;
    		}
    
    	case WM_DESTROY:
    		PostQuitMessage (0);
    		break;
    
    	default:
    		return DefWindowProc (hwnd, message, wParam, lParam);
    	}
    
    	return 0;
    }

    SubClassedEditProc.cpp

    Code:
    /*
    	This is SubclassedEditProc.c
    */
    #include "stdafx.h"
    #include <ShellAPI.h>
    
    #define WIN32_LEAN_AND_MEAN
    
    #include "SubclassedEditProc.h"
    
    //	the pointer to the edit's old window procedure
    //	this will be used to call the old procedure inside the new window procedure
    WNDPROC oldEditProcedure = 0;
     
    //	the new edit's window procedure prototype
    LRESULT CALLBACK newEditProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
     
    	switch (message)
    	{
    		//	This is the message we want to handle...
    		case WM_DROPFILES:
    		{
    			//	Now comes the code that retrieves the dropped file's path...
    			//	I guess this is not relevant so you don't struggle understanding it.
    			//	Just know that 'buffer' will store the dropped file's path.
    			HDROP hDrop = (HDROP)wParam;
    			TCHAR buffer[MAX_PATH];
    			int nFilesDropped = DragQueryFile (hDrop, 0, buffer, MAX_PATH);
     
    			if (nFilesDropped) {
    				SetWindowText (hwnd, buffer);
    			}
     
    			DragFinish (hDrop);
    			return 0;
    		}
     
    		//	The other message are simply forwarded to the old window procedure
    		default:
    			//	This is just me being too cautious... the 'oldEditProcedure' pointer will never be null if you're careful
    			if (oldEditProcedure) {
    				//	The CallWindowProc() API is responsible for calling the 'oldEditProcedure', we are not going to just call it directly, see MSDN for details
    				return CallWindowProc (oldEditProcedure, hwnd, message, wParam, lParam);
    			}
    			else {
    				//	Your application should never reach this point, because you were supposed to set the 'oldEditProcedure' pointer to point to the old window procedure.
    				return DefWindowProc (hwnd, message, wParam, lParam);
    			}
    	}
    }

    headerfile...
    Code:
    /*
    	This is SubclassedEditProc.h
    */
     
    #ifndef __SUBCLASSED_EDIT_H_INCLUDED__
    #define __SUBCLASSED_EDIT_H_INCLUDED__
     
    #include <windows.h>
     
    //	the pointer to the edit's old window procedure
    //	this will be used to call the old procedure inside the new window procedure
    extern WNDPROC oldEditProcedure;
     
    //	the new edit's window procedure prototype
    LRESULT CALLBACK newEditProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
     
    #endif
    Problems... Link Error

    Code:
     error LNK2019: unresolved external symbol _WinMain@16 referenced in function ___tmainCRTStartup
    Not sure whether is looking for WinMain() or main() function????

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    What errors? Also, it's looking for WinMain, as the linker error says.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #3
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by Elysia View Post
    What errors? Also, it's looking for WinMain, as the linker error says.
    Got this code as an example which did not include WinMain()... If i add WinMain in my prog, where do i create a window (or call the CreateWindowEx())? Or could some1 give me a code example on how will WinMain() look like since i'm subclassing.. I know how to do WinMain() but my guesses it will be shorter than usual...

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    WinMain is no more special than main. It's just a function so you can create your window wherever you want, including WinMain.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by Elysia View Post
    WinMain is no more special than main. It's just a function so you can create your window wherever you want, including WinMain.
    I've added WinMain() to get the program to Build... It does build but does not run, obviously am missing something on my WinMain()

    Code:
    //Main window
    int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
    {
    	InitCommonControls();
    
            // Missing code....??
    	
    
    }
    What do i add... Or how do i call newEditProcedure()?

  6. #6
    HelpingYouHelpUsHelpUsAll
    Join Date
    Dec 2007
    Location
    In your nightmares
    Posts
    223
    From theForger's Win32 API Programming Tutorial , you will need something like this in WinMain:
    Code:
        //Step 1: Registering the Window Class
        WNDCLASSEX wc;
        HWND hwnd;
        MSG Msg;
    
        wc.cbSize  = sizeof(WNDCLASSEX);
        .....
    
        if(!RegisterClassEx(&wc))
        {
            MessageBox(NULL, "Window Registration Failed!", "Error!",
                MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
    
        // Step 2: Create the Window
          ...
    
        if(hwnd == NULL)
        {
            MessageBox(NULL, "Window Creation Failed!", "Error!",
                MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
    
        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);
    
        // Step 3: The Message Loop
        while(GetMessage(&Msg, NULL, 0, 0) > 0)
        {
            TranslateMessage(&Msg);
            DispatchMessage(&Msg);
        }
        return Msg.wParam;
    }
    long time no C; //seige
    You miss 100% of the people you don't C;
    Code:
    if (language != LANG_C && language != LANG_CPP)
        drown(language);

  7. #7
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by P4R4N01D View Post
    From theForger's Win32 API Programming Tutorial , you will need something like this in WinMain:
    Code:
        //Step 1: Registering the Window Class
        WNDCLASSEX wc;
        HWND hwnd;
        MSG Msg;
    
        wc.cbSize  = sizeof(WNDCLASSEX);
        .....
    
        if(!RegisterClassEx(&wc))
        {
            MessageBox(NULL, "Window Registration Failed!", "Error!",
                MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
    
        // Step 2: Create the Window
          ...
    
        if(hwnd == NULL)
        {
            MessageBox(NULL, "Window Creation Failed!", "Error!",
                MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
    
        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);
    
        // Step 3: The Message Loop
        while(GetMessage(&Msg, NULL, 0, 0) > 0)
        {
            TranslateMessage(&Msg);
            DispatchMessage(&Msg);
        }
        return Msg.wParam;
    }
    But may not apply the same for Subclassing!!!! Which is what am doing...

  8. #8
    HelpingYouHelpUsHelpUsAll
    Join Date
    Dec 2007
    Location
    In your nightmares
    Posts
    223
    Whether you are going to subclass a control or not, the WinMain function remains the same (except for controls that are created there). I subclassed the edit control in WinMain when I created an app like this (see WM_CHAR problems)

    Also, you don't call newEditProcedure(). When the application receives a message from the subcalssed control, the message is sent to that subclassed procedure (if you have implemented it correctly and are not using lccWin32). This is probably taken care of in the message loop (TranslateMessage and DispatchMessage).
    long time no C; //seige
    You miss 100% of the people you don't C;
    Code:
    if (language != LANG_C && language != LANG_CPP)
        drown(language);

  9. #9
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by P4R4N01D View Post
    Whether you are going to subclass a control or not, the WinMain function remains the same (except for controls that are created there).
    Here's my attempt..

    Code:
    //Main window
    int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
    {
        WNDCLASSEX WndClsEx;
        HWND hwnd;
        MSG Msg;
    
         WndClsEx.cbSize        = sizeof(WNDCLASSEX);
         WndClsEx.style         = CS_HREDRAW | CS_VREDRAW;
         WndClsEx.lpfnWndProc   = WndProcedure;
         WndClsEx.cbClsExtra    = 0;
         WndClsEx.cbWndExtra    = 0;
         WndClsEx.hIcon		   = LoadIcon(hInstance, MAKEINTRESOURCE(400)); 
         WndClsEx.hCursor	   = LoadCursor(hInstance, MAKEINTRESOURCE(200)); 
         WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
         WndClsEx.lpszMenuName  = NULL;
         WndClsEx.lpszClassName = ClsName;
         WndClsEx.hInstance     = hInstance;
         WndClsEx.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
    
        if(!RegisterClassEx(&WndClsEx))
        {
            MessageBox(NULL, "Window Registration Failed!", "Error!",
                MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
    
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
    
         while( GetMessage(&Msg, NULL, 0, 0) )
         {
    	TranslateMessage(&Msg);
    	DispatchMessage(&Msg);
         }
    
         return 0;
    }

    In my code above, ShowWindow(hWnd, nCmdShow) expects hWnd of a created window... Since the window is created inside the windows procedure function as below...

    Code:
    case WM_INITDIALOG:
    		{
    			HWND edit = CreateWindowEx (
    				WS_EX_ACCEPTFILES,	
    				TEXT("EDIT"),
    				TEXT("You can drag and drop a file here..."),
    				WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | ES_LEFT,
    				10, 10,		//	position
    				300, 22,	//	size
    				hwnd,
    				(HMENU)IDC_MY_SUBCLASSED_EDIT,	
    				(HINSTANCE)GetModuleHandle (0),
    				0
    				);
    
    			if(edit == NULL)
    			{
    				MessageBox(NULL, "Window Creation Failed!", "Error!",
    					MB_ICONEXCLAMATION | MB_OK);
    				return 0;
    			}
    			oldEditProcedure = (WNDPROC)GetWindowLongPtr (edit, GWLP_WNDPROC);			
    
    			SetWindowLongPtr (edit, GWLP_WNDPROC, (LONG_PTR)newEditProcedure);
    			break;
    		}

    How does WinMain() receive the handle of the edit window to show it? Or should i declare hWnd or HWND edit globally?

  10. #10
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    This is the complete program, compiles, runs but no dialog/edit window is created! Oly the main blank window shows... It seems the subclass window is not even called because when i run on Debug mode and run to cursor where window's suppose to be created, program never jumps to there, any faults?

    Code:
    #include "stdafx.h"
    #include <windows.h>
    #include <ShellAPI.h>
    #include <windowsx.h>
    #include <commctrl.h>
    #pragma comment( lib, "comctl32.lib" ) 
    
    #define WIN32_LEAN_AND_MEAN
    #define IDC_MY_SUBCLASSED_EDIT 2008
    
    const char *ClsName = "SubClassing";
    const char *WndName = "Edit Box";
    WNDPROC oldEditProcedure = 0;
    
    LRESULT CALLBACK newEditProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
    LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
    
    //Main window
    int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
    {
    	WNDCLASSEX WndClsEx;
    	HWND hWnd;
    	MSG Msg;
    
    	WndClsEx.cbSize        = sizeof(WNDCLASSEX);
    	WndClsEx.style         = CS_HREDRAW | CS_VREDRAW;
    	WndClsEx.lpfnWndProc   = WindowProcedure;
    	WndClsEx.cbClsExtra    = 0;
    	WndClsEx.cbWndExtra    = 0;
    	WndClsEx.hIcon		   = LoadIcon(hInstance, MAKEINTRESOURCE(400)); 
    	WndClsEx.hCursor	   = LoadCursor(hInstance, MAKEINTRESOURCE(200)); 
    	WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    	WndClsEx.lpszMenuName  = NULL;
    	WndClsEx.lpszClassName = ClsName;
    	WndClsEx.hInstance     = hInstance;
    	WndClsEx.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
    
    	if(!RegisterClassEx(&WndClsEx))
    	{
    		MessageBox(NULL, "Window Registration Failed!", "Error!",
    			MB_ICONEXCLAMATION | MB_OK);
    		return 0;
    	}
    
    	// Create the window object
    	hWnd = CreateWindowEx(0,
    		ClsName,
    		WndName,
    		WS_OVERLAPPEDWINDOW,
    		CW_USEDEFAULT,
    		CW_USEDEFAULT,
    		CW_USEDEFAULT,
    		CW_USEDEFAULT,
    		NULL,
    		NULL,
    		hInstance,
    		NULL);
    
    	// Find out if the window was created
    	if( !hWnd ) // If the window was not created,
    		return FALSE; // stop the application
    
    	ShowWindow(hWnd, nShowCmd);
    	UpdateWindow(hWnd);
    
    	while( GetMessage(&Msg, NULL, 0, 0) )
    	{
    		TranslateMessage(&Msg);
    		DispatchMessage(&Msg);
    	}
    
    	return 0;
    }
    
    LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	switch (message)                 
    	{
    	case WM_CREATE:
    		{
    			HWND edit = CreateWindowEx (
    				WS_EX_ACCEPTFILES,	
    				TEXT("You can drag and drop a file here..."),
    				TEXT("Edit/Browse"),
    				WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | ES_LEFT,
    				10, 
    				10,		//	position
    				300, 
    				22,	//	size
    				hwnd,
    				(HMENU)IDC_MY_SUBCLASSED_EDIT,
    				(HINSTANCE)GetModuleHandle (0),
    				0
    				);
    
    			oldEditProcedure = (WNDPROC)GetWindowLongPtr (edit, GWLP_WNDPROC);			
    			SetWindowLongPtr (edit, GWLP_WNDPROC, (LONG_PTR)newEditProcedure);
    			break;
    		}
    
    	case WM_DESTROY:
    		PostQuitMessage (0);
    		break;
    
    	default:
    		return DefWindowProc (hwnd, message, wParam, lParam);
    	}
    
    	return 0;
    }
    
    LRESULT CALLBACK newEditProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	switch (message)
    	{
    	case WM_DROPFILES:
    		{
    			HDROP hDrop = (HDROP)wParam;
    			TCHAR buffer[MAX_PATH];
    			int nFilesDropped = DragQueryFile (hDrop, 0, buffer, MAX_PATH);
    
    			if (nFilesDropped) {
    				SetWindowText (hwnd, buffer);
    			}
    
    			DragFinish (hDrop);
    			return 0;
    		}
    
    	default:
    		return DefWindowProc (hwnd, message, wParam, lParam);
    	}
    
    	return CallWindowProc (oldEditProcedure, hwnd, message, wParam, lParam);
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. edit box
    By beene in forum Windows Programming
    Replies: 3
    Last Post: 11-11-2006, 04:40 AM
  2. WS_HSCROLL in ES_READONLY edit box error
    By Homunculus in forum Windows Programming
    Replies: 4
    Last Post: 02-13-2006, 08:46 AM
  3. setting fixed floats in edit box
    By WaterNut in forum Windows Programming
    Replies: 4
    Last Post: 08-13-2004, 09:13 AM
  4. how to define the variable of a edit box?
    By Jasonymk in forum Windows Programming
    Replies: 2
    Last Post: 02-10-2003, 09:23 PM
  5. Limiting Characters in Edit Box :: MFC
    By kuphryn in forum Windows Programming
    Replies: 5
    Last Post: 06-02-2002, 10:21 AM