Вызов кода из дочернего процесса

Тема в разделе "WASM.ASSEMBLER", создана пользователем Jin X, 13 фев 2018.

  1. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.328
    Таким, что в ядре COM уже реализован маршаллинг аргументов всех типов, которые есть в VARIANT. А типы аргументов она возьмет из typelib.

    Думаю, работать будет довольно быстро, учитывая, что вся эта байда затевалась для офисных продуктов мс, которые процентов на 80 из нее и состоят. Этот код толпа индусов уже лет 20 полирует :)
     
  2. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    860
    Из библиотеки типов.
    Зависит от маршалера.
     
  3. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Для родителя – может быть. Для дочки (что важнее) – явно SendMessage.
     
  4. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    В общем, померил я скорость SendMessage. Если окно не найдено, то выполняется очень быстро (буквально за 50 с небольшим тактов). Если это "моё" окно (и оно обрабатывает это сообщение), скорость сравнима со скоростью SetEvent/ResetEvent (даже чуть быстрее: 1220 vs 1400-1550 тактов, причём это тестировалось в Delphi). Другие окна – в среднем раз в 40-47 дольше (порядка 50-57К тактов у меня... если не брать во внимание Excel, например, у которого, судя по всему, обработчик тяжёлый).
    SignalObjectAndWait в цикле в 2-х разных потоках (одного процесса) выдают около 2700 тактов. Вот только без shared-memory и в разных потоках не проверял...
     
  5. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    Jin X,

    Ваши тесты не корректны. Во первых при невалид хэндле не произойдёт никакой ядерный вызов - проверка валидности описателей выполняется в юм. Во вторых есть у теневых сервисов механизм пакетной обработки. Так например рисуется текст. Работает следующим образом. Некоторые действия отлаживаются, необходимое событие сохраняется в буфер. Буфер может держать множество событий. Далее при вызове любого теневого сервиса ядро перед его обработкой развернёт все события из буфера. Это механизм оптимизации. Таким образом если вы ничего в цикле не вызываете, кроме тестовой апи, то профайл будет существенно отличаться от того же вызова сервиса, но при нормальной работе гуя.
     
    Jin X нравится это.
  6. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    > скорость сравнима со скоростью SetEvent/ResetEvent

    Скорость чего именно - сервисной обработки или доставки события ?

    Гуй асинхронный, сигналящий поток быстро вернётся из ядра, но сообщение неизвестно когда будет доставлено, так как существует их очередь - событие будет добавлено в очередь.
     
  7. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Так, я и говорю, что там 50 тактов всего затрачивается.
    Выполнения всего SendMessage и всего SetEvent (SignalObjectAndWait и пр).
    Ну ок, есть много "но", тем не менее общая картина ясна: через Event'ы всё работает многократно быстрее, чем через SendMessage.
     
  8. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Сделаю тестовый образец – скину :derisive:
    p.s. Странно как-то смайлы преобразуются... например ;) выдаёт ;)
     
  9. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    В общем, вот такую штуку сделал. Это вариант без передачи параметров и получения результата. Просто запуск команд в родительском процессе.
    На работает долго: от 40-60 (если повезёт) до 200+ тыс. тиков ЦП (бывало даже 300 тыс).
    Запускать так: IPCEventServer.exe IPCEventUser.exe

    p.s. Всё равно громоздко выходит (для дочки). Открытие Event'ов с проверкой чего только стоит...

    IPCEventServer:
    Код (ASM):
    1. format  PE Console 4.0
    2. entry   start
    3.  
    4. include 'win32axp.inc'
    5.  
    6. ;-- CODE SECTION -------------------------------------------------------------------------------------------------------
    7.  
    8. .code
    9. start:
    10.  
    11.                 cinvoke printf, <'SERVER: Starting...',13,10>
    12.                 stdcall ParseCommandLine
    13.                 test    eax,eax
    14.                 jz      .noparam
    15.                 mov     ebx,eax
    16.  
    17.                 cinvoke printf, <'SERVER: Creating events...',13,10>
    18.                 stdcall CreateEvents
    19.                 test    eax,eax
    20.                 jnz     .ev_error
    21.  
    22.                 cinvoke printf, <'SERVER: Running specified command line...',13,10>
    23.                 invoke  CreateProcess, 0, ebx, 0, 0, 0, 0, 0, 0, sinfo, pinfo
    24.                 test    eax,eax
    25.                 jz      .run_error
    26.  
    27.                 mov     eax,[pinfo.hProcess]
    28.                 mov     [pid],eax
    29.  
    30.                 cinvoke printf, <'SERVER: Listening to command events...',13,10>
    31.                 .repeat
    32.                         stdcall WaitForCommandEvent
    33.                         mov     ebx,eax
    34.                         .if     ebx = 0
    35.                                 cinvoke printf, <'SERVER: Process is finished.',13,10>
    36.                         .elseif ebx = 1
    37.                                 cinvoke printf, <'SERVER: Quit command is fetched.',13,10>
    38.                         .elseif ebx = 2
    39.                                 cinvoke printf, <'SERVER: Init command is fetched.',13,10>
    40.                         .elseif ebx = 3
    41.                                 cinvoke printf, <'SERVER: First command is fetched.',13,10>
    42.                         .elseif ebx = 4
    43.                                 cinvoke printf, <'SERVER: Second command is fetched.',13,10>
    44.                         .else
    45.                                 cinvoke printf, <'SERVER: Error is occured.',13,10>
    46.                         .endif
    47.                 .until  signed ebx <= 1
    48.  
    49.                 invoke  Sleep, 1200
    50.                 cinvoke printf, <'SERVER: Finishing...',13,10>
    51.  
    52.                 invoke  CloseHandle, [pinfo.hThread]
    53.                 invoke  CloseHandle, [pinfo.hProcess]
    54.         .finish:
    55.                 invoke  CloseHandle, [dwEvQuit]
    56.                 invoke  CloseHandle, [dwEvInit]
    57.                 invoke  CloseHandle, [dwEvFirst]
    58.                 invoke  CloseHandle, [dwEvSecond]
    59.         .exit:
    60.                 invoke  Sleep, 2000
    61.                 invoke  ExitProcess, 0
    62.  
    63.         .noparam:
    64.                 cinvoke printf, <'SERVER: No command line is specified!',13,10>
    65.                 jmp     .exit
    66.  
    67.         .ev_error:
    68.                 cinvoke printf, <'SERVER: Event #%i create error!',13,10>, eax
    69.                 jmp     .exit
    70.  
    71.         .run_error:
    72.                 invoke  GetLastError
    73.                 cinvoke printf, <'SERVER: Run error #%i!',13,10>, eax
    74.                 jmp     .finish
    75.  
    76. ; Return pointer to filename string in EAX (0 if no params)
    77. proc            ParseCommandLine uses edi
    78.                 invoke  GetCommandLine
    79.                 mov     edi,eax
    80.                 cinvoke strlen, edi
    81.                 test    eax,eax
    82.                 jz      .noparam
    83.  
    84.                 lea     ecx,[eax-1]
    85.                 mov     al,'"'
    86.                 scasb
    87.                 je      @F
    88.                 mov     al,' '
    89.         @@:     test    al,al
    90.                 repne scasb
    91.                 jne     .noparam
    92.  
    93.                 mov     al,' '
    94.                 cmp     al,al
    95.                 repe scasb
    96.                 je      .noparam
    97.  
    98.                 lea     eax,[edi-1]
    99.                 ret
    100.  
    101.         .noparam:
    102.                 xor     eax,eax
    103.                 ret
    104. endp
    105.  
    106. ; Return EAX = 0 if ok or EAX = event number with error
    107. proc            CreateEvents uses ebx
    108.                 xor     ebx,ebx
    109.  
    110.                 invoke  CreateEvent, 0, 0, 0, 'IPC test "Quit" event'
    111.                 inc     ebx
    112.                 test    eax,eax
    113.                 jz      .error
    114.                 mov     [dwEvQuit],eax
    115.  
    116.                 invoke  CreateEvent, 0, 0, 0, 'IPC test "Init" event'
    117.                 inc     ebx
    118.                 test    eax,eax
    119.                 jz      .error
    120.                 mov     [dwEvInit],eax
    121.  
    122.                 invoke  CreateEvent, 0, 0, 0, 'IPC test "First" event'
    123.                 inc     ebx
    124.                 test    eax,eax
    125.                 jz      .error
    126.                 mov     [dwEvFirst],eax
    127.  
    128.                 invoke  CreateEvent, 0, 0, 0, 'IPC test "Second" event'
    129.                 inc     ebx
    130.                 test    eax,eax
    131.                 jz      .error
    132.                 mov     [dwEvSecond],eax
    133.  
    134.                 invoke  CreateEvent, 0, 0, 0, 'IPC test "Continue" event'
    135.                 inc     ebx
    136.                 test    eax,eax
    137.                 jz      .error
    138.                 mov     [dwEvContinue],eax
    139.  
    140.                 xor     ebx,ebx
    141.         .error:
    142.                 mov     eax,ebx
    143.                 ret
    144. endp
    145.  
    146. ; Return command number in EAX (0 = process is finished, -1 = error)
    147. proc            WaitForCommandEvent
    148.                 invoke  WaitForMultipleObjects, EventCount, Events, 0, -1
    149.                 push    eax
    150.                 invoke  SetEvent, [dwEvContinue]
    151.                 pop     eax
    152.                 cmp     eax,EventCount
    153.                 jb      @F
    154.                 or      eax,-1
    155.         @@:     ret
    156. endp
    157.  
    158. ;-- DATA SECTION -------------------------------------------------------------------------------------------------------
    159.  
    160. struc           STARTUPINFO {
    161.   . = $
    162.   .cb           dd      .size
    163.   .lpReserved   dd      ?
    164.   .lpDesktop    dd      ?
    165.   .lpTitle      dd      ?
    166.   .dwX          dd      ?
    167.   .dwY          dd      ?
    168.   .dwXSize      dd      ?
    169.   .dwYSize      dd      ?
    170.   .dwXCountChars dd     ?
    171.   .dwYCountChars dd     ?
    172.   .dwFillAttribute dd   ?
    173.   .dwFlags      dd      ?
    174.   .wShowWindow  dw      ?
    175.   .cbReserved2  dw      ?
    176.   .lpReserved2  dd      ?
    177.   .hStdInput    dd      ?
    178.   .hStdOutput   dd      ?
    179.   .hStdError    dd      ?
    180.   .size = $-.
    181. }
    182.  
    183. struc           PROCESS_INFORMATION {
    184.   . = $
    185.   .hProcess     dd      ?
    186.   .hThread      dd      ?
    187.   .dwProcessId  dd      ?
    188.   .dwThreadId   dd      ?
    189.   .size = $-.
    190. }
    191.  
    192. .data
    193.  
    194. sinfo           STARTUPINFO
    195. pinfo           PROCESS_INFORMATION
    196. Events          label
    197. pid             rd      1
    198. dwEvQuit        rd      1
    199. dwEvInit        rd      1
    200. dwEvFirst       rd      1
    201. dwEvSecond      rd      1
    202. EventCount      =       ($-Events)/4
    203. dwEvContinue    rd      1
    204.  
    205. ;-- IMPORT SECTION -----------------------------------------------------------------------------------------------------
    206.  
    207. section '.idata' import data readable
    208.  
    209. library kernel32, 'kernel32.dll',\
    210.         msvcrt, 'msvcrt.dll'
    211.  
    212.         import_kernel32
    213.         all_api
    214. import  msvcrt,\
    215.         printf, 'printf',\
    216.         strlen, 'strlen'
    IPCEventUser:
    Код (ASM):
    1. format  PE Console 4.0
    2. entry   start
    3.  
    4. include 'win32axp.inc'
    5.  
    6. SYNCHRONIZE     =       0x00100000
    7. EVENT_MODIFY_STATE =    2
    8.  
    9. ;-- CODE SECTION -------------------------------------------------------------------------------------------------------
    10.  
    11. .code
    12. start:
    13.  
    14.                 cinvoke printf, <13,10,'  USER: Starting...',13,10>
    15.  
    16.                 cinvoke printf, <'  USER: Opening events...',13,10>
    17.                 stdcall OpenEvents
    18.                 test    eax,eax
    19.                 jnz     .ev_error
    20.  
    21.                 invoke  Sleep, 1000
    22.  
    23.                 cinvoke printf, <13,10,'  USER: Testing Init command...',13,10>
    24.                 stdcall SendCommandEvent, [dwEvInit]
    25.                 stdcall ShowResult, eax
    26.                 invoke  Sleep, 1000
    27.  
    28.                 cinvoke printf, <13,10,'  USER: Testing First command...',13,10>
    29.                 stdcall SendCommandEvent, [dwEvFirst]
    30.                 stdcall ShowResult, eax
    31.                 invoke  Sleep, 1000
    32.  
    33.                 cinvoke printf, <13,10,'  USER: Testing Second command...',13,10>
    34.                 stdcall SendCommandEvent, [dwEvSecond]
    35.                 stdcall ShowResult, eax
    36.                 invoke  Sleep, 1000
    37.  
    38.                 invoke  MessageBox, 0, "Send 'Quit' command?", '', MB_YESNO or MB_ICONQUESTION or MB_TASKMODAL or MB_SETFOREGROUND
    39.                 cmp     eax,IDYES
    40.                 jne     @F
    41.                 cinvoke printf, <13,10,'  USER: Testing Quit command...',13,10>
    42.                 stdcall SendCommandEvent, [dwEvQuit]
    43.                 stdcall ShowResult, eax
    44.                 invoke  Sleep, 1000
    45.         @@:
    46.                 cinvoke printf, <13,10,'  USER: Finishing...',13,10>
    47.         .finish:
    48.                 invoke  CloseHandle, [dwEvInit]
    49.                 invoke  CloseHandle, [dwEvFirst]
    50.                 invoke  CloseHandle, [dwEvSecond]
    51.                 invoke  CloseHandle, [dwEvQuit]
    52.                 invoke  CloseHandle, [dwEvContinue]
    53.         .exit:
    54.                 invoke  ExitProcess, 0
    55.  
    56.         .ev_error:
    57.                 cinvoke printf, <'  USER: Event #%i open error!',13,10>, eax
    58.                 jmp     .exit
    59.  
    60. ; Return EAX = 0 if ok or EAX = event number with error
    61. proc            OpenEvents uses ebx
    62.                 xor     ebx,ebx
    63.  
    64.                 invoke  OpenEvent, EVENT_MODIFY_STATE, 0, 'IPC test "Init" event'
    65.                 inc     ebx
    66.                 test    eax,eax
    67.                 jz      .error
    68.                 mov     [dwEvInit],eax
    69.  
    70.                 invoke  OpenEvent, EVENT_MODIFY_STATE, 0, 'IPC test "First" event'
    71.                 inc     ebx
    72.                 test    eax,eax
    73.                 jz      .error
    74.                 mov     [dwEvFirst],eax
    75.  
    76.                 invoke  OpenEvent, EVENT_MODIFY_STATE, 0, 'IPC test "Second" event'
    77.                 inc     ebx
    78.                 test    eax,eax
    79.                 jz      .error
    80.                 mov     [dwEvSecond],eax
    81.  
    82.                 invoke  OpenEvent, EVENT_MODIFY_STATE, 0, 'IPC test "Quit" event'
    83.                 inc     ebx
    84.                 test    eax,eax
    85.                 jz      .error
    86.                 mov     [dwEvQuit],eax
    87.  
    88.                 invoke  OpenEvent, SYNCHRONIZE, 0, 'IPC test "Continue" event'
    89.                 inc     ebx
    90.                 test    eax,eax
    91.                 jz      .error
    92.                 mov     [dwEvContinue],eax
    93.  
    94.                 xor     ebx,ebx
    95.         .error:
    96.                 mov     eax,ebx
    97.                 ret
    98. endp
    99.  
    100. ; Returns time (CPU ticks) in EAX (< 0 = negative SignalObjectAndWait inadmissible result code)
    101. proc            SendCommandEvent Handle
    102.                 xor     eax,eax
    103.                 cpuid   ; serialization
    104.                 rdtsc
    105.                 push    eax
    106.                 invoke  SignalObjectAndWait, [Handle], [dwEvContinue], 2000, 0
    107.                 mov     ecx,eax
    108.                 rdtsc
    109.                 pop     edx
    110.                 sub     eax,edx
    111.                 jecxz   @F
    112.                 mov     eax,ecx
    113.                 neg     eax
    114.         @@:     ret
    115. endp
    116.  
    117. proc            ShowResult CPUTime
    118.                 invoke  Sleep, 200
    119.                 mov     eax,[CPUTime]
    120.                 test    eax,eax
    121.                 js      .error
    122.                 cinvoke printf, <'  USER: Time elapsed: %i CPU ticks.',13,10>, eax
    123.                 jmp     @F
    124.         .error:
    125.                 neg     eax
    126.                 cinvoke printf, <'  USER: Waiting is failed (SignalObjectAndWait result = %i)...',13,10>, eax
    127.         @@:     ret
    128. endp
    129.  
    130. ;-- DATA SECTION -------------------------------------------------------------------------------------------------------
    131.  
    132. .data
    133.  
    134. dwEvInit        rd      1
    135. dwEvFirst       rd      1
    136. dwEvSecond      rd      1
    137. dwEvQuit        rd      1
    138. dwEvContinue    rd      1
    139.  
    140. ;-- IMPORT SECTION -----------------------------------------------------------------------------------------------------
    141.  
    142. section '.idata' import data readable
    143.  
    144. library kernel32, 'kernel32.dll',\
    145.         user32, 'user32.dll',\
    146.         msvcrt, 'msvcrt.dll'
    147.  
    148.         import_kernel32
    149.         import_user32
    150.         all_api
    151. import  msvcrt,\
    152.         printf, 'printf'
     

    Вложения:

    • IPCEvents.zip
      Размер файла:
      4,8 КБ
      Просмотров:
      434
    Последнее редактирование: 26 фев 2018
  10. RET

    RET Well-Known Member

    Публикаций:
    17
    Регистрация:
    5 янв 2008
    Сообщения:
    789
    Адрес:
    Jabber: darksys@sj.ms
    Indy_, +100500, видимо наруду шадов нравится, сами не зная чеко кодят. Есть же шаред мем и прочие фичи, даже взять rpcrt4.... 4 строчки кода
     
    Последнее редактирование: 26 фев 2018
  11. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    RET, ну давайте посчитаем (в случае с RtlRemoteCall)...

    1. OpenFileMapping (нам же надо получить хендлы процесса и потока, а также адреса функций)
    2. MapViewOfFile
    3. [Nt]SuspendThread
    4. NtGetContextThread (нам же надо передать функции родителя контекст, чтобы он мог сделать NtContinue)
    5. RtlRemoteCall
    6. ResumeThread
    7. UnmapViewOfFile
    8. CloseHandle

    А если окажется, что дочерний процесс не может использовать хендлы процесса и потока, открытые родителем, то добавится ещё 4 строки:
    OpenProcess
    OpenThread
    CloseHandle(pid)
    CloseHandle(tid)

    Я ничего не забыл? :)

    Ах да, надо ещё структуру данных, находящихся в shared memory описать...

    А вот тут можно поподробнее? Что сие такое и как его юзать?
     
  12. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    Jin X,

    В вашем списке тайминг не предсказуем в 3, 4, 5 и 6. Эти все пункты сводятся к одному 5, так как это он и делает(асинхронная доставка кернел APC).

    > Что сие такое и как его юзать?

    Этот механизм слишком кривой, толстый и вам он точно не нужен.

    Рядом есть топик про синхронизацию RWL. Вы сформулируйте задачу, что бы можно было её решить. А так не ясно что вам нужно. Между процессами проекции отображаются аппаратно, там нет наверно смысла говорить про задержки. Тормоза происходят в интерфейсе, в синхронизациях. Если вас устраивает какой то топорный гуй механизм, тогда и любой нэйтивный сгодится походу, так как они на порядки шустрее.
     
  13. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Т.е. 3, 4 и 6 можно убрать, 5 сам всё сделает?

    Вот эта?
    Та тема к этой не имеет никакого отношения.

    Сейчас я уже понял, что смысла так делать вообще нет. Проще обойтись сопроводительной DLL-кой, которая будет подгружаться дочерним процессом и вызов будет идти напрямую. Это будет быстро и просто, как табуретка. А если родителю нужно будет иметь доступ к данным из DLL, то вполне сойдёт вариант #17.

    Сейчас уже мне сами варианты общения между процессами интересен :)
    Как это сделать проще, быстрее и т.д. В образовательных целях, так сказать...

    Например?
     
  14. RET

    RET Well-Known Member

    Публикаций:
    17
    Регистрация:
    5 янв 2008
    Сообщения:
    789
    Адрес:
    Jabber: darksys@sj.ms
    Из дочки
    NtQueryInformationProcess ->NtOpenProcess-> RtlRemoteCall, к примеру, имхо натив
     
  15. Jin X

    Jin X Active Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    369
    Адрес:
    Кольца Сатурна
    Какую инфу этой функцией нужно запрашивать и для чего? И где брать ProcessHandle, если FileMapping мы не используем?
     
  16. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    Jin X,

    Курите матчасть, win internals, там грамотные люди всё популярно описали. Первый закон ньютона помните, что бы что то получить нужно что то отдать. Имеется ввиду время на изучение основ.
     
    Jin X и RET нравится это.