Мне нужно запустить exe-приложение в качестве фонового процесса в Windows Xp, используя C / api [duplicate]

Новые кодеры иногда пишут такой код:

my_calculator.button_0 = tkinter.Button(root, text=0)
my_calculator.button_1 = tkinter.Button(root, text=1)
my_calculator.button_2 = tkinter.Button(root, text=2)
...

Затем кодер остается с кучей именованных переменных с усилием кодирования O ( m * n ), где m - это число именованных переменных, а n - это количество раз, к которому необходимо получить доступ к группе переменных (включая создание) , Более проницательный новичок отмечает, что единственная разница в каждой из этих строк - это число, которое изменяется на основе правила и решает использовать цикл. Тем не менее, они зациклились на том, как динамически создавать эти имена переменных, и могут попробовать что-то вроде этого:

for i in range(10):
    my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)

Вскоре они обнаруживают, что это не сработает.

Если программа требует произвольных переменных «имена», лучше всего подходит словарь, как объясняется в других ответах. Однако, если вы просто пытаетесь создать много переменных, и вы не возражаете ссылаться на них с последовательностью целых чисел, вы, вероятно, ищете list. Это особенно верно, если ваши данные однородны, например, ежедневные показания температуры, еженедельные оценки викторины или сетка графических виджета.

Это можно собрать следующим образом:

my_calculator.buttons = []
for i in range(10):
    my_calculator.buttons.append(tkinter.Button(root, text=i))

Этот list также может быть создан в одной строке с пониманием:

my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]

Результат в любом случае - это заполненный list, с первым элементом, к которому обращаются с помощью my_calculator.buttons[0], следующего с my_calculator.buttons[1] и т. д. Имя переменной «base» становится именем list, и для доступа к нему используется различный идентификатор.

Наконец, не забудьте другие структуры данных, такие как set - это аналогично словарю, за исключением того, что каждое «имя» не имеет привязанного к нему значения. Если вам просто нужна «сумка» объектов, это может быть отличным выбором. Вместо этого:

keyword_1 = 'apple'
keyword_2 = 'banana'

if query == keyword_1 or query == keyword_2:
    print('Match.')

У вас будет следующее:

keywords = {'apple', 'banana'}
if query in keywords:
    print('Match.')

Используйте последовательность list для последовательности похожих объектов, a set для произвольного - помещенный пакет предметов или dict для мешка с именами со связанными значениями.

108
задан rlbond 12 June 2009 в 07:36
поделиться

11 ответов

