I wasn't able to run the project because it couldn't load the
imagelist and toolbar, but it looks like in the dblclick procedure
your doing a lockwindowupdate and then you are doing the
sendmessage to get the lb_count. I think it may fail because the
lb is locked? Try sendmessaging before the lockwindowupdate.
HTH
VB/Office Guru™ (AKA: Gangsta Yoda™ ®)
I dont answer coding questions via PM. Please post a thread in the appropriate forum.
1. Thanks for deleting thread.
2. Thanks for idea re FindWindowEx.
----------------------------
Using Spy++ your way returns the left listbox handle not right BUT also returns a count of "4" which is the original count of tool buttons in the right -- (????) -- but since count taken after "Reset" count should be "7" NOT 4.
Also interesting is that toolbar buttons belong (parent is) the Form NOT the listbox.
Have redone code incorporating you idea along with some debug routines.
Any interest in helping me solve this? If so, post response and will post updated code.
As coded the first button is automatically transferred from the right to the left.
The objective is at startup to:
1. Add all needed buttons to the toolbar
2. Transfer at startup selected buttons so they do not show to left listbox, which leaves them available to end user when involking toolbar and segregates those currently showing from those not. IHMO this is how MS meant to use the Customize method.
3. Setting toolbars to (Visible = False) does not allow user to select and using "<--Remove" causes them to be deleted NOT transferred.
1. AT StartUp, Add all needed buttons to the toolbar (these will initially appear in the right listbox because of the Toolbar Add Method).
2. AT Starup, using the API, transfer buttons, you do NOT want to be visible in the toolbar from the right to the left listbox.
---------------------
AFTER startup, when the end user involkes the Customize method he should see buttons currently showing on the toolbar in the right listbox and those NOT showing but available in left listbox.
IHMO this is how MS meant to use the Customize method.
Currently the API code JUST finds the first button "Copy" and transfers it from right to left. This is because the Reset button was pressed using SendKey which by default selected the first button.
I WANT TO BE ABLE TO SELECT ANY BUTTON using the API (by name, key or index) and transfer it from right to left.
NO code is included to do this (e.g "Print" button) as I could not get Spy++ to even find any button in either listbox.
ALSO, the button count should be 7 not 4 as 7 buttons are in the right listbox when LB_GETCOUNT is executed.
Last edited by dw85745; Nov 22nd, 2004 at 08:46 AM.
Essentially, you require a method to transfer a ListItem of your choice (Copy, Print, etc.) to the listbox of your choice? (Either right or left)
This might get a little tricky for 2 reasons
1) They use graphics
2) We might have to write code to synchronize the modified listboxes with the toolbar display.
It will be easier to instead "guide" VB into performing the operations for you. By "guide" I mean, selecting the appropiate item in the listbox, and invoking the code from the Add/Remove buttons via SendKeys or SendMessage.
This "guide" approach simplifies the process by allowing VB to manage the underlying coding. All you have to do is select your desired ListItem in the ListBox, then use SendMessage or SendKeys to execute the Add/Remove buttons.
It will be easier to instead "guide" VB into performing the operations for you. By "guide" I mean, selecting the appropiate item in the listbox, and invoking the code from the Add/Remove buttons via SendKeys or SendMessage
This is the approach I'm trying. My first attempt (see first post with attached zip) was API, but decided "SendKeys" as easier.
HOWEVER to use SendKeys-- you still need to ID the listbox button which is where the PROBLEM IS?
Any ideas why:
1. LB_GETCOUNT returns 4 rather than 7 ?
(SendKeys "Reset" occurs AFTER the Add Method to add the 3 additional buttons and BEFORE the count is taken
2. Why Spy++ can't find the listbox "TEXT" associated with the image?
LB_SETCURSEL is used to set the current selection in the listbox.
BM_CLICK is used to click the "remove" button, which invokes the necessary code to transfer the selected item from the right listbox, to the left.
The whole SaveToolBar, RestoreToolBar bit at initialization seemed rather unnecessary, so I removed them from the project (you can always uncommet them)
You might even want to rewrite some of the SendMessage lines into procedures.
Only thing left is to trap the WM_ACTIVATE message so
that at startup the Customize form can be invoked using
the .Customize method and then a message to Close the Customized form.
This way ALL buttons will be available to user after StartUp, with
those showing in the toolbar on the right and those available to
the user to change the toolbar on the left.
As I recall, WM_ACTIVATE, in this instance will require a SystemWide hook.
----------------------
I found it interesting that the key to the listbox was:
VB Code:
SendMessage hListBox2, LB_SETCURSEL, -1, 0
FYI a call to "GetListBoxItems" after executing above line will now return
the correct string which provides a text listing of all items (buttons).
Yes, a hook is the way to go, but I don't think it has to be system wide (will get back to you on it).
Here's something else I was thinking of. What if you were to write your code into a function, and just execute this function everytime you invoke the "Customize" method of the toolbar. To simplify further, write a wrapper function that does both.
One big problem is when you trigger Customize like tbr.Customize all code stops on this line as the Customize form now has the focus.
A double click allows you to trap the Customize handle so processing can continue.
--------------------------------------
I was thinking of something similiar but still working on the details. Something like:
1. Rather than calling the function at startup, call the function the first time the customize method is triggered. Use a static variable (probably global) and at first call add and transfer (Right to Left LB) the available buttons. Prior to closing the Customize form save the button names (or keys).
2. While the App is active, any time Customized is triggered, all buttons should show properly, both those on the toolbar (right listbox) and available (left LB) -- will double check this tomorrow.
3. Still working on how to load the Customized form after the first time the App is run
1. Checked on the form and once toolbar buttons manipulated, the Customize form keeps them as set during execution even if the Customize form loses focus.
2. Doesn't appear system wide hook is needed. Using a module variable (see example) appears to solve problem.
3. All that is still needed in Sample is way to save and reload toolbar as designed by user.
Spoke a little too soon. Ran into problems saving toolbar configuration on QueryUnload. Replicating of Doubleclick on toolbar works to trigger call to "Save" routine, but "Customize" form doesn't load from DBLClick so so handle returns "0".
When I double-click the toolbar, the customize dialog closes, but if I do it a second time, it re-opens and stays.
If I press the commandbutton first, the customize dialog will always open then close right after. I suspsect it has to do with an ignored error, but I'll investigate this further later today
1. First double click on toolbar adds the extra buttons and transfers them to the listbox. This way the extra buttons stay in the imagelist control unless needed -- better use memory.
Per your post noticed that the Customize should stay up after
extra buttons loaded. Will check on this.
2. Any subsequent double click just brings up the customized form to allow user to make adjustment.
3. Command1 is being used to test the TBSaveConfig which will be invoked at QueryUnload. This way the user can adjust tools anyway he wants while App is running (Customized save the setup while App running).
4. Save is only needed for the next time the App is run.
4. Thinking may need a WH to trap Customize activating
Last edited by dw85745; Nov 28th, 2004 at 04:32 PM.
I'm leaning towards a custom message being sent, though theoretically, dispatching the appropiate messages should trigger it (if it exists) indirectly.
Just as I suspected, there is a customized message being sent indirectly, when the "Customize" method is invoked.
Sending this message, alone, has no effect. Interestingly, not even WM_LBUTTONDOWN/UP or the double-click messages are being processed by the toolbar. This lead me to discover that the toolbar is actually a container for another window. I'll experiment some more with this.
Will modifiy code with your post.
Had planned to try and track the message stream this weekend and well as hopefully implement WH_GETMESSAGE for tbr.Customize from a menu.
there is a customized message being sent indirectly
Not sure what you mean by the above?
Are you referring to the parent (container) child relationship of the toolbar?
Are you referring to the parent (container) child relationship of the toolbar?
David
Yes. Inside the toolbar, there is another window that's processes double-click messages into invoking the "Customize" method, hence the reason why sending messages to the actual toolbar, itself, will not work, because we want to send to the internal window (not the parent window).
The code I supplied earlier will get the handle of this internal window. Send your mouse-events to it, and the customize dialog should appear.
Been working on this toolbar problem on and off all week with an HCBT hook.
Not working.
QUESTIONS
Before I abandon HCBT and look at HGETMESSAGE can you explain
how you decide which HOOK to use, or is this trial/error and experience?
Do you know any place (SDK does NOT give the detail I want) that would provide specific information such as below for each of the 15 hook types.
****************************
My assessment for the toolbar would be:
1. Try and hook when the buttons are being created and/or placed
into the listboxes so that I could redirect them to the listbox of choice.
My guess is that the buttons would be added AFTER the customize form
as well as the listboxes exist, but before ShowWindow.
Based on the following HCBT does not appear to allow me to hook into where I need to hook. Here's what I've determined with HCBT.
Re: HCBT_CREATEWND
-----------------
I can get each Class hwnd, and Class name on the
Customize form, BUT at this point the text of the
control (such as "Reset") is NOT available other than through
the CREATEWND structure.
---> My conclusion is that HCBT_CREATEWND hooks just after class and window creation. BUT SINCE THE BUTTONS ARE ADDED AFTER CREATION
BUT BEFORE ACTIVATION, do I need to do this by looking for each Button being put into the listbox??? Tried by AddExtraButton routine here but
keep locking up.
---------------
This just returns the "Customize" Form and "Form1"
My conclusion here is that this hooks just before ShowWindow.
---> You would think this would be a good place to modify the Customize form
but so far my attempts have yielded "Method Customizee of object IToolbar failed"
and a lockup.
I, personally, like use WH_GETMESSAGE, but if you're using a WH_CBT (Computer based training, FYI) hook, you're interested in the HCBT_CREATEWND notification. This will be sent just prior to the window creation.
And you're right: Chances are, the buttons have not even been created yet (the window, itself, isn't created yet) so you won't be able to get their handles at this point. All buttons are probably be created in the WM_CREATE event of the parent window, so it's safe to obtain handles for these buttons in the WM_ACTIVATE event. In order to gain access to this event, subclass the window.
Each time a button is clicked, it sends a WM_COMMAND message to the parent form, with the lParam parameter containing the handle of the button pressed, and the high-order bits containing a BN_CLICKED notification code. Catch these, and you should be good to go.
What is it you're trying to do again? Check when a specific button is clicked?