如何使用Windows API“ GetTcpTable”查找可用的TCP端口?

问题描述

我正在尝试使用Windows API“ GetTcpTable”,但我不知道如何准备数据结构“ PMIB_TCPTABLE”并从中获取返回值。

PROCEDURE GetTcpTable EXTERNAL "Iphlpapi":U:
   DEFINE OUTPUT        ParaMETER mTcpTable              AS HANDLE TO MEMPTR. // the API expects a pointer,so use HANDLE TO Syntax to pass one
   DEFINE INPUT-OUTPUT  ParaMETER SizePointer            AS HANDLE TO LONG.
   DEFINE INPUT         ParaMETER Order                  AS LONG.
   DEFINE RETURN        ParaMETER IPHLPAPI_DLL_LINKAGE   AS LONG.
END PROCEDURE.
 
DEFINE VARIABLE mTcpTable        AS MEMPTR   NO-UNDO.
DEFINE VARIABLE SizePointer      AS INT      NO-UNDO.
DEFINE VARIABLE Order            AS INT      NO-UNDO.
DEFINE VARIABLE IPHLPAPI         AS INT      NO-UNDO.
 
DEFINE VARIABLE mTempValue       AS MEMPTR   NO-UNDO.
DEFINE VARIABLE dwNumEntries     AS INT      NO-UNDO.
DEFINE VARIABLE dwState          AS INT      NO-UNDO.
DEFINE VARIABLE dwLocalAddr      AS INT64    NO-UNDO.
DEFINE VARIABLE dwLocalPort      AS INT      NO-UNDO.
DEFINE VARIABLE dwRemoteAddr     AS INT64    NO-UNDO.
DEFINE VARIABLE dwRemotePort     AS INT      NO-UNDO.
 
DEFINE VARIABLE ix     AS INTEGER NO-UNDO.
 
SizePointer = 4.
Order = 1.
SET-SIZE(mTcpTable) = SizePointer.
RUN GetTcpTable(OUTPUT mTcpTable,INPUT-OUTPUT SizePointer,INPUT Order,OUTPUT IPHLPAPI). //get ERROR_INSUFFICIENT_BUFFER and kNow the real buffer Now
 
MESSAGE "IPHLPAPI is " IPHLPAPI SKIP // ERROR_INSUFFICIENT_BUFFER = 122
        "SizePointer is " SizePointer SKIP
   VIEW-AS ALERT-Box.
 
SET-SIZE(mTcpTable) = 0.
SET-SIZE(mTcpTable) = SizePointer.
RUN GetTcpTable(OUTPUT mTcpTable,OUTPUT IPHLPAPI). 
 
MESSAGE "IPHLPAPI is " IPHLPAPI SKIP  // NO_ERROR = 0
        "SizePointer is " SizePointer SKIP
        GET-LONG(mTcpTable,1) SKIP //dwNumEntries
   VIEW-AS ALERT-Box.
 
IF IPHLPAPI = 0 THEN DO:
   dwNumEntries = GET-LONG(mTcpTable,1).
 
   OUTPUT TO VALUE ("C:\temp\debug.txt") UNBUFFERED.
   DO ix = 0 TO dwNumEntries - 1.
      dwState                 = GET-UNSIGNED-LONG(mTcpTable,5 + ix * 20). // get value of dwState
      dwLocalAddr             = GET-UNSIGNED-LONG(mTcpTable,9 + ix * 20). // get value of dwLocalAddr
 
      SET-SIZE(mTempValue)    = 2.
      PUT-BYTE(mTempValue,2)  = GET-UNSIGNED-SHORT(mTcpTable,13 + ix * 20).
      PUT-BYTE(mTempValue,1)  = GET-UNSIGNED-SHORT(mTcpTable,14 + ix * 20).
      dwLocalPort             = GET-UNSIGNED-SHORT(mTempValue,1). // get value of dwLocalPort,The maximum size of an IP port number is 16 bits,so only the lower 16 bits should be used. The upper 16 bits may contain uninitialized data.
      SET-SIZE(mTempValue)    = 0.
 
      dwRemoteAddr            = GET-UNSIGNED-LONG(mTcpTable,17 + ix * 20). // get value of dwRemoteAddr
 
      SET-SIZE(mTempValue)    = 2.
      PUT-BYTE(mTempValue,21 + ix * 20).
      PUT-BYTE(mTempValue,22 + ix * 20).
      dwRemotePort            = GET-UNSIGNED-SHORT(mTempValue,1). // get value of dwRemotePort,so only the lower 16 bits should be used. The upper 16 bits may contain uninitialized data.
      SET-SIZE(mTempValue)    = 0.
 
      PUT UNFORMATTED dwState "~t" dwLocalAddr "~t" dwLocalPort "~t" dwRemoteAddr "~t" dwRemotePort "~r".
   END.
   OUTPUT CLOSE.
END.
 
SET-SIZE(mTcpTable) = 0.
  • 是否有更好的方法获取较低的16位?我不确定为什么需要将字节以相反的顺序放入mTempValue中,它是否与x86 PC的小字节序有关?
  • 如果我在其他位计算机上运行代码,如何获得正确的起始位置以读取值

我认为问题可以立即解决
https://community.progress.com/s/feed/0D54Q000088eIeASAU?t=1602495359075&searchQuery
谢谢大家:)

解决方法

Microsoft的文档通常具有结构的定义(请参见https://docs.microsoft.com/en-us/windows/win32/api/tcpmib/ns-tcpmib-mib_tcptable)。一旦知道了这些以及与之相关/指向其他的其他信息,就可以使用MEMPTR数据类型以及对其进行操作的各种功能来创建和操作它们:SET-SIZE(),{{1}通常使用}和GET-BYTES()https://docs.progress.com/bundle/openedge-programmimg-interfaces/page/Shared-Library-and-DLL-Support.html上有相关文档。