Sign in to follow this  
MystikReasons

WinAPI Combo Box wont show

Recommended Posts

Hello

 

I have a problem with my combo box that  I've created.

I've already asked in another forum, but they didn't knew the error.

 

Thats where I create the Combo Box and I call this Init function in the constructor.

void ComboBox::Initialize()
{
	wWindow wWindow;

	////////////////////////////////////
	//								  //
	//		Combobox Informations	  //
	//								  //    
	////////////////////////////////////	
	TCHAR Combobox_File[7][13] =
	{
		TEXT("New"), TEXT("Open"), TEXT("Add"), TEXT("Save		Ctrl+S"),
		TEXT("Save As..."), TEXT("Save All"), TEXT("Exit		Alt+F4")
	};
 
	// Create the parameters for FILE Combobox
	//
	// Uses the CreateWindow function to create a child window of 
	// the application window. The WC_COMBOBOX window style specifies  
	// that it is a combobox.
	int xPos = 100;					// Horizontal position of the window
	int yPos = 100;					// Vertical position of the window
	int nWidth = 200;				// Width of the window
	int nHeight = 200;				// Height of the window
	hWndParent = wWindow.getHwnd();	// Get the window from the Window Class

	// Create the Combobox_File
	hWndComboBox_File = CreateWindow(WC_COMBOBOX, TEXT(""),
										  CBS_DROPDOWN | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE,
										  xPos, yPos, nWidth, nHeight, hWndParent, NULL, HINST_THISCOMPONENT,
										  NULL);

	TCHAR A[16];
	int k = 0;

	memset(&A, 0, sizeof(A));
	// Go trough every TEXT in the string
	for (k = 0; k <= 8; k += 1)
	{
		// Copies a string
		wcscpy_s(A, sizeof(A) / sizeof(TCHAR), (TCHAR*)Combobox_File[k]);

		// Add string to combobox
		SendMessage(hWndComboBox_File, (UINT)CB_ADDSTRING, (WPARAM)0, (LPARAM)A);
	}

	// Send the CB_SETCURSEL message to display an initial item 
	// in the selection field  
	SendMessage(hWndComboBox_File, CB_SETCURSEL, (WPARAM)2, (LPARAM)0);

	return;
}

And here I create a instance of the Combo Box.

HRESULT wWindow::Initialize()
{
HRESULT hr;
ComboBox m_comboBox; // Create a instance for ComboBox
// Initialize all the combo boxes here

// Create the window class.
WNDCLASSEX wcex    = { sizeof(WNDCLASSEX) };

wcex.style         = CS_HREDRAW | CS_VREDRAW; // The class styles - CS_HREDRAW: Redraws the window if a movement changes the width of the client area.
// CS_VREDRAW: Redraws the window if a movement changes the height of the client area.

wcex.lpfnWndProc   = wWindow::WndProc; // A pointer to the windows procedure.
wcex.cbClsExtra   = 0; // The number of extra bytes to allocate the window-class structure.
wcex.cbWndExtra    = sizeof(LONG_PTR); // The number of extra bytes to allocate following the window instance.
wcex.hInstance     = HINST_THISCOMPONENT; // A handle to the instance that contains the window procedure for the class.
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // A handle to the class background brush.
wcex.lpszMenuName  = NULL; // Pointer to a null-terminated character string that specifies the resource name of the class menu.
wcex.hCursor       = LoadCursor(NULL, IDC_ARROW); // A handle to the class cursor, contains the cursor for the window.
wcex.lpszClassName = TEXT("DemoApp"); // The name of the class

// Register the window class.
RegisterClassEx(&wcex);

// Create the application window.
//
// Because the CreateWindow function takes its size in pixels, we
// obtain the system DPI and use it to scale the window size.
int dpiX = 0;
int dpiY = 0;
HDC hdc = GetDC(NULL);

if (hdc)
{
dpiX = GetDeviceCaps(hdc, LOGPIXELSX); // Get the pixels from width
dpiY = GetDeviceCaps(hdc, LOGPIXELSY); // Get the pixels from height
ReleaseDC(NULL, hdc);
}

// Create the window
m_hwnd = CreateWindow(TEXT("DemoApp"), // Class name.
 TEXT("CircuitSim"), // Window name.
 WS_OVERLAPPEDWINDOW |WS_HSCROLL | WS_VSCROLL, // Window style - WS_OVERLAPPEDWINDOW: The window is an overlapped window.
 CW_USEDEFAULT, // Use the default x position.
 CW_USEDEFAULT, // Use the default y position.
 static_cast<UINT>(ceil(640.f * dpiX / 96.f)), // Use the width, which we calculated with the pixels.
 static_cast<UINT>(ceil(480.f * dpiY / 96.f)), // Use the height, which we calculated with the pixels.
 NULL, // A handle to the parent window
 NULL, // A handle to a menu
 HINST_THISCOMPONENT, // A handle to the instance of the module
 this); // A pointer to a value to be passed to the window through the CREATESTRUCT structure

// Check if the window passed the following checks - S_OK: Operation sucessful
// E_FAIL: Unspecified failure
hr = m_hwnd ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
ShowWindow(m_hwnd, SW_MAXIMIZE); // Show the window - SW_MAXIMIZE: set the window to fullscreen
UpdateWindow(m_hwnd);
}

