Перечисление именованных каналов в Windows - PullRequest
4 голосов
/ 27 января 2009

У меня проблемы с подключением к именованному каналу (в этом случае быстрый именованный канал cgi) Согласно MSDN, я должен использовать CreateFile () или CallNamedPipe () (плоский API C, синхронный - нет перекрывающихся операций ввода-вывода) http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx

Все же я получаю INVALID_HANDLE_VALUE, и когда я получаю GetLastError (), он равен нулю!?

Мне также интересно, могу ли я просто перечислить все именованные каналы с помощью какого-либо вызова . , а затем проанализировать тот, который я ищу: "\. \ Труба \ FastCGI \"

и есть ли у кого-нибудь опыт с этими комментариями: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/225878

Ответы [ 7 ]

4 голосов
/ 19 февраля 2009

проблема заключается здесь:


    TmpInfo = DirInfo;   
    while(1)   
    {   
       if(TmpInfo->NextEntryOffset==0)   
         break;   

       TmpInfo->FileDirectoryInformationClass.FileName[TmpInfo->FileNameLength/sizeof(WCHAR)] = NULL;   

       wprintf(L"%s (%d, %d)\n",TmpInfo->FileDirectoryInformationClass.FileName,   
                                TmpInfo->EndOfFile.LowPart,   
                                TmpInfo->AllocationSize.LowPart );   

       TmpInfo = (PFILE_QUERY_DIRECTORY)((DWORD)TmpInfo+TmpInfo->NextEntryOffset);   
    }   

сразу после «while (1)» вы проверяете, есть ли Next EntryOffset == 0 это означает, что о последней записи никогда не сообщается, переместите «if (...) break»; после вызова "wprintf (...)", и вы сможете перечислить все каналы.

EDIT
Для тех из вас, кто хотел бы получить полный исходный код (не требуя DDK), вот он. Пожалуйста, обратите внимание, что это не мой код, и он был найден здесь . Единственным изменением между этим кодом и оригиналом является исправление ошибки, как описано выше.

РЕДАКТИРОВАТЬ v2.0
Нашел еще одну ошибку в коде ниже. Когда он выводит информацию о текущем элементе, через который он проходит, он ставит нулевой символ в конце имени. Этот нулевой символ на самом деле перезаписывает первые 2 байта следующей записи, что просто перезаписывает 2 наименее значимых байта переменной 'NextEntryOffset' в этой записи (обычно в результате чего она становится равной 0), следовательно, только первые 2 элемента каждый перечисляется из каждого вызова 'NtQueryDirectoryFile'.

Я добавил исправление в приведенный ниже код, который должен решить эту проблему (сохранить очищенный WCHAR, а затем восстановить его после печати. ​​Немного взлома, но это всего лишь пример кода для правильной реализации, либо избегайте использования wprintf для напечатайте имя или скопируйте его в другой буфер, который вы можете смело обнулять до конца).

<Ч />

// pipelist.cpp (Windows NT/2000)   
//   
// This example will show how you can enumerate all named pipes   
// active on a system.   
//   
// (c)2000 Ashot Oganesyan K, SmartLine, Inc   
// mailto:ashot@aha.ru, http://www.protect-me.com, http://www.codepile.com   

#include <windows.h>   
#include <stdio.h>  

#define FileDirectoryInformation 1   
#define STATUS_NO_MORE_FILES 0x80000006L   

typedef struct   
{   
    USHORT Length;   
    USHORT MaximumLength;   
    PWSTR  Buffer;   
} UNICODE_STRING, *PUNICODE_STRING;   

