Using WINAPI how do I change the value of a checkbox button? - c++

Currently I have a checkbox created in WM_CREATE:
hwndButtonPollFlag =
CreateWindow(
TEXT("BUTTON"),
TEXT(sA.getMonitor(monitorSelected)->szDevice),
WS_CHILD | WS_VISIBLE | SS_WHITERECT | BS_CHECKBOX,
0,
0,
0,
0,
hwnd,
(HMENU)IDB_PollFlag,
hInstance,
NULL);
I am trying to change it's value whenever another button is clicked with:
if (sA.getScreenArray(monitorSelected)->getPollFlag())
{
SetWindowLongPtr(hwndButtonPollFlag, GCL_STYLE, WS_VISIBLE | BST_CHECKED);
}
else
{
SetWindowLongPtr(hwndButtonPollFlag, GCL_STYLE, WS_VISIBLE | BST_UNCHECKED);
}
SetWindowText(hwndButtonPollFlag, TEXT(sA.getMonitor(monitorSelected)->szDevice));
This does change the text displayed next to the checkbox but not the actual state of the button. Also I would like the checkbox to have only two states (checked or unchecked) is there any other way to create that effect other than in the button return have something along the lines of:
switch (HIWORD(wParam))
{
case BST_CHECKED:
sA.getScreenArray(monitorSelected)->setPollFlag(true);
return 0;
case BST_INDETERMINATE:
if (sA.getScreenArray(monitorSelected)->getPollFlag())
{
SetWindowLongPtr(hwndButtonPollFlag, GCL_STYLE, WS_VISIBLE | BST_UNCHECKED);
}
else
{
SetWindowLongPtr(hwndButtonPollFlag, GCL_STYLE, WS_VISIBLE | BST_CHECKED);
}
return 0;
case BST_UNCHECKED:
sA.getScreenArray(monitorSelected)->setPollFlag(false);
return 0;
}
EDIT: As Mark Ransom said I used messages with the BM_GETCHECK and BM_SETCHECK flag as so:
case IDB_MONITOR:
monitorSelected = LOWORD(lParam);
if (sA.getScreenArray(monitorSelected)->getPollFlag())
{
SendMessage(hwndButtonPollFlag, BM_SETCHECK, BST_CHECKED, NULL);
}
else
{
SendMessage(hwndButtonPollFlag, BM_SETCHECK, BST_UNCHECKED, NULL);
}
SetWindowText(hwndButtonPollFlag, TEXT(sA.getMonitor(monitorSelected)->szDevice));
return 0;
case WM_COMMAND:
//sA.getScreenArray(monitorSelected)->setPollFlag(LOWORD(lParam));
switch (LOWORD(wParam))
{
case IDB_PollFlag:
if (SendMessage(GetDlgItem(hwnd, IDB_PollFlag), BM_GETCHECK, 0, 0) == BST_CHECKED)
{
SendMessage(hwndButtonPollFlag, BM_SETCHECK, BST_CHECKED, NULL);
sA.getScreenArray(monitorSelected)->setPollFlag(true);
}
else {
SendMessage(hwndButtonPollFlag, BM_SETCHECK, BST_UNCHECKED, NULL);
sA.getScreenArray(monitorSelected)->setPollFlag(false);
}
break;
}
return 0;

You need to send the BM_SETCHECK message.
SendMessage(hwndButtonPollFlag, BM_SETCHECK, BST_CHECKED, 0);

BST_CHECKED and BST_UNCHECKED aren't window styles, they're simply flag values used by the CheckDlgButton and IsDlgButtonChecked API functions. CheckDlgButton is the function to call to change its state.
(Or, you can send BM_SETCHECK and BM_GETCHECK messages directly to the button for the same effect).

Related

Handling the hotkey for menu item