Cygwin имеет полнофункциональную функцию fork () в Windows. Таким образом, если использование Cygwin приемлемо для вас, тогда проблема решается в том случае, если производительность не является проблемой. В противном случае вы можете посмотреть, как Cygwin реализует fork (). Из довольно старой архитектуры Cygwin doc :
5.6. Создание процесса Вызов fork в Cygwin особенно интересен, поскольку он плохо отображается поверх Win32 API. Это очень затрудняет правильную реализацию. В настоящее время ветвь Cygwin является реализацией без копирования при записи, аналогичной той, что была в ранних версиях UNIX. Первое, что происходит, когда родительский процесс разветвляется на дочерний процесс, - это то, что родительский процесс инициализирует пробел в таблице процессов Cygwin для дочернего элемента. Затем он создает приостановленный дочерний процесс с помощью вызова Win32 CreateProcess. Затем родительский процесс вызывает setjmp для сохранения своего собственного контекста и устанавливает указатель на него в области общей памяти Cygwin (общей для всех задач Cygwin). Затем он заполняет дочерние разделы .data и .bss, копируя из своего собственного адресного пространства в приостановленное дочернее адресное пространство. После инициализации адресного пространства дочернего объекта дочерний процесс запускается, пока родительский объект ожидает мьютекса. Ребенок обнаруживает, что он разветвлен и выполняет прыжки в длину с использованием сохраненного буфера перехода. Затем дочерний объект устанавливает мьютекс, на котором ожидает родительский элемент, и блокирует другой мьютекс. Это сигнал для родителя скопировать свой стек и кучу в дочерний элемент, после чего он освобождает мьютекс, которого ожидает дочерний элемент, и возвращается из вызова fork. Наконец, ребенок выходит из режима блокировки последнего мьютекса, воссоздает все отображенные в памяти области, переданные ему через общую область, и возвращается из самого форка. Хотя у нас есть некоторые идеи относительно того, как ускорить работу В нашей реализации fork за счет уменьшения количества переключений контекста между родительским и дочерним процессами fork почти наверняка будет неэффективным в Win32. К счастью, в большинстве случаев порожденное семейством вызовов, предоставляемое Cygwin, можно заменить пару fork / exec с небольшими усилиями. Эти вызовы отображаются чисто поверх Win32 API. В результате они намного эффективнее. Изменение программы драйвера компилятора для вызова spawn вместо fork было тривиальным изменением и увеличило скорость компиляции на двадцать-тридцать процентов в наших тестах. Однако spawn и exec представляют свои собственные трудности. Поскольку в Win32 нет никакого способа сделать настоящий exec, Cygwin должен изобрести свои собственные идентификаторы процессов (PID). В результате, когда процесс выполняет несколько вызовов exec, будет несколько PID Windows, связанных с одним PID Cygwin. В некоторых случаях заглушки каждого из этих процессов Win32 могут задерживаться, ожидая выхода из своего exec'd процесса Cygwin. Звучит как большая работа, не так ли? И да, это slooooow. РЕДАКТИРОВАТЬ: документ устарел, пожалуйста, посмотрите этот отличный ответ для обновления
74
ответ дан Community 5 November 2018 в 09:41
поделиться
  • 1
    Это хороший ответ, если вы хотите написать приложение Cygwin для Windows. Но в целом это не лучшее, что нужно сделать. По сути, модели процессов и потоков * nix и Windows совершенно разные. CreateProcess () и CreateThread () являются в целом эквивалентными API – Foredecker 13 June 2009 в 05:08
  • 2
    Разработчики должны помнить, что это неподдерживаемый механизм, и IIRC действительно склонен нарушать всякий раз, когда какой-либо другой процесс в системе использует внедрение кода. – Harry Johnston 6 April 2014 в 03:33
  • 3
    Другая ссылка на реализацию больше не действительна. – PythonNut 27 November 2014 в 19:28
  • 4
    Отредактировано, чтобы оставить только другую ссылку ответа – Laurynas Biveinis 28 November 2014 в 06:14
  • 5
    @Foredecker, на самом деле вы [g1] не должны этого делать [/g1], даже если вы пытаетесь написать «приложение cygwin». Он пытается имитировать
    function isSameObject(objectA, objectB) {
       unique_ref = "unique_id_" + performance.now();
       objectA[unique_ref] = true;
       isSame = objectB.hasOwnProperty(unique_ref);
       delete objectA[unique_ref];
       return isSame;
    }
    
    object1 = {something:true};
    object2 = {something:true};
    object3 = object1;
    
    console.log(isSameObject(object1, object2)); //false
    console.log(isSameObject(object1, object3)); //true
    
    Unix, но выполняет это с помощью

    неплотного решения

    , и вы должны быть готовы к неожиданным ситуациям.
    – Pacerier 13 August 2015 в 11:11

Я, конечно, не знаю подробностей об этом, потому что я никогда не делал этого, но родной NT API имеет возможность разветвлять процесс (подсистема POSIX в Windows нуждается в этой возможности - я не уверен, что подсистема POSIX поддерживается даже больше).

Поиск ZwCreateProcess () должен содержать дополнительную информацию - например, этот бит информации от Максима Шацких :

Самым важным параметром здесь является SectionHandle. Если этот параметр равен NULL, ядро ​​перекроет текущий процесс. В противном случае этот параметр должен быть дескриптором объекта раздела SEC_IMAGE, созданного в EXE-файле, перед вызовом ZwCreateProcess ().

Хотя обратите внимание, что Коринна Виншен указывает, что Cygwin обнаружил использование ZwCreateProcess ( ) еще ненадежный :

Iker Arizmendi писал (а):

> Because the Cygwin project relied solely on Win32 APIs its fork
> implementation is non-COW and inefficient in those cases where a fork
> is not followed by exec.  It's also rather complex. See here (section
> 5.6) for details:
>  
> http://www.redhat.com/support/wpapers/cygnus/cygnus_cygwin/architecture.html

Этот документ довольно старый, 10 лет или около того. Хотя мы все еще используем вызовы Win32 для эмуляции fork, метод изменился заметно. В частности, мы больше не создаем дочерний процесс в приостановленном состоянии, если только конкретные данные не нуждаются в специальной обработке в родительском элементе, прежде чем они будут скопированы в дочерний. В текущем выпуске 1.5.25 единственный случай для дочернего ребенка - открытые сокеты в родительском. Предстоящая версия 1.7.0 вообще не будет приостановлена.