typedef struct   
{   
    LONG Status;   
    ULONG Information;   
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;   

typedef struct {   
    ULONG NextEntryOffset;   
    ULONG FileIndex;   
    LARGE_INTEGER CreationTime;   
    LARGE_INTEGER LastAccessTime;   
    LARGE_INTEGER LastWriteTime;   
    LARGE_INTEGER ChangeTime;   
    LARGE_INTEGER EndOfFile;   
    LARGE_INTEGER AllocationSize;   
    ULONG FileAttributes;   
    ULONG FileNameLength;   
    union {   
        struct {   
            WCHAR FileName[1];   
        } FileDirectoryInformationClass;   

        struct {   
            DWORD dwUknown1;   
            WCHAR FileName[1];   
        } FileFullDirectoryInformationClass;   

        struct {   
            DWORD dwUknown2;   
            USHORT AltFileNameLen;   
            WCHAR AltFileName[12];   
            WCHAR FileName[1];   
    } FileBothDirectoryInformationClass;   
    };   
} FILE_QUERY_DIRECTORY, *PFILE_QUERY_DIRECTORY;   


// ntdll!NtQueryDirectoryFile (NT specific!)   
//   
// The function searches a directory for a file whose name and attributes   
// match those specified in the function call.   
//   
// NTSYSAPI   
// NTSTATUS   
// NTAPI   
// NtQueryDirectoryFile(   
//    IN HANDLE FileHandle,                      // handle to the file   
//    IN HANDLE EventHandle OPTIONAL,   
//    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,   
//    IN PVOID ApcContext OPTIONAL,   
//    OUT PIO_STATUS_BLOCK IoStatusBlock,   
//    OUT PVOID Buffer,                          // pointer to the buffer to receive the result   
//    IN ULONG BufferLength,                     // length of Buffer   
//    IN FILE_INFORMATION_CLASS InformationClass,// information type   
//    IN BOOLEAN ReturnByOne,                    // each call returns info for only one file   
//    IN PUNICODE_STRING FileTemplate OPTIONAL,  // template for search   
//    IN BOOLEAN Reset                           // restart search   
// );   
typedef LONG (WINAPI *PROCNTQDF)( HANDLE,HANDLE,PVOID,PVOID,PIO_STATUS_BLOCK,PVOID,ULONG,   
                                  UINT,BOOL,PUNICODE_STRING,BOOL );   

PROCNTQDF NtQueryDirectoryFile;   

void main(void)   
{   
    LONG ntStatus;   
    IO_STATUS_BLOCK IoStatus;   
    HANDLE hPipe;   
    BOOL bReset = TRUE;   
    PFILE_QUERY_DIRECTORY DirInfo,   
                          TmpInfo;   


    NtQueryDirectoryFile = (PROCNTQDF)GetProcAddress(   
                                      GetModuleHandle("ntdll"),   
                                      "NtQueryDirectoryFile"   
                                      );   

    if (!NtQueryDirectoryFile)   
       return;   

    hPipe = CreateFile("\\\\.\\Pipe\\",GENERIC_READ,   
                       FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,   
                       NULL,OPEN_EXISTING,0,NULL);   

   if(hPipe == INVALID_HANDLE_VALUE)   
     return;   

   DirInfo = (PFILE_QUERY_DIRECTORY) new BYTE[1024];   

   printf("Pipe name (Number of instances, Maximum instances)\n\n");   
   while(1)   
   {   
       ntStatus = NtQueryDirectoryFile(hPipe,NULL,NULL,NULL,&IoStatus,DirInfo,1024,   
                                       FileDirectoryInformation,FALSE,NULL,bReset);   

       if (ntStatus!=NO_ERROR)   
       {   
          if (ntStatus == STATUS_NO_MORE_FILES)   
             break;   

          return;   
       }   

       TmpInfo = DirInfo;   
       while(1)   
       {
          // Store old values before we mangle the buffer
          const int endStringAt = TmpInfo->FileNameLength/sizeof(WCHAR);
          const WCHAR oldValue = TmpInfo->FileDirectoryInformationClass.FileName[endStringAt];

          // Place a null character at the end of the string so wprintf doesn't read past the end
          TmpInfo->FileDirectoryInformationClass.FileName[endStringAt] = NULL;   

          wprintf(L"%s (%d, %d)\n",TmpInfo->FileDirectoryInformationClass.FileName,   
                                   TmpInfo->EndOfFile.LowPart,   
                                   TmpInfo->AllocationSize.LowPart );   

          // Restore the buffer to its correct state
          TmpInfo->FileDirectoryInformationClass.FileName[endStringAt] = oldValue;

          if(TmpInfo->NextEntryOffset==0)   
            break;   

          TmpInfo = (PFILE_QUERY_DIRECTORY)((DWORD)TmpInfo+TmpInfo->NextEntryOffset);   
       }   

       bReset = FALSE;   
   }   

   delete DirInfo;   
   CloseHandle(hPipe);   
}   

3 голосов
/ 24 февраля 2009

Если вам нужен скомпилированный инструмент, который может сделать это за вас, взгляните на «PipeList» от SysInternals (принадлежит Microsoft).

Скачать здесь

1 голос
/ 27 января 2009

Использование недокументированной функции:

// NtQueryDirectoryFile (
// IN HANDLE FileHandle, // дескриптор файла
// В РУЧКЕ EventHandle ДОПОЛНИТЕЛЬНО,
// IN PIO_APC_ROUTINE ApcRoutine НЕОБЯЗАТЕЛЬНО,
// IN PVOID ApcContext ДОПОЛНИТЕЛЬНО,
// OUT PIO_STATUS_BLOCK IoStatusBlock,
// OUT PVOID Buffer, // указатель на буфер для получения результата
// INLONG BufferLength, // длина буфера
// IN FILE_INFORMATION_CLASS InformationClass, // тип информации
// IN BOOLEAN ReturnByOne, // каждый вызов возвращает информацию только для одного файла
// IN PUNICODE_STRING FileTemplate НЕОБЯЗАТЕЛЬНО, // шаблон для поиска
// IN BOOLEAN Сброс // возобновить поиск
//);

1 голос
/ 27 января 2009

Правильно ли вы экранируете имя канала? Это должно выглядеть так: \\\\.\\pipe\\FastCGI

См. Демо клиента именованных каналов для получения дополнительной информации.

0 голосов
/ 26 февраля 2009

Хорошо, я обнаружил еще одну ошибку в коде, используемом для генерации списка каналов (подробности в посте о первой ошибке).

Поскольку информация в ссылке, следующей за "и имеет ли кто-либо опыт работы с этими комментариями", я понимаю, о чем они говорят, не могли бы вы быть более конкретным в отношении того, что вы не понимаете или вам интересно ( Часть о неспособности выполнять неблокирующие операции - своего рода ложь между прочим, хотя это не сделано "традиционным" способом Unix-систем).

0 голосов
/ 24 февраля 2009

Первая обратная косая черта имени канала была отключена программным обеспечением форума. Название трубы:

\\.\pipe\test

(не нужно экранировать на языке, который я использую для тестирования)

Я написал два приложения: одно трубо-сервер, одно трубо-клиент для тестирования блокировки и т. Д. Они работают отлично.

Я создаю трубу с:

Pipe_Name      = "\\.\pipe\test"
MaxInstances   = 1
OutBufferSize  = 1024
InBufferSize   = 1024

hPipe = CreateNamedPipe(_
Pipe_Name, _                                     ' Name of the Pipe
PIPE_ACCESS_DUPLEX, _                            ' Specifies the pipe access/overlapped/write-through/security access modes 
PIPE_TYPE_MESSAGE OR PIPE_READMODE_MESSAGE, _    ' Specifies the type, read, and wait modes of the pipe handle
MaxInstances, _                                  ' Specifies the maximum number of instances that can be created for this pipe
OutBufferSize, _                                 ' Specifies the number of bytes to reserve for the output buffer
InBufferSize, _                                  ' Specifies the number of bytes to reserve for the input buffer
0, _                                             ' Specifies the default time-out value, in milliseconds
Security_Declaration)                            ' Pointer to a SECURITY_ATTRIBUTES structure 

Он не возвращает INVALID_HANDLE_VALUE, но действительный дескриптор, который я использую впоследствии и работает отлично Они блокируются, как и ожидалось, и общаются нормально.

0 голосов
/ 19 февраля 2009

Спасибо, что поймали это. Я преобразовал этот код в другой язык, похожий на C, и использовал: FILE_NAMES_INFORMATION так как я ищу только имена

Затем я создал именованный канал с другим приложением:

 \\.\pipe\test
...