Процесс (родитель) запускает другой процесс (дочку). Дочка должна вызвать функции родителя. Как это сделать оптимальнее всего? Под оптимальностью я подразумеваю высокую скорость, т.е. минимальные задержки (и желательно чтобы разброс этих задержек был тоже минимален, т.е. если при первом вызове мы потратили 1000 тактов, то при втором – тоже ≈1000). Короче, нужно сделать что-то типа небольшого API для дочки. При этом родитель, в принципе, свободен и может заниматься только (ну или почти только) обработкой API. Когда дочка вызывает функцию родителя, она должна остановиться и дождаться завершения работы этой функции родителя. Для дочки весь этот процесс должен быть максимально простым, в идеале – через 1-2 вызова WinAPI, безо всяких там поисков процесса родителя, затем OpenProcess и прочей бодяги. Если будет передача параметров и возвращаемое значение, будет замечательно, но это не критично. Важнее всего просто тупо запуск функции. И ещё: можно ли (и как) запустить дочерний процесс с своём адресном пространстве (и тогда каким-то простым способом получить адрес "главной" API-функции родителя и вызывать его через call)? p.s. Да, можно сделать не через запуск, а просто создать DLL-ку и подцепить её к дочке, и там уже использовать в лёгкую, но мне надо именно через запуск а-ля CreateProcess.
Не пользовался никогда. Как я понял, функция запускает код, который находится в стороннем (remote) процессе, так? Т.е. дочерний процесс может запустить так функцию родителя. Но надо же ещё адрес этой функции передать как-то дочке. Коду передаётся указатель. А как он получит доступ к данным по переданному адресу, когда эти данные находятся в другом процессе (адресном пространстве)?
Так. Через lpParameter Перед созданием потока в дочернем процессе должна быть выделена область памяти для этих нужд через VirtualAllocEx, заполнить ее если надо данными через WriteProcessMemory, ну и далее по плану.
Jin X, > Дочка должна вызвать функции родителя. Не корректная и не понятная постановка задачи. Выполнение кода в чужом адресном пространстве невозможно. Процессор выполняет код в течении кванта лишь в одном ап. Всё множество способов удалённого исполнения кода основано на IPC, есть даже штатные апи, типо RtlRemoteCall(). Опишите вопрос понятным образом. Обычно подобные проблемы упираются в защиту.
Fail, CFG это примитивный механизм защиты, если вы будите вызывать описанные в карте адреса, то проблем конечно не возникнет. Да и однозначно на ваш вопрос ответить нельзя - есть куча механизмов защиты, а помимо их у меня давно свои разработки, так что я начинаю в них путаться, так как память о них становится не важной и они забываются, когда есть более общие методы.
Indy_, ты обсуждаешь кфг, с человеком, который не использовал CreateRemoteThread ... Jin X, читни рихтера, там целая глова норм языком описана, про удаленный поток. либо ипс замути на шаренной памяти/пайпах, на это наврени рпц уже. грузить пе в твоем случае не вариант вообще
Jin X, COM заюзай, там все уже реализовано. Флаг CLSCTX_LOCAL_SERVER как раз для этого - когда объект создается и существует в одном процессе, а методы интерфейса дергаются в другом. Система сама займется передачей данных между процессами и синхронизацией.
Спасибо за множество вариантов, но как-то всё усложнили, ИМХО Задача была сделать всё максимально просто (для дочки), при этом очень быстро (в плане вызова). Но ощущение, что совсем просто это сделать не получится (да и что быстро – не факт). Короче говоря, достичь уровня простоты и скорости, приближённых к вызову DLL-функций, как я понял, надежды мало. p.s. А так, можно же у родителя создать окно, а дочка делает FindWindow и потом тупо SendMessage(WM_USER+). Куда уж проще? Но вряд ли это будет достаточно быстро (не замерял, правда).
COM же, ну Он для этого и проектировался. Более того, родитель может быть не просто в другом процессе, а в другом процессе на другом компе в другой стране и для дочки это будет так же просто, как вызвать функцию DLL. WM_USER просто передаст wParam и lParam как есть, т.е. если в последнем передашь указатель на структуру или строку, то в другой процесс дойдет только указатель, но не сами данные. WM_COPYDATA надо юзать для передачи чего-либо кроме двордов через оконные сообщения между процессами.
Jin X, Самый эффективный механизм это нэйтив lpc. Пайпы слишком тормозные, что бы говорить про профайл. lpc мощный механизм, но если сравнить со своей реализацией, то тоже не фонтан". Межпроцессный синхронный обмен данными можно элементарно построить на быстрых синхронизациях и разделяемой памяти.
RtlRemoteCall , да она так же работает, как и обычное внедрение. NTSTATUS NTAPI RtlRemoteCall( IN HANDLE Process, IN HANDLE Thread, IN PVOID CallSite, IN ULONG ArgumentCount, IN PULONG Arguments, IN BOOLEAN PassContext, IN BOOLEAN AlreadySuspended ); NtSuspendThread - >NtWriteVirtualMemory-> NtSetContextThread->NtResumeThread
Для чего создавать окно? Можно через PostThreadMessage послать очереди сообщений потока, но это асинхронная функция. Используя WaitForSingleObject можно сделать синхронный вызов через PostThreadMessage и QueueUserApc. Передать адрес функции можно через командную строку, переменные среды, пайпы и т.д. Используя маршалинг можно сделать вообще как обычный вызов метода COM. Также можно юзать RPC, вот пример
Можно сделать вручную через объекты-события для синхронизации. Вот небольшой пример "вызова" функции из процесса родителя (без проверок ошибок): Родитель: Code (C++): void foo(); struct tSharedMem { HANDLE hEvents[2]; }; int _tmain(int argc, _TCHAR* argv[]) { HANDLE hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(tSharedMem), L"mymap"); tSharedMem *pShared = (tSharedMem*)MapViewOfFile(hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(tSharedMem)); SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; pShared->hEvents[0] = CreateEvent(&sa, FALSE, FALSE, NULL); pShared->hEvents[1] = CreateEvent(&sa, FALSE, FALSE, NULL); STARTUPINFO si; PROCESS_INFORMATION pi; GetStartupInfo(&si); CreateProcess(L"child.exe", NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); BOOL bState = TRUE; while (bState) { switch (SignalObjectAndWait(pShared->hEvents[0], pShared->hEvents[1], INFINITE, FALSE)) { case WAIT_OBJECT_0: foo(); break; default: std::cout << "an error occured\r\n"; bState = FALSE; } } CloseHandle(pShared->hEvents[1]); CloseHandle(pShared->hEvents[0]); UnmapViewOfFile(pShared); CloseHandle(hMap); return 0; } void foo() { std::cout << "called from other process\r\n"; } Дочерний процесс каждую секунду вызывает foo (тоже без проверок, демонстрационный вариант): Code (C++): struct tSharedMem { HANDLE hEvents[2]; }; int _tmain(int argc, _TCHAR* argv[]) { HANDLE hMap = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, L"mymap"); tSharedMem *pShared = (tSharedMem*)MapViewOfFile(hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(tSharedMem)); while (true) { Sleep(1000); // Вызываем функцию из родительского процесса каждую секунду SignalObjectAndWait(pShared->hEvents[1], pShared->hEvents[0], INFINITE, FALSE); } return 0; }
И разве это будет работать быстро??? И разве это предельно просто? В том-то и дело, что асинхронная. А используя окно можно сделать просто через SendMessage. Что проще? Ну, вообще я думал об этом, только не через FileMapping, а используя именные Event'ы, хотя shared memory всё равно пригодится, чтобы передавать параметры или тупо номер функции. Ну или запускать разные функции, используя несколько Event'ов, ожидая их в родительской проге через WaitForMultipleObjects. Вариант с COM интересен, но опять же, это не 2 строчки кода для дочки, а описание интерфейса (особенно приятно делать его в MASM32) + всякие там CoInitialize, CoCreateInstance... Хотя, бесспорно очень универсальный вариант. Но будет ли это работать быстро при межпроцессовом взаимодействии? Читаю "LPC", думаю: "Что это?" Какой именно Native IPC? Конкретный вариант, плиз. Типа того, что привёл Thetrik? Ещё раз повторюсь, что простота (причём, предельная простота, буквально из пары строк) – это важнейший критерий. И скорость тоже. Короче, надо померить скорость SendMessage, пока что это самое простое...
Каким образом система поймёт, что это указатель и сколько нужно передать данных? Каковы при этом накладные расходы (скорость)?