Изменение текущего рабочего каталога cmd (из дочернего процесса) - PullRequest
0 голосов
/ 21 февраля 2020

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

Теперь, прежде чем этот пост будет помечен как дубликат: мне известно о этом и этом вопросе , который был задан в значительной степени именно для этой проблемы, но с использованием Linux вместо Windows, а также довольно широким и unspecifi c, и я знаю, что аналогичные ограничения применяются и к Windows (изменение рабочего каталога моего процесса не изменит рабочего каталога родителя).

На самом деле есть рабочий решение этого вопроса для linux. Однако для этого используется gdb, и я хотел бы решить эту задачу, используя только встроенные Windows утилиты (WinAPI, do tNET, et c. ).

То, что я пробовал до сих пор

Мне удалось использовать Cheat Engine и функции OpenProcess() / WriteProcessMemory() WinAPI для успешного переопределения рабочего каталога cmd. Однако это решение кажется неаккуратным и не работает хорошо (или, по крайней мере, требует дополнительной работы.)

Мой вопрос

Есть ли другое (может быть, проще?) путь на Windows чтобы этого добиться? Как способ вызвать / внедрить код в процесс cmd для непосредственного выполнения cd whatever\directory\I\want без переопределения его памяти? Я видел функции CreateRemoteThread(), но мне не удалось найти способ их использования.

К вашему сведению: я в основном использую C#, но решения на C / C ++ тоже должны помочь если они основаны на собственных библиотеках Microsoft.

Ответы [ 2 ]

0 голосов
/ 12 марта 2020

Я получил это работает. Как и предполагалось, SendInput наконец-то добился цели. Я использовал комбинацию вызовов WinAPI для GetForegroundWindow() / SetForegroundWindow() и метода Windows Forms System.Windows.Forms.SendKeys.SendWait(), чтобы добиться того, что я хотел:

После вызова моей программы cd -wrapper (sd.exe) ) и предоставляя мой пользовательский целевой каталог (~ / home), он генерирует соответствующую команду вместе с «Enter-Pressed-Event» для отправки его родительскому процессу cmd.

enter image description here

Вот полный C# код:

if (args.Length != 1)
{
    Console.WriteLine(Directory.GetCurrentDirectory());
    return;
}
string targetDirectory = args[0];
string command = string.Empty;
if (targetDirectory.Equals("~"))
{
    command = @"pushd C:\Users\fred\Desktop";
}
else if (!Directory.Exists(targetDirectory))
{
    Console.WriteLine("I/O Error: No such file or directory.");
    return;
}
else
{
    command = @"cd " + targetDirectory;
}
Target target = Target.Create(Process.GetCurrentProcess().GetParentProcess());
target.SendKeys(command + "{ENTER}", true);

Обратите внимание, что я вроде как начал писать полный Framework для этой и подобных проблем наряду с этим проектом, который содержит все мои разные Подходы к этому вопросу и низкоуровневые вызовы WinAPI, а также методы Extension для получения родительского процесса: D

Поскольку было бы немного излишним вставлять весь этот код в этот ответ, вот GitHub . Если я смогу найти время, я go опережу и оптимизирую код, но сейчас это подойдет. Надеюсь, это поможет любому, кто столкнулся с подобной проблемой:)

0 голосов
/ 21 февраля 2020

В этом посте описана реализация функции Windows, которая запускает дочерний процесс, создает каналы к stdin и stdout, из которых отправляется команда, и возвращается ответ. Наконец, как только все ответы получены, дочерний процесс завершается. Если это звучит знакомо, то в принципе это похоже на функцию Linux popen () , за исключением того, что эта реализация была специально создана для захвата ответа в буфер любой команды, которая возвращает один. (Также включен вариант для использования, когда не требуется или не требуется никакого ответа.)

Полный источник может быть адаптирован для использования в автономном исполняемом файле или в качестве API. (.dll) В любом случае, полученные функции принимают и обрабатывают любую команду, используя стандартный синтаксис Windows CMD. Функция cmd_rsp(...) возвращает ответ Windows через stdout в буфер для определения собственного размера.

Экспортированные прототипы:

int __declspec(dllexport) cmd_rsp(const char *command, char **chunk, unsigned int size);  
int __declspec(dllexport) cmd_no_rsp(const char *command);  

Простой вариант использования при получении ответа:

#include "cmd_rsp.h"
int main(void)
{
    char *buf = {0};
    buf = calloc(100, 1);//initialize to some initial size
    if(!buf)return 0;
    cmd_rsp("dir /s", &buf, 100);//buffer will grow to accommodate response as needed.
    printf("%s", buf);
    free(buf);

    return 0;
}

Простой вариант использования, когда ответ не требуется:

#include "cmd_rsp.h"
int main(void)
{
    cmd_no_rsp("cd C:\\dir1\\dir2");

    return 0;
}

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

Команда, чтобы перейти в каталог sqlite, а затем выполнить запрос:

cd c:\\tempExtract\\sqlite\\Tools\\sqlite-tools-win32-x86-3250300 && sqlite3.exe .\\extract.db \"select * from event, eventdata where eventType=38 and eventdata .eventid=event.eventid\

Команда для перехода в каталог teraterm, затем выполнить скрипт:

"c:\\Program Files (x86)\\teraterm\" && ttpmacro c:\\DevPhys\\LPCR_2\\play\\Play.ttl

Команда для изменения каталога, а затем выполнить команду для отправки нескольких настроек канала цифрового сбора.

cd C:\\Dir1\\Dir2\\Dir3\\support\\Exes\\WriteDigChannel && .\\WriteDigChannel.exe P1_CH0 1 &&  .\\WriteDigChannel.exe P1_C H0 0 &&  .\\WriteDigChannel.exe P1_CH0 1

Рекурсивный поиск в каталоге из указанного местоположения:

cd C:\\dir1\\dir2 && dir /s /b  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...