在Windows中枚举命名管道

5
我在连接命名管道(在这种情况下是快速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\”
还有人对这些评论有经验吗:http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/225878
7个回答

5
问题出在这里:

    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(...)”调用之后,您应该能够枚举所有的管道。

编辑
对于那些想要完整源代码(不需要DDK)的人,请注意。请注意,这不是我的代码,它在这里找到。此代码与原始代码之间的唯一更改是如上所述的错误修复。

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

我已经向下面的代码添加了一个修复程序,可以解决此问题(存储被清除的WCHAR,然后在打印后恢复它。这是一种折衷的方法,但这只是一些示例代码,对于一个正确的实现,要么避免使用wprintf打印名称,要么将其复制到另一个您可以安全地将其结尾设置为NULL的缓冲区中)。

// pipelist.cpp (Windows NT/2000) // // 本示例将展示如何枚举系统上所有活动的命名管道。 // // (c)2000 Ashot Oganesyan K, SmartLine, Inc // mailto:ashot@aha.ru, http://www.protect-me.com, http://www.codepile.com
#include #include
#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!) // // 该函数搜索目录以查找文件名和属性与函数调用中指定的那些相匹配的文件。 // // NTSYSAPI // NTSTATUS // NTAPI // NtQueryDirectoryFile( // IN HANDLE FileHandle, // 文件句柄 // IN HANDLE EventHandle OPTIONAL, // IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, // IN PVOID ApcContext OPTIONAL, // 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 Reset // 重新开始搜索 // ); 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("管道名 (实例数,最大实例数)\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) { // 存储我们修改缓冲区之前的旧值 const int endStringAt = TmpInfo->FileNameLength/sizeof(WCHAR); const WCHAR oldValue = TmpInfo->FileDirectoryInformation

1
代码在x64模式下无法运行。到目前为止,我已经发现了两个问题:(DWORD)TmpInfo(应该将DWORD替换为64位值)。IO_STATUS_BLOCK应该有一个LONG* Status字段,而不是LONG Status - AdamF

4
如果您需要一个可以为您完成此操作的编译工具,请查看微软旗下的SysInternals的“PipeList”。

在此下载


1
你是否正确转义了管道名称?它应该是这样的:\\\\.\\pipe\\FastCGI 更多信息请参见命名管道客户端演示

1

使用未记录的函数:

// NtQueryDirectoryFile(
// IN HANDLE FileHandle, // 文件句柄
// IN HANDLE EventHandle OPTIONAL,
// IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
// IN PVOID ApcContext OPTIONAL,
// 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 Reset // 重启搜索
// );


你仍然需要转义反斜杠。演示程序是用C语言编写的,它也对其进行了转义。 - Kevin
我使用C语言是因为它是事实上的语言,但我使用另一种语言来实现,这种语言不需要转义反斜杠。 - Mike Trader

0

感谢您发现了这个问题。我将此代码转换为另一种类似于C语言的语言,并使用了FILE_NAMES_INFORMATION,因为我只需要查找名称。

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

 \\.\pipe\test

0

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

至于链接中“是否有人有这些评论的经验”的信息,我理解他们在谈论什么,你能否更具体地说明你不理解或感到好奇的是什么(关于无法执行非阻塞操作的部分有点虚假,尽管它不是以Unix系统的“传统”方式完成的)。


谢谢Grant。你收到我的电子邮件了吗? - Mike Trader
是的,那确实帮助我朝着正确的方向前进,看到它们都是错误的,但返回不同的值让我尝试了一些值,最终揭示了问题所在。 - Grant Peters

0

论坛软件切掉了管道名称的第一个反斜杠。管道名称为:

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接