Как вы передаете параметры из сценария VBA в excel во внешний исполняемый файл (C#) в качестве аргументов?

У меня есть встроенная кнопка на листе Excel, которая вызывает сценарий VBA. В этом скрипте я читаю текущий каталог, анализирую и использую его для генерации значений для передачи аргументов string[] внешнему исполняемому файлу C#. Я прошел много итераций этого, и он действительно вызывает исполняемый файл, но похоже, что передаваемые параметры являются нулевыми (пустыми) при запуске С#.exe. Я могу использовать этот C# .exe в других программах и передавать аргументы, но этот сценарий VBA не работает должным образом. Я также знаю, что он передает правильное количество параметров, поскольку я не получаю исключение за пределы от C # .exe. В настоящее время я конвертирую все эти аргументы в строки, пытаясь устранить эту проблему, но, скорее всего, в этом нет необходимости. Код VBA прилагается:

Sub ButtonSG1b7_Click()

Dim FileLocation
Dim ProgramName
Dim length

FileLocation = ActiveWorkbook.FullName
length = Len(FileLocation) - 5
ProgramName = Left(FileLocation, length)
ProgramName = Right(ProgramName, 10)
length = Len(FileLocation) - 15
FileLocation = Left(FileLocation, length)
length = Len(FileLocation) - 2
FileLocation = Right(FileLocation, length)

MsgBox "File Location : " & FileLocation & "    Program Name: " & ProgramName

Dim str0 As String
Dim str1 As String
Dim str2 As String
Dim str3 As String
Dim str4 As String
Dim str5 As String
Dim str6 As String

str0 = "H:\StageGate\Administration\Scripts\GetLatestFileOpen.exe "
str1 = "H:"
str2 = FileLocation
str3 = "Common"
str4 = "\Market Feasibility "
str5 = ProgramName
str6 = ".xlsx"


MsgBox str0 & str1 & str2 & str3 & str4 & str5 & str6
Shell (str0 & str1 & str2 & str3 & str4 & str5 & str6)

End Sub

Изменить (добавление предварительного кода C#, включающего библиотеку Solidworks EPDM, которая принимает аргументы, преобразует их в список и использует этот список для предоставления строкового пути к файлу для получения последней версии в папке в хранилище EPDM, а затем открывает обновленную локальную копию файла .) :

using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using EPDM.Interop.epdm;

class Program
{
static void Main(string[] args)
{

    IEdmFolder5 ppoRetParentFolder;
    List<string> filePath = new List<string>(args);

    if (filePath.Any())
    {
        filePath.RemoveAt(0);  //really need to just stop having the script call passing this argument.
    }


    if (Directory.Exists(@"C:\StageGate")) {
        filePath.Insert(0,"C:");
    }
    else if (Directory.Exists(@"H:\StageGate"))
    {
        filePath.Insert(0,"H:");
    }
    else
    {
        MessageBox.Show("StageGate not found.");
    }

    string newFilePath = string.Join("", filePath.ToArray());
    filePath.RemoveAt(5);
    filePath.RemoveAt(4);
    filePath.RemoveAt(3);
    string folderPathstr = string.Join("", filePath.ToArray());
    //MessageBox.Show(folderPathstr);

    //Have to create vault object to work with BatchGet
    EdmVault5 vault = new EdmVault5();
    //Replace My_Vault with your vault name
    vault.LoginAuto("StageGate", 0);
    //Set the 2 here equal to how many folders you want to get (not counting subfolders)
    EdmSelItem[] folderArray = new EdmSelItem[1];
    IEdmBatchGet bg = (IEdmBatchGet)vault.CreateUtility(EdmUtility.EdmUtil_BatchGet);

    //Create and array element for eachf older you want to get, replace folder locations with your folders
    folderArray[0].mlDocID = 0;
    folderArray[0].mlProjID = vault.GetFolderFromPath(folderPathstr).ID;
    //fa[1].mlDocID = 0;
    //fa[1].mlProjID = vault.GetFolderFromPath("C:\\My_Vault\\FolderPath").ID;

    bg.AddSelection(vault, folderArray);
    bg.CreateTree(0, (int)EdmGetCmdFlags.Egcf_IncludeAutoCacheFiles);  //Egcf_IncludeAutoCacheFiles will get latest version of file
    bg.GetFiles(0, null);

    if (File.Exists(newFilePath))
    {

        Process process = Process.Start(newFilePath); //can't just open the file.  Need to create new windows process to have the file open in the default application(process)
        //File.Open(newPath, FileMode.Open);
    }
    else
    {
        MessageBox.Show("File not found.");
    } 

person Sherd    schedule 24.04.2015    source источник
comment
Поскольку во втором параметре есть пробел, вы пытались использовать ' по обе стороны строки, чтобы указать его как один аргумент вместо двух (или больше, в зависимости от пробелов)?   -  person Ron Beyer    schedule 24.04.2015
comment
Мне нужно, чтобы сценарий передал 6 аргументов, поскольку именно этого ожидает программа на С#. Указание его в качестве одного аргумента приводит к тому, что исполняемый файл C# выдает исключение System.OutofRange. Мне пришлось написать сценарий таким образом, поскольку используемое хранилище EPDM не включает способ форматирования моих аргументов в одну строку, поэтому я передаю 6 необходимых переменных.   -  person Sherd    schedule 25.04.2015
comment
В любом случае, все, что содержит пробел, должно быть экранировано. Например, \Market Feasability будет интерпретироваться как два аргумента, а не как один.   -  person Ron Beyer    schedule 25.04.2015


Ответы (1)


Прочитав ваш код C#, я вижу, что ваш код ожидает как минимум 6 аргументов.

Этот код VBA экранирует любые пробелы, которые могут появиться в вашем пути, и передает их в качестве аргументов командной строки:

Sub ButtonSG1b7_Click()

Dim FileLocation
Dim ProgramName
Dim length

FileLocation = ActiveWorkbook.FullName
length = Len(FileLocation) - 5
ProgramName = Left(FileLocation, length)
ProgramName = Right(ProgramName, 10)
length = Len(FileLocation) - 15
FileLocation = Left(FileLocation, length)
length = Len(FileLocation) - 2
FileLocation = Right(FileLocation, length)

MsgBox "File Location : " & FileLocation & "    Program Name: " & ProgramName

Dim args(0 To 6) As String
Dim cmdln As String, i as Integer

args(0) = "H:\StageGate\Administration\Scripts\GetLatestFileOpen.exe"
args(1) = "H:"
args(2) = FileLocation
args(3) = "Common"
args(4) = "\Market Feasibility "
args(5) = ProgramName
args(6) = ".xlsx"

cmdln=arg(0)
For i = 1 To 6
cmdln=cmdln & " """ & args(i) & """"
Next i
MsgBox "VBA Code Writes: " & cmdln
Shell (cmdln)

End Sub

Теперь ваш код С# должен прочитать эти параметры:

class Program
{
static void Main(string[] args)
{
Console.WriteLine("C# Code Reads: "+String.Join(" ", args));
}
}

Если 2 процесса возвращают одну и ту же строку командной строки, то любые исключения, которые могут возникнуть в следующих строках, не связаны с обменом данными VBA-C#.

person Uri Goren    schedule 24.04.2015
comment
Это заставляет меня теперь выдавать ошибку System.ArgumentOutOfRange вместо нулевой ошибки. Я отредактирую исходный пост, включив в него код С#. - person Sherd; 25.04.2015
comment
это огромный шаг вперед :-) - person Uri Goren; 25.04.2015
comment
Если этот ответ был полезен, пожалуйста, примите ответ или хотя бы проголосуйте за него. - person Uri Goren; 25.04.2015
comment
Извините, ушел с работы и не успел это проверить. Я обязательно проголосую, когда получу еще несколько очков репутации, и проверю как ответ, как только смогу проверить! - person Sherd; 25.04.2015
comment
Пришлось внести некоторые изменения в структуру расположения файлов, но она работает. Одна из причин, по которой я переместил это во внешний скрипт на листе Excel, заключалась в том, что вы не можете открыть другой файл Excel внутри Excel. Внешний скрипт C# отлично подходит для этого. Ценю твою помощь! Если вы получите представителя, проголосуйте за мой вопрос. Я хотел бы получить еще 5, чтобы иметь возможность голосовать за других! - person Sherd; 27.04.2015