ListView multiple selection behavior? - winapi

The ListView in Comtl32.dll v6.0 does multiple selection (when using Shift key) as follows (x means selected)
00xxxx
xxxxxx
xxxx00
Earlier versions of ListView do it as follows :
00xx00
00xx00
00xx00
Is there any way to have it do the first way (the comctl32 v6.0 way)?
Thanks John

The short answer is no. But because that seems incomplete...
The ListView does not expose an API that allows you to change its selection behavior, and as Hans obliquely puts it in his comment, the only way to change the behavior of the ListView control found in versions of comctl32.dll prior to version 6.0 is with a time machine. There's a lot of unique behavior built into the ListView control regarding selection events, so even if you were to try and owner draw the control to modify the appearance of the selection behavior, you'd suddenly be faced with having to handle a nearly ridiculous number of window messages that could potentially cause a selection change.
It's also worth pointing out that this question is misguided on an entirely different level. If the user of your application is running a version of Windows that includes a version of comctl32.dll prior to version 6.0, this is the behavior that they expect out of the ListView control. Overriding and changing that would be nothing but confusing to them, because it wouldn't work the same way as every other ListView control found on their computer. By contrast, if the user of your application is running a version of Windows that includes comctl32.dll v6 or later, the ListView control will already perform as you describe by default. (And you shouldn't go wanting to change it for exactly the same reasons.)

Related

Notification/subscription method for Windows 10 theme change

As yolu may have noticed, MS introduced a modern kind of 'theming' in Windows 10 regarding the basic OS elements like start menu and taskbar. With newer versions, you can choose a 'light' theme as an alternative to the default black theme.
I was wondering if there is an API or hook to elegantly and (more importantly) efficiently check live for theme changes (Did not find anything in the MS docs regarding this, but often enough these gems are pretty hidden there IMHO).
Specific problem: When you have a desktop application with a system tray icon, chances are high that you designed it to be bright. Nearly all of the modern Windows icons feature such a style (simple and white, yielding good readability on the black taskbar). Now you can provide a different version in a darker style for the light theme, but how to notice when to apply this on the fly?
I'm aware of the registry key under HCU (Software/Microsoft/Windows/CurrentVersion/Themes/Personalize) which is what I'm utilizing right now. However, blindly checking for change every x milliseconds seems pretty awkward.
If no such thing is available, I'm also happy to hear some ideas for more efficient implementations of such a check.
Method 1: Use RegNotifyChangeKeyValue
Notifies the caller about changes to the attributes or contents of a
specified registry key.
Methon 2: Use WM_SETTINGCHANGE
Applications should send WM_SETTINGCHANGE to all top-level windows when they make changes to system parameters. (This message cannot be sent directly to a window.) To send the WM_SETTINGCHANGE message to all top-level windows, use the SendMessageTimeout function with the hwnd parameter set to HWND_BROADCAST.
I tend to use the second method, I have tried, and have been able to work successfully.
Minimum code example:
case WM_SETTINGCHANGE:
{
if (!lstrcmp(LPCTSTR(lParam), L"ImmersiveColorSet"))
{
//theme has been changed
}
}

Allow selection in Explorer-style list view to start in the first column

In Windows 7's Windows Explorer list view (what allegedly is not list view at all) in the Details view, you can start selection marquee in the first (Name) column. You just need to start outside the actual name.
The same is true for default-style list view control in Details view.
But if you set the list view control to the Explorer style (using the SetWindowTheme), what should mimic the Windows Explorer, this does not work anymore. You can start selection in the second and later columns only.
SetWindowTheme(listView1.Handle, "explorer", null);
Is there any way to make list view mimic the Explorer selection style?
I suppose there's no settings to enable such behavior and this would have to be coded. Like handling the mouse down and triggering selection. But I have no idea how to do that.
Thanks.
Ntb, I'm using C++Builder, but this should be purely Win32 issue. I've tested this with WinForms too (hence the C# sample above).
Is there any way to make list view it mimic the Explorer selection style?
No, SysListView32 in explorer theme does not behave that way. The control used by the modern Explorer is actually DirectUIHwnd. And you are not able to use one of them.
The only way to get the behaviour of DirectUIHwnd is to code it yourself. I expect that's possible to do but I'd also expect it to be very difficult to achieve.
Actually there is a way to mimic Explorer selection behavior. It requires a lot of additional declarative work, but it is possible.
You need to get undocumented IListView interface via undocumented LVM_QUERYINTERFACE message (note that interface declaration and GUIDs are different for Windows Vista and Windows 7+). Details about constants and declarations can be found here:
IListView at Geoff Chappell - Software Analyst or
Undocumented List View Features at Code Project.
After acquiring the interface all you need is simply a call to SetSelectionFlags(1, 1) method. Voila you are done.

How to clear old Grid control?

What VB6 code will clear the contents of an old Grid control?
The Grid control is derived from GRID32.OCX. Here are the version details of this file:
The code provided here does not work: http://support.microsoft.com/kb/88911
I fished GRID32.OCX out of my Visual Studio CDs, installed it and tried the process described at http://support.microsoft.com/kb/88911 .
Even though it is for a different version (and, yes, the version I installed is the one you've highlighted), it worked correctly for me (except that, as I have Option Explicit by default, I had to add Dim i%, j% at the start of the Form_Load).
Do you have code in the RowColChange or SelChange events that could be affecting the changes?

IsWindow(activeX.GetSafeHwnd()) always false after upgrade to VS2010

I have an MFC application that uses an ancient (circa 1999) third-party ActiveX control.
Since upgrading the project from VS2008 to VS2010, I'm having problems...
In the OnSize handler of the parent dialog IsWindow always returns false for the handle returned by control.GetSafeHwnd(), even when GetSafeHwnd() returns a non-NULL value. The rest of the control's parent dialog is displayed fine, but it doesn't seem to respond to any input.
I've seen this article, but GetSafeHwnd() isn't returning NULL in this case (after the first time that it is called, which is before the control is instantiated).
The control does cause the trace message "Control wants to be windowless" to be output when it's loaded. However it also does this when compiled in VS2008, so this may be a red herring. Searching for this message points me to creating a class derived from COleControlSite, and denying the control windowless-ness, but it seems there are no good example of this available, and as I say, it's not clear that this is really the cause of the problem.
I've also found this issue mentioned on MSDN's VS2010 porting page:
"An ActiveX control compiled by using Visual C++ 6.0, when embedded in
a dialog box in a project developed by using Visual C++ 2010, may
cause your program to assert at run time. In this situation, open the
ATL or MFC project associated with the ActiveX control in Visual C++
2010, and recompile it.. The assert will be in the file occcont.cpp,
on this line in source: ASSERT(IsWindow(pTemp->m_hWnd))."
I assume that there's something about VS6-compiled ActiveX controls that causes the window handles to be treated as invalid by the current Win32 implementation of IsWindow. The suggested solution is of course unhelpful as it's a third-party control, and we can't recompile it.
Has anyone managed to get around this?
I've already found solutions for VS2010 projects not running on Windows 2000, and errors linking to ODBC, but don't seem to be able to find anything on this one.
Thanks,
Chris
I didn't find a solution to this in the end - upgraded the controls to a VS2010-compatible version.
For what it's worth: if you don't care whether the control will appear transparent or not, you may force the control to have a window anyway - even though it can operate without a window.
You see, the ActiveX control must first ask the container (the window which will host the control) if it's okay to be activated without a window. This is simply because not all containers support windowless activation.
If this interface (IOleInPlaceSiteWindowless) returns okay then it proceeds with this special windowless activation, if not a window will be created for the control as normal.
Disclaimer:
I don't know if this 'unnecessary' window will make the assertion failure go away. In other words: I don't know if the window handle is passed down 'deep' enough into the AX control.
More about the IOleInPlaceSiteWindowless interface:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682300(v=vs.85).aspx

How can I get the name of a Visual Basic control given its HWND?

I'm working on a little macro record/replay tool which can automate a few very old Visual Basic 6 GUIs we have. To do so, I'm identifying the controls by their name (the value of the name property of a control, that is).
One part of this tool needs to determine the name of a control given its HWND. For newer Visual Basic applications which were done using VB.NET, I can use the WM_GETCONTROLNAME window message. This works nicely.
However, this message is not understood by older windows. Is there any way to do this for controls of Visual Basic 6 applications? A solution which does not require being in the process of the GUI would be preferrable, but if I had a solution which only works inside the GUI process then that would be acceptable as well (since I can do the injection myself).
UPDATE: One thing I just tried, this moderate success: I used the AccessibleObjectFromWindow to check for implementations of the IAccessible interface of the object which shows the given HWND. In case I get an implementation (it seems that many [all?] Visual Basic controls implement this interface), I use the accName property to read out the "accessible name". Sometimes this does yield a useful string, but usually it doesn't.
I believe the only way would be getting inside the process and obtaining a pointer to the Form object, yet I have no idea how to do it from outside.
Is it possible you add support for the WM_GETCONTROLNAME to those older applications?
Or maybe, you could identify the controls by some other, natively-available properties?
Other that that, as Raymond is saying, there isn't much you can do.
Can you modify the vb6 apps? if so in each form load event you could iterate me.controls and use the SetProp(ctrl.hwnd, "MYNAME:" & ctrl.name, 0) api to add the name to the window's own property list, then in your other app you can EnumProps(ctrl_HWND) looking for the one that begins with MYNAME: and parse out the value.

Resources