Мой вопрос касается привязок Win32-Ada, предоставляемых пакетами:
Я хотел бы использовать следующую функцию, определенную в пакете Win32.Mgmtapi
:
function SnmpMgrOidToStr
(oid : access Win32.Snmp.AsnObjectIdentifier;
string : access Win32.LPSTR)
return Win32.BOOL;
У меня есть доступ к переменной Variable_Binding
типа Win32.Snmp.a_RFC1157VarBind_t
.В пакете определены следующие четыре типа Win32.Snmp
:
type AsnObjectIdentifier is record
idLength : Win32.UINT;
ids : Win32.PUINT;
end record;
subtype AsnObjectName is AsnObjectIdentifier;
type RFC1157VarBind is record
name : AsnObjectName;
value : AsnObjectSyntax;
end record;
type a_RFC1157VarBind_t is access all RFC1157VarBind;
Сокращенный пример кода:
with Win32;
with Win32.Mgmtapi;
with Win32.Snmp;
procedure Test is
begin
-- [...]
declare
Variable_Binding : aliased Win32.Snmp.a_RFC1157VarBind_t := (...);
OID_String : access Win32.LPSTR;
Return_Value : Win32.BOOL;
begin
Return_Value := Win32.Mgmtapi.SnmpMgrOidToStr
(oid => Variable_Binding.name, -- type is not compatible
string => OID_String);
end;
end Test;
Мои три вопроса:
- Функция
SnmpMgrOidToStr
требуется тип доступа для параметра name
.Компонент name
, определенный в типе RFC1157VarBind
, не совместим с этим типом доступа.Каковы мои варианты преобразования компонента name
переменной Variable_Binding
в тип доступа? - Я предполагаю, что функция
SnmpMgrOidToStr
выделяет необходимую память для переменной OID_String
типа Win32.LPSTR
.Как преобразовать тип Win32.LPSTR
в строку Ada (String
/ Unbounded_String
)? - Как освободить выделенную память после разговора в строку Ada?
Обновление:
Я добавил полный пример SNMP.Для этого требуется включенная и настроенная служба Windows SNMP.Выходные данные программы должны быть:
Opened session.
Converted string to object identifier.
Copied object identifier.
Sent request.
Type is: 4
WORKSTATION
system.sysName.0
Closed session.
Документация функции SnmpMgrRequest
гласит:
Примечание Массив SnmpVarBind, на который указывает структура SnmpVarBindListдолжен быть выделен с использованием функции SnmpUtilMemAlloc.
И в соответствии с документацией функции SnmpUtilMemAlloc
функция SnmpUtilMemFree
должна использоваться для освобождениявыделенная память.
Я думаю, что я правильно распределяю память, используя этот вызов процедуры:
-- Allocate memory
-- Allocated memory is not freed properly
SnmpUtilMemAlloc (Win32.UINT (Win32.Snmp.RFC1157VarBind'Size * System.Storage_Unit));
Новые вопросы:
- Является ли этот вызов процедуры правильным?
- Как использовать функцию
SnmpUtilMemFree
для освобождения выделенной памяти?
В данный момент память не освобождается должным образом в соответствии с инструментом Dr.Память (версия 2.2.0-1):
Error #1: LEAK 1536 direct bytes 0x0418b850-0x0418be50 + 0 indirect bytes
# 0 replace_RtlAllocateHeap [d:\drmemory_package\common\alloc_replace.c:3771]
# 1 KERNELBASE.dll!GlobalAlloc +0x6d (0x75404015 <KERNELBASE.dll+0x14015>)
# 2 snmpapi.dll!SnmpUtilMemAlloc +0xf (0x73db1ee8 <snmpapi.dll+0x1ee8>)
# 3 _ada_snmp_example [C:/Users/username/Desktop/SNMPExample/src/snmp_example.adb:123]
# 4 main [C:\Users\username\Desktop\SNMPExample\obj/b__snmp_example.adb:259]
Полный исходный код:
with Ada.Text_IO;
with Ada.Unchecked_Conversion;
with Interfaces.C.Strings;
with System;
with Win32;
with Win32.Mgmtapi;
with Win32.Snmp;
procedure SNMP_Example
is
-- Imported functions and procedures
procedure SnmpUtilMemAlloc (nBytes : Win32.UINT);
pragma Import (Stdcall, SnmpUtilMemAlloc, "SnmpUtilMemAlloc");
procedure SnmpUtilMemFree (pMem : Win32.LPVOID);
pragma Import (Stdcall, SnmpUtilMemFree, "SnmpUtilMemFree");
function SnmpUtilOidCpy
(DestObjId : access Win32.Snmp.AsnObjectIdentifier;
SrcObjId : access Win32.Snmp.AsnObjectIdentifier)
return Win32.INT;
pragma Import (Stdcall, SnmpUtilOidCpy, "SnmpUtilOidCpy");
procedure SnmpUtilOidFree (Obj : access Win32.Snmp.AsnObjectIdentifier);
pragma Import (Stdcall, SnmpUtilOidFree, "SnmpUtilOidFree");
procedure SnmpUtilVarBindFree (VarBind : access Win32.Snmp.RFC1157VarBind);
pragma Import (Stdcall, SnmpUtilVarBindFree, "SnmpUtilVarBindFree");
procedure SnmpUtilVarBindListFree (VarBindList : access Win32.Snmp.RFC1157VarBindList);
pragma Import (Stdcall, SnmpUtilVarBindListFree, "SnmpUtilVarBindListFree");
-- Conversion related
function To_LPVOID is new Ada.Unchecked_Conversion (Win32.LPSTR, Win32.LPVOID);
function To_PCSTR is new Ada.Unchecked_Conversion (Win32.PBYTE, Win32.PCSTR);
-- Linker options
pragma Linker_Options ("-lmgmtapi");
pragma Linker_Options ("-lsnmpapi");
-- Connection related (Ada)
IP_Address : constant String := "127.0.0.1";
Community_String : constant String := "public";
Timeout_MS : constant Integer := 500;
Number_Of_Retries : constant Integer := 1;
-- Connection related (C)
IP_Address_C : Interfaces.C.Strings.chars_ptr := Interfaces.C.Strings.New_String (IP_Address);
Community_String_C : Interfaces.C.Strings.chars_ptr := Interfaces.C.Strings.New_String (Community_String);
-- Connection related (Win32)
IP_Address_Win32 : constant Win32.LPSTR := Win32.To_PSTR (IP_Address_C);
Community_String_Win32 : constant Win32.LPSTR := Win32.To_PSTR (Community_String_C);
Timeout_MS_Win32 : constant Win32.INT := Win32.INT (Timeout_MS);
Number_Of_Retries_Win32 : constant Win32.INT := Win32.INT (Number_Of_Retries);
-- Comparison of types related
use type Interfaces.C.int;
use type Win32.BOOL;
use type Win32.Mgmtapi.LPSNMP_MGR_SESSION;
-- Session
SNMP_Session : Win32.Mgmtapi.LPSNMP_MGR_SESSION;
-- Custom types
type Counter_Type is mod 2**32 - 1;
type Gauge_Type is mod 2**32 - 1;
begin
-- Open session
SNMP_Session := Win32.Mgmtapi.SnmpMgrOpen
(lpAgentAddress => IP_Address_Win32,
lpAgentCommunity => Community_String_Win32,
nTimeOut => Timeout_MS_Win32,
nRetries => Number_Of_Retries_Win32);
if SNMP_Session = null then
Ada.Text_IO.Put_Line ("Failed to open session.");
else
Ada.Text_IO.Put_Line ("Opened session.");
Send_Request : declare
-- Request related (Ada)
SNMP_Object_Identifier_Ada : constant String := ".1.3.6.1.2.1.1.5.0";
-- Request related (C)
SNMP_Object_Identifier_C : Interfaces.C.Strings.chars_ptr := Interfaces.C.Strings.New_String (SNMP_Object_Identifier_Ada);
-- Request related (Win32)
SNMP_Object_Identifier_Win32 : constant Win32.LPSTR := Win32.To_PSTR (SNMP_Object_Identifier_C);
SNMP_Object_Identifier : aliased Win32.Snmp.AsnObjectIdentifier;
Variable_Bindings : aliased Win32.Snmp.RFC1157VarBindList;
Variable_Bindings_Entry : aliased Win32.Snmp.RFC1157VarBind;
Error_Status : aliased Win32.Snmp.AsnInteger;
Error_Index : aliased Win32.Snmp.AsnInteger;
Return_Value_String_To_OID_Conversion : Win32.BOOL;
Return_Value_OID_Copy : Win32.INT;
Return_Value_Request : Win32.INT;
Return_Value_OID_To_String_Conversion : Win32.BOOL;
begin
Return_Value_String_To_OID_Conversion := Win32.Mgmtapi.SnmpMgrStrToOid
(string => SNMP_Object_Identifier_Win32,
oid => SNMP_Object_Identifier'Access);
if Return_Value_String_To_OID_Conversion = 0 then
Ada.Text_IO.Put_Line ("Failed to convert string to object identifier.");
else
Ada.Text_IO.Put_Line ("Converted string to object identifier.");
-- Allocate memory
-- Allocated memory is not freed properly
SnmpUtilMemAlloc (Win32.UINT (Win32.Snmp.RFC1157VarBind'Size * System.Storage_Unit));
Return_Value_OID_Copy := SnmpUtilOidCpy
(DestObjId => Variable_Bindings_Entry.name'Unrestricted_Access,
SrcObjId => SNMP_Object_Identifier'Access);
if Return_Value_OID_Copy = 0 then
Ada.Text_IO.Put_Line ("Failed to copy object identifier.");
else
Ada.Text_IO.Put_Line ("Copied object identifier.");
-- Construct variable bindings entry
Variable_Bindings_Entry.value.asnType := Win32.Snmp.ASN_NULL;
-- Construct variable bindings
Variable_Bindings.len := 1;
Variable_Bindings.list := Variable_Bindings_Entry'Unchecked_Access;
Return_Value_Request := Win32.Mgmtapi.SnmpMgrRequest
(session => SNMP_Session,
requestType => Win32.Snmp.ASN_RFC1157_GETREQUEST,
variableBindings => Variable_Bindings'Access,
errorStatus => Error_Status'Access,
errorIndex => Error_Index'Access);
if Return_Value_Request = 0 then
Ada.Text_IO.Put_Line ("Failed to send request.");
else
Ada.Text_IO.Put_Line ("Sent request.");
Ada.Text_IO.Put_Line ("Type is:" & Win32.BYTE'Image (Variable_Bindings.list.value.asnType));
case Variable_Bindings.list.value.asnType is
when Win32.Snmp.ASN_INTEGER =>
Ada.Text_IO.Put_Line (Integer'Image (Integer (Variable_Bindings.list.value.asnValue.number)));
when Win32.Snmp.ASN_OCTETSTRING =>
Ada.Text_IO.Put_Line (Interfaces.C.Strings.Value (Win32.To_Chars_Ptr (To_PCSTR (Variable_Bindings.list.value.asnValue.string.stream))));
when Win32.Snmp.ASN_RFC1155_COUNTER =>
Ada.Text_IO.Put_Line (Counter_Type'Image (Counter_Type (Variable_Bindings.list.value.asnValue.counter)));
when Win32.Snmp.ASN_RFC1155_GAUGE =>
Ada.Text_IO.Put_Line (Gauge_Type'Image (Gauge_Type (Variable_Bindings.list.value.asnValue.counter)));
when Win32.Snmp.ASN_RFC1155_TIMETICKS =>
Ada.Text_IO.Put_Line (Duration'Image (Duration (Variable_Bindings.list.value.asnValue.ticks) / 100));
when others =>
Ada.Text_IO.Put_Line ("Unsupported type.");
end case;
-- Convert object identifier to string
Convert_OID_To_String : declare
OID_String_Win32 : aliased Win32.LPSTR;
begin
Return_Value_OID_To_String_Conversion := Win32.Mgmtapi.SnmpMgrOidToStr
(oid => Variable_Bindings.list.name'Unrestricted_Access,
string => OID_String_Win32'Unchecked_Access);
if Return_Value_OID_To_String_Conversion = 0 then
Ada.Text_IO.Put_Line ("Failed to convert object identifier to string.");
else
Ada.Text_IO.Put_Line (Interfaces.C.Strings.Value (Win32.To_Chars_Ptr (OID_String_Win32)));
end if;
SnmpUtilMemFree (To_LPVOID (OID_String_Win32));
end Convert_OID_To_String;
-- Free memory
SnmpUtilOidFree (SNMP_Object_Identifier'Access);
SnmpUtilVarBindFree (Variable_Bindings_Entry'Access);
SnmpUtilVarBindListFree (Variable_Bindings'Access);
Interfaces.C.Strings.Free (IP_Address_C);
Interfaces.C.Strings.Free (Community_String_C);
Interfaces.C.Strings.Free (SNMP_Object_Identifier_C);
end if;
end if;
end if;
end Send_Request;
Close_Session : declare
Return_Value : constant Win32.BOOL := Win32.Mgmtapi.SnmpMgrClose (SNMP_Session);
begin
if Return_Value = 0 then
Ada.Text_IO.Put_Line ("Failed to close session.");
else
Ada.Text_IO.Put_Line ("Closed session.");
end if;
end Close_Session;
end if;
end SNMP_Example;