return hr;
}

 

Does anyone know the problem?  :huh:

 

Best regards

MystikReasons

Edited by MystikReasons

Share this post


Link to post
Share on other sites
I don’t have the resources or time to look into it now, but as an aside you are not copying your strings correctly.

Your strings are “TCHAR” but you are using wcscpy_s, which copies “wchar_t”.
_tcscpy_s is meant to copy TCHAR values.


L. Spiro

Share this post


Link to post
Share on other sites

Just a quick guess, but you are passing NULL for the parent window in your combobox' CreateWindow function. That should probably be the handle of your main window. Otherwise you will have to specify the error more precisely.

Share this post


Link to post
Share on other sites

Hello Prototype

 

No im passing a handle for the parentwindow

hWndParent = wWindow.getHwnd();	// Get the window from the Window Class

// Create the Combobox_File
	hWndComboBox_File = CreateWindow(WC_COMBOBOX, TEXT(""),
										  CBS_DROPDOWN |
										  CBS_HASSTRINGS |
										  WS_CHILD |
										  WS_OVERLAPPED |
										  WS_VISIBLE,
										  xPos,
										  yPos,
										  nWidth,
										  nHeight,
										  hWndParent, // HERE
										  NULL,
										  HINST_THISCOMPONENT,
										  NULL);

I dont get an error, it starts the program correct and it also shows the main window with my settings for it.

It seems like it doesn't get the message from the combo box but I dont know why.

 

EDIT: Also used the debugger to find the problem, but it works normally.

The program copies the strings and then sends via the function SendMessage.

Edited by MystikReasons

Share this post


Link to post
Share on other sites

Hello Prototype

 

No im passing a handle for the parentwindow

Sorry, my bad. So does the combo actually show and then, what's your WndProc look like? Perhaps you can display all incoming messages and see if you are missing something. You could also use tools like Spy++ (if that's still around:)) to monitor window messages.

HTH

Share this post


Link to post
Share on other sites

 

 

Sorry, my bad. So does the combo actually show and then, what's your WndProc look like? Perhaps you can display all incoming messages and see if you are missing something. You could also use tools like Spy++ (if that's still around:)) to monitor window messages.

 

No the combo box doesn't show at all even if I call it in the Init function of the window.

 

Thats my WndProc.

LRESULT CALLBACK wWindow::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	LRESULT result = 0;

	if (message == WM_CREATE)
	{
		LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
		wWindow *pWindow = (wWindow *)pcs->lpCreateParams;

		::SetWindowLongPtrW(
			hwnd,
			GWLP_USERDATA,
			PtrToUlong(pWindow)
		);

		result = 1;
	}
	else
	{
		wWindow *pWindow = reinterpret_cast<wWindow *>(static_cast<LONG_PTR>(
			::GetWindowLongPtrW(
				hwnd,
				GWLP_USERDATA)));

		bool wasHandled = false;

		if (pWindow)
		{
			switch (message)
			{
				case WM_COMMAND:
				{
					// If the user makes a selection from the list:
					//   Send CB_GETCURSEL message to get the index of the selected list item.
					//   Send CB_GETLBTEXT message to get the item.
					//   Display the item in a messagebox.
					if (HIWORD(wParam) == CBN_SELCHANGE)
					{
						int ItemIndex = SendMessage((HWND)lParam, (UINT)CB_GETCURSEL,
												   (WPARAM)0, (LPARAM)0);

						TCHAR  ListItem[256];

						(TCHAR)SendMessage((HWND)lParam,
										  (UINT)CB_GETLBTEXT,
										  (WPARAM)ItemIndex,
										  (LPARAM)ListItem);
						 
						// TODO:
						// Do something after that
					}

					wasHandled = true;
					result = 0;
				} break;

				// The WM_DISPLAYCHANGE message is sent to all windows when the display resolution has changed.
				case WM_DISPLAYCHANGE:
				{		
					InvalidateRect(hwnd, NULL, FALSE);
				} 
				wasHandled = true;
				result = 0;
				break;

				// Destroy the window
				case WM_DESTROY:
				{
					PostQuitMessage(0);
				} 		
				wasHandled = true;
				result = 1;
				break;
			}
		}

		if (!wasHandled)
		{
			result = DefWindowProc(hwnd, message, wParam, lParam);
		}
	}

	return result;
}

