Почему MAKEINTRESOURCE() работает?

Макрос определяется как:

#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i))))
#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i))))

Почему это может быть использовано для указания идентификатора ресурса (16-разрядного беззнакового int) или его имени (указателя на массив из char)? Разве это не ограничивает адресное пространство (в 32-разрядной системе) до 16 бит? В противном случае, как система знает, использую ли я идентификатор или имя?

Ответ 1

Это работает, потому что Windows не позволяет отображать страницы для первого 64 КБ адресного пространства. Улавливать ссылки на нулевые указатели. Но я думаю, что также улавливать ошибки указателя в программах, которые были преобразованы из 16-разрядной версии Windows.

Побочным эффектом является то, что это позволяет надежно различать идентификаторы ресурсов, упакованные в значение указателя, поскольку они всегда указывают на непередаваемую память.

Ответ 2

Макрос MAKEINTRESOURCE просто выполняет кастинг между числовым параметром и указателем на строку. Указатель строки недействителен и не может быть разыменован как имя ресурса. Однако API обработки ресурсов обнаруживает такие указатели по их абсолютной величине и рассматривает их как идентификатор ресурса, а не имя ресурса. Поскольку API-интерфейс C не поддерживает перегрузку, они не могут определить две функции, такие как:

HICON LoadIcon(HINSTANCE hInstance,LPCTSTR lpIconName);
HICON LoadIcon(HINSTANCE hInstance,UINT resourceId);

Итак, разработчики API решили использовать ту же функцию для обоих случаев, предоставляя макрос MAKEINTRESOURCE для пользователей API. Я считаю, что две различные функции могут выглядеть лучше:

HICON LoadIconByName(HINSTANCE hInstance,LPCTSTR lpIconName);
HICON LoadIconById(HINSTANCE hInstance,UINT resourceId);

Но это не так, как реализован Windows API. Действительный идентификатор ресурса всегда меньше минимально возможного значения указателя. Параметр имени ресурса передается API без этого макроса, и его значение не ограничено.

Ответ 3

Да, это ограничивает адресное пространство, но не так сильно, как вы думаете. Они эффективно вырезали 64 КБ вашего 4 ГБ адресного пространства. Большинство, если не все, этого 64 КБ уже зарезервированы для других вещей в Windows, поэтому эффективная потеря - ничто.

В целом, это экономия пространства, потому что им не нужен дополнительный бит информации, чтобы различать указатель и целочисленный идентификатор. Это было изобретено в плохие старые времена, когда пространство было на высоте.