I'm new to win32 programming and haven't worked around with cpp for a long time. What I intend to do is to get a window's HWND via spy++, and get the text of this window. The problem is that I don't know how to create a HWND object, could anyone give me some idea? Thanks a lot!
If you have the numeric value of the HWND, you can cast it to the right type. Start with an integer of the right size, e.g.:
uintptr_t numeric_hwnd = 0x987654;
HWND hwnd = reinterpret_cast<HWND>(numeric_hwnd);
Can anyone help me how I update a HWND value through an edit control or any other kind of text box? I tried the following
void ChwndtestDlg::OnBnClickedButton1()
{
TCHAR thebuffer[100];
HWND thetext = (HWND)thebuffer;
GetDlgItemText(IDC_EDITWINDOW, thebuffer, 100);
::SendMessage(thetext,WM_SETTEXT,0,(LPARAM)L"hello");
}
But, that does not work! I'm new to all of this, and I'll be grateful for any help. Please bear in mind that I already know about enumwindows, and I have already successfully changed text in another program from my program, but I want to actually update the HWND in my edit control. It is supposed to work like so...
program 2's current hwnd = 0x00000:
open my program -> open program #2 -> input 0x00000 into textbox in my program -> click button in my program to update the hwnd value -> input text in my programs text editor -> text goes to program 2's text editor. I'm aware that there are other ways of doing this, but I would really like to do it the way I have described. Thanks in advance. I found a similar question, but the answer was to use enumwindows, but I don't want to use that.
You are typecasting the TCHAR[] itself to an HWND. That will never work. You need to extract the TCHAR[] text from the edit control, then use _stscanf() or similar parsing function to convert that text value to an integer which can be typecasted to an HWND, then assign your other text to that HWND as needed.
For example:
void ChwndtestDlg::OnBnClickedButton1()
{
CString sWnd;
if (GetDlgItemText(IDC_HWNDEDIT, sWnd) > 0)
{
HWND hWnd;
if (_stscanf((LPTSTR)sWnd, _T("%p"), &hWnd) == 1)
{
CString sText;
GetDlgItemText(IDC_TEXTEDIT, sText);
::SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)(LPTSTR)sText);
}
}
}
There is a similar question here but I'm looking for a C++ version.
I want to create a .rs file with a DialogBox that uses a string as a variable instead a " " so I can change it in the program.
For example: In
DEFPUSHBUTTON "Hello World", IDOK, 8, 24, 75, 14
the "Hello World" would become a variable name, which I can 'define' or set in the program.
Why? I'm trying to make a DialogBox, like a 'template', and make many instances around the program with different Text in but same buttons in them.
Hope my gibberish is understanded.
Unfortunately, this is not possible. The caption text for a control must be a constant string because the resource file is actually compiled separately from your application and has no knowledge of variables defined elsewhere in your program's code.
Resource files do support string tables, but even these require the strings to be constant values. The advantage is that you can modify the resource file without access to the rest of the source code, which makes things like localization possible, even by outside translators.
So you're stuck hard-coding the initial caption of your DEFPUSHBUTTON. It can be an empty string or whatever value you want; you just need a placeholder. And you can put all of the possible captions in a string table (which I would recommend), but you cannot link the two using any automated mechanism.
You need to write the code to do this yourself. You could certainly dynamically generate resources, but that's quite a bit of trouble. I think the simplest way of doing this is just to create the dialog (using your "template" resource file), retrieve the handle of the controls whose caption text you want to change, and send them a WM_SETTEXT message with the new string. In fact, the SetDlgItemText function will do exactly this for you.
Perhaps that would be easier to explain with some code. Assume that you have a dialog resource defined, including all of your controls. All of the controls you wish to modify will need to have a unique ID assigned to each of them so that you can distinguish between them at runtime. It doesn't matter what the initial values you assign in the resource file are, as you're going to be changing them right off the bat. It might look like this:
IDD_TEMPLATE DIALOG DISCARDABLE 0, 0, xx, xx
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
CAPTION "Dialog Template"
FONT 8, "MS Sans Serif"
BEGIN
CTEXT "Placeholder text", IDC_MESSAGE, xx, xx, xx, xx
DEFPUSHBUTTON "Placeholder", IDOK, xx, xx, xx, xx
PUSHBUTTON "Cancel", IDCANCEL, xx, xx, xx, xx
END
Then, in your dialog procedure (DialogProc), handle the WM_INITDIALOG message as follows:
INT_PTR CALLBACK TemplateDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
// Load the caption strings you want to use from the string table
// in the resource file, or get them from wherever you want.
// These are the "variables" you wanted to use in the question.
TCHAR* pszMessage;
LoadString(hInstance, /* instance handle for app or resource DLL */
IDS_MESSAGE, /* ID of the string resource to load */
reinterpret_cast<LPTSTR>(&pszMessage),
0);
TCHAR* pszOkBtn;
LoadString(hInstance, IDS_OKBUTTON, reinterpret_cast<LPTSTR>(&pszOkBtn), 0);
// ...etc.
// Set the caption text for each control.
SetDlgItemText(hwndDlg, /* handle to the dialog box window */
IDC_MESSAGE, /* ID of the control to modify */
pszMessage); /* variable containing text to set */
SetDlgItemText(hwndDlg, IDOK, pszOkBtn);
// ...etc.
// And, if you want to set some other properties, you can do that too.
// For example, you might set the caption of the dialog itself.
TCHAR* pszTitle;
LoadString(hInstance, IDS_DLGCAPTION, reinterpret_cast<LPTSTR>(&pszTitle), 0);
SetWindowText(hwndDlg, pszTitle);
// ...etc.
return TRUE; // set the default focus
}
// ...process other messages as necessary
}
return FALSE; // we did not process the message
}
While I think Cody Gray's answer is better, there is always the option of creating your dialog template in-memory, and modifying it as you create new instances of the dialog. I wouldn't recommend it unless you find this kind of thing fun (I'm one of those people). I certainly wouldn't recommend it for what you're asking, but it is technically an option...
DialogBoxIndirect takes a pointer to a structure that is made up of a header (DLGTEMPLATE) that describes the dialog box itself, followed by the specified number of controls (DLGITEMTEMPLATE).
Effectively you can use the above to build a new in-memory dialog template each time you want a DialogBox with different text on the button. However, that's a little extreme if all you really want to do is change some text, which as Cody says, you can do with SetDlgItemText.
If you're really curious, here's an example.
I am writing a small test program, and for that i require the handle of an edit control. I have copied the value of the handle from Spy ++ (lets say 000A0B40).
So i did the following
#define editControlHandle 0x000A0B40
int *intHandle;
intHandle=(int*)editControlHandle;
HWND handle=(HWND)intHandle;
int textlength=GetWindowTextLength(handle);
I also did a getlasterror and it gave me error_success.
GetWindowTextLength cannot retrieve the length of the text of an edit control in another application.
Documentation
When we have a RichEdit control and send it an EM_AUTOURLDETECT message with WPARAM set to TRUE, it nicely hightlights the detected URLs and sends the EN_LINK notifications.
But it does this only for text that is entered into the control. I haven't found the way to do it for text that's loaded into the control with SetWindowText or EM_STREAMIN.
Please help! Thanks
Upd:
I've created a test application from scratch and it works fine there. I think the problem might be that I have superclassed the control, that is, created a new window class and just use the window procedure of the original class. I'm gonna try subclassing the control instead..
I just knocked up a basic WTL dialog based app containing a riched20 control and the following works fine:
CRichEditCtrl richedit = GetDlgItem(IDC_RICHEDIT);
richedit.SetAutoURLDetect(TRUE);
richedit.SetWindowText(_T("http://www.stackoverflow.com"));
I have some old MFC code that does something similar, albeit with ES_STREAM, and it works OK too.
FWIW the WTL CRichEditCtrl wrapper is pretty thin. SetAutoURLDetect simply calls SendMessage passing it EM_AUTOURLDETECT.
I am compiling with _RICHEDIT_VER set to 0x0200 FWIW.
Without knowing the format of the text you are trying to add to the control with SetWindowText and EM_STREAMIN I'm going to take a guess and say this might have something to do with the control's text mode. After setting the contents of the control try sending it a EM_GETTEXTMODE message and see if the TM_PLAINTEXT bit is set. If this is the case then try sending a EM_SETTEXTMODE message followed by EM_AUTOURLDETECT. Your code should look something like this:
UINT textmode = (UINT)::SendMessage(handle_to_control, EM_GETTEXTMODE, 0, 0);
if(textmode & TM_PLAINTEXT) {
textmode &= ~TM_PLAINTEXT; // Clear the TM_PLAINTEXT bit
textmode |= TM_RICHTEXT; // Set the TM_RICHTEXT bit
if(::SendMessage(handle_to_control, EM_SETTEXTMODE, textmode, 0) != 0) {
// Failed to set the text mode
}
}
::SendMessage(handle_to_control, EM_AUTOURLDETECT, TRUE, 0);
You might just have to rewrite the text to the control to get it to re-parse.