Одна из причин не использовать ZwCreateProcess заключалась в том, что до версии 1.5.25 мы по-прежнему поддерживаем пользователей Windows 9x. Однако две попытки использовать ZwCreateProcess для систем на базе NT потерпели неудачу по той или иной причине.

Было бы очень хорошо, если бы этот материал был бы лучше или вообще документирован, особенно пара данных и как подключите процесс к подсистеме. Хотя fork не является концепцией Win32, я не вижу, что было бы плохо сделать fork проще.

54
ответ дан Community 22 August 2018 в 12:14
поделиться
  • 1
    Это хороший ответ, если вы хотите написать приложение Cygwin для окон. Но в целом это не самое лучшее. По сути, модели обработки файлов и потоков * nix и Windows совершенно разные. CreateProcess () и CreateThread () являются обычно эквивалентными API – Foredecker 13 June 2009 в 05:08
  • 2
    Interix доступен в Windows Vista Enterprise / Ultimate как «Подсистема для UNIX-приложений»: ru.wikipedia.org/wiki/Interix – bk1e 13 June 2009 в 19:03
  • 3
    @Foredecker - это может быть неправильный ответ, но CreateProcess () / CreateThread () также может быть ошибочным. Это зависит от того, хотите ли вы «способ Win32 делать вещи» или «как можно ближе к семантике fork ()». CreateProcess () ведет себя значительно по-другому, чем fork (), поэтому Cygwin необходимо много работать для его поддержки. – Michael Burr 13 June 2009 в 19:29
  • 4
    @jon: Я попытался исправить ссылки и скопировать соответствующий текст в ответ (так что будущие неработающие ссылки не являются проблемой). Тем не менее, этот ответ достаточно давно, что я не на 100% уверен, что цитата, которую я нашел сегодня, - это то, о чем я говорил в 2009 году. – Michael Burr 20 July 2013 в 00:31
  • 5
    @Michael Burr: Спасибо! Всегда хорош для архивных целей. – Jonathan Baldwin 20 July 2013 в 01:30
  • 6
    Разработчики должны иметь в виду, что это неподдерживаемый механизм, и IIRC действительно склонен к разрыву, когда какой-либо другой процесс в системе использует инъекцию кода. – Harry Johnston 6 April 2014 в 03:33
  • 7
    Если люди хотят & quot; fork с немедленным exec ", то, возможно, CreateProcess является кандидатом. Но fork без exec часто бывает желательным, и это то, что водители люди просят реального fork. – Aaron McDaid 16 October 2014 в 18:56
  • 8
    Другая ссылка на реализацию больше не действительна. – PythonNut 27 November 2014 в 19:28
  • 9
    Отредактировано, чтобы оставить ссылку другого ответа только – Laurynas Biveinis 28 November 2014 в 06:14
  • 10
    Печальная история подсистемы Microsoft POSIX также была довольно интересной для Interix. – Roman Starkov 9 May 2015 в 13:27
  • 11
    @Foredecker, на самом деле вы не должны этого делать , даже если вы пытаетесь написать «приложение cygwin». Он пытается имитировать fork Unix, но он выполняет это с помощью негерметичного решения , и вы должны быть готовы к непредвиденным ситуациям. – Pacerier 13 August 2015 в 11:11

Люди пытались реализовать fork в Windows. Это самая близкая вещь, которую я могу найти:

Снято с: http://doxygen.scilab.org/5.3/d0/d8f/forkWindows_8c_source.html#l00216

static BOOL haveLoadedFunctionsForFork(void);