Yes I found Spy++, now I only have to find out how it works  :rolleyes:

Share this post


Link to post
Share on other sites

@Amr0

 

How do I call the InitCommonControlsEx?

I only find this https://msdn.microsoft.com/en-us/library/windows/desktop/bb775507(v=vs.85).aspx but I dont know how to use it  :rolleyes:

 

Can I make it this way?

Because I get an error.

 

Severity Code Description Project File Line Suppression State
Error LNK2019 Reference to non-resolved external symbol "__imp_InitCommonControlsEx" in function "WinMain".
INITCOMMONCONTROLSEX InitCtrlEx;

	InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
	InitCtrlEx.dwICC = ICC_LINK_CLASS, ICC_PROGRESS_CLASS;
	InitCommonControlsEx(&InitCtrlEx);

	if (!InitCommonControlsEx(&InitCtrlEx))
	{
		int nResult = GetLastError();
		MessageBox(NULL,
			L"Could not initialize common controls class!",
			L"Initialization failure",
			MB_ICONERROR);
	}

EDIT: I call it in the WinMain function

Share this post


Link to post
Share on other sites
INITCOMMONCOONTROLSEX icc;
icc.dwSize = sizeof(icc);
icc.dwICC = ICC_STANDARD_CLASSES;
InitCommonControlsEx(&icc);

That said, in my experience calling this function is rarely required in normal circumstances, so I doubt your problem is caused by this, because if it was, then CreateWindow() would return NULL instead of a window handle.... which you are not checking for.

hWndComboBox_File = CreateWindow(...);
if( !hWndComboBox)
    MessageBox("Failed to create combo box. Last error: " + GetLastError() );

And again, the WS_OVERLAPPED style is not valid for a child window if I'm not mistaken.

Share this post


Link to post
Share on other sites

@Fredericvo

 

I move the instantiate now after I register and create the main window, but it still doesn't work.

Heres the code for the core functions.

