Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Перенаправление стандартных потоков 
:(
    Опции темы
Nastya
Дата 2.4.2005, 13:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 27.3.2002
Где: Мариуполь

Репутация: 3
Всего: 44



Такая ситуация, надо перенаправить поток stdout, так что бы при использовании функций printf, puts и т.д. все выводимые данные выводились в мое окно (а конкретно в RichEdit на нем).
При этом это должно происходить не только в моем модуле, но и во всех загружаемых моим модулях dll-ках.

Т.е есть все printf -ы в моей программе со всеми вызываемыми ею примочками должны итди в мое окно.
О как!!!!
Кто поможет?



--------------------
Что бы понять рекурсию, надо понять рекурсию

"Профессионал - это человек сделавший все возможные ошибки в очень узкой области". Н.Бор
PM MAIL   Вверх
Sun
Дата 4.4.2005, 11:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Account removed
***


Профиль
Группа: Экс. модератор
Сообщений: 1611
Регистрация: 14.8.2002

Репутация: нет
Всего: 48



Самое простое решение - перенаправить вывод в пайп.
Код

int outPipe[2];
pipe(outPipe);
dup2(outPipe[1], STDOUT_FILENO);
close(outPipe[1]);
FILE *out = fdopen(outPipe[0], "r");

Дальше используя файловый дескриптор out читать из него данные.


--------------------
Account removed
PM MAIL   Вверх
Nastya
Дата 4.4.2005, 11:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 27.3.2002
Где: Мариуполь

Репутация: 3
Всего: 44



Sun, все хорошо но есть два но
1. Это то что приложение у меня НЕ консольное.
2. При таком расскладе как написал ты (или почти таком) в нутри приложение все работает, а вот функции, вызываемой dll выводят в некуда а ради них все и затевалась.
Объясняю ситуацию.
Для упрощения работаю не с pipe, а с дисковым фалом (приблизительно так)
Код

FILE* stream;
stream = freopen( "freopen.out", "w",stdout );
HMODULE hmod = LoadLibrary(DllName);
F f = (F)GetProcAddress(hmod,fName);
printf("This is from Maindlg\r\n");
f(m_SerialPort);
fclose(stream);    

Так вот фраза "This is from Maindlg\r\n" в файл благополучно записалась, а вот тот printf, который был в функции ушел в некуда.

Дальше инетересние. Значенеи переменой stdout (это 1-ый элемент массива _iob, описанный в stdlib.h) имеет разные значения внутри основго модуля и внутри dll.
Далю "финт ушами", вместно LoadLibrary вызываю
LoadLibraryEx(DllName,NULL,DONT_RESOLVE_DLL_REFERENCES)
- в смысле грузись моя дллька, токль DllMain просьба не выполнять.
При этом обращение к функциям типа printf и GetStdHandle - вызывает ошибку времени выполнения (очень где-то глубоко)

ребята, бьюсь над этим уже много времени.
ПЛИЗ, помогайте


--------------------
Что бы понять рекурсию, надо понять рекурсию

"Профессионал - это человек сделавший все возможные ошибки в очень узкой области". Н.Бор
PM MAIL   Вверх
Nastya
Дата 4.4.2005, 12:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 27.3.2002
Где: Мариуполь

Репутация: 3
Всего: 44



Вобще, судя по всему весь вопрос грубо говоря сводится к выяснению следующих деталей
1. Где/когда/кем ведется заполненение массиво _iob ( т.е. определения значений переменных stdin,stdout,stderr)
2. И что же такое деллает загрузчик при условии, что фуекция DllMain У меня пустая (ведь делает что-то стервец smile)



--------------------
Что бы понять рекурсию, надо понять рекурсию

"Профессионал - это человек сделавший все возможные ошибки в очень узкой области". Н.Бор
PM MAIL   Вверх
Sun
Дата 4.4.2005, 12:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Account removed
***


Профиль
Группа: Экс. модератор
Сообщений: 1611
Регистрация: 14.8.2002

Репутация: нет
Всего: 48



Нашел подходящую функцию
Цитата

SetStdHandle

The SetStdHandle function sets the handle for the standard input, standard output, or standard error device.


BOOL SetStdHandle(
  DWORD nStdHandle,
  HANDLE hHandle
);

Parameters
nStdHandle
[in] Standard device for which the handle to be set. This parameter can be one of the following values.

Value Meaning
STD_INPUT_HANDLE Handle to the standard input device.
STD_OUTPUT_HANDLE Handle to the standard output device.
STD_ERROR_HANDLE Handle to the standard error device.

hHandle
[in] Handle to set to the specified device.




--------------------
Account removed
PM MAIL   Вверх
Nastya
Дата 4.4.2005, 12:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 27.3.2002
Где: Мариуполь

Репутация: 3
Всего: 44



Sun. солнышко, я нашла это давно, но пока никакой пользе мне это не принисло.
Ели я правльно думаю то, смотри:
Все потоки можно рассматиривать как файлы:
- у файла есть файловы дискриптор int
- может быть определена структура FILE*
- есть HANDLE (виндузовский)
Тк вот все эти функции переопределения потоков, что _dup2, что SetStdHandle, работают с теми же файлами, но каждый своим путем.
Причем для получения HANDLA из файлового дискриптора или наоборот (вобщем любого из трех вышеописанных описателей из любого) есть специальные функци.
Так что твое предложение из тупика нас пока не вывело.

Жду еще




--------------------
Что бы понять рекурсию, надо понять рекурсию

"Профессионал - это человек сделавший все возможные ошибки в очень узкой области". Н.Бор
PM MAIL   Вверх
Sun
Дата 4.4.2005, 12:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Account removed
***


Профиль
Группа: Экс. модератор
Сообщений: 1611
Регистрация: 14.8.2002

Репутация: нет
Всего: 48



Хм..Странно однако. Видимо где-то в другом месте идет переопределение вывода. Тогда можно попробовать сделать перехват для CreateFile и если будет идти создание "CONOUT$" файла - делать подмену файловго дескриптора. Или сделать перехват для SetStdHandle, так как похоже его кто-то вызывает.


--------------------
Account removed
PM MAIL   Вверх
Nastya
Дата 4.4.2005, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 27.3.2002
Где: Мариуполь

Репутация: 3
Всего: 44



Цитата
Хм..Странно однако. Видимо где-то в другом месте идет переопределение вывода. Тогда можно попробовать сделать перехват для CreateFile и если будет идти создание "CONOUT$" файла - делать подмену файловго дескриптора. Или сделать перехват для SetStdHandle, так как похоже его кто-то вызывает.


Как ты себе это представляешь?

Вся проблема в том, что желательно dll не трогать. Т.е. все делается в основном модуле.
dll и знать не должна куда она выводит


--------------------
Что бы понять рекурсию, надо понять рекурсию

"Профессионал - это человек сделавший все возможные ошибки в очень узкой области". Н.Бор
PM MAIL   Вверх
Sun
Дата 4.4.2005, 13:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Account removed
***


Профиль
Группа: Экс. модератор
Сообщений: 1611
Регистрация: 14.8.2002

Репутация: нет
Всего: 48



Цитата(Nastya @ 4.4.2005, 10:19)
Как ты себе это представляешь?

Вся проблема в том, что желательно dll не трогать. Т.е. все делается в основном модуле.
dll и знать не должна куда она выводит

Если предположение что в Dll идет перенаправление вывода верно, то нужно перехватить это перенаправление, установив ловушки для вызова функций SetStdHandle и CreateFile. Тогда если в Dll будет идти попытка перенаправления вывода, мы будем это перехватывать и подменять файловый дескриптор на тот который нам нужен. Что-то вроде такого
Код

BOOL Hook_SetStdHandle(
  DWORD nStdHandle,
  HANDLE hHandle
) {
  if (nStdHandle == STD_OUTPUT_HANDLE) {
    // ничего не делаем
  } else {
     Real_SetStdHandle(nStdHandle, hHandle); .// вызываем настоящую функцию
  }
}

HANDLE Hook_CreateFile(
  LPCTSTR lpFileName,
  DWORD dwDesiredAccess,
  DWORD dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD dwCreationDisposition,
  DWORD dwFlagsAndAttributes,
  HANDLE hTemplateFile
) {
  if (strcmp(lpFileName, "CONOUT$")) {
      return OurStdOutHandle; // подменяем результат на наш файловый дескриптор
  }
  return Real_CreateFile(... ); // во всех других случаях передаем управление оргинальной CreateFile функции
}



--------------------
Account removed
PM MAIL   Вверх
Nastya
Дата 4.4.2005, 13:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 27.3.2002
Где: Мариуполь

Репутация: 3
Всего: 44



Ой, по моему это слишком smile
Кроме того, я не уверена ,что CreateFile в принцепе будет. Может просто инициализироваться массив _iob.
Можно попробывать, но как-то такой вариант ТЯЖЕЛОВАТ (в смысле ресурсов)


--------------------
Что бы понять рекурсию, надо понять рекурсию

"Профессионал - это человек сделавший все возможные ошибки в очень узкой области". Н.Бор
PM MAIL   Вверх
Nastya
Дата 4.4.2005, 16:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 27.3.2002
Где: Мариуполь

Репутация: 3
Всего: 44



Вот код, уже с pipe, не обошлось без помощи ребят с форума rsdn.ru smile
Код

HANDLE StdHandle,hPipe;
hPipe = CreateNamedPipe(PIPE_STDOUT_NAME,
                                PIPE_ACCESS_DUPLEX, 
                                PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 
                                PIPE_UNLIMITED_INSTANCES, 
                                512, 512, 0,
                                NULL);        
    

    StdHandle = CreateFile(PIPE_STDOUT_NAME,
                            GENERIC_WRITE |GENERIC_READ,
                            FILE_SHARE_WRITE |FILE_SHARE_READ,
                            NULL,
                            CREATE_ALWAYS,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL);
    
    ConnectNamedPipe(PIPE_STDOUT_NAME,NULL);


    SetStdHandle(STD_OUTPUT_HANDLE,StdHandle);
    SetStdHandle(STD_ERROR_HANDLE ,StdHandle);
    stdout->_file= _open_osfhandle((long) StdHandle,_O_TEXT);
    stderr->_file= _open_osfhandle((long) StdHandle,_O_TEXT);


Из hPipe потом читаем



--------------------
Что бы понять рекурсию, надо понять рекурсию

"Профессионал - это человек сделавший все возможные ошибки в очень узкой области". Н.Бор
PM MAIL   Вверх
Sun
Дата 4.4.2005, 17:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Account removed
***


Профиль
Группа: Экс. модератор
Сообщений: 1611
Регистрация: 14.8.2002

Репутация: нет
Всего: 48



Цитата(Nastya @ 4.4.2005, 13:29)
Вот код, уже с pipe, не обошлось без помощи ребят с форума rsdn.ru smile

Но проблема и дальше не решена? Вывод в Dll дальше не перехватывается?


--------------------
Account removed
PM MAIL   Вверх
Nastya
Дата 5.4.2005, 08:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 27.3.2002
Где: Мариуполь

Репутация: 3
Всего: 44



Почему, все запускаемы мной dll-ки пишут в мой pipe.
Причем не имеет значение как организован вывод в sttdout при помощи printf, puts или cout<<


--------------------
Что бы понять рекурсию, надо понять рекурсию

"Профессионал - это человек сделавший все возможные ошибки в очень узкой области". Н.Бор
PM MAIL   Вверх
alrond
Дата 27.7.2006, 17:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 33
Регистрация: 27.7.2006

Репутация: нет
Всего: 6



Привет!
вынежден поднять эту тему  smile 
У меня та же задача, что надо все из dll перенаправлять в мой файл и обрабатывать...
Но не могу подключить код, который Nastya реализовала 

Код

HANDLE StdHandle,hPipe;
hPipe = CreateNamedPipe(PIPE_STDOUT_NAME,
                                PIPE_ACCESS_DUPLEX, 
                                PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 
                                PIPE_UNLIMITED_INSTANCES, 
                                512, 512, 0,
                                NULL);        
    
    StdHandle = CreateFile(PIPE_STDOUT_NAME,
                            GENERIC_WRITE |GENERIC_READ,
                            FILE_SHARE_WRITE |FILE_SHARE_READ,
                            NULL,
                            CREATE_ALWAYS,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL);
    
    ConnectNamedPipe(PIPE_STDOUT_NAME,NULL);
    SetStdHandle(STD_OUTPUT_HANDLE,StdHandle);
    SetStdHandle(STD_ERROR_HANDLE ,StdHandle);
    stdout->_file= _open_osfhandle((long) StdHandle,_O_TEXT);
    stderr->_file= _open_osfhandle((long) StdHandle,_O_TEXT);


вот сюда

Код

#include <iostream>
#include <tchar.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

typedef int (*importFunction_int)(int, char* []);

int _tmain(int argc, _TCHAR* argv[])
{
int vvod;

HINSTANCE hinstLib = LoadLibrary("test.dll");
    if (hinstLib == NULL) {
        printf("ERROR: unable to load DLL\n");
        return 1;
    }

importFunction_int vyvod;
    
vyvod = (importFunction_int)GetProcAddress(hinstLib, "vyvod");
    if (vyvod == NULL) {
        printf("ERROR: unable to find DLL function\n");
        return 1;
    }
    
vvod = vyvod(argc, argv);
FreeLibrary(hinstLib);
return 0;
}


dll получает из командной строки опции и работая выдает результаты на консоль...
хочется из консоли перенаправить в exe через пайп...помогите!!!
Как вставить вышеназванное решение?
весь интернет перерыл, нашел только здесь и здесь http://www.rsdn.ru/forum/Message.aspx?mid=13172
да и то, не полные коды...
Есть много примеров с пайпами, но для варианта старта сторонней программы, а не dll
Пример: http://www.codenet.ru/progr/bcb/pipes.php

(исходники dll-ки есть, но все исправить нереально, слишком много кода) 
PM MAIL   Вверх
alrond
Дата 1.8.2006, 15:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 33
Регистрация: 27.7.2006

Репутация: нет
Всего: 6



Привет!
вставил я код, компилируется без ошибок, в файл все stdout из dll записываются, но не получается читать из пайпа (или файла).
Проверял, все сообщения из этого кода идут в никуда, в файл записываются только stdout из dll
Как можно работать в этом случае? smile 


Код

#include <iostream>
#include <tchar.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>

typedef int (*importFunction_int)(int, char* []);

int _tmain(int argc, _TCHAR* argv[])
{
#define PIPE_STDOUT_NAME "a.txt"
HANDLE StdHandle,hPipe; 
hPipe = CreateNamedPipe(PIPE_STDOUT_NAME,
                                PIPE_ACCESS_DUPLEX, 
                                PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 
                                PIPE_UNLIMITED_INSTANCES, 
                                512, 512, 0,
                                NULL);        
    
    StdHandle = CreateFile(PIPE_STDOUT_NAME,
                            GENERIC_WRITE |GENERIC_READ,
                            FILE_SHARE_WRITE |FILE_SHARE_READ,
                            NULL,
                            CREATE_ALWAYS,
                            FILE_ATTRIBUTE_NORMAL,
                            NULL);
    
    ConnectNamedPipe(PIPE_STDOUT_NAME,NULL);
    SetStdHandle(STD_OUTPUT_HANDLE,StdHandle);
    SetStdHandle(STD_ERROR_HANDLE ,StdHandle);
    stdout->_file= _open_osfhandle((long) StdHandle, _O_TEXT);
    stderr->_file= _open_osfhandle((long) StdHandle, _O_TEXT);

    HINSTANCE hinstLib = LoadLibrary("testeth.dll");
    if (hinstLib == NULL) {
        printf("ERROR: unable to load DLL\n");
        return 1;
    }

importFunction_int vyvod;
    
    vyvod = (importFunction_int)GetProcAddress(hinstLib, "vyvod");
    if (vyvod == NULL) {
        printf("ERROR: unable to find DLL function\n");
        return 1;
    }

vyvod(argc, argv);
FreeLibrary(hinstLib);


    DWORD dwRead;
    char chBuf[1000];
     for( ;; )
     {
       if(!ReadFile(hPipe, chBuf, 999, &dwRead, NULL) || dwRead == 0)
         break;
       chBuf[dwRead / sizeof(char)] = '\0';
       puts(chBuf);
     }

    return 0;
}

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0586 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.