The following is my winapi program that window contains 3 sets of controls:
The controls that created directly in the window
The controls in Group1
The controls in Group2
When I press Tab-key , it only traverse in set1.
Why I can't switch to the child control of the group1 and group2 by Tab-key?
#include <Windows.h>
LRESULT __stdcall WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message)
{
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, RGB(0, 0, 255));
SetBkMode(hdcStatic, TRANSPARENT);
return (LRESULT)GetStockObject(NULL_BRUSH);
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////
void CreateEdit(const HWND &parent, const int &x, const int &y, const int &id) {
CreateWindow(L"EDIT", L"", WS_BORDER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, x, y, 200, 20, parent, (HMENU)id, NULL, NULL);
}
////////////////////////////////////////////////////////////////////////////
int __stdcall wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
WNDCLASSEX wndclass{};
wndclass.cbSize = sizeof(wndclass);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.hInstance = hInstance;
wndclass.hbrBackground = CreateSolidBrush(RGB(255, 128, 255));
wndclass.lpszClassName = L"test";
RegisterClassEx(&wndclass);
HWND hWndMainWindow = CreateWindow(
wndclass.lpszClassName,
L"test",
WS_EX_OVERLAPPEDWINDOW | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE,
100, 100, 500, 500,
NULL, NULL, hInstance, NULL);
::ShowWindow(hWndMainWindow, SW_SHOW);
::UpdateWindow(hWndMainWindow);
//Creating Controls~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int x = 10, y = 20, id = 100;
HWND g1 = CreateWindow(L"button", L"Group1", WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP | WS_GROUP, 0, 50, 220, 200, hWndMainWindow, (HMENU)++id, NULL, NULL);
//Controls in Group1
CreateEdit(g1, x, (y += 30), ++id);
CreateEdit(g1, x, (y += 30), ++id);
CreateEdit(g1, x, (y += 30), ++id);
CreateEdit(g1, x, (y += 30), ++id);
HWND g2 = CreateWindow(L"button", L"Group2", WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP | WS_GROUP, 260, 50, 220, 200, hWndMainWindow, (HMENU)++id, NULL, NULL);
y = 20;
//Controls in Group2
CreateEdit(g2, x, (y += 30), ++id);
CreateEdit(g2, x, (y += 30), ++id);
CreateEdit(g2, x, (y += 30), ++id);
CreateEdit(g2, x, (y += 30), ++id);
//The controls that create directly in the main window
y = 270;
CreateWindow(L"static", L"Main Window Controls", WS_CHILD | WS_VISIBLE, x, y, 200, 30, hWndMainWindow, (HMENU)++id, NULL, NULL);
CreateEdit(hWndMainWindow, x, (y += 30), ++id);
CreateEdit(hWndMainWindow, x, (y += 30), ++id);
CreateEdit(hWndMainWindow, x, (y += 30), ++id);
CreateEdit(hWndMainWindow, x, (y += 30), ++id);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
if (!IsDialogMessage(hWndMainWindow, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
The two child windows that host "Group1" and "Group2" both need to be marked as "control parents" with the WS_EX_CONTROLPARENT style. This style means:
The window itself contains child windows that should take part in
dialog box navigation. If this style is specified, the dialog manager
recurses into children of this window when performing navigation
operations such as handling the TAB key, an arrow key, or a keyboard
mnemonic
Change your code to create those windows as follows:
HWND g1 = CreateWindowEx(WS_EX_CONTROLPARENT, L"button", L"Group1", WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP | WS_GROUP, 0, 50, 220, 200, hWndMainWindow, (HMENU)++id, NULL, NULL);
HWND g2 = CreateWindowEx(WS_EX_CONTROLPARENT, L"button", L"Group2", WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP | WS_GROUP, 260, 50, 220, 200, hWndMainWindow, (HMENU)++id, NULL, NULL);
(As an aside, it seems wrong to make your windows children of the groupbox. They don't need to be - you can just position them inside it but make them siblings of it instead of children. The groupbox is specifically designed to work this way - I don't know how well it will work with the controls as children.)
Since you're not creating a dialog box, your main window should be created with the WS_EX_CONTROLPARENT style.
Make sure that you only place this style on your main window. The child windows should not be using this style.
Related
I want to disable the radio buttons when I select the checkbox. It works when I pass hwnd in addFunc2(), however, I need it to be in the second tab but somehow I can't find any way to make it work.
I apologize if its confusing, I'm very new at this, and my first time posting here. Please let me know if I need to clarify it more. Please refer to the images and some of my code below:
Result of code:
What I need:
HWND hRadio1, hRadio2, hTab, g_tabPanes[2];
HWND CreateTabPane(HWND tabctrl, int id, HINSTANCE instance)
{
RECT rcTab;
GetClientRect(tabctrl, &rcTab);
TabCtrl_AdjustRect(tabctrl, FALSE, &rcTab);
int wd = rcTab.right - rcTab.left;
int hgt = rcTab.bottom - rcTab.top;
return CreateWindow(
L"static", L"",
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
rcTab.left, rcTab.top, wd, hgt,
tabctrl,
(HMENU)id,
instance,
NULL
);
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
{
addControl(hwnd);
HINSTANCE hInst = GetModuleHandle(NULL);
RECT rc; int dx, dy;
GetClientRect(hwnd, &rc);
dx = rc.right - rc.left;
dy = rc.bottom - rc.top;
TCITEM tie = {
TCIF_TEXT | TCIF_IMAGE,
0, 0,
NULL,
0, -1, 0
};
hTab = CreateWindowEx(NULL, WC_TABCONTROL, _T(""),
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
0, 0, dx, dy, hwnd,
(HMENU)1001, hInst, NULL
);
tie.pszText = (LPWSTR)_T("Tab 1");
TabCtrl_InsertItem(hTab, 0, &tie);
tie.pszText = (LPWSTR)_T("Tab 2");
TabCtrl_InsertItem(hTab, 1, &tie);
for (int i = 0; i < 2; i++)
g_tabPanes[i] = CreateTabPane(hTab, TAB_ID + i, hInst);
addFunc1(g_tabPanes[0]);
addFunc2(g_tabPanes[1]);
break;
}
case WM_COMMAND:
{
switch (wParam)
{
case ID_CHECKBOX:
{
switch (HIWORD(wParam))
{
case BN_CLICKED:
if (SendDlgItemMessage(hwnd, ID_CHECKBOX, BM_GETCHECK, 0, 0))
{
EnableWindow(hRadio1, true);
EnableWindow(hRadio2, true);
}
else
{
EnableWindow(hRadio1, false);
EnableWindow(hRadio2, false);
}
break;
}
}
break;
case WM_NOTIFY:
{
LPNMHDR ns = (LPNMHDR)lParam;
if ((ns->idFrom == 1001) && (ns->code == TCN_SELCHANGE))
{
int pane = TabCtrl_GetCurSel(hTab);
for (int i = 0; i < 2; i++)
if (pane == i)
ShowWindow(g_tabPanes[i], SW_SHOW);
else
ShowWindow(g_tabPanes[i], SW_HIDE);
}
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
void addFunc2(HWND hwnd)
{
HWND hCheckbox;
CreateWindow(TEXT("static"), TEXT("Duplex: "), WS_CHILD | WS_VISIBLE,
75, 10, 90, 25, hwnd, NULL, NULL, NULL);
hCheckbox = CreateWindow(L"button", L"Print on both sides", WS_CHILD | WS_VISIBLE |
BS_AUTOCHECKBOX | WS_TABSTOP,
75, 30, 150, 30, hwnd, (HMENU)ID_CHECKBOX, g_hinst, NULL);
hRadio1 = CreateWindow(L"button", L"Flip on long edge", WS_CHILD | WS_VISIBLE |
BS_AUTORADIOBUTTON | WS_TABSTOP,
75, 55, 150, 30, hwnd, (HMENU)ID_RADIO1, g_hinst, NULL);
hRadio2 = CreateWindow(L"button", L"Flip on short edge", WS_CHILD | WS_VISIBLE |
BS_AUTORADIOBUTTON | WS_TABSTOP,
75, 80, 150, 30, hwnd, (HMENU)ID_RADIO2, g_hinst, NULL);
SendMessage(hCheckbox, BM_SETCHECK, BST_CHECKED, 0);
SendMessage(hRadio1, BM_SETCHECK, BST_CHECKED, 0);
My goal is to create 5 groups of radio buttons (i know it contradict with the title but you still get the point) for user choice using only Win32 API (so no window form here).
I tried using a combination of groupbox and SetWindowLongPtr but it still not working as expected (note that im using GWLP_WNDPROC as the index). If i use SetWindowLongPtr to a group box then that groupbox is gone and everything else work as expected.
I could use a "virtual" group box but it reduce the efficency of my code. Some one might recommend using WS_GROUP but it only apply if there are 2 group of radio buttons ( I think ). And i also dont like using resource so is there any solution to this problem or i just have to stuck with the "virtual" group box?
Minimal reproducible sample:
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp)
{
switch (uMsg)
{
default:
return DefWindowProc(hwnd, uMsg, wp, lp);
}
}
int WINAPI wWinMain(HINSTANCE hinst, HINSTANCE hiprevinst, PWSTR nCmdLine, int ncmdshow)
{
const wchar_t CLASS_NAME[] = L"Sample";
WNDCLASS wc = { };
wc.lpfnWndProc = WndProc;
wc.hInstance = hinst;
wc.lpszClassName = CLASS_NAME;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(
0,
CLASS_NAME,
L"Sample window",
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, // Window style
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL,
NULL,
hinst,
NULL);
HWND groupbox = CreateWindowEx(0, L"Button", L"Groupbox", WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 10, 10, 100, 100, NULL, NULL, hinst, NULL);
HWND radiobutton1 = CreateWindowEx(0, L"Button", L"Groupbox", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON, 10, 10, 60, 60, groupbox, NULL, hinst, NULL);
SetWindowLongPtr(groupbox, GWLP_WNDPROC, (LONG)WndProc);
SendMessage(groupbox, NULL, NULL, TRUE);
ShowWindow(hwnd, ncmdshow);
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
Due to i stripped so much of the necessary function away, you need to go to task manager and kill the process named "Autoclicker" for some reason to be able to recompile it again
Make sure you handle WM_DESTROY otherwise window won't close properly.
The radio buttons, all child dialog items, and all child windows should be created in WM_CREATE section of parent window. They need the HWND handle from parent window.
SetWindowLongPtr(.. GWLP_WNDPROC ...) is an old method used for subclassing. Your usage is incorrect. You don't need it anyway.
It's unclear what SendMessage(groupbox, NULL, NULL, TRUE); is supposed to do.
Just add the radio buttons, make sure the first radio button has an added WS_TABSTOP|WS_GROUP as shown below
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp)
{
switch (uMsg)
{
case WM_CREATE:
{
HINSTANCE hinst = GetModuleHandle(0);
auto add = [&](const wchar_t* name,
int id, int x, int y, int w, int h, bool first = false)
{
DWORD style = WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON;
if (first) style |= WS_GROUP | WS_TABSTOP;
return CreateWindowEx(0, L"Button", name, style,
x, y, w, h, hwnd, (HMENU)id, hinst, NULL);
};
HWND groupbox1 = CreateWindowEx(0, L"Button", L"Groupbox1",
WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 2, 2, 250, 120, hwnd, NULL, hinst, NULL);
HWND radio1 = add(L"radio1", 1, 10, 30, 200, 20, true);
HWND radio2 = add(L"radio2", 2, 10, 51, 200, 20);
HWND radio3 = add(L"radio3", 3, 10, 72, 200, 20);
HWND radio4 = add(L"radio4", 4, 10, 93, 200, 20);
HWND groupbox2 = CreateWindowEx(0, L"Button", L"Groupbox2",
WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 280, 2, 250, 120, hwnd, NULL, hinst, NULL);
HWND radio11 = add(L"radio1", 11, 300, 30, 200, 20, true);
HWND radio12 = add(L"radio2", 12, 300, 51, 200, 20);
HWND radio13 = add(L"radio3", 13, 300, 72, 200, 20);
HWND radio14 = add(L"radio4", 14, 300, 93, 200, 20);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wp, lp);
}
}
int WINAPI wWinMain(HINSTANCE hinst, HINSTANCE hiprevinst, PWSTR nCmdLine, int ncmdshow)
{
const wchar_t CLASS_NAME[] = L"Sample";
WNDCLASS wc = { };
wc.lpfnWndProc = WndProc;
wc.hInstance = hinst;
wc.lpszClassName = CLASS_NAME;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(0, CLASS_NAME, L"Sample window",
WS_OVERLAPPEDWINDOW, 0, 0, 800, 600,
NULL, NULL, hinst, NULL);
ShowWindow(hwnd, ncmdshow);
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
I'm trying to create window that contain richedit control and listbox control,
the problem is that the second control which I create, doesn't show up.
I mean:
case WM_CREATE: // In main window procedure
{
/* Center the main window */
This->CenterWindow(hwnd);
/* Initialize the clients list */
This->InitListClients(hwnd);
/* Initialize the server log */
This->InitEditLog(hwnd);
return 0;
}
If InitListClients function will be first, only the listbox will show up,
if InitEditLog will be first, only the richedit will show up.
Here are the functions:
void ApostleServer::InitEditLog(HWND &_hwnd)
{
LoadLibrary(TEXT("Riched32.dll"));
hEditLog = CreateWindowEx(WS_EX_STATICEDGE, "richedit", "bla", WS_CHILD | WS_VISIBLE | ES_MULTILINE, 10, 10, 390, 310, _hwnd, NULL, (HINSTANCE)GetWindowLong(_hwnd, GWL_HINSTANCE), NULL);
}
void ApostleServer::InitListClients(HWND &_hwnd)
{
hListClients = CreateWindowEx(WS_EX_STATICEDGE, "listbox", "bla", WS_CHILD | WS_VISIBLE | LBS_NOTIFY, 550, 20, 150, 150, _hwnd, NULL, (HINSTANCE)GetWindowLong(_hwnd, GWL_HINSTANCE), NULL);
}
I'm kinda newbie with winapi and I couldn't find solution for this problem.
Thanks.
EDIT:
As I commented, the cause of the problem is the use of class members.
Here is a whole code that I've wrote and has the same problem:
#include <Windows.h>
#include <stdlib.h>
class Server
{
public:
/* Fields */
MSG* msg;
WNDCLASSW* wc;
HWND hListClients;
HWND hEditLog;
/* Methods */
void InitEditLog(HWND &_hwnd)
{
LoadLibrary(TEXT("Riched32.dll"));
hEditLog = CreateWindowExW(WS_EX_STATICEDGE, L"richedit", L"Text", WS_CHILD | WS_VISIBLE | ES_MULTILINE, 10, 10, 390, 306, _hwnd, (HMENU)2, (HINSTANCE)GetWindowLong(_hwnd, GWL_HINSTANCE), NULL);
}
void InitListClients(HWND &_hwnd)
{
// Here I'm using hListClients class member, and that what cause the problem (I will see only the list on the window)
hListClients = CreateWindowExW(WS_EX_STATICEDGE, L"listbox", L"asd", WS_CHILD | WS_VISIBLE | LBS_NOTIFY, 410, 10, 160, 306, _hwnd, (HMENU)1, (HINSTANCE)GetWindowLong(_hwnd, GWL_HINSTANCE), NULL);
// If I was only creating the listbox (without returning handler), I will see the listbox and the richedit.
}
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
Server* This = (Server*)GetWindowLongW(hwnd, GWL_USERDATA);
switch(msg)
{
case WM_CREATE:
{
/* Initialize the clients list */
This->InitListClients(hwnd); // Attention that I called this function first.
/* Initialize the server log */
This->InitEditLog(hwnd);
// If I would call this function first, I will see only the richedit.
return 0;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
Server(HINSTANCE &_hInstance)
{
msg = new MSG;
wc = new WNDCLASSW;
wc->style = CS_HREDRAW | CS_VREDRAW;
wc->cbClsExtra = 0;
wc->cbWndExtra = 0;
wc->lpszClassName = L"ApostleServer";
wc->hInstance = _hInstance;
wc->hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc->lpszMenuName = NULL;
wc->lpfnWndProc = WndProc;
wc->hCursor = LoadCursor(NULL, IDC_ARROW);
wc->hIcon = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassW(&(*wc));
CreateWindowW(wc->lpszClassName, L"Apostle Server", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 600, 400, 0, 0, _hInstance, 0);
while(GetMessage(&(*msg), NULL, 0, 0))
{
TranslateMessage(&(*msg));
DispatchMessage(&(*msg));
}
}
};
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
Server* srvr = new Server(hInstance);
return 0;
}
Problem solved by creating the controls on WM_CREATE message (but not to set control handlers!), and set the control handlers after the creation of the main window.
WM_CREATE message:
case WM_CREATE:
{
/* Center the main window */
This->CenterWindow(hwnd);
/* Initialize the clients list */
This->InitListClients(hwnd);
/* Initialize the server log */
This->InitEditLog(hwnd);
return 0;
}
After main window creation:
RegisterClassW(&(*wc));
hMainWindow = CreateWindowW(wc->lpszClassName, L"Apostle Server", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 600, 400, 0, 0, _hInstance, 0);
/* Set controls handlers */
hListClients = GetDlgItem(hMainWindow, IDC_LISTCLIENTS);
hEditLog = GetDlgItem(hMainWindow, IDC_EDITLOG);
InitEditLog and InitListClients functions:
void ApostleServer::InitEditLog(HWND &_hwnd)
{
LoadLibrary(TEXT("Riched32.dll"));
CreateWindowExW(WS_EX_STATICEDGE, L"richedit", L"Text", WS_CHILD | WS_VISIBLE | ES_MULTILINE, 10, 10, 390, 306, _hwnd, (HMENU)IDC_EDITLOG, (HINSTANCE)GetWindowLong(_hwnd, GWL_HINSTANCE), NULL);
}
void ApostleServer::InitListClients(HWND &_hwnd)
{
CreateWindowExW(WS_EX_STATICEDGE, L"listbox", L"asd", WS_CHILD | WS_VISIBLE | LBS_NOTIFY, 410, 10, 160, 306, _hwnd, (HMENU)IDC_LISTCLIENTS, (HINSTANCE)GetWindowLong(_hwnd, GWL_HINSTANCE), NULL);
}
OK, so i am writing this program in C++ that is supposed to append the clipboard text into the edit control inside the Auto-Clipboard tab. I have setup the program so that it supports unicode text.
The program appends the text correctly when i copy text outside the program. But if i copy text that is from the program, it shows me as if it is copying ansi characters that needs to be converted int unicode.
I am not sure if the problem is from the edit control or from the Clipboard. Is the edit control output not in unicode? Or is the clipboard copying as ansi and pasting as unicode?
Edit: So i find out that according to MSDN documentations, WM_COPY in edit controls are handled in CF_TEXT mode instead of CF_UNICODETEXT for the clipboard:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms649022(v=vs.85).aspx
And so, i added some subclassing starting with my AutoClipboardEdit control but for some reason i get currupted heap error on WM_DRAWCLIPBOARD messages. So i am stuck there:
Edit2: I got it working by not freeing the allocated memory of the text string used on the clipboard. In this case the name of the variable is hMem2. It seems that if i free hMem2, the program crashes with a "corrupted heap" error. My guess is that the OS itself manages and frees the memory. It does seem possible since the SetClipboardData argument for the data is a pointer. I also tried to test if memory actually leaked by sending a WM_COPY message into a infinite loop to see if the heap would increase forever; but far it didn't seem so.
So, i need someone to confirm to me that there is no memory leak or that the OS actually does manage and free the clipboard accordingly.
Here is the complete source code:
#define UNICODE
#define _UNICODE
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#pragma comment(lib, "Comctl32.lib")
#include <tchar.h>
#include <Windows.h>
#include <CommCtrl.h>
#include <sstream>
using namespace std;
TCHAR temp[1024];
enum TabIndexes
{
ID_ReadingPageTab,
ID_AutoClipboardTab
};
enum WindowControls
{
ID_SelectAll,
ID_TabControls,
ID_ReadingPageEdit,
ID_AutoClipboardEdit,
ID_AutoClipboardCheckbox,
ID_AutoReadCheckbox,
ID_AutoClearCheckbox,
ID_ReadPauseResumeButton,
ID_StopButton
};
//***************Global Variables***************
HWND MainWindowHandle;
HWND ClipboardViewer;
HWND TabControls;
HWND ReadingPageEdit;
HWND AutoClipboardEdit;
HWND AutoClipboardCheckbox;
HWND AutoReadCheckbox;
HWND AutoClearCheckbox;
HWND ReadPauseResumeButton;
HWND StopButton;
RECT WindowReactangle;
RECT EditControlsDimension;
HACCEL SelectAll;
int Textlength;
void ShowReport()
{
LPTSTR ErrorText = NULL;
FormatMessage
(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, //dwFlags
NULL, //lpSource
GetLastError(), //dwMessageId
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //dwLanguageId
(LPTSTR)&ErrorText, //lpBuffer
0, //nSize
NULL //*Arguments
);
MessageBox(NULL, ErrorText, TEXT("Last Error:"), MB_OK);
}
void OutputBox(LPTSTR OutputText)
{
MessageBox(NULL, OutputText, _T("WARNING!!!"), MB_OK);
}
WNDPROC OldProc;
LRESULT CALLBACK EditControl
(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
WPARAM StartOfSelectection;
LPARAM EndOfSelection;
int SelectionSize;
int TextSize;
TCHAR* hMem1;
TCHAR* hMem2;
if (uMsg == WM_COPY)
{
OpenClipboard(NULL);
SendMessage(hwnd, EM_GETSEL, (WPARAM)&StartOfSelectection, (LPARAM)&EndOfSelection);
SelectionSize = EndOfSelection - StartOfSelectection + 1;
TextSize = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
TextSize -= (TextSize - EndOfSelection - 1);
hMem1 = new TCHAR[TextSize]();
ZeroMemory(hMem1, TextSize*sizeof(TCHAR));
SendMessage(hwnd, WM_GETTEXT, TextSize, (LONG)hMem1);
hMem2 = new TCHAR[SelectionSize]();
ZeroMemory(hMem2, SelectionSize*sizeof(TCHAR));
for(int Index=0; StartOfSelectection<EndOfSelection; ++StartOfSelectection)
hMem2[Index++] = hMem1[StartOfSelectection];
SetClipboardData(CF_UNICODETEXT, (HANDLE)hMem2);
CloseClipboard();
delete[] hMem1;
//delete[] hMem2;
}
return OldProc(hwnd, uMsg, wParam, lParam);
}
void CreateControls(HWND hWndParent)
{
GetClientRect(hWndParent, &WindowReactangle);
const INITCOMMONCONTROLSEX CommonControls = {sizeof(INITCOMMONCONTROLSEX), ICC_TAB_CLASSES};
InitCommonControlsEx(&CommonControls);
TabControls = CreateWindow
(
WC_TABCONTROL, //lpClassName
NULL, //lpWindowName
WS_VISIBLE | WS_CHILD, //dwStyle
WindowReactangle.left, //x
WindowReactangle.top, //y
WindowReactangle.right, //nWidth
WindowReactangle.bottom - 100, //nHeight
hWndParent, //hWndParent
(HMENU)ID_TabControls, //hMenu
NULL, //hInstance
NULL //lpParam
);
TCITEM TabItemStructure = {0};
TabItemStructure.mask = TCIF_TEXT;
TabItemStructure.pszText = _T("Reading Page");
SendMessage(TabControls, TCM_INSERTITEM, ID_ReadingPageTab, (LPARAM)&TabItemStructure);
TabItemStructure.pszText = _T("Auto-Clipboard");
SendMessage(TabControls, TCM_INSERTITEM, ID_AutoClipboardTab, (LPARAM)&TabItemStructure);
ACCEL AcceleratorStructure;
AcceleratorStructure.fVirt = FCONTROL | FVIRTKEY;
AcceleratorStructure.key = 0x41;
AcceleratorStructure.cmd = ID_SelectAll;
SelectAll = CreateAcceleratorTable(&AcceleratorStructure, 1);
ReadingPageEdit = CreateWindow
(
_T("EDIT"), //lpClassName
NULL, //lpWindowName
WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_BORDER | ES_MULTILINE, //dwStyle
5, //x
30, //y
WindowReactangle.right - 10, //nWidth
WindowReactangle.bottom - 135, //nHeight
TabControls, //hWndParent
(HMENU)ID_ReadingPageEdit, //hMenu
NULL, //hInstance
NULL //lpParam
);
AutoClipboardEdit = CreateWindow
(
_T("EDIT"), //lpClassName
NULL, //lpWindowName
WS_CHILD | WS_VSCROLL | WS_BORDER | ES_MULTILINE, //dwStyle
5, //x
30, //y
WindowReactangle.right - 10, //nWidth
WindowReactangle.bottom - 135, //nHeight
TabControls, //hWndParent
(HMENU)ID_AutoClipboardEdit, //hMenu
NULL, //hInstance
NULL //lpParam
);
AutoClipboardCheckbox = CreateWindow
(
_T("BUTTON"), //lpClassName
_T("Auto-Clipboard"), //lpWindowName
BS_AUTOCHECKBOX | WS_VISIBLE | WS_CHILD, //dwStyle
10, //x
WindowReactangle.bottom -100 +10, //y
150, //nWidth
25, //nHeight
hWndParent, //hWndParent
(HMENU)ID_AutoClipboardCheckbox, //hMenu
NULL, //hInstance
NULL //lpParam
);
SendMessage(AutoClipboardCheckbox, BM_CLICK, TRUE, 0);
OldProc = (WNDPROC)SetWindowLongPtr(AutoClipboardEdit, GWLP_WNDPROC, (LONG)EditControl);
AutoReadCheckbox = CreateWindow
(
_T("BUTTON"), //lpClassName
_T("Auto-Read"), //lpWindowName
BS_AUTOCHECKBOX | WS_VISIBLE | WS_CHILD, //dwStyle
10, //x
WindowReactangle.bottom -100 +35, //y
150, //nWidth
25, //nHeight
hWndParent, //hWndParent
(HMENU)ID_AutoReadCheckbox, //hMenu
NULL, //hInstance
NULL //lpParam
);
AutoClearCheckbox = CreateWindow
(
_T("BUTTON"), //lpClassName
_T("Auto-Clear"), //lpWindowName
BS_AUTOCHECKBOX | WS_VISIBLE | WS_CHILD, //dwStyle
10, //x
WindowReactangle.bottom -100 +60, //y
150, //nWidth
25, //nHeight
hWndParent, //hWndParent
(HMENU)ID_AutoReadCheckbox, //hMenu
NULL, //hInstance
NULL //lpParam
);
}
LRESULT WINAPI MainWindowProcedure
(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch(uMsg)
{
//Clipboard Events
case WM_CHANGECBCHAIN:
if ((HWND)wParam == ClipboardViewer)
ClipboardViewer = (HWND)lParam;
return 0;
case WM_DRAWCLIPBOARD:
OpenClipboard(NULL);
SendMessage(AutoClipboardEdit, EM_SETSEL, (WPARAM)-1, (LPARAM)-1);
SendMessage(AutoClipboardEdit, EM_REPLACESEL, 0, (LPARAM)GetClipboardData(CF_UNICODETEXT)); //CF_TEXT //CF_UNICODETEXT
CloseClipboard();
break;
//Window Controls Events
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_SelectAll:
if (HIWORD(wParam)==1)
SendMessage(GetFocus(), EM_SETSEL, (WPARAM)0, (LPARAM)-1);
break;
case ID_AutoClipboardCheckbox:
if (SendMessage(AutoClipboardCheckbox, BM_GETCHECK, 0, 0) == BST_CHECKED)
ClipboardViewer = SetClipboardViewer(hwnd);
else
ChangeClipboardChain(hwnd, ClipboardViewer);
break;
}
return 0;
//Tab Controls Events
case WM_NOTIFY:
if (SendMessage(TabControls, TCM_GETCURSEL, 0, 0))
{
ShowWindow(ReadingPageEdit, SW_HIDE);
ShowWindow(AutoClipboardEdit, SW_SHOW);
} else
{
ShowWindow(AutoClipboardEdit, SW_HIDE);
ShowWindow(ReadingPageEdit, SW_SHOW);
}
break;
//Main Window Events
case WM_SIZE:
{
int LOPARAM = lParam & 0xFFFF;
int HIPARAM = lParam >> 16;
SetWindowPos(TabControls, NULL, 0, 0, LOPARAM, HIPARAM-100, SWP_DRAWFRAME);
SetWindowPos(ReadingPageEdit, NULL, 5, 30, LOPARAM-10, HIPARAM-100-35, SWP_DRAWFRAME);
SetWindowPos(AutoClipboardEdit, NULL, 5, 30, LOPARAM-10, HIPARAM-100-35, SWP_DRAWFRAME);
SetWindowPos(AutoClipboardCheckbox, NULL, 10, HIPARAM-100+10, 150, 25, SWP_DRAWFRAME);
SetWindowPos(AutoReadCheckbox, NULL, 10, HIPARAM-100+35, 150, 25, SWP_DRAWFRAME);
SetWindowPos(AutoClearCheckbox, NULL, 10, HIPARAM-100+60, 150, 25, SWP_DRAWFRAME);
return 0;
}
case WM_CREATE:
CreateControls(hwnd);
return 0;
case WM_DESTROY:
DestroyAcceleratorTable(SelectAll);
ChangeClipboardChain(hwnd, ClipboardViewer);
PostQuitMessage(ERROR_SUCCESS);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
void CreateMainWindow()
{
WNDCLASSEX WindowClassStructure;
WindowClassStructure.cbSize = sizeof(WNDCLASSEX);
WindowClassStructure.style = CS_HREDRAW | CS_VREDRAW;
WindowClassStructure.lpfnWndProc = MainWindowProcedure;
WindowClassStructure.cbClsExtra = 0;
WindowClassStructure.cbWndExtra = 0;
WindowClassStructure.hInstance = NULL;
WindowClassStructure.hIcon = LoadIcon(NULL, IDI_INFORMATION);
WindowClassStructure.hCursor = LoadCursor(NULL, IDC_ARROW);
WindowClassStructure.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
WindowClassStructure.lpszMenuName = NULL;
WindowClassStructure.lpszClassName = _T("MainClass");
WindowClassStructure.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
RegisterClassEx(&WindowClassStructure);
MainWindowHandle = CreateWindow
(
_T("MainClass"), //lpClassName
_T("Clipboard Reader"), //lpWindowName
WS_VISIBLE | WS_OVERLAPPEDWINDOW, //dwStyle
CW_USEDEFAULT, //x
CW_USEDEFAULT, //y
640, //nWidth
480, // nHeight
NULL, //hWndParent
NULL, //hMenu
NULL, //hInstance
NULL //lpParam
);
}
int WINAPI _tWinMain
(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow
)
{
CreateMainWindow();
MSG MessageStructure = {0};
while(MessageStructure.message != WM_QUIT)
{
if (PeekMessage(&MessageStructure, NULL, 0, 0, PM_REMOVE))
{
if (!TranslateAccelerator(MainWindowHandle, SelectAll, &MessageStructure))
{
TranslateMessage(&MessageStructure);
DispatchMessage(&MessageStructure);
}
}
}
return MessageStructure.wParam;
}
I know it is a very simple question but i currently cant create a parent window...
My code:
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
static HWND paste;
static HWND update_list;
/*HWND changeuser = CreateWindow(0, 0,
0,
0, 0, x, y,
0, (HMENU)changeuser2, 0, NULL); */
switch(msg)
{
case WM_CREATE:
meniu(hwnd);
CreateWindow(TEXT("static"), TEXT("\nSuckers online:"),
WS_VISIBLE | WS_CHILD | SS_CENTER,
0, 0, x, 55,
hwnd, (HMENU)delete, NULL, NULL);
connected = CreateWindow(TEXT("edit"), TEXT(""),
WS_VISIBLE | WS_CHILD | WS_VSCROLL| ES_MULTILINE ,
0, 60, x, 340,
hwnd, (HMENU)delete2, NULL, NULL);
CreateWindow(TEXT("static"), TEXT(""),
WS_VISIBLE | WS_CHILD | SS_CENTER|BS_PUSHBUTTON,
0, 405, x, 358,
hwnd, (HMENU) delete3, NULL, NULL);
paste = CreateWindow(TEXT("Edit"), TEXT("Paste the ip here"),
WS_VISIBLE | WS_CHILD | SS_CENTER,
x/2 - 60, 410, 120, 40,
hwnd, (HMENU) ip, NULL, NULL);
CreateWindow(TEXT("Button"), TEXT("Connect!"),
WS_VISIBLE | WS_CHILD | SS_CENTER | BS_PUSHBUTTON,
x/2 - 120, 450, 120, 40,
hwnd, (HMENU) connect2, NULL, NULL);
update_list = CreateWindow(TEXT("Button"), TEXT("Update the list!"),
WS_VISIBLE | WS_CHILD | SS_CENTER | BS_PUSHBUTTON,
x/2, 450, 120, 40,
hwnd, (HMENU) update, NULL, NULL);
_beginthread( lista, 0, (void*)(0) );//begin thread lista
break;
case WM_CTLCOLORSTATIC : {
HBRUSH br = CreateSolidBrush(RGB(80,67,77)); // change background color
SetTextColor((HDC)wParam,RGB(0,102,51)); //the controls text color
return (LRESULT) br;
}
case WM_COMMAND:
switch LOWORD(wParam)
{
case exit:
PostQuitMessage(0);
break;
case ip:
int nr;
nr = GetWindowTextLength(paste);
if (nr >= 17)
SetWindowText(paste, "");
break;//omor textul, ca sa pot sa fac paste
case connect2:
GetWindowText(paste,adresa,16);
_beginthread( start, 0, (void*)(0) ); //as\ici se face conexiunea principala
//DestroyWindow(hwnd);
MessageBox(0,"Connected with the user","Ok",0);
break;
case update:
exit2 = true;
Sleep(100);
SetWindowText(connected,"");
_beginthread( lista, 0, (void*)(0) );//begin thread lista
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
I want the other windows created to be the child of the changeuser window...
I just cant make it happen...
Any help will be appreciated!
To change the window of a parent, use SetParent().
But i would think about the structure - if you need to change the parent of one or more windows in a normal dialog setting, it is likely these windows should have a different parent.
In your case there is a problem in your handling of window messages though:
If your message handler receives WM_DESTROY you call PostQuitMessage(), which probably results in your application closing.
There are two ways you can handle that:
use different window processes for your main dialog and child dialogs (preferably)
or use the hwnd parameter to decide wether you call PostQuitMessage()
You can't 'replace' a window. If you need to tear down and replace your main window, delete it and make a new one. Windows only get the parent flag when they have children, not because you tell them to.