HRESULT wWindow::Initialize()
{
	HRESULT hr;

	// Create the window class.
	WNDCLASSEX wcex    = { sizeof(WNDCLASSEX) };

	wcex.style         = CS_HREDRAW | CS_VREDRAW;		// The class styles - CS_HREDRAW: Redraws the window if a movement changes the width of the client area.
														// CS_VREDRAW: Redraws the window if a movement changes the height of the client area.

	wcex.lpfnWndProc   = wWindow::WndProc;				// A pointer to the windows procedure.
	wcex.cbClsExtra	   = 0;								// The number of extra bytes to allocate the window-class structure.
	wcex.cbWndExtra    = sizeof(LONG_PTR);				// The number of extra bytes to allocate following the window instance.
	wcex.hInstance     = HINST_THISCOMPONENT;			// A handle to the instance that contains the window procedure for the class.
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);	// A handle to the class background brush.
	wcex.lpszMenuName  = NULL;							// Pointer to a null-terminated character string that specifies the resource name of the class menu.
	wcex.hCursor       = LoadCursor(NULL, IDC_ARROW);	// A handle to the class cursor, contains the cursor for the window.
	wcex.lpszClassName = TEXT("DemoApp");				// The name of the class

	// Register the window class.
	RegisterClassEx(&wcex);

	// Create the application window.
	//
	// Because the CreateWindow function takes its size in pixels, we
	// obtain the system DPI and use it to scale the window size.
	int dpiX = 0;
	int dpiY = 0;
	HDC hdc = GetDC(NULL);

	if (hdc)
	{
		dpiX = GetDeviceCaps(hdc, LOGPIXELSX);	// Get the pixels from width
		dpiY = GetDeviceCaps(hdc, LOGPIXELSY);	// Get the pixels from height
		ReleaseDC(NULL, hdc);
	}

	// Create the window
	m_hwnd = CreateWindow(TEXT("DemoApp"),								// Class name.
						  TEXT("CircuitSim"),							// Window name.
						  WS_OVERLAPPEDWINDOW |WS_HSCROLL | WS_VSCROLL,							// Window style - WS_OVERLAPPEDWINDOW: The window is an overlapped window.
						  CW_USEDEFAULT,								// Use the default x position.
						  CW_USEDEFAULT,								// Use the default y position.
						  static_cast<UINT>(ceil(640.f * dpiX / 96.f)),	// Use the width, which we calculated with the pixels.
						  static_cast<UINT>(ceil(480.f * dpiY / 96.f)),	// Use the height, which we calculated with the pixels.
						  NULL,											// A handle to the parent window
						  NULL,											// A handle to a menu
						  HINST_THISCOMPONENT,							// A handle to the instance of the module
						  this);										// A pointer to a value to be passed to the window through the CREATESTRUCT structure

	ComboBox m_comboBox;	// Create a instance for ComboBox
							// Initialize all the combo boxes here

	// Check if the window passed the following checks - S_OK: Operation sucessful
	//													 E_FAIL: Unspecified failure
	hr = m_hwnd ? S_OK : E_FAIL;
	if (SUCCEEDED(hr))
	{
		ShowWindow(m_hwnd, SW_MAXIMIZE);	// Show the window - SW_MAXIMIZE: set the window to fullscreen
		UpdateWindow(m_hwnd);
	}
	
	return hr;
}

LRESULT CALLBACK wWindow::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	LRESULT result = 0;

	if (message == WM_CREATE)
	{
		LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
		wWindow *pWindow = (wWindow *)pcs->lpCreateParams;

		::SetWindowLongPtrW(
			hwnd,
			GWLP_USERDATA,
			PtrToUlong(pWindow)
		);

		result = 1;
	}
	else
	{
		wWindow *pWindow = reinterpret_cast<wWindow *>(static_cast<LONG_PTR>(
			::GetWindowLongPtrW(
				hwnd,
				GWLP_USERDATA)));

		bool wasHandled = false;

		if (pWindow)
		{
			switch (message)
			{
				case WM_COMMAND:
				{
					// If the user makes a selection from the list:
					//   Send CB_GETCURSEL message to get the index of the selected list item.
					//   Send CB_GETLBTEXT message to get the item.
					//   Display the item in a messagebox.
					if (HIWORD(wParam) == CBN_SELCHANGE)
					{
						int ItemIndex = SendMessage((HWND)lParam, (UINT)CB_GETCURSEL,
												   (WPARAM)0, (LPARAM)0);

						TCHAR  ListItem[256];

						(TCHAR)SendMessage((HWND)lParam,
										  (UINT)CB_GETLBTEXT,
										  (WPARAM)ItemIndex,
										  (LPARAM)ListItem);
						 
						// TODO:
						// Do something after that
					}

					wasHandled = true;
					result = 0;
				} break;

				// The WM_DISPLAYCHANGE message is sent to all windows when the display resolution has changed.
				case WM_DISPLAYCHANGE:
				{		
					InvalidateRect(hwnd, NULL, FALSE);
				} 
				wasHandled = true;
				result = 0;
				break;

				// Destroy the window
				case WM_DESTROY:
				{
					PostQuitMessage(0);
				} 		
				wasHandled = true;
				result = 1;
				break;
			}
		}

		if (!wasHandled)
		{
			result = DefWindowProc(hwnd, message, wParam, lParam);
		}
	}

	return result;
}
void ComboBox::Initialize()
{
	wWindow wWindow;	// Create a instance of wWindow class

	////////////////////////////////////
	//								  //
	//		Combobox Informations	  //
	//								  //    
	////////////////////////////////////	
	TCHAR Combobox_File[7][13] =
	{
		TEXT("New"), TEXT("Open"), TEXT("Add"), TEXT("Save		Ctrl+S"),
		TEXT("Save As..."), TEXT("Save All"), TEXT("Exit		Alt+F4")
	};
 
	// Create the parameters for FILE Combobox
	//
	// Uses the CreateWindow function to create a child window of 
	// the application window. The WC_COMBOBOX window style specifies  
	// that it is a combobox.
	int xPos = 100;					// Horizontal position of the window
	int yPos = 100;					// Vertical position of the window
	int nWidth = 200;				// Width of the window
	int nHeight = 200;				// Height of the window
	hWndParent = wWindow.getHwnd();	// Get the window from the Window Class

	// Create the Combobox_File
	hWndComboBox_File = CreateWindow(WC_COMBOBOX, TEXT(""),
										  CBS_DROPDOWN |
										  CBS_HASSTRINGS |
										  WS_CHILD |
										  WS_VISIBLE,
										  xPos,
										  yPos,
										  nWidth,
										  nHeight,
										  hWndParent,
										  NULL,
										  HINST_THISCOMPONENT,
										  NULL);

	TCHAR A[17];
	int k = 0;

	memset(&A, 0, sizeof(A));
	// Go trough every TEXT in the string
	for (k = 0; k <= 8; k += 1)
	{
		// Copies a string
		_tcscpy_s(A, sizeof(A) / sizeof(TCHAR), (TCHAR*)Combobox_File[k]);

		// Add string to combobox
		SendMessage(hWndComboBox_File, (UINT)CB_ADDSTRING, (WPARAM)0, (LPARAM)A);
	}

	// Send the CB_SETCURSEL message to display an initial item 
	// in the selection field  
	SendMessage(hWndComboBox_File, CB_SETCURSEL, (WPARAM)2, (LPARAM)0);

	return;
}
int WINAPI WinMain(
	HINSTANCE     /* hInstance */,
	HINSTANCE     /* hPrevInstance */,
	LPSTR     /* lpCmdLine */,
	int)     /* nCmdShow */
{
	 
	HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
	if (SUCCEEDED(CoInitialize(NULL)))
	{
		{
			wWindow app;

			if (SUCCEEDED(app.Initialize()))
			{
				app.RunMessageLoop();
			}
		}
		CoUninitialize();
	}
	return 0;
}


