Hi,
--- Alexandre Julliard julliard@winehq.org wrote:
The IsWindow check is useless, what you need is to verify that it's really a combobox. The right way to do that is probably to send a CB_GETCOMBOBOXINFO message instead.
How about something like this instead?
Index: dlls/user/combo.c =================================================================== RCS file: /home/wine/wine/dlls/user/combo.c,v retrieving revision 1.8 diff -u -r1.8 combo.c --- dlls/user/combo.c 23 Dec 2004 17:21:05 -0000 1.8 +++ dlls/user/combo.c 15 Mar 2005 19:09:52 -0000 @@ -27,7 +27,6 @@ * If you discover missing features, or bugs, please note them below. * * TODO: - * - GetComboBoxInfo() * - ComboBox_[GS]etMinVisible() * - CB_GETCOMBOBOXINFO * - CB_GETMINVISIBLE, CB_SETMINVISIBLE @@ -2293,10 +2292,27 @@ /************************************************************************* * GetComboBoxInfo (USER32.@) */ -BOOL WINAPI GetComboBoxInfo(HWND hwndCombo, /* [in] handle to combo box */ - PCOMBOBOXINFO pcbi /* [in/out] combo box information */) -{ - FIXME("\n"); - return FALSE; - +BOOL WINAPI +GetComboBoxInfo(HWND hwndCombo, /* [in] handle to combo box */ + PCOMBOBOXINFO pcbi /* [in/out] combo box information */) +{ + static const WCHAR ComboBoxW[] = { 'C', 'o', 'm', 'b', 'o', 'B', 'o', 'x', 0 }; + CHAR szBuffer[MAX_PATH + 1]; + int dwSize; + LPHEADCOMBO lphc; + + dwSize = GetClassNameW(hwndCombo, szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0])-1); + + if (lstrcmpiW(szBuffer, ComboBoxW) != 0) + return FALSE; + + lphc = (LPHEADCOMBO)GetWindowLongPtrW( hwndCombo, 0 ); + + pcbi->hwndCombo = hwndCombo; + pcbi->hwndList = lphc->hWndLBox; + pcbi->hwndItem = lphc->hWndEdit; + pcbi->rcItem = lphc->textRect; + pcbi->rcButton = lphc->buttonRect; + pcbi->stateButton = lphc->wState; + return TRUE; }
__________________________________ Do you Yahoo!? Read only the mail you want - Yahoo! Mail SpamGuard. http://promotions.yahoo.com/new_mail
Steven Edwards steven_ed4153@yahoo.com writes:
Hi,
--- Alexandre Julliard julliard@winehq.org wrote:
The IsWindow check is useless, what you need is to verify that it's really a combobox. The right way to do that is probably to send a CB_GETCOMBOBOXINFO message instead.
How about something like this instead?
Much worse, the class name is not a valid way of checking the Windows type. You really need to send a message.
Alexandre Julliard wrote:
Much worse, the class name is not a valid way of checking the Windows type. You really need to send a message.
The results of the research I just did:
1. GetComboBoxInfo works with all handles, even with handles not belonging to the calling process 2. It does NOT send a message, not even in the case it doesn't belong to the calling process 3. It sets the last error code to ERROR_WINDOW_NOT_COMBOBOX and returns FALSE if the window handle isn't a combo box 4. It sets the last error code to ERROR_INVALID_MENU_HANDLE and returns FALSE if the window handle is invalid 5. If the cbSize field of the COMBOBOXINFO structure doesn't match, it sets the last error code to ERROR_INVALID_PARAMETER and returns FALSE
Because of 1. and 2. it's only possible to implement it in win32k unless one wants to determine the window owner, open a process handle and read the memory, a win32k implementation would be cleaner.
Sure, win32k doesn't exist in wine so it's a task for wineserver.
Just for the record: I wrote a very basic test application where I can enter a window handle, in combination with MS Spy++ it just takes < 5 minutes to find out. A simple SetLastError(0) before the function call and a GetLastError() after it revealed the error codes. print everything to the screen and modify the cbSize parameter and you got all the information. If you insist I can attach the test application as a proof, but you have to enter window handles yourself and run MS Spy++.
This information was gathered in less than 5 minutes by just testing, no reverse engineering or whatsoever was involved. However, since it might set the last error code to ERROR_WINDOW_NOT_COMBOBOX I expect it to check the window class name.
Best Regards, Thomas
Thomas Weidenmueller wrote:
- It sets the last error code to ERROR_INVALID_MENU_HANDLE and
returns FALSE if the window handle is invalid
It's supposed to be ERROR_INVALID_WINDOW_HANDLE of course.
Thomas
"Thomas Weidenmueller" wine-patches@reactsoft.com wrote:
Since you didn't provide your test app I wrote my own (attached). My comments are based on its results.
The results of the research I just did:
- GetComboBoxInfo works with all handles, even with handles not
belonging to the calling process
Most likely it's true.
- It does NOT send a message, not even in the case it doesn't belong to
the calling process
True, but that might be an internal message catched by the message handling code.
- It sets the last error code to ERROR_WINDOW_NOT_COMBOBOX and returns
FALSE if the window handle isn't a combo box
True. That might be accomplished by retrieving a window data pointer with GetWindowLongPtrW and testing some internal fields.
- It sets the last error code to ERROR_INVALID_MENU_HANDLE and returns
FALSE if the window handle is invalid
ERROR_INVALID_WINDOW_HANDLE as corrected.
- If the cbSize field of the COMBOBOXINFO structure doesn't match, it
sets the last error code to ERROR_INVALID_PARAMETER and returns FALSE
Poor Microsoft programmers even decided to fail if cbi.cbSize = sizeof(cbi) + 1, i.e. if it's enough space to store the result.
Because of 1. and 2. it's only possible to implement it in win32k unless one wants to determine the window owner, open a process handle and read the memory, a win32k implementation would be cleaner.
In Wine we can always send our custom WINE_GETCOMBOBOXINFO message if a window belongs to other process.
My test app shows that Windows correctly handles a superclassed window, so the thesis that it checks the class name is wrong.
Dmitry Timoshkov wrote:
Since you didn't provide your test app I wrote my own (attached). My comments are based on its results.
Well, since I was lazy I wrote it in Delphi and you'd have to enter window handles yourself, I didn't attach it but since I keep being accused of tainted sources I tried to clarify this.
The results of the research I just did:
- GetComboBoxInfo works with all handles, even with handles not
belonging to the calling process
Most likely it's true.
That's right, the reason I mentioned is that Christoph's implementation won't work because of different address spaces. Even if it points to the desktop heap (which ReactOS doesn't have yet) it's not guaranteed to work because it might have gotten mapped to another base address. So the implementation basically can't work this way.
- It does NOT send a message, not even in the case it doesn't belong
to the calling process
True, but that might be an internal message catched by the message handling code.
I of course only checked if a message would get dispatched to the window procedure of the owning thread. I don't know how windows handles it internally but I assume it reads the information from the desktop heap without reading the ptr using GetWindowLongPtr. If of course might send an internal message that only gets dispatched internally, but that'd be much overhead that could easily be a avoided. I forgot to mention that the function even works if the thread that owns the combo box hangs, it immediately returns the requested information. So sending a (internal) special message is not likely in my opinion.
- It sets the last error code to ERROR_WINDOW_NOT_COMBOBOX and
returns FALSE if the window handle isn't a combo box
True. That might be accomplished by retrieving a window data pointer with GetWindowLongPtrW and testing some internal fields.
That however only works for controls owned by a thread of the same process.
- If the cbSize field of the COMBOBOXINFO structure doesn't match,
it sets the last error code to ERROR_INVALID_PARAMETER and returns FALSE
Poor Microsoft programmers even decided to fail if cbi.cbSize = sizeof(cbi) + 1, i.e. if it's enough space to store the result.
That actually is common in the native api. Unless the buffer needed may vary depending on the content it returns, in most cases the size fields have to match. There are however a few exceptions I found by tests. One reason however might be to support different structure versions (.e.g. GetVersionEx()). So I don't think it's a "bad thing(tm)". Plus you might find bugs caused by using incorrect structure layouts.
In Wine we can always send our custom WINE_GETCOMBOBOXINFO message if a window belongs to other process.
Unless the window owner thread hangs, that then causes the caller to hang as well, which is not the case in windows. Sending a message with a timout would not work correctly if the system is too busy to process the request in time, even if the target thread doesn't hang.
My test app shows that Windows correctly handles a superclassed window, so the thesis that it checks the class name is wrong.
As I haven't tested that case, I guess you're right.
Best Regards, Thomas