【问题标题】:Enumerating Named Pipes in Windows在 Windows 中枚举命名管道
【发布时间】:2009-01-26 23:05:40
【问题描述】:

我无法连接到命名管道(在本例中为快速 cgi 命名管道) 根据 MSDN,我应该使用 CreateFile() 或 CallNamedPipe() (平面 C API,同步 - 无重叠 I/O) http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx

但我得到 INVALID_HANDLE_VALUE 并且当我 GetLastError() 时它为零!?

我还想知道是否可以使用某种类型的 . 调用枚举所有命名管道,然后解析出我正在寻找的管道: "\.\pipe\FastCGI\"

有没有人有使用这些 cmets 的经验: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/225878

【问题讨论】:

    标签: named-pipes


    【解决方案1】:

    问题出在这里:

    
        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)”之后,您检查 NextEntryOffset == 0 这意味着最后一个条目永远不会被报告,移动“if(...) break;”在“wprintf(...)”调用之后,您应该能够枚举所有管道。

    EDIT
    对于那些想要完整源代码(不需要 DDK)的人来说,这里是。请注意,这不是我的代码,而是找到了here。此代码与原始代码之间的唯一变化是上面详述的错误修复。

    EDIT v2.0
    在下面的代码中发现了另一个错误。当它打印有关它正在迭代的当前项目的信息时,它会在名称的末尾放置一个空字符。这个空字符实际上覆盖了下一个条目的前 2 个字节,这恰好覆盖了该条目中“NextEntryOffset”变量的 2 个最低有效字节(通常导致它等于 0),因此只有前 2 个项目是每个从每个“NtQueryDirectoryFile”调用中枚举。

    我在下面的代码中添加了一个修复程序,应该可以解决这个问题(存储 WCHAR 被清除,然后在打印后恢复它。有点黑客,但这只是一些示例代码,为了正确实现,要么避免使用 wprintf打印名称,或将其复制到另一个缓冲区,您可以安全地将其结尾 NULL)。


    // 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); }

    【讨论】:

    • 代码在 x64 模式下不起作用。到目前为止,我发现了 2 个问题:(DWORD)TmpInfoDWORD 应替换为 64 位值)。 IO_STATUS_BLOCK 应该有 LONG* Status 字段而不是 LONG Status
    【解决方案2】:

    如果您想要一个可以为您执行此操作的编译工具,请查看 SysInternals(Microsoft 拥有)的“PipeList”。

    Download Here

    【讨论】:

      【解决方案3】:

      您是否正确转义了管道名称?它应该看起来像:\\\\.\\pipe\\FastCGI

      请参阅Named Pipe Client Demo 了解更多信息。

      【讨论】:

        【解决方案4】:

        使用未记录的函数:

        // NtQueryDirectoryFile(
        // IN HANDLE FileHandle, // 文件句柄
        // 在 HANDLE EventHandle 可选,
        // 在 PIO_APC_ROUTINE ApcRoutine 可选,
        // 在 PVOID ApcContext 中是可选的,
        // OUT PIO_STATUS_BLOCK IoStatusBlock,
        // OUT PVOID Buffer, // 指向接收结果的缓冲区的指针
        // IN ULONG BufferLength, // 缓冲区长度
        // IN FILE_INFORMATION_CLASS InformationClass,// 信息类型
        // IN BOOLEAN ReturnByOne, // 每次调用只返回一个文件的信息
        // IN PUNICODE_STRING FileTemplate OPTIONAL, // 搜索模板
        // IN BOOLEAN 重置 // 重新开始搜索
        // );

        【讨论】:

        • 您仍然需要转义反斜杠。该演示是用 C 编写的,它也逃脱了它们。
        • 正确。我使用 C 是因为它是事实上的语言,但我使用另一种不需要转义反斜杠的语言来实现。
        【解决方案5】:

        管道名称的第一个反斜杠被论坛软件截断。管道名称为:

        \\.\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,而是一个有效的句柄,我随后使用它并且完美地工作 他们按预期阻止并正常通信。

        【讨论】:

          【解决方案6】:

          好的,我在用于生成管道列表的代码中发现了另一个错误(关于第一个错误的帖子中的详细信息)。

          至于“以及是否有人对这些 cmets 有经验”之后的链接中的信息,我了解他们在说什么,您能否更具体地说明您不了解或好奇的内容(顺便说一句,关于无法执行非阻塞操作的部分有点谎言,尽管它不是以 unix 系统的“传统”方式完成的)。

          【讨论】:

          • 感谢格兰特。你收到我的电子邮件了吗?
          • 是的,这帮助我朝着正确的方向前进,看到它们都错了,但都没有返回相同的值,这让我尝试了一些最终揭示了问题的值。
          【解决方案7】:

          感谢您了解这一点。我将此代码转换为另一种类似 C 的语言并使用: FILE_NAMES_INFORMATION 因为我只是在寻找名字

          然后我用另一个应用程序创建了一个命名管道:

           \\.\pipe\test
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-07-10
            • 2010-12-18
            • 2012-01-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多