Edited by MystikReasons

Share this post


Link to post
Share on other sites

I get an error from GetLastError, saved it in an txt. file
What does this error mean to my problem?



ERROR_ALREADY_EXISTS

Cannot create a file when that file already exists.

183 (0xB7)



It literally means what it means and seems unrelated to your problem. Are you using CreateFileEx somewhere in your code? If CreateWindowEx succeeds it's not going to "reset" the error value.
http://microsoft.public.win32.programmer.ui.narkive.com/OamvbzgN/createwindowex-returns-error-already-exists

Share this post


Link to post
Share on other sites
Does your ComboBox class destroy the handle in its destructor?

In your wWindow::Initialize you create a local ComboBox instance, which is destroyed when the function is left.



Also, in your ComboBox::Initialize you create a local wWindow instance, which obviously has no connection to the main app window. Therefore your parent HWND is NULL.

What does the debugger say? Is

hWndComboBox_File = CreateWindow...

actually setting a value not equil NULL to hWndComboBox_File ? Edited by Endurion

Share this post


Link to post
Share on other sites

 

 

It literally means what it means and seems unrelated to your problem. Are you using CreateFileEx somewhere in your code? If CreateWindowEx succeeds it's not going to "reset" the error value. 
http://microsoft.public.win32.programmer.ui.narkive.com/OamvbzgN/createwindowex-returns-error-already-exists 

Thank you for that useful information.

 

 

 

Does your ComboBox class destroy the handle in its destructor?

In your wWindow::Initialize you create a local ComboBox instance, which is destroyed when the function is left.



Also, in your ComboBox::Initialize you create a local wWindow instance, which obviously has no connection to the main app window. Therefore your parent HWND is NULL.

What does the debugger say? Is

hWndComboBox_File = CreateWindow...

actually setting a value not equil NULL to hWndComboBox_File ? 

The debugger says, that the hWndComboBox_File NULL is.

Yes I'm creating a wWindow instance, which I used to get the hWnd but the instance is also deleting itself, because its on the stack.

hWndParent = wWindow.getHwnd();	// Get the window from the Window Class

Could this be the error?

Edited by MystikReasons

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this