Что нового

[Баг] Ошибка в функции _GUICtrlMenu_EnableMenuItem

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Нашел ошибку в функции
Код:
_GUICtrlMenu_EnableMenuItem()
В ней есть неправильная строка:
Код:
If $aResult[0] = 0 Then Return SetError(10, 0, False)
Должно быть:
Код:
If $aResult[0] = -1 Then Return SetError(10, 0, False)
Эта ошибка присутствует в версиях от 3.3.6.1 до 3.3.10.2 (других у меня нет).
Справка англ. и рус.

PS
Не понятно мне, почему возвращаемое значение API функции EnableMenuItem BOOL, если она может вернуть и -1, и 0, и 1, и 2, и т.д.? :scratch:
 

asdf8

Скриптер
Сообщения
564
Репутация
152
madmasles [?]
Не понятно мне, почему возвращаемое значение API функции EnableMenuItem BOOL, если она может вернуть и -1, и 0, и 1, и 2, и т.д.?

Из справки к DllCall :
Код:
BOOL - 32 битное целое
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Это ошибка в описании функции, возвращаемое значение имеет тип UINT. Что касается типа BOOL, то 0 всегда интерпритируется как FALSE, а любое значение отличное от 0 как TRUE. Но поскольку UINT и BOOL являются 4-байтными типами, то ошибки не возникает.
 
Автор
madmasles

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Yashied [?]
Это ошибка в описании функции
Ошибка на MSDN? Первый раз встречаю такое! :shok:

PS
Забыл показать пример.
Код:
Global $h_Gui, $a_Res, $h_Menu, $a_State[4] = [0x00000001, 0x00000002, 0x00000003, 0x00000000]

$h_Gui = GUICreate('Test', 200, 200)
GUISetState()
Sleep(1000)
$a_Res = DllCall('user32.dll', 'hwnd', 'GetSystemMenu', 'hwnd', $h_Gui, 'int', 0)
If (@error) Or (Not $a_Res[0]) Then Exit 13
$h_Menu = $a_Res[0]
For $i = 0 To 3
;~ 	$SC_CLOSE = 0xF060
;~ 	$MF_GRAYED = 0x00000001
;~ 	$MF_DISABLED = 0x00000002
;~ 	0x00000003 = BitOR($MF_DISABLED, $MF_GRAYED)
	$a_Res = DllCall('user32.dll', 'bool', 'EnableMenuItem', 'handle', $h_Menu, 'uint', 0xF060, 'uint', $a_State[$i])
	If (@error) Or ($a_Res[0] = -1) Then Exit $i + 23
	ConsoleWrite('previous state ($a_Res[0]): ' & $a_Res[0] & @LF)
	Sleep(1000)
Next
Do
Until GUIGetMsg() = -3;$GUI_EVENT_CLOSE
 
Автор
madmasles

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Yashied [?]
Там полно ошибок.
Печально...


Добавлено:
Сообщение автоматически объединено:

Yashied [?]
Это ошибка в описании функции, возвращаемое значение имеет тип UINT.
Если использовать тип UINT, то, при попытке изменить состояние заведомо не существующего пункта, возвращает 4294967295, а не -1. Если использовать int или bool, то возвращает -1.
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
madmasles [?]
Если использовать тип UINT, то, при попытке изменить состояние заведомо не существующего пункта, возвращает 4294967295, а не -1
Знак минус находится в старшем байте, естественно при рассмотрении числа как беззнаковое этот старший байт превращает маленькое число в огромное, почти предел диапазона, типа было 0000001, стало 1000001.

BOOL - 32 битное целое. Естественно он возвратить какое либо число, в памяти то они все в цифрах.

Я просто проверил что у Notepad деактивировался пункт, а результат был False, значит не что-то не то. При удаче должен быть True.
 
Автор
madmasles

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
AZJIO [?]
Я просто проверил что у Notepad деактивировался пункт, а результат был False, значит не что-то не то. При удаче должен быть True.
Так как пункт меню был активным, то функция EnableMenuItem вернула 0 - предыдущее состояние пункта. В этом и есть ошибка (см. 1-ое сообщение).
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
madmasles сказал(а):
Если использовать тип UINT, то, при попытке изменить состояние заведомо не существующего пункта, возвращает 4294967295, а не -1. Если использовать int или bool, то возвращает -1.

Это нормально. 4294967295 = FFFFFFFF = -1. Поскольку функция возвращает флаги состояния (тип UINT), то по логике тип должен быть беззнаковым. Такие ситуации встречаются сплош и рядом. Также очевидно, что функция DllCall() должна интерпритировать результат в соответствии с указанным типом, т.е. в данном случае возвращать TRUE (1) или FALSE (0). Но в случае с логическим типом этого не происходит.

P.S.

Имено по это причине я в WinAPIEx UDF использовал INT вместо BOOL и byte вместо BOOLEAN.
 
Верх