Как стать автором
Обновить

IPC::Open3. Решение проблемы с STDERR

Время на прочтение2 мин
Количество просмотров1.3K
Когда мы пишем графическое приложение, бывает что требуется вызывать внешние программы и читать из STDOUT/STDERR.
С этим прекрасно справляется модуль IPC::Open3.

Однако, программу Вы написали, все работает, но Вы не хотите чтобы пользователь (или Вы) видели ненужное окно терминала.

Есть несколько вариантов его скрыть:

1. Запускать скрипт через wperl.exe, а не через perl.exe
2. ???

Рассмотрим программу
use strict;

use Tkx;
use IPC::Open3;

my $mw = Tkx::widget->new('.');
my $tw = $mw->new_text();

my $bt = $mw->new_ttk__button(
    -text => 'dir',
    -command => sub {
        my($rdr, $pid);
        $pid = open3( undef, $rdr, undef, 'dir' );
        $tw->insert( 'end', do { local $/; <$rdr> } );
    },
);

Tkx::pack( $tw );
Tkx::pack( $bt );

Tkx::MainLoop;


image

Вызывается команда dir, и выводится ее результат. (не обращайте внимания на кодировку).

Все работает, но если Вы запустите скрипт через wperl.exe, то при вызове open3 получите ошибку:
open3: Can't call method "close" on an undefined value at C:/perl5.8/lib/IPC/Open3.pm line 368.

open3: Can't call method "close" on an undefined value at C:/perl5.8/lib/IPC/Open3.pm line 368.


Проблема в том что, wperl не создает стандартные потоки (STDIN, STDOUT, STDERR).

Я долго ломал голову, как заставить работать программу. Пробовал вызывать WINAPI внутри тела программы, запускать через bat файл (работает, но не со всеми программами), однако решение оказалось наудивление простым.

Необходимо использовать функцию ShellExecute из shell32.dll c аттрибутом SW_HIDE.

Ниже код лоадера на Си.
#include <stdio.h>
#include <windows.h>

static char *ldr_file = "app.pl";
static char *ldr_path = "";

int main(int argc, char *argv[])
{
  int code;
  LoadLibrary("shell32.dll");
  
  code = (int) ShellExecute(NULL, "open", ldr_file, ldr_path, NULL, SW_HIDE);
  if (code <= 32)
  {
	char buf[200];
	sprintf(buf, "Cannot run application. Code: %d", code);
	MessageBox(
		NULL,
		buf,
		"Dynld Error",
		MB_ICONERROR | MB_OK
	);
  }

  return code;
}


Компилировать gcc из MinGW.
gcc -mwindows loader.c -o loader.exe

Теги:
Хабы:
Всего голосов 5: ↑4 и ↓1+3
Комментарии6

Публикации

Истории

Ближайшие события

Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн
Конференция «IT IS CONF 2024»
Дата20 июня
Время09:00 – 19:00
Место
Екатеринбург