I have created a new menu item "Extra" and add it to the window's main menu.
HMENU menu = GetMenu(hWnd);
HMENU popup = CreatePopupMenu();
AppendMenu(menu, MF_STRING | MF_POPUP, (UINT)popup, L"Extra");
SetMenu(hWnd, popup);
Next I inserted new item to "Extra" item with hotkey:
#define IDM_ITEM1 12310
and:
MENUITEMINFOW mmi;
mmi.cbSize = sizeof(MENUITEMINFOW);
mmi.fMask = MIIM_STRING | MIIM_ID;
mmi.fType = MFT_STRING;
mmi.dwTypeData = L"First item\tCtrl+N";
mmi.wID = IDM_ITEM1;
InsertMenuItemW(popup, 1, true, &mmi);
And handle "First item" click:
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDM_ITEM1:
{
MessageBox(0, L"First", L"", MB_OK);
break;
}
}
break;
}
And now when I click on "First item" a message box is appeared.
But when I press Ctrl+N hotkey - nothing happens. Why? How to fix this (without using accelerator resources)?
without using accelerator resources ?
You need to create an array of ACCEL and then call the CreateAcceleratorTable function:
ACCEL s_accel[2] = {{FCONTROL | FVIRTKEY, TEXT('C'), IDM_COLOR},
{FCONTROL | FVIRTKEY, TEXT('Q'), IDM_QUIT}};
HACCEL h_accel = CreateAcceleratorTable(s_accel, 2);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(hwnd, h_accel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
DestroyAcceleratorTable(h_accel);

Block ESC and Enter keys in modeless dialog box (Win32, non-MFC)

There're some articles written on this subject, but none of them worked in my case. I'm writing the following using Win32 (no MFC). The goal is to prevent ESC or ENTER keys from closing the modeless dialog box.
Here's the dialog template:
IDD_DIALOG_1 DIALOGEX 0, 0, 345, 179
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION ""
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "New Pt",IDC_CHECK_NEW_PT,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,7,3,39,12
CONTROL "Lines",IDC_CHECK_LINES,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,54,3,39,12
CONTROL "Curves",IDC_CHECK_CURVES,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,94,3,39,12
CONTROL "Ellipses",IDC_CHECK_ELLIPSE,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,134,3,39,12
CONTROL "Circles",IDC_CHECK_CIRCLE,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,174,3,39,12
LTEXT "Pen Size:",IDC_STATIC,242,7,30,8
EDITTEXT IDC_EDIT_PEN_SIZE,275,3,40,14,ES_CENTER | ES_AUTOHSCROLL | ES_NUMBER
CONTROL "",IDC_SPIN_PEN_SIZE,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,316,3,11,14
EDITTEXT IDC_EDIT_SRC,7,19,331,106,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL
END
To trap those two keys, I change the message loop to this:
MSG msg;
// Main message loop:
for(int nR;;)
{
nR = ::GetMessage(&msg, nullptr, 0, 0);
if(!nR)
{
break;
}
else if(nR == -1)
{
//Error
ASSERT(NULL);
break;
}
if(ghActiveModelessDlg)
{
BOOL bProcessAsDlgMsg = TRUE;
if(msg.message == WM_KEYDOWN ||
msg.message == WM_KEYUP)
{
//Try to trap ESC & Enter keys
if(msg.wParam == VK_ESCAPE)
{
//Do not process
bProcessAsDlgMsg = FALSE;
}
else if(msg.wParam == VK_RETURN)
goto lbl_check_enter;
}
else if(msg.message == WM_CHAR)
{
//Try to trap ESC & Enter key
if(msg.wParam == 27)
{
//ESC - Do not process
bProcessAsDlgMsg = FALSE;
}
else if(msg.wParam == '\r')
{
lbl_check_enter:
//See what window is it
WCHAR buffClass[256];
if(::GetClassName(msg.hwnd, buffClass, _countof(buffClass)) &&
lstrcmpi(buffClass, L"edit") == 0 &&
(::GetWindowLongPtr(msg.hwnd, GWL_STYLE) & ES_WANTRETURN))
{
//This is edit ctrl that can handle its own Enter keystroke
}
else
{
//Do not process
bProcessAsDlgMsg = FALSE;
}
}
}
if(bProcessAsDlgMsg)
{
if(::IsDialogMessage(ghActiveModelessDlg, &msg))
{
continue;
}
}
}
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
And ghActiveModelessDlg is set from within DlgProc for the modeless dialog as such:
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(hDlg)
{
//...
case WM_ACTIVATE:
{
//Needed to ensure that keyboard shortcuts are properly processed in the message loop
ghActiveModelessDlg = wParam != WA_INACTIVE ? hDlg : NULL;
}
break;
}
return 0;
}
This works ... in most cases. Except this one.
Here's the sequence. Put the focus into the multi-line edit box, then hit any letter/number key and then ESC:
It will then close the dialog.
Any idea how can it pass my override code above?
PS. Interesting observations.
1) If I just hit ESC first, my code traps it. It's only when I hit some other key and then ESC it fails.
2) If I comment out the line that calls IsDialogMessage (and a subsequent continue) it stops accepting ESC. So my guess is that it's not the edit control that does this.
if we want let close dialog only by clicking close X button in system menu (or by ALT+F4) and disable close by ESC and ENTER key - all what we need - call DestroyWindow when process (WM_SYSCOMMAND, SC_CLOSE) and do nothing on (WM_COMMAND, IDCANCEL, IDOK). we not need special message loop or subcluss any controls. and not have buttons with IDOK/ IDCANCEL id in dialog
INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SYSCOMMAND:
if ((wParam & 0xfff0) == SC_CLOSE) DestroyWindow(hwndDlg);
break;
case WM_COMMAND:
switch (wParam)
{
case MAKEWPARAM(IDOK, BN_CLICKED):
case MAKEWPARAM(IDCANCEL, BN_CLICKED):
// ignore this
break;
....
}
}
....
}
IsDialogMessage translates ESC key into WM_COMMAND IDCANCEL and ENTER into WM_COMMAND IDOK. To suppress default handling (closing dialog), process them in your dialog procedure:
switch (message)
{
case WM_CLOSE:
// Handle WM_CLOSE here so it wouldn't generate WM_COMMAND IDCANCEL
// that would be ignored in WM_COMMAND handler.
DestroyWindow(hDlg);
return TRUE;
case WM_COMMAND:
if ( LOWORD(wParam) == IDCANCEL || LOWORD(wParam) == IDOK )
// Prevent default handling by original dialog procedure.
return TRUE;
break;
// other cases...
}
RbMm has a good solution. So I'll mark it as the answer.
While waiting for a reply I was able to adjust my original message loop and came up with my own solution. So here it is.
Blocking the Enter key is easy. All I needed to do was to define a default button (either in the dialog editor in VS, or by sending the DM_SETDEFID message) and it will handle all the Enter keystrokes.
The gist for blocking ESC keystrokes was not to pass any keyboard messages bearing the ESC keystroke to any common controls (or children of the dialog window.) As #IInspectable quoted in the comments, some of those common controls are quite old and are not implemented up to spec. Moreover, Microsoft usually doesn't fix old UI bugs and simply calls them features.
So I accomplished the fix by the following modification that will re-route (or reflect) all such messages to my DlgProc, which also has the benefit over RbMm's code in that it also allows me to come up with my own processing for the ESC keystrokes.
Also eliminated goto for goto-purists:
MSG msg;
// Main message loop:
for(int nR; nR = ::GetMessage(&msg, nullptr, 0, 0);)
{
if(nR == -1)
{
//Error
ASSERT(NULL);
break;
}
//Need special processing for modeless dialogs
if(ghActiveModelessDlg)
{
//Try to catch ESC keystrokes
if(
((msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) && msg.wParam == VK_ESCAPE) ||
(msg.message == WM_CHAR && msg.wParam == 27)
)
{
//Was this message sent to the dialog window?
if(ghActiveModelessDlg != msg.hwnd)
{
//If no, then reflect it to our dialog window
::PostMessage(ghActiveModelessDlg, msg.message, msg.wParam, msg.lParam);
continue;
}
}
else
{
//Dialog's special message-processing
if(::IsDialogMessage(ghActiveModelessDlg, &msg))
{
continue;
}
}
}
//Regular processing
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

Create derived control at runtime cause assertion

I am trying to create a control at run-time, but it causes assertion, and I don't know what's causing it. The control I am using is the Tree ComboBox Control from this link: https://www.codeproject.com/Articles/187762/Tree-ComboBox-Control
I added the code to register the class as follow:
CTreeComboBox::CTreeComboBox()
...
{
...
RegisterWindowClass();
}
CTreeComboBox::~CTreeComboBox()
{
m_BrushAlert.DeleteObject();
}
BOOL CTreeComboBox::RegisterWindowClass()
{
WNDCLASS wndcls;
HINSTANCE hInst = AfxGetInstanceHandle();
if (!(::GetClassInfo(hInst, _T("TreeComboBox"), &wndcls)))
{
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
wndcls.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = _T("TreeComboBox");
if (!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return FALSE;
}
}
return TRUE;
}
I tried to create the control at run-time using the following code in the test program:
BOOL CTestComboBoxDlg::OnInitDialog()
{
...
m_ComboBox2.CreateEx(WS_EX_CLIENTEDGE, _T("TreeComboBox"), _T(""), WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP,
CRect(0, 0, 100, 50), this, 100000, NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
I also tried creating the control using a button click event thinking that I should let the GUI finish initializing, but the same error occur:
void CTestComboBoxDlg::OnBnClickedButton1()
{
m_ComboBox2.CreateEx(WS_EX_CLIENTEDGE, _T("TreeComboBox"), _T(""), WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP,
CRect(0, 0, 100, 50), this, 100000, NULL);
}
When I run the program, it stopped at the file dbgrptt.cpp at the following line:
__try
{
if (_CRT_ASSERT == nRptType && _InterlockedIncrement(&_crtAssertBusy) > 0)
{
/* use only 'safe' functions -- must not assert in here! */
_ERRCHECK(_itoa_s(nLine, szLineMessage, DBGRPT_MAX_MSG, 10));
OutputDebugStringA("Second Chance Assertion Failed: File ");
OutputDebugStringA(szFile ? szFile : "<file unknown>");
OutputDebugStringA(", Line ");
OutputDebugStringA(szLineMessage);
OutputDebugStringA("\n");
It stop here===> _CrtDbgBreak();
retval=-1;
__leave;
}
The program run fine if I create the control manually using the Visual Studio GUI editor, so I am not sure what's wrong. Can you help me figure out how to create this control at run-time?
Note: change the statement: TRACE1(_T("Item selected: %s\n"), GetItemText(hItem)); to TRACE(_T("Item selected: %s\n"), GetItemText(hItem)); in the file ComboTreeCtrlExt.cpp if you if you want to run the code and are using MFC
To answer my own question. Move the following code from the CTreeComboBox::PreSubclassWindow() to the CTreeComboBox::OnCreate()
CRect rect(0, 0, 0, 0);
DWORD dwStyle = WS_POPUP | WS_BORDER;
CWnd* pWnd = &m_Tree;
pWnd->CreateEx(0, WC_TREEVIEW, NULL, dwStyle, rect, GetParent(), 0, NULL);
m_Tree.Init(this);
GetClientRect(rect);
SetDroppedWidth(rect.Width());
SetDroppedHeight(m_nDroppedHeight);
dwStyle = CBS_DROPDOWNLIST & GetStyle();
ASSERT(CBS_DROPDOWNLIST == dwStyle);

moving window and resize bottom flickers

I am trying to make a kind of popup notification window that slides out of the task bar.
At the moment I am only trying to get it to work if the taskbar is on bottom of screen, I have it working like it should.
But the problem im having is when the window is starting to appear/slide the bottom part of it flickers (depending on how big i have set my m_nIncrement value, it flashes the bottom area the same size as the m_nIncrement value)
The window disappears fine with no flicker.
//MyWindow
WNDCLASS wc =
{
CS_HREDRAW | CS_VREDRAW, __sWndProcDlg, 0, 0, g_hInst, nullptr,
LoadCursor(nullptr, IDC_ARROW), (HBRUSH)::GetStockObject(BLACK_BRUSH),
nullptr, m_lpszClassName
};
if (!RegisterClass(&wc))
return;
m_hWnd = CreateWindowEx(WS_EX_NOACTIVATE, m_lpszClassName, NULL, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, m_hWndParent, NULL, g_hInst, NULL);
//ShowWindow
void _ShowWindow(int _show)
{
unsigned int nDesktopWidth = m_rcDesktop.right - m_rcDesktop.left;
unsigned int nDesktopHeight = m_rcDesktop.bottom - m_rcDesktop.top;
unsigned int nScreenWidth = ::GetSystemMetrics(SM_CXSCREEN);
unsigned int nScreenHeight = ::GetSystemMetrics(SM_CYSCREEN);
BOOL bTaskbarOnRight = nDesktopWidth<nScreenWidth && m_rcDesktop.left == 0;
BOOL bTaskbarOnLeft = nDesktopWidth<nScreenWidth && m_rcDesktop.left != 0;
BOOL bTaskBarOnTop = nDesktopHeight<nScreenHeight && m_rcDesktop.top != 0;
BOOL bTaskbarOnBottom = nDesktopHeight<nScreenHeight && m_rcDesktop.top == 0;
if (_show)
{
ShowWindow(m_hWnd, SW_SHOW);
if (bTaskbarOnBottom)
{
m_nCurrentPos.cx = m_rcDesktop.right - m_sMaxSize.cx;
m_nCurrentPos.cy = m_rcDesktop.bottom - m_nCurrentSize.cy;
m_nTaskbarPlacement = TASKBAR_ON_BOTTOM;
}
KillTimer(m_hWnd, IDT_DISAPPEARING);
SetTimer(m_hWnd, IDT_APPEARING, 1, nullptr);
}
else
{
KillTimer(m_hWnd, IDT_APPEARING);
if (bTaskbarOnRight)
m_nCurrentPos.cx = m_rcDesktop.right - m_sMaxSize.cx;
else if (bTaskbarOnLeft)
m_nCurrentPos.cx = m_rcDesktop.left;
else if (bTaskBarOnTop)
m_nCurrentPos.cy = m_rcDesktop.top;
else //if (bTaskbarOnBottom)
m_nCurrentPos.cy = m_rcDesktop.bottom - m_nCurrentSize.cy;
SetTimer(m_hWnd, IDT_DISAPPEARING, 1, NULL);
}
}
//__OnTimer
LRESULT __OnTimer(HWND hWnd, UINT nIDEvent)
{
int m_nIncrement = 20;
if (nIDEvent == IDT_APPEARING)
{
switch (m_nTaskbarPlacement)
{
case TASKBAR_ON_BOTTOM:
if (m_nCurrentPos.cy > (m_rcDesktop.bottom - m_sMaxSize.cy))
{
m_nCurrentPos.cy -= m_nIncrement;
m_nCurrentSize.cy = m_rcDesktop.bottom - m_nCurrentPos.cy;
}
else
KillTimer(hWnd, IDT_APPEARING);
break;
}
SetFocus(hWnd);
SetWindowPos(hWnd, HWND_TOPMOST, m_nCurrentPos.cx, m_nCurrentPos.cy, m_sMaxSize.cx, m_nCurrentSize.cy, SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOACTIVATE);
}
else if (nIDEvent == IDT_DISAPPEARING)
{
switch (m_nTaskbarPlacement)
{
case TASKBAR_ON_BOTTOM:
if (m_nCurrentPos.cy < m_rcDesktop.bottom)
{
m_nCurrentPos.cy += m_nIncrement;
m_nCurrentSize.cy = m_rcDesktop.bottom - m_nCurrentPos.cy;
}
else
{
KillTimer(hWnd, IDT_DISAPPEARING);
MoveWindow(m_hWnd, 0, 0, 0, 0, FALSE);
ShowWindow(m_hWnd, SW_HIDE);
}
break;
}
SetWindowPos(hWnd, HWND_TOPMOST, m_nCurrentPos.cx, m_nCurrentPos.cy, m_sMaxSize.cx, m_nCurrentSize.cy, SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOACTIVATE);
}
return true;
}
use AnimateWindow instead. it is easy to use. you may need to handle WM_PRINT, and this also is quit straightforward.
if ever you want to keep working on your code then:
1) remove from popup class the flags CS_HREDRAW & CS_VREDRAW
2) handle WM_ERASEBACKGROUND
finally. if it is a popup window, do not call SetFocus(); maybe you have to set zorder to TOP_MOST
good luck

RichEdit's EM_AUTOURLDETECT message recognizes link, but I can't click it

I have a RichEdit control in a dialog box. The RichEdit control displays RTF text. EM_AUTOURLDETECT causes the RichEdit control to properly format and recognize the hyperlink. When the mouse hovers over the link, the pointer changes to a hand, but the browser doesn't launch once the link is clicked.
Am I missing some kind of event handler code?
case WM_INITDIALOG:
{
// Create Richedit
HWND hwndRE = CreateWindowA("RichEdit20A", "", WS_CHILD | WS_BORDER | WS_VSCROLL | ES_READONLY | ES_MULTILINE, 10, 10, 480, 220, hDlgWnd, 0, hInst, 0);
SendMessage(hwndRE ,EM_AUTOURLDETECT,(WPARAM)TRUE,(LPARAM)0);
//SendMessage(hwndRE ,EM_SETEVENTMASK, 1, ENM_LINK | ENM_CHANGE);
ShowWindow(hwndRE, SW_SHOWNORMAL);
SETTEXTEX SetTextEx;
char* aboutdata = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil\\fcharset0 Verdana;}}\\viewkind4\\uc1\\pard\\qc\\b\\f0\\fs20 www.whateverdomain.com} ");
SendMessage(hwndRE, EM_SETTEXTEX,(WPARAM)&SetTextEx, (LPARAM)(LPCTSTR)aboutdata);
return TRUE;
}
You can try something like this:
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code)
{
case EN_LINK:
ENLINK * enLinkInfo = (ENLINK *)lParam;
if (enLinkInfo->msg == WM_LBUTTONUP)
{
// code which gets clicked URL using enLinkInfo->chrg and saves it in
// "urlString"
ShellExecute(NULL, "open", urlString, NULL, NULL, SW_SHOWNORMAL);
}
break;
.... // More cases on WM_NOTIFY switch.
}
break;
Basically, when the WM_NOTIFY code is EN_LINK, you get the clicked URL and launch it using ShellExecute.
Have a look at EN_LINK:
http://msdn.microsoft.com/en-us/library/bb787970(VS.85).aspx