I'm new to #in32 and making simple chatting app.
Now I implement edit control to write message, submit by Enter key but not Ctrl + Enter. (I want Ctrl + Enter to make new line.)
I made them using sub procedure.
The problem is that when I submit message by Enter the edit control makes a second line, and cursor point that.
I want make edit control clearly when press Enter.
Here's my code
LRESULT CALLBACK SubEditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
HDC hdc;
PAINTSTRUCT ps;
RECT rt = { 20,20,200,500 };
switch (uMsg)
{
case WM_KEYDOWN:
switch (wParam) {
case VK_RETURN:
if (!GetAsyncKeyState(VK_CONTROL)) {
hdc = GetDC(GetParent(hEdit));
TCHAR buff[1024];
GetWindowText(hEdit, buff, 1024);
SetDlgItemText(GetParent(hEdit), ID_EDIT, (LPCWSTR)"");
DrawText(hdc, buff, -1, &rt, DT_LEFT);
ReleaseDC(GetParent(hEdit), hdc);
}
break;
}
break;
default:
return CallWindowProc(DefEditProc, hWnd, uMsg, wParam, lParam);
}
return FALSE;
}
Related
Is there a way to automatically/by default set the mouse cursor to point inside a newly created window (using for e.g. the CreateWindow function)? I know that for keyboard input there is a SetFocus() function, but haven't found a similar function for a mouse.
As #IInspectable said, the following is the code implementation.
LRESULT CALLBACK WndProcNOP(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
RECT rcClient;
GetWindowRect(hwnd, &rcClient);
int x = rcClient.left + (rcClient.right - rcClient.left) / 2;
int y = rcClient.top + (rcClient.bottom - rcClient.top) / 2;
SetCursorPos(x, y);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
return 0;
}
I try to change standart WndProc function. I have this code:
HWND btn = CreateWindowEx(WS_EX_TRANSPARENT | WS_EX_CLIENTEDGE, L"BUTTON", L"Window title", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON
, 50, 50, 50, 50, (HWND)XApplicationMainWindow->window->_wnd, (HMENU)123,
(HINSTANCE)GetWindowLongPtr(XApplicationMainWindow->window->_wnd, GWLP_HINSTANCE), NULL);
SetWindowLongPtrW(btn, GWLP_WNDPROC, (LONG_PTR)SubclassWindowProc);
I can use L"BUTTON" class name, but when I change WndProc function I'll have a problem.
On this picture, you can see the blank square and normal button. If I try to create new WNDCLASS or WNDCLASSEX, I'll have nothing... Why?
How can I change the standart WndProc function, if I use L"BUTTON" class name?
It's my second WndProc:
LRESULT CALLBACK SubclassWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CREATE:
break;
case WM_COMMAND:
//Event click
switch (LOWORD(wParam))
{
case 123:
OutputDebugStringA("Subclass click2");
break;
default:
break;
}
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
DefWindowProc() is the wrong window procedure for your SubclassWindowProc() to be calling.
You need to call the previous window procedure that you are replacing - the window procedure that handles all of the button's default behaviors (like drawing the button so it actually looks like a button, and responding to user input like a button, etc). SetWindowLongPtr() returns a pointer to that procedure to you, but you are currently ignoring it.
See Subclassing Controls on MSDN for more details.
Try this instead:
WNDPROC btnWndProc;
LRESULT CALLBACK SubclassWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_COMMAND:
//Event click
switch (LOWORD(wParam))
{
case 123:
OutputDebugStringA("Subclass click2");
break;
}
break;
}
return CallWindowProc(hWnd, btnWndProc, uMsg, wParam, lParam);
}
...
HWND btn = CreateWindowEx(...);
btnWndProc = (WNDPROC) SetWindowLongPtrW(btn, GWLP_WNDPROC, (LONG_PTR)SubclassWindowProc);
Alternatively, using SetWindowSubclass(), which is safer than using SetWindowsLongPtr(), eg:
LRESULT CALLBACK SubclassWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
switch (uMsg) {
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, SubclassWindowProc, uIdSubclass);
break;
case WM_COMMAND:
//Event click
switch (LOWORD(wParam))
{
case 123:
OutputDebugStringA("Subclass click2");
break;
}
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
...
HWND btn = CreateWindowEx(...);
SetWindowSubclass(btn, SubclassWindowProc, 1, 0);
Now, that being said, your subclass will never call OutputDebugStringA(), because it will never receive the WM_COMMAND message you are expecting. When a button is clicked, a WM_COMMAND message is not sent to the button itself. The button posts a WM_COMMAND message to the button's parent window instead (in this case, to XApplicationMainWindow->window->_wnd). So, you need to handle the WM_COMMAND message in the window procedure of the parent window, not in the window procedure of the button itself.
Otherwise, if you still want to subclass the button itself, you will have to handle the WM_LBUTTON(DOWN|UP) and WM_KEY(DOWN|UP)/WM_CHAR messages that the button receives and then subsequently translates into a WM_COMMAND message for its parent window.
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ HDC hdc;
int count=1; int xs,ys,xe,ye;
switch (message)
{
case WM_LBUTTONDOWN
hdc=GetDC(hwnd);
if(count%2!=1){
xs=GET_X_LPARAM(lParam);
ys=GET_Y_LPARAM(lParam);}
else{
xe=GET_X_LPARAM(lParam);
ye=GET_Y_LPARAM(lParam);
drawline(hdc,xs,ys,xe,ye);
}
ReleaseDC(hwnd,hdc);
count++;
break;
case WM_DESTROY:
PostQuitMessage (0);
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
I've tried , but there's something wrong with this code.
Use
if(count%2 == 1)
insted of
if(count%2 != 1)
Might work then.
I am writting dll with global hooks. One of the task is viewing clipboard and deleting all data from it when someone perform copy operation. Here is my callback function for window:
string test("my data");
LRESULT CALLBACK WndHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_CREATE:
nextClipboardViewer = SetClipboardViewer(windowHandler);
MessageBeep(MB_ICONINFORMATION);
break;
case WM_CHANGECBCHAIN:
if((HWND) wParam == nextClipboardViewer)
nextClipboardViewer == (HWND) lParam;
else if(nextClipboardViewer != NULL)
SendMessage(nextClipboardViewer, msg, wParam, lParam);
break;
case WM_DRAWCLIPBOARD:
if(OpenClipboard(windowHandler)) {
EmptyClipboard();
HGLOBAL hClipboardData;
hClipboardData = GlobalAlloc(GMEM_MOVEABLE, test.size() + 1);
char * pchData;
pchData = (char*)GlobalLock(hClipboardData);
memcpy(pchData, test.c_str(), test.size() + 1);
GlobalUnlock(hClipboardData);
SetClipboardData(CF_TEXT, hClipboardData);
CloseClipboard();
}
SendMessage(nextClipboardViewer, msg, wParam, lParam);
break;
case WM_DESTROY:
ChangeClipboardChain(windowHandler, nextClipboardViewer);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
return 0;
}
I am just trying replace information in clipboard, but this code doesn't work.
Updated: Now i am using invisible window and SetClipboardViewer for monitoring changes. But data in clipboard doesn't change.
I doubt it's really safe to change the contents of the clipboard while processing a WM_DRAWCLIPBOARD message - at the very least I'm surprised you don't trigger an infinite loop (since your calls to EmptyClipboard() and SetClipboardData() could be triggering another WM_DRAWCLIPBOARD message). Possibly the system has protection against that - I've never tried to find out - but it still feels wrong :)
Try this version, which:
Moves the clipboard update to a separate message that the window posts to itself (moving it outside of the clipboard change the notification code)
Uses a global flag to ignore changes it makes itself.
Note: I think the actual bug with your code was that when you're processing WM_CREATE, windowHandler is not yet assigned. You are presumably setting that to the value CreateWindowEx returns, but when WM_CREATE is being processed CreateWindowEx hasn't actually returned yet. This means the clipboard viewer is never actually established correctly. I've changed the references to use hwnd to fix this.
string test("my data");
#define MSG_UPDATECLIPBOARD (WM_APP + 1)
static bool g_fIgnoreClipboardChange = false;
LRESULT CALLBACK WndHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_CREATE:
nextClipboardViewer = SetClipboardViewer(hwnd);
MessageBeep(MB_ICONINFORMATION);
break;
case WM_CHANGECBCHAIN:
if((HWND) wParam == nextClipboardViewer)
nextClipboardViewer = (HWND) lParam;
else if(nextClipboardViewer != NULL)
SendMessage(nextClipboardViewer, msg, wParam, lParam);
break;
case WM_DRAWCLIPBOARD:
if (!g_fIgnoreClipboardChange)
PostMessage(hwnd, MSG_UPDATECLIPBOARD, 0, 0);
if(nextClipboardViewer != NULL)
SendMessage(nextClipboardViewer, msg, wParam, lParam);
break;
case MSG_UPDATECLIPBOARD:
g_fIgnoreClipboardChange = true;
if(OpenClipboard(hwnd)) {
HGLOBAL hClipboardData;
hClipboardData = GlobalAlloc(GMEM_MOVEABLE, test.size() + 1);
char * pchData;
pchData = (char*)GlobalLock(hClipboardData);
memcpy(pchData, test.c_str(), test.size() + 1);
GlobalUnlock(hClipboardData);
SetClipboardData(CF_TEXT, hClipboardData);
CloseClipboard();
}
g_fIgnoreClipboardChange = false;
break;
case WM_DESTROY:
ChangeClipboardChain(hwnd, nextClipboardViewer);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
return 0;
}
I am trying to Subclass the Listbox and the Edit Control of a Combobox for some customasing reasons. Below is the code work . Subclassing for Edit Control is working perfect but Listbox is not getting the messeage of MouseDown.
void Subclass(HWND hComboBox)
{
HWND hEdit=FindWindowEx(hComboBox, NULL, WC_EDIT, NULL);
HWND hCombo=FindWindowEx(hComboBox, NULL, WC_LISTBOX, NULL);
SetProp(hEdit, TEXT("Wprc"), (HANDLE)GetWindowLongPtr(hEdit, GWL_WNDPROC));
SubclassWindow(hEdit, ComboBox_Proc);
SetProp(hCombo, TEXT("Wprc1"), (HANDLE)GetWindowLongPtr(hCombo, GWL_WNDPROC));
SubclassWindow(hCombo, ComboBox_Proc1);
}
static LRESULT CALLBACK ComboBox_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CHAR:
break;
case WM_KEYDOWN:
break;
case WM_DESTROY:
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (DWORD)GetProp(hwnd, TEXT("Wprc")));
RemoveProp(hwnd, TEXT("Wprc"));
break;
default:
return CallWindowProc((WNDPROC)GetProp(hwnd, TEXT("Wprc")), hwnd, msg, wParam, lParam);
}
return FALSE;
}
static LRESULT CALLBACK ComboBox_Proc1(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
//PROBLEM IS HERE
break;
case WM_DESTROY:
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (DWORD)GetProp(hwnd, TEXT("Wprc1")));
RemoveProp(hwnd, TEXT("Wprc1"));
break;
default:
return CallWindowProc((WNDPROC)GetProp(hwnd, TEXT("Wprc1")), hwnd, msg, wParam, lParam);
}
return FALSE;
}
The ListBox part of a ComboBox is of type COMBOLBOX (with L).
The ComboLBox window is not a child of the ComboBox window.
The only way I found to subclass the COMBOLBOX control is as follows.
Windows sends the WM_CTLCOLORLISTBOX message to the COMBOBOX (no L) before the listbox is drawn. The lParam of this message contains the handle of the listbox.
case WM_CTLCOLORLISTBOX:
{
if ( !hSubclassedListBox )
{
hSubclassedListBox = (HWND)lParam;
SubclassWindow(hSubclassedListBox , MyLBProc);
}
}
Alsoo see this link for more information
For those who are using Visual Studio with WINVER set to 0500 or higher (Windows XP or later), you can use the GetComboBoxInfo function (passing the handle to the ComboBox), which will return (in a COMBOBOXINFO structure) the handles to both the Edit box and the ComboLBox (ListBox). The handles can then be used to get the CWnd-derived objects they represent.