NO

Author Topic: CoolMenu  (Read 9444 times)

sapero

  • Guest
CoolMenu
« on: April 04, 2013, 10:02:37 PM »
CoolMenu - this is a remake of Jan99CQA Coolbar, but converted to C language.

The example application has a rebar with custom made menu, and a simple toolbar, where only Edit and Help items are implemented.
This menu is basing on a toolbar control, can display only text buttons, supports keyboard navigation.

Minimum operating system: Windows XP (SetWindowSubclass api), but could be lowered after replacing SetWindowSubclass with unsafe SetWindowLong(GWL_WNDPROC)

All the best!

Added missing toolbar bitmap. Fixed XP issue. Added manifest and a #if to .rc file.
« Last Edit: April 05, 2013, 11:14:26 PM by sapero »

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: CoolMenu
« Reply #1 on: April 04, 2013, 10:45:04 PM »
File not found: 'Toolbar.bmp'

Re "unsafe": Do you refer to Raymond Chen's "what would happen if somebody else had subclassed the window"? (Safer subclassing)

Shouldn't be a problem if a) you are the author and b) you don't suffer from multiple personality disorder ;-)

sapero

  • Guest
Re: CoolMenu
« Reply #2 on: April 05, 2013, 01:45:24 AM »
I'm sorry for that, added missing file to attachment in the first post.

Unsafe - I have read it multiple times, mostly on MSDN pages and blogs (including The Old New Thing!), and in the local help system.

If you start extending an older project by adding new subclasses, it is just as much as a new call to SetWindowSubclass with another callback address, instead taking a deadmatch with SetWindowLong, taking care who removes its subclass first.

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2091
Re: CoolMenu
« Reply #3 on: April 05, 2013, 09:09:39 AM »
Minimum operating system: Windows XP (SetWindowSubclass api), but could be lowered after replacing SetWindowSubclass with unsafe SetWindowLong(GWL_WNDPROC)
Windows 2000 SP4 with comctl32 v. 5.81 have SetWindowSubclass api too ?
« Last Edit: April 05, 2013, 10:46:19 AM by timovjl »
May the source be with you

sapero

  • Guest
Re: CoolMenu
« Reply #4 on: April 05, 2013, 09:42:01 AM »
NO, it is there but it's not exported. My friend wrote a routine to call it internally.

Code: [Select]
typedef BOOL    (__stdcall*SETWNDSUB)(HWND hWnd,SUBCLASSPROC pfnSubclass,UINT_PTR uIdSubclass,DWORD_PTR dwRefData);
typedef LRESULT (__stdcall*DEFSSUBPRC)(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
typedef BOOL    (__stdcall*REMWINSUB)(HWND hWnd,SUBCLASSPROC pfnSubclass,UINT_PTR uIdSubclass);
SETWNDSUB pfnSetWindowSubclass;
DEFSSUBPRC pfnDefSubclassProc;
REMWINSUB pfnRemoveWindowSubclass;

void init(void) {
LONG_PTR base = (LONG_PTR)LoadLibrary(TEXT("comctl32.dll"));
*(LONG_PTR*)&pfnSetWindowSubclass = base + 0x424EA;
*(LONG_PTR*)&pfnDefSubclassProc = base + 0x425FC;
*(LONG_PTR*)&pfnRemoveWindowSubclass = base + 0x42592;
}

The offsets should be individually calculated, best with downloaded comctl32.pdb and debughelp apis.

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2091
Re: CoolMenu
« Reply #5 on: April 05, 2013, 10:43:30 AM »
They are exported by ordinals in that version ?

http://vb.mvps.org/samples/HookXP/

PS:
I use VirtualBox for testing Win2K compability.
Example program compiled in Win2K with PellesC 7 and it's works there too.

EDIT: More info: http://code.msdn.microsoft.com/windowsdesktop/CppWindowsSubclassing-2ef7ee53
Quote
1. Subclassing Controls Prior to ComCtl32.dll version 6

The first is usable by most windows operating systems (Windows 2000, XP and later). You can put a control in a subclass and store user data within a control. You do this when you use versions of ComCtl32.dll prior to version 6 which ships with Microsoft Windows XP. There are some disadvantages in creating subclasses with earlier versions of ComCtl32.dll.

     The window procedure can only be replaced once.

     It is difficult to remove a subclass after it is created.

     Associating private data with a window is inefficient.

     To call the next procedure in a subclass chain, you cannot cast the old window procedure and call it, you must call it using CallWindowProc.

To make a new control it is best to start with one of the Windows common controls and extend it to fit a particular need. To extend a control, create a control and replace its existing window procedure with a new one. The new procedure intercepts the control's messages and either acts on them or passes them to the original procedure for default processing. Use the SetWindowLong or SetWindowLongPtr function to replace the WNDPROC of the control.
« Last Edit: April 05, 2013, 11:19:17 AM by timovjl »
May the source be with you

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: CoolMenu
« Reply #6 on: April 05, 2013, 04:24:06 PM »
I'm sorry for that, added missing file to attachment in the first post.

Thanks, it looks nice. On XP, there is a glitch - the toolbar does not draw until you move over it with the mouse pointer; on Win7-32 it works 100%.

Quote
Unsafe - I have read it multiple times, mostly on MSDN pages and blogs (including The Old New Thing!), and in the local help system.

If you start extending an older project by adding new subclasses, it is just as much as a new call to SetWindowSubclass with another callback address, instead taking a deadmatch with SetWindowLong, taking care who removes its subclass first.

If you have control over your code, it's no problem. If you are not the author, or if you forgot what that code means which you wrote over two weeks ago, just don't remove the subclass. You can still disable it by clearing a flag that determines a branch etc.

Normally there is no need to remove a subclass.

sapero

  • Guest
Re: CoolMenu
« Reply #7 on: April 05, 2013, 08:01:16 PM »
Solved the issue on XP - it is a possible wrong check of structure length. Some apis are developed by "-Wall --pedantic -Dstrict" coders which do not allow passing larger buffers than required :)
Attachment updated, successfully tested on XP.

