无法理解这个c ++ typedef

时间:2016-01-23 20:15:53

标签: c++ typedef

我不确定如何阅读此代码:

typedef NTSTATUS(NTAPI* QUERYINFORMATIONPROCESS)(
  IN   HANDLE ProcessHandle,
  IN   PROCESSINFOCLASS ProcessInformationClass,
  OUT  PVOID ProcessInformation,
  IN   ULONG ProcessInformationLength,
  OUT  PULONG ReturnLength OPTIONAL
  );

NTSTATUSQUERYINFORMATIONPROCESStypedef的名称吗?如果是这样,实际类型是什么?这是一个函数指针类型吗?用法是:

QUERYINFORMATIONPROCESS QueryInformationProcess =
    (QUERYINFORMATIONPROCESS)GetProcAddress(
    hDll, "NtQueryInformationProcess");

  if (QueryInformationProcess)
  {
    NTSTATUS ntStatus = QueryInformationProcess(
      processInformation.hProcess,
      PROCESSINFOCLASS::ProcessBasicInformation,
      &pbi, sizeof(pbi), &uLength);
  […]

这来自“C ++ Multithreading Cookbook”,它没有解释这段代码。感谢您的帮助!

5 个答案:

答案 0 :(得分:4)

typedef NTSTATUS(NTAPI* QUERYINFORMATIONPROCESS)(
  IN    HANDLE ProcessHandle,
  IN    PROCESSINFOCLASS ProcessInformationClass,
  OUT  PVOID ProcessInformation,
  IN    ULONG ProcessInformationLength,
  OUT  PULONG ReturnLength OPTIONAL
  );

这里的难点在于这是一个函数指针:

当声明一个函数指针时,为了将它与返回指针的函数区分开来,我们需要围绕它的括号括起来:

(*QUERYINFORMATIONPROCESS)

指针之前的NTAPI告诉编译器调用约定(如何传递参数[寄存器,堆栈,参数的顺序],如何完成参数的清理等)。

剩下的东西只是返回类型(NTSTATUS)和函数的参数。

一个更简单的例子是:

 typedef int (*funcptr)(int x); 

现在,相对容易看出它是一个返回int的函数,它是指向函数的指针,并且它采用的是一个参数int x

答案 1 :(得分:3)

在没有Microsoft宏的情况下编写它,它是

typedef NTSTATUS (*QUERYINFORMATIONPROCESS)(
  HANDLE ProcessHandle,
  PROCESSINFOCLASS ProcessInformationClass,
  PVOID ProcessInformation,
  ULONG ProcessInformationLength,
  PULONG ReturnLength
  );

这是一个名为" QUERYINFORMATIONPROCESS"的函数指针类型。

具体来说,它是指向NtQueryInformationProcess的指针,需要从DLL加载。

(看来你的书的作者有拼写问题。)

答案 2 :(得分:1)

它是指向函数的指针的typedef,称为QUERYINFORMATIONPROCESS。此函数需要5个参数,并返回NTSTATUS。

答案 3 :(得分:1)

有一条规则可以帮助阅读称为Clockwise/Spiral规则的详细类型定义。该规则是一个三步算法,引用原始文章的步骤是:

  1. 从未知元素开始,以螺旋/顺时针方向移动;在制定以下元素时,用相应的英语声明替换它们:
    • [X]或[] =>数组X大小为......或数组未定义大小......
    • (type1,type2)=>函数传递type1和type2返回...
    • * =>指针... ...
  2. 以螺旋/顺时针方向继续这样做,直到所有标记都被覆盖。
  3. 首先要在括号中解决任何问题!
  4. 通常有用的是知道哪个标识符对应于类型以识别未知元素(可能存在多个这样的元素)。在您的情况下 - 了解所有(NTSTATUSNTAPIHANDLEPROCESSINFOCLASSPVOIDULONGPULONG )是类型。

    本文提供了有关应用规则的有用示例。

    此外,我在Google中找到了一张图片,说明了该规则: Applying the spiral/clockwise rule

    识别未知元素:

    • void是一种类型
    • signal,嗯,看起来像一个未知元素。此外,它是 位于星号的右侧,就我而言,不能是变量/ typedef名称
    • intvoid - types
    • fp,第二个未知元素(请记住,我之前提到过可能有多个未知元素)
    • intint - types

    现在首先应用最左边未知元素的规则,即signal

    1. signal向右移动并遇到第一个左括号:signal是一个带有int的功能和精心设计的功能
    2. 让我们分析第二个未知元素fp,它也是signal的第二个参数。从fp顺时针旋转并遇到右括号,然后是星号:fp是指向某个东西的指针。
    3. 继续从*fp移动并遇到左括号:fp是一个指向函数的指针,该函数采用int并返回一些内容。
    4. 继续移动并遇到voidfp是一个指向int并返回void的函数的指针。
    5. 现在我们已将第二个参数解码为signalsignal是一个函数,它采用int, and a pointer to a function taking an int and returning void`
    6. 继续从signal(移动并遇到星号:signal是一个返回指针的函数...
    7. 继续从(*移动并遇到最右边的左括号:signal是一个函数(我在这里省略了参数)返回指向函数的指针int
    8. 最后,遇到voidsignal是一个函数(我在这里省略了参数)返回指向函数的指针,该函数采用int并返回{{1} }。
    9. P.S。您的问题中的typedef可以使用void声明用现代C ++编写:

      using

      它没有太大变化,但using QUERYINFORMATIONPROCESS = NTSTATUS(NTAPI*)( IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL ); 与实际定义有更多分离,使其更具可读性。在编写新代码时,请考虑使用typedef-name代替using: - )

答案 4 :(得分:0)

这将是一个函数指针typedef,它将类型QUERYINFORMATIONPROCESS定义为此类型的别名:

NTSTATUS(NTAPI*)(
  IN   HANDLE ProcessHandle,
  IN   PROCESSINFOCLASS ProcessInformationClass,
  OUT  PVOID ProcessInformation,
  IN   ULONG ProcessInformationLength,
  OUT  PULONG ReturnLength OPTIONAL
  );

如示例所示,

QUERYINFORMATIONPROCESS QueryInformationProcess =
    (QUERYINFORMATIONPROCESS)GetProcAddress(
    hDll, "NtQueryInformationProcess");

它扩展成这样的东西:

NTSTATUS(NTAPI* QueryInformationProcess)(
  IN   HANDLE ProcessHandle,
  IN   PROCESSINFOCLASS ProcessInformationClass,
  OUT  PVOID ProcessInformation,
  IN   ULONG ProcessInformationLength,
  OUT  PULONG ReturnLength OPTIONAL
  ) = 
    (NTSTATUS(NTAPI*)(
      IN    HANDLE ProcessHandle,
      IN    PROCESSINFOCLASS ProcessInformationClass,
      OUT  PVOID ProcessInformation,
      IN    ULONG ProcessInformationLength,
      OUT  PULONG ReturnLength OPTIONAL
    ))GetProcAddress(hDll, "NtQueryInformationProcess");

(不是100%肯定,如果这是正确的扩展,我发现函数指针一般都很尴尬。)

使用函数指针typedef是因为函数指针语法实际上本身就是笨拙的,而像这样的函数指针别名使用标准语法。

有关函数指针的更多信息,请参阅this answer

此外,它是一个Windows功能的指针,它使用标准的Windows标识符(NTSTATUS,NTAPI,IN,OUT,HANDLE,PROCESSINFOCLASS,PVOID,ULONG和PULONG)。

根据Windows文件,这些标识符为:

// ntdef.h
typedef __success(return >= 0) LONG NTSTATUS;
// See https://stackoverflow.com/questions/3378622/how-to-understand-the-ntstatus-nt-success-typedef-in-windows-ddk

// WinNT.h
#define NTAPI __stdcall
// __stdcall is a Windows calling convention, used by Visual Studio when compiling Windows code.

typedef void *PVOID;

#ifdef STRICT
    typedef void *HANDLE;
    #if 0 && (_MSC_VER > 1000)
        #define DECLARE_HANDLE(name) struct name##__; typedef struct name##__ *name
    #else
        #define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name
    #endif
#else
    typedef PVOID HANDLE;
    #define DECLARE_HANDLE(name) typedef HANDLE name
#endif


// WinDef.h
typedef unsigned long ULONG;
typedef ULONG *PULONG;

#ifndef IN
    #define IN
#endif

#ifndef OUT
    #define OUT
#endif

IN和OUT用作程序员辅助,而类型是为程序员提供一致的界面。不完全确定PROCESSINFOCLASS;它似乎在ntdll.dll中定义,与NtQueryInformationProcess本身一起定义。根据{{​​3}},它的定义如下:

private enum PROCESSINFOCLASS : int
{
  ProcessBasicInformation = 0,
  ProcessQuotaLimits,
  ProcessIoCounters,
  ProcessVmCounters,
  ProcessTimes,
  ProcessBasePriority,
  ProcessRaisePriority,
  ProcessDebugPort,
  ProcessExceptionPort,
  ProcessAccessToken,
  ProcessLdtInformation,
  ProcessLdtSize,
  ProcessDefaultHardErrorMode,
  ProcessIoPortHandlers, // Note: this is kernel mode only
  ProcessPooledUsageAndLimits,
  ProcessWorkingSetWatch,
  ProcessUserModeIOPL,
  ProcessEnableAlignmentFaultFixup,
  ProcessPriorityClass,
  ProcessWx86Information,
  ProcessHandleCount,
  ProcessAffinityMask,
  ProcessPriorityBoost,
  MaxProcessInfoClass
} ;

这似乎已过时,但this MSDN thread似乎有更新版本,似乎与this site一致。

希望这有帮助。