справочник по операторам объявления vba для API Win32 - PullRequest
0 голосов
/ 30 мая 2020

Вопросы о том, как вызывать Win32 API из VBA, задавались много раз раньше, но я искал и не могу найти ответы, которые ищу.

Я хотел бы узнать, как to fi sh!

То есть, мне нужно общее руководство о том, как писать операторы объявления VBA для использования произвольных API Win32. Это не список заявлений объявления для некоторого выбора API Win32 (который, вероятно, не включает API, который я ищу сейчас, или тот, который я буду искать через шесть месяцев).

Общее Guide научит меня, как обрабатывать разные типы данных C / Win32. Как для 32-битного, так и для 64-битного офиса.

Этот топ c на , адаптирующий VBA для 64-битного офиса , полезен в этом, например, он говорит мне, что я могу использовать LongPtr и 32-разрядная или 64-разрядная версия Office адаптируют это соответствующим образом. Но это полезно только в том случае, если я знаю, когда для 32-разрядной версии требуется Long.

Этот VB. Net topi c говорит, что «как все» не поддерживается. Но это VB. Net, а не VBA. Я так понимаю, что «Любой» по-прежнему подходит для VBA. Но когда я его использую? Для API, которые принимают VOID? Или pVOID? или LPVOID?

В качестве конкретного c примера путаницы мне нужно адаптировать это объявление:

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSrc As Any, ByVal ByteLen As Long)

Per MSDN , последний параметр - SIZE_T :

void CopyMemory(
_In_       PVOID  Destination,
_In_ const VOID   *Source,
_In_       SIZE_T Length
);

Я видел, как некоторые адаптации для 64-битного Office оставляют это в объявлении как ByVal ... As Long, но другие меняют его на LongPtr. Я не знаю, что правильно.

И я действительно не хочу зависать при неудачном вызове ядра.

Кто-нибудь знает хорошее общее руководство на этом материале, который говорит вам, что вам нужно знать, чтобы выяснить, как следует обрабатывать любой Win32 API?

1 Ответ

0 голосов
/ 01 июня 2020

общее руководство по написанию операторов объявления VBA для использования произвольных Win32 API.

Вот как я это делаю.

I go to https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types и найдите нужный мне тип данных ( Ctrl + F ).
Если он определен в терминах другого типа с той же страницы, Я тоже ищу это ( Ctrl + F ), пока не приду к типу basi c.
Затем я использую тип подходящего размера из VB. int - это Long, short - Integer, char* - String, wchar_t* - LongPtr, где вам нужно передать StrPtr, void* - LongPtr.

Я так понимаю, что «As Any» по-прежнему подходит для VBA. Но когда я его использую? Для API, которые принимают VOID? Или pVOID? или LPVOID?

As Any полезно, когда

  • вы не хотите объявлять фактический тип, который он получает (например, это сложная структура, параметр является необязательным , и вы его не используете)
  • Там может быть несколько разных вещей, которые могут быть переданы туда, и вы хотите передать их все в разных точках

В противном случае это всегда возможно, безопасно и правильно повторно объявить As Any с использованием фактического типа, указанного в заголовке API. Часто это указатель ByVal LongPtr.

Сохранение As Any накладывает больше ответственности на вызывающего, но дает им больше гибкости. Повторное объявление As Any как фактического типа устраняет опасность за счет указанной гибкости.

CopyMemory - прекрасный пример этого принципа.
Объявление pDest As Any, pSrc As Any является наиболее гибким и может использоваться как:

Dim a As Long, b As Long

CopyMemory a, b, ...                             ' Copying from variable b to a (a = b)
CopyMemory ByVal VarPtr(a), ByVal VarPtr(b), ... ' Same
Dim a As LongPtr, b As LongPtr

CopyMemory ByVal a, ByVal b, ...   ' Copying from memory pointed to by b to memory pointed to by a

, что является гибким, но при неправильном использовании:

Dim a As Long, b As Long

CopyMemory ByVal a, ByVal b, ...  ' Wrong: passing values as pointers; likely memory access violation
CopyMemory VarPtr(a), VarPtr(b), ... ' Wrong: passing pointers to pointers;
                                     ' Overwrites the temporary storage VB provides
                                     ' No crash, but no meaningful copying either
Dim a As LongPtr, b As LongPtr

CopyMemory a, b, ...              ' Likely wrong: copying the pointer value of b into a (a = b)

вы можете взломать sh и / или повредить data.

Объявив те же параметры, что и ByVal pDest As LongPtr, ByVal pSrc As LongPtr, вы теряете возможность передавать Long s ByRef, как в первом примере, и вам нужно будет явно использовать VarPtr каждый раз, но вы выиграли ' Не нужно слишком много думать, как вызвать функцию. Тем не менее, есть некоторая опасность, потому что вы все равно можете называть его CopyMemory a, b с параметрами Long, и он будет сканировать sh для передачи значений в качестве указателей, но, по крайней мере, вы увидите из определения функции, что вы передаете что-то не так, а As Any не подскажет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...