REBARBANDINFO.cbSize changed from sizeof(REBARBANDINFO) to FIELD_OFFSET(REBARBANDINFO,rcChevronLocation).
Another posibility would be changing WINVER in project options, to target minimum XP.

Timovjl, I am not a fan of win2k, I have jumped from win98 directly to XP, and now again jumped over Vista to Seven. Have used win2k only several times to just check a if program (under VirtualPC) will import all apis. But it is good to hear that these apis are exported at least by ordinals.

I have a tool which scans the whole hdd, tries to load any file as a dll, and collects all exported functions by name, so then I can choose one of databases and search for a function, to see which module is exporting it. Could not find SetWindowSubclass in w2k database, so I think it's time to embed symbols downloader/loading to that tool.

czerny

  • Guest
Re: CoolMenu
« Reply #8 on: April 05, 2013, 10:01:30 PM »
PORC: D:\C\wwl\coolmenu\main.rc(17): error: File not found: 'c:/windows/windowsshell.manifest'.
*** Fehlercode: 1 ***

I don't have a file windowsshell.manifest on my w2k box.
I don't even have a directory c:/windows/
:-)
czerny

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: CoolMenu
« Reply #9 on: April 05, 2013, 10:09:04 PM »
1 MANIFEST "c:/windows/windowsshell.manifest"

Interesting - it doesn't complain on my box (XP SP3).
EDIT: ... because the file is present... never seen before!

There is one more odd little glitch: Direct after launching, the caption does not display correctly, you see the icon plus "ol menu". When you click the "About", the caption changes and displays OK.

In the About box, it might be an idea to use a hollow brush instead of white.

A very nice demo, congrats.
« Last Edit: April 05, 2013, 10:11:04 PM by jj2007 »

sapero

  • Guest
Re: CoolMenu
« Reply #10 on: April 05, 2013, 10:33:47 PM »
Czerny, you can safely remove that entry from .rc file, it specifies a manifest for common controls, not used below XP. It's my bad habit to reuse existing files.
The About dialog uses a syslink control, which may cause the dialog to fail while creating on your box. Can be removed also, but please keep the associated #define in main.h for the C-compiler.

Jj2007 - yes, that file exists in %windir% on XP and above, but very few people know about it. Probably only sniffers and totalcmd users.
I haven't noticed what you just reported.

EDIT: replaced resource manifest with file manifest, moved syslink control to #if (_WIN32_WINNT >= 0x501) in the resource script.
« Last Edit: April 05, 2013, 11:16:32 PM by sapero »

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: CoolMenu
« Reply #11 on: April 05, 2013, 11:27:35 PM »
You can see the icon, but "Cool" is half hidden, see image below. On first redraw, it looks correct - probably the icon loads with a delay.

Actually, it's sufficient to exchange the order of these three lines:

   SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)app->hIcon);

   // initially hide manubar
   if (app->hwndCoolMenu && app->hwndRebar)
      SetMenu(hwndDlg, NULL);


... and voilĂ , it displays fine from the beginning.
« Last Edit: April 05, 2013, 11:31:09 PM by jj2007 »

czerny

  • Guest
Re: CoolMenu
« Reply #12 on: April 06, 2013, 02:13:43 PM »
In older versions of COMCTL32 InitCommonControls supports only ICC_WIN95_CLASSES. Use InitCommonControlsEx and ICC_COOL_CLASSES.

czerny

  • Guest
Re: CoolMenu
« Reply #13 on: April 06, 2013, 03:12:11 PM »
There is a difference between the visible size of the menu and the real size. So you can see an anesthetic, big gap between menu and toolbar.

bela374

  • Guest
Re: CoolMenu
« Reply #14 on: June 22, 2013, 08:30:02 AM »
Do you refer to Raymond Chen's "what would happen if somebody else had subclassed the window"?