int fork(void) 
{
    HANDLE hProcess = 0, hThread = 0;
    OBJECT_ATTRIBUTES oa = { sizeof(oa) };
    MEMORY_BASIC_INFORMATION mbi;
    CLIENT_ID cid;
    USER_STACK stack;
    PNT_TIB tib;
    THREAD_BASIC_INFORMATION tbi;

    CONTEXT context = {
        CONTEXT_FULL | 
        CONTEXT_DEBUG_REGISTERS | 
        CONTEXT_FLOATING_POINT
    };

    if (setjmp(jenv) != 0) return 0; /* return as a child */

    /* check whether the entry points are 
       initilized and get them if necessary */
    if (!ZwCreateProcess && !haveLoadedFunctionsForFork()) return -1;

    /* create forked process */
    ZwCreateProcess(&hProcess, PROCESS_ALL_ACCESS, &oa,
        NtCurrentProcess(), TRUE, 0, 0, 0);

    /* set the Eip for the child process to our child function */
    ZwGetContextThread(NtCurrentThread(), &context);

    /* In x64 the Eip and Esp are not present, 
       their x64 counterparts are Rip and Rsp respectively. */
#if _WIN64
    context.Rip = (ULONG)child_entry;
#else
    context.Eip = (ULONG)child_entry;
#endif

#if _WIN64
    ZwQueryVirtualMemory(NtCurrentProcess(), (PVOID)context.Rsp,
        MemoryBasicInformation, &mbi, sizeof mbi, 0);
#else
    ZwQueryVirtualMemory(NtCurrentProcess(), (PVOID)context.Esp,
        MemoryBasicInformation, &mbi, sizeof mbi, 0);
#endif

    stack.FixedStackBase = 0;
    stack.FixedStackLimit = 0;
    stack.ExpandableStackBase = (PCHAR)mbi.BaseAddress + mbi.RegionSize;
    stack.ExpandableStackLimit = mbi.BaseAddress;
    stack.ExpandableStackBottom = mbi.AllocationBase;

    /* create thread using the modified context and stack */
    ZwCreateThread(&hThread, THREAD_ALL_ACCESS, &oa, hProcess,
        &cid, &context, &stack, TRUE);

    /* copy exception table */
    ZwQueryInformationThread(NtCurrentThread(), ThreadBasicInformation,
        &tbi, sizeof tbi, 0);
    tib = (PNT_TIB)tbi.TebBaseAddress;
    ZwQueryInformationThread(hThread, ThreadBasicInformation,
        &tbi, sizeof tbi, 0);
    ZwWriteVirtualMemory(hProcess, tbi.TebBaseAddress, 
        &tib->ExceptionList, sizeof tib->ExceptionList, 0);

    /* start (resume really) the child */
    ZwResumeThread(hThread, 0);

    /* clean up */
    ZwClose(hThread);
    ZwClose(hProcess);

    /* exit with child's pid */
    return (int)cid.UniqueProcess;
}
static BOOL haveLoadedFunctionsForFork(void)
{
    HANDLE ntdll = GetModuleHandle("ntdll");
    if (ntdll == NULL) return FALSE;

    if (ZwCreateProcess && ZwQuerySystemInformation && ZwQueryVirtualMemory &&
        ZwCreateThread && ZwGetContextThread && ZwResumeThread &&
        ZwQueryInformationThread && ZwWriteVirtualMemory && ZwClose)
    {
        return TRUE;
    }

    ZwCreateProcess = (ZwCreateProcess_t) GetProcAddress(ntdll,
        "ZwCreateProcess");
    ZwQuerySystemInformation = (ZwQuerySystemInformation_t)
        GetProcAddress(ntdll, "ZwQuerySystemInformation");
    ZwQueryVirtualMemory = (ZwQueryVirtualMemory_t)
        GetProcAddress(ntdll, "ZwQueryVirtualMemory");
    ZwCreateThread = (ZwCreateThread_t)
        GetProcAddress(ntdll, "ZwCreateThread");
    ZwGetContextThread = (ZwGetContextThread_t)
        GetProcAddress(ntdll, "ZwGetContextThread");
    ZwResumeThread = (ZwResumeThread_t)
        GetProcAddress(ntdll, "ZwResumeThread");
    ZwQueryInformationThread = (ZwQueryInformationThread_t)
        GetProcAddress(ntdll, "ZwQueryInformationThread");
    ZwWriteVirtualMemory = (ZwWriteVirtualMemory_t)
        GetProcAddress(ntdll, "ZwWriteVirtualMemory");
    ZwClose = (ZwClose_t) GetProcAddress(ntdll, "ZwClose");

    if (ZwCreateProcess && ZwQuerySystemInformation && ZwQueryVirtualMemory &&
        ZwCreateThread && ZwGetContextThread && ZwResumeThread &&
        ZwQueryInformationThread && ZwWriteVirtualMemory && ZwClose)
    {
        return TRUE;
    }
    else
    {
        ZwCreateProcess = NULL;
        ZwQuerySystemInformation = NULL;
        ZwQueryVirtualMemory = NULL;
        ZwCreateThread = NULL;
        ZwGetContextThread = NULL;
        ZwResumeThread = NULL;
        ZwQueryInformationThread = NULL;
        ZwWriteVirtualMemory = NULL;
        ZwClose = NULL;
    }
    return FALSE;
}
15
ответ дан Eric des Courtis 22 August 2018 в 12:14
поделиться
  • 1
    Обратите внимание, что большая часть проверки ошибок отсутствует - например, ZwCreateThread возвращает значение NTSTATUS, которое можно проверить с помощью макросов SUCCEEDED и FAILED. – BCran 11 October 2013 в 10:27
  • 2
    Что произойдет, если fork выйдет из строя, это приведет к сбою программы, или поток просто сработает? Если он сбой программы, то это не работает. Просто любопытно, потому что я ищу реальное решение и надеюсь, что это может быть достойной альтернативой. – leetNightshade 28 April 2014 в 21:26
  • 3
    Я хотел бы отметить, что в предоставленном коде есть ошибка. hasLoadedFunctionsForFork - глобальная функция в заголовке, но статическая функция в файле c. Оба они должны быть глобальными. И в настоящее время сбой вилки, добавив проверку ошибок сейчас. – leetNightshade 28 April 2014 в 22:04

