Автоматизация процедуры MS Access VBA - назначьте строковую переменную для InputBox

Я пытаюсь автоматизировать на первый взгляд очень простую задачу через C# - передать строковое значение в inputBox, вызываемый через функцию VBA.

Для этого я использовал Visual C# .NET Automation Client для создания экземпляра MS Access и открытия необходимой базы данных:

using System.Management.Automation;
using Access = Microsoft.Office.Interop.Access;

Access.Application oAccess = new Access.Application();
        oAccess.Visible = true;
        oAccess.OpenCurrentDatabase("D:\\path\\to\\database", false, "");
      

В упомянутой базе данных у нас есть макрос, который вызывает функцию VBA через действие «RunCode». Затем этот public Function вызывает другой private Sub:

Public Function ImportMappingDatabases()
  ImportMappings InputBox("Specify Path", "Path", mstrcDefaultPath), _
    InputBox("Choose Package", "Package", "")
End Function

Private Sub ImportMappings(Optional Path As String = mstrcDefaultPath, Optional Package As String = "")

Вот где я застрял. Поле ввода с заголовком «Path» хочет, чтобы пользователь ввел определенный путь, который более поздний код использует по причинам, которые не нужно объяснять. То же самое относится и к полю ввода с заголовком «Package». Я предполагаю, что есть способ "передать" строковое значение из кода С# в поле ввода поля ввода, но я не знаю, как обратиться к полю ввода и установить значение. После этого от пользователя требуется нажать кнопку «ОК» или «Отмена», применяется тот же вопрос, я попытаюсь обобщить его в 1 предложении:

Как получить ссылку на это поле ввода, установить значение ввода и «щелкнуть» одну из кнопок?

Больше информации:

Я вызываю публичную функцию через: oAccess.Run("ImportMappingDatabases");

Я не могу изменить функции/подпрограммы VBA.

Обновление 1:

Проверьте мой ответ ниже.

Я думаю, вам нужно будет использовать вызовы Win API для заполнения полей ввода.

Tim Williams 21.12.2020 19:22

Жаль, что нельзя изменить VBA Sub. Если бы у Sub был аргумент, значение можно было бы передать аргументу через Run. По крайней мере, я могу в VBScript, так что предположим, что C# тоже может. oAccess.Run "ImportMappingDatabases", varInput; Макросы не использую.

June7 21.12.2020 20:22

Вы не пытаетесь использовать потребление и автоматизацию объектов, а пытаетесь эмулировать клавиатуру - и это не очень практично. Это очень похоже на попытку очистить веб-сайт и ввести значения — сложно, подвержено ошибкам и не так уж надежно. Если общедоступная подпрограмма (для функции) была создана в VBA, вы можете использовать + вызывать + использовать эту подпрограмму VBA. Но такие подпрограммы не могут запрашивать у пользователя ввод с клавиатуры, так как теперь вам нужно использовать нажатия клавиш для эмуляции нажатий клавиш. Вы больше не можете делать это, а затем использовать программу .net как класс, которому требуется ввод с клавиатуры консоли.

Albert D. Kallal 21.12.2020 21:43

@TimWilliams Можете ли вы предоставить какой-либо ресурс, указывающий мне правильное направление, пожалуйста? .

l000p 22.12.2020 08:59

@AlbertD.Kallal В этом конкретном случае мы получаем «нажатия клавиатуры» в виде автоматически сгенерированного массива строк, который впоследствии можно использовать для ввода, что является лишь частью шагов, которые ранее выполнялись вручную и, как вы догадались, - очень подвержен ошибкам. Попытка здесь состоит в том, чтобы использовать то, что у нас есть, в качестве устаревшего кода — у владельца программного обеспечения все еще нет разрешения на прикосновение к VBA.

l000p 22.12.2020 08:59
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
195
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел способ получить дескриптор inputBox и способ передать ему строковое значение. Вам нужен следующий импорт:

[DllImport("User32.dll", CharSet = CharSet.Auto)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("User32.dll", CharSet = CharSet.Auto)] static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter,
                                                                           string lpcClassName, string lpcWindowTitle);
[DllImport("User32.dll", CharSet = CharSet.Auto)] static extern UInt32 SendMessage(IntPtr handle, UInt32 message,
                                                                                           IntPtr wParam, string lParam);

Затем вы можете использовать вызовы Win API, чтобы найти окно MS Access и дескрипторы окна inputBox:

IntPtr parent = FindWindow(null, "The access Window title here");
IntPtr childInputBox = IntPtr.Zero;
IntPtr TextBox = IntPtr.Zero;
if (parent != IntPtr.Zero)
{
   childInputBox = FindWindowEx(parent, IntPtr.Zero, string.Empty, "InputBox name here");
  if (childInputBox != IntPtr.Zero)
  {
    TextBox = FindWindowEx(childInputBox, IntPtr.Zero, "Edit", 
    string.Empty);
    if (TextBox != IntPtr.Zero)
    {
      SendMessage(TextBox, WM_SETTEXT, new IntPtr(0), "Your out string to the input here");
    }
  }
}

Здесь я наткнулся на стену, потому что на самом деле мне нужно вызвать свой макрос, прежде чем я попытаюсь захватить ручку. Итак, вызов макроса с помощью:

oAccess.Run("TheNameOfTheMacro");

Будет запускать его в том же потоке, поэтому наше приложение Window Forms станет непригодным для использования, пока макрос не будет выполнен. Это усложнение привело к тому, что я получил разрешение на расширение кода VBA с помощью общедоступной функции, принимающей строку в качестве параметра (как обсуждалось в комментариях), и продолжил оттуда. Если вы когда-нибудь решите, что вам нужно использовать поле ввода, вам нужно запустить макрос в другом потоке и каким-то образом проверить, «вызвано ли» поле ввода, если да, то отправьте сообщение.

Другие вопросы по теме