Имеет ли значение битность ОС или это просто приложение, о котором мне нужно беспокоиться? - PullRequest
1 голос
/ 08 июля 2019

Некоторые предположения: (поправьте меня, если не прав)

Игнорируя 16-битные данные, VBA может работать на 32- или 64-битных хостах Office. 64-разрядную версию Office можно запускать только в 64-разрядной ОС, тогда как 32-разрядную версию Office можно запускать в 64-разрядной версии Windows / macOS или другой операционной системы 32 или .

Начиная с VBA7, у нас есть тип LongPtr, который становится Long в 32-битном Office (#Win64 = False), LongLong в 64-битном Office (#Win64 = True), независимо битность ОС

Мой вопрос: В API, которые имеют дело с указателями (адресами в памяти), имеет ли значение разрядность ОС или это только приложение, выполняющее код, который нас интересует (32 / 64-битный хост Office / VBA)?


Текущее понимание:

С одной стороны, я понимаю, почему это может не иметь значения:

  • VBA, работающая в 32-битном Excel, будет иметь 32-битное адресное пространство (независимо от ОС)
  • Следовательно, любые указатели на собственную память должны быть 32-разрядными (т. Е. Long s - LongPtr дает нам это)
  • Аналогично, 64-битный VBA (обязательно в 64-битной ОС, но действительно может быть где угодно) имеет 64-битное адресное пространство (каждый указатель имеет длину 64 бита и относится к блоку памяти шириной 64 бита)
  • Поэтому любые указатели на собственную память должны быть 64-битными (т. Е. LongLong s - LongPtr дает нам это)
  • Итак, LongPtr точно представляет указатель на собственную память моего кода, независимо от разрядности ОС

Однако я могу представить времена, когда битность ОС могла бы иметь значение

  • Запуск 32-разрядного VBA в 64-разрядной ОС, но при обращении к областям в памяти другого 64-разрядного приложения тип LongPtr оценивается как Long и будет слишком коротким, чтобы представлять максимум Размер указателя доступен в этой ОС.
  • Точно так же 64-разрядный VBA, обращающийся к памяти 32-разрядного приложения, обнаружил бы, что его тип указателя слишком велик для хранения адреса
  • Теперь пользующийся доверием тип LongPtr на самом деле имеет неправильную длину для представления указателя на адрес в памяти вне собственного адресного пространства VBA!

Проблемы могут теперь возникать в зависимости от разрядности ОС, а не от разрядности Office / VBA. Если мы запускаем VBA7 в 32-битной ОС, тогда LongPtr будет правильной длиной для любого куска памяти, который вы захотите использовать; это подходящий тип данных указателя в 99,9% случаев, поскольку все, что делает ОС, является 32-разрядным (игнорируя 16-разрядное).

Однако тот же 32-битный код VBA7, который выполняется вместо 64-битной ОС, может столкнуться с трудностями при попытке использовать LongPtr для хранения 32-битных адресов. Я чувствую, что довольно часто смешивать 32-битные и 64-битные приложения в 64-битной ОС, так что это может быть реальной проблемой.

32-разрядные VBA6 и более ранние приложения, работающие в 32-разрядных и 64-разрядных операционных системах, могут сталкиваться с аналогичными проблемами, только без помощи LongPtr


Теперь я понимаю, что это довольно надуманная ситуация, кто захочет получить доступ к памяти другого приложения, верно? На самом деле это настолько изобретательно, что я не уверен, что смогу когда-нибудь придумать ситуацию, в которой это важно и о чем стоит беспокоиться. Может ли приложение когда-либо получить адрес в памяти другого приложения с другой разрядностью? Может быть, есть некоторые средства защиты от чтения и записи, предотвращающие это.

Возможно, доступ к дескриптору окна другого приложения был бы одним из таких случаев; это общедоступная память, и, возможно, разрядность дескриптора окна отражает разрядность приложения или операционной системы, и в этом случае мой 32-разрядный VBA мог бы содержать ссылку на 64-разрядную Hwnd, Я не уверен ...


PS Я знаю, что существуют ситуации, отличающиеся от длины указателя, где битность ОС может быть важной. Я знаю одного; функция SetWindowLong требовала разных объявлений в 64-битной и 32-битной Windows - хотя IIUC теперь была решена с помощью функции SetWindowLongPtr, которая идентична для обеих. Но о любых других подобных причудах было бы полезно знать, я только фокусируюсь на длине указателя, потому что у меня есть проблема, которая требует конкретной информации.

PPS приходит к выводу, можете ли вы даже получить битность ОС во время компиляции; Я думаю, что вы можете сделать вывод из MAC_OFFICE_VERSION, а ofc Win64 = True означает 64-битную версию Office и де-факто 64-битную ОС. Но я не уверен, есть ли способ узнать, работает ли 32-битный VBA в 64-битной Windows ...

Ответы [ 2 ]

3 голосов
/ 08 июля 2019

Конечно, битность ОС имеет значение.

Вы можете увидеть этот ответ для случая, когда нам нужен специальный код для 32-битного офиса в 64-битной Windows (правильная регистрация DLL-библиотек COM для использования в 32-битных приложениях).

Тест, который я использую там:

#If Win64 Then
    Const Win64 = True
#Else
    Const Win64 = False
#End If
If Not Win64 And Environ$("ProgramW6432") <> vbNullString Then
    '32 bits Office on Win 64
Else
    'Either 32-bits Windows, or 64-bits Office on 64-bits windows
End If

Afaik, вы не можете определить это во время компиляции, только во время выполнения.

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

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

2 голосов
/ 08 июля 2019

A LongPtr всегда правильно для вашего процесса . Вам не нужно беспокоиться о его размере. Вам не нужна константа WIN64 для ее использования. Фактически, единственная константа, которая вам обычно нужна, это VBA7, которая сообщает вам, доступен ли LongPtr. Если это так, используйте его, если нет, вы определенно x86, поэтому используйте Long.

Кроме того, Windows x64 имеет целый уровень совместимости, который называется WoW64 . Как 32-битное приложение, работающее в 64-битной Windows, вы ничего не замечаете и работаете так, как если бы ОС была 32-битной. Размер вашего указателя составляет четыре байта, ваши типы данных размером с указатель, такие как HWND s, имеют размер четыре байта, поэтому, опять же, вам не нужно беспокоиться об этом, если вы только обратитесь к VBA7 и правильно поместите LongPtr в все места, где должен появляться аргумент размером с указатель.

Таким образом, для рутинных вещей внутри вашего процесса и для взаимодействия с ОС и ее объектами вам не нужно беспокоиться о или вашей собственной или битовой ОС, и вы не ' Тоже нужна постоянная WIN64.


Теперь вы специально упоминаете получение и использование указателей, которые действительны для процессов с битовой разницей, отличной от вашей. Да, это может быть проблемой, но эта проблема не относится к VBA.

Если, как приложение VBA, вам нужно прочитать память произвольного процесса произвольной битности, вам нужно сравнить свою собственную битность с ее битностью. На этом этапе вы могли бы использовать константу WIN64, но в этом случае гораздо удобнее проверить Len(long_ptr_variable) во время выполнения, чем иметь отдельные ветви кода.

Проведя тест,

  • Если ваша битность выше, вы можете читать память другого процесса без ограничений.
  • Если ваша разрядность меньше, вы можете достичь виртуальной памяти большого парня настолько, насколько позволяет ваш 4-байтовый указатель.
    • И если вам нужно выйти за пределы этого, вам придется потерпеть неудачу ( или нет ).

Но учтите, что даже в этом случае вас не волнует ни битрейт ОС, ни константа WIN64! Вы заботитесь только о разрядности своего процесса по сравнению с разрядностью другого процесса.

...