Ваши лучшие варианты: CreateProcess () или CreateThread () . Здесь есть дополнительная информация о портировании здесь .

2
ответ дан John T 22 August 2018 в 12:14
поделиться

В следующем документе представлена ​​некоторая информация о переносе кода из UNIX в Win32: https://msdn.microsoft.com/en-us/library/y23kc048.aspx

Помимо всего прочего, это указывает на то, что модель процесса отличается от двух систем и рекомендует рассматривать CreateProcess и CreateThread, где требуется поведение типа fork ().

35
ответ дан MCCCS 22 August 2018 в 12:14
поделиться

До того, как Microsoft представила свою новую «подсистему Linux для Windows», CreateProcess() была самой близкой вещью Windows к fork(), но Windows требует указать исполняемый файл для запуска в этом процессе.

Процесс создания UNIX сильно отличается от Windows. Его вызов fork() в основном дублирует текущий процесс почти в целом, каждый в своем собственном адресном пространстве, и продолжает запускать их отдельно. Хотя сами процессы разные, они все еще работают с одной и той же программой . Здесь здесь для хорошего обзора модели fork/exec.

Going наоборот, эквивалент Windows CreateProcess() представляет собой fork()/exec() пару функций в UNIX.

Если вы портировали программное обеспечение на Windows, а вы не Смысл слоя перевода, Cygwin предоставил возможность, которую вы хотите, но это было довольно kludgey.

Конечно, с новой подсистемой Linux , ближайшей вещь Windows fork() на самом деле fork(): -)

5
ответ дан paxdiablo 22 August 2018 в 12:14
поделиться
2
ответ дан sjcaged 22 August 2018 в 12:14
поделиться

Если вы только заботитесь о создании подпроцесса и ожидаете его, возможно, _spawn * API в process.h достаточно. Вот еще информация об этом:

https://docs.microsoft.com/en-us/cpp/c-runtime-library/process-and-environment-control https://en.wikipedia.org/wiki/Process.h

1
ответ дан solstice333 22 August 2018 в 12:14
поделиться
3
ответ дан user3502619 22 August 2018 в 12:14
поделиться

Нет простого способа эмуляции fork () в Windows.

Я предлагаю вам вместо этого использовать потоки.

2
ответ дан VVS 22 August 2018 в 12:14
поделиться
  • 1
    Ну, с честью, реализация fork была точно , что сделал CygWin. Но, если вы когда-либо читали , как , они это делали, yor & quot; нет простого способа & quot; это грубое недоразумение :-) – paxdiablo 5 April 2018 в 01:11

Ну, на самом деле окна не имеют ничего подобного. Тем более что fork может использоваться для концептуального создания потока или процесса в * nix.

Итак, я должен сказать:

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')
/
#foo.py
import os
print os.getcwd()
print __file__

#in the interactive interpreter
>>> import foo
/Users/jason
foo.py

#and finally, at the shell:
~ % python foo.py
/Users/jason
foo.py

и

>>> import collections #note that collections is a C extension in Python 2.5
>>> collections.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-
dynload/collections.so'

(я слышал, что для приложений на C

__file__

лучше).

35
ответ дан MCCCS 5 November 2018 в 09:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: