Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
QM handling of C declarations
#1
Gintaras,
I really have hard time trying to port some C definitions in wanapi to QM....in fact, pointers and references do not seem handled the same in QM,
and that makes me lose a large amount of time

This is just an example, no real code needed for the moment....

somewhere in Winapi is this

dll iphlpapi #NotifyIpInterfaceChange @Family Callback !*CallerContext !InitialNotification *NotificationHandle
Callback: function !*CallerContext MIB_IPINTERFACE_ROW*Row NotificationType

NETIOAPI_API NotifyIpInterfaceChange(
_In_ ADDRESS_FAMILY Family,
_In_ PIPINTERFACE_CHANGE_CALLBACK Callback,
_In_ PVOID CallerContext,
_In_ BOOLEAN InitialNotification,
_Inout_ HANDLE *NotificationHandle
);

I try to understand how to handle this.

I did:


int y
_i=NotifyIpInterfaceChange(AF_UNSPEC &sub.g 0 1 &y)
if(_i=NO_ERROR) out "ok"
CancelMibChangeNotify2(y)

Frome there, i get "OK" result, so it works

#sub g v
function !*CallerContext MIB_IPINTERFACE_ROW*Row NotificationType (like definition above)


the problem here is that Row is defined as a pointer variable of MIB_IPINTERFACE_ROW type.

from MSDN
When the callback function is received when a change occurs and the Row parameter is not NULL, the pointer to the MIB_IPINTERFACE_ROW structure passed in the Row parameter contains incomplete data. The information returned in the MIB_IPINTERFACE_ROW structure is only enough information that an application can call the GetIpInterfaceEntry function to query complete information on the IP interface that changed. When the callback function is received, an application should allocate a MIB_IPINTERFACE_ROW structure and initialize it with the Family, InterfaceLuid and InterfaceIndex members in the MIB_IPINTERFACE_ROW structure pointed to by the Row parameter received. A pointer to this newly initialized MIB_IPINTERFACE_ROW structure should be passed to the GetIpInterfaceEntry function to retrieve complete information on the IP interface that was changed.

So i must declare a new MIB_IPINTERFACE_ROW, get Family, InterfaceLuid and InterfaceIndex from Row into it, then pass it to GetIpInterfaceEntry to get information.

an example program did that: http://www.antillia.com/sol9.2.0/classe ... ifier.html

As the code is not aimed to code something, i'd just like some explainations, and understant how QM handles pointers, references from Winapi C declarations (links are welcome)
#2
You probably saw QM help topic "Pointer, reference, array".

Differences of pointer usage in C/C++ and QM:
1. To access members of user-defined type (struct) through pointer, in C/C++ you write pointer->member. In QM - pointer.member.
2. QM does not have pointer arithmetic. C/C++ expression pointer+1 in QM must be pointer+sizeof(TYPE). But array access is the same - pointer[i].
3. In C/C++ pointer variables are often declared like int *p. It is the same as int* p (like in QM) when declaring single pointer. When multiple, in C/C++ you write int *p1, *p2.... In QM - int* p1 p2 (in C/C++ p2 would be not pointer).
4. Very often need to cast pointer type. In C/C++ it is TYPE1* p1=...; TYPE2* p2=(TYPE2*)p1. In QM you use operator + instead of (TYPE2*), like TYPE1* p1=...; TYPE2* p2=+p1.
5. QM is less strict, for example in your callback can be MIB_IPINTERFACE_ROW&Row (reference instead pointer, which is physically the same). Unless Row is an array, not a pointer to a single variable.
6. Don't remember now. Your questions can help to continue this list.

Your code is correct.

> So i must declare a new MIB_IPINTERFACE_ROW, get Family, InterfaceLuid and InterfaceIndex from Row into it, then pass it to GetIpInterfaceEntry to get information.
Exactly. if(Row!=0) MIB_IPINTERFACE_ROW r2; r2.Family=Row.Family...
#3
ok I understand some things better now.

2 more queries though

1. what kind of variable can be

str*&t variable

can't get it (from QM manual)

2. if you ever have spare time, it would be nice you port to QM the cited example, would be a great way to learn, and i'm sure would interest many of QM users who would like to go deeper in their programing skills and QM understanding

http://www.antillia.com/sol9.2.0/classe ... ifier.html
#4
The same as in C++. str*& means reference to str*. Physically is and behaves like str** (pointer to str*), but in code used like str*.
#5
yes, i supposed that, without seeing the aim of it

IIRC (i'm at work, so can't test in real)

int u=3

int* p=&u

p=memory address of u
*p=value of u = 3
&p=memory address of p

int**y =&p
&y = memoruy adress of y
y=memory address of p
*y = memory address of u
**y=value of u = 3

So i don't get the meaning of using str*&...

in the example from external site, there is still something confusing:

the callback function

static void WINAPI InterfaceChangeCallback(PVOID callerContext,
PMIB_IPINTERFACE_ROW row,
MIB_NOTIFICATION_TYPE notificationType)

is only declared on the beginning of code, and used in main procedure.
i understand that it fills on its own the parameters, the PMIB_IPINTERFACE_ROW row variable which must be filled is not declared anywhere.

Usually, functions are used with declared variables, even uninitialized, and filled later when a function use them.

1. How this work?
2. in the code in the site, Row is neither reference nor pointer (PMIB_IPINTERFACE_ROW row), which seems logical as from point 1., it is unavailable to code as not declared or initialized.

So the callback function can't find memory address for it (not a pointer) and can't pass it (reference).

But in QM headers, you state it as
Callback: function !*CallerContext MIB_IPINTERFACE_ROW*Row NotificationType

Where Row is a pointer

3. If so, how must I call Row as pointer or reference in code later? in your example, seems by reference as you use Row.family in your answer above.

Sorry to bore you, but i'd really like to understand...
#6
Quote:int**y =&p
&y = memoruy adress of y
y=memory address of p
*y = memory address of u
**y=value of u = 3

So i don't get the meaning of using str*&...

Less * and & in code.
In C/C++ also easier to access members. C++ example with *&: x->m. C++ example with **: (*x)->m. QM does not have -> and instead allows x.m in all cases where possible.

-----------------

Type PMIB_IPINTERFACE_ROW probably is a typedef or #define for MIB_IPINTERFACE_ROW*. Like the famous LPSTR actually is char*. When you see P or LP at the beginning of a type name in C/C++ code, it is probably a pointer. Microsoft always uses this naming convention.

Quote:the PMIB_IPINTERFACE_ROW row variable which must be filled is not declared anywhere
I see that the callback calls interfaceChanged(), which calls GetIpInterfaceEntry() (WinAPI) and passes the same row variable, not another MIB_IPINTERFACE_ROW variable.

3. Use as pointer. Or replace MIB_IPINTERFACE_ROW*Row to MIB_IPINTERFACE_ROW&Row and use as reference. When accessing members, in QM it is the same in both cases: Row.member.
#7
Quote:Less * and & in code.
In C/C++ also easier to access members. C++ example with *&: x->m. C++ example with **: (*x)->m. QM does not have -> and instead allows x.m in all cases where possible.

Ok, i think under the hood, QM has some optimisation and internal casting for making things easier, the same as passing a variable using +operator, which can be confusing when used to genuine syntax..but ok for me, as long i can "connect" both syntaxes...maybe less * or & are good after all

Quote:Type PMIB_IPINTERFACE_ROW probably is a typedef or #define for MIB_IPINTERFACE_ROW*. Like the famous LPSTR actually is char*. When you see P or LP at the beginning of a type name in C/C++ code, it is probably a pointer. Microsoft always uses this naming convention.

oops, missed that, yes it's in the MSDN declaration, my bad, so focused on MIB_IPINTERFACE_ROW of QM that i did not see it, yes indeed in example, it refers to a pointer, so your conversion is correct (how could it be different anyway)....


typedef struct _MIB_IPINTERFACE_ROW {
ADDRESS_FAMILY Family;
NET_LUID InterfaceLuid;
NET_IFINDEX InterfaceIndex;
.../...
} MIB_IPINTERFACE_ROW, *PMIB_IPINTERFACE_ROW;


Quote:the PMIB_IPINTERFACE_ROW row variable which must be filled is not declared anywhere
I see that the callback calls interfaceChanged(), which calls GetIpInterfaceEntry() (WinAPI) and passes the same row variable, not another MIB_IPINTERFACE_ROW variable.

Exactly, so my question stands: how can a function initialize a variable not even declared in the main code????????

static void WINAPI InterfaceChangeCallback(PVOID callerContext,
PMIB_IPINTERFACE_ROW row,
MIB_NOTIFICATION_TYPE notificationType) <--------- Main callback function, waiting for the unknow MIB_IPINTERFACE_ROW pointer
{
.....
notifier ->interfaceChanged(row, notificationType) <--- Certainly passed as a pointer, but which address this pointer points to as row is never declared?????
}
.../...
virtual void interfaceChanged(
PMIB_IPINTERFACE_ROW row, <--------- same row coming from nowhere
MIB_NOTIFICATION_TYPE notificationType)
{
const char* family = "Unknown";
if (row) {
//Is row is not NULL?
family = getFamily(row->Family); <--------- the -> syntax confirms the pointer type

Quote:3. Use as pointer. Or replace MIB_IPINTERFACE_ROW*Row to MIB_IPINTERFACE_ROW&Row and use as reference. When accessing members, in QM it is the same in both cases: Row.member.

Indeed from upper code, it is a pointer. But as a pointer, it must be pointing to a memory address to be usable, as reference, it must exist....

But my code fails on row.family statement, because it seems an invalid pointer, as it is not initialized, giving then invalid pointer error at execution.

In my QM code, row variable is not filled by the callback function it seems to be the best hypothesis.

Maybe i must use v command as it is coded in a sub function, maybe something else, will try later after work....

thanks for you patiente and time anyway, i'm sure i'll get it working with your support
#8
How I imagine all this:

void run()
{
Calls NotifyIpInterfaceChange (WinAPI) and passes address of callback function InterfaceChangeCallback.
}

void NotifyIpInterfaceChange(...) //this func is in iphlpapi.dll
{
MIB_IPINTERFACE_ROW row; //creates the variable and fills some its members
Calls your callback function and passes row address to it.
}

void InterfaceChangeCallback( MIB_IPINTERFACE_ROW* row)
{
Calls interfaceChanged and passes row to it.
}

void interfaceChanged(MIB_IPINTERFACE_ROW* row)
{
Calls GetIpInterfaceEntry (WinAPI) and passes row.
}

void GetIpInterfaceEntry(MIB_IPINTERFACE_ROW* row) //this func is in iphlpapi.dll
{
Fills row members.
}
#9
Ok, seems o be that way

in MSDN

"The invocation of the callback function specified in the Callback parameter is serialized.
The callback function should be defined as a function of type VOID"

Is ! = VOID in QM (not sure i actually saw it in QM doc, with byte IIRC),

and PVOID is !* then?

so callback function is type void, must it begin with function! <---- ! for void type?

if (NotifyIpInterfaceChange(family,
(PIPINTERFACE_CHANGE_CALLBACK)InterfaceChangeCallback,
this,
(BOOLEAN)initialNotification, //FALSE, 2009/09/26
&hNotification) == NO_ERROR)

how code the third element, which is "this" from a QM macro/function, maybe important to make code work

I put 0 in my code, but maybe an handle to main routine is needed?
#10
C/C++ void is not a type. It is a keyword that in different contexts means different things:
void as a function return type means "does not have a return type", "returns nothing". In QM the function should begin with "function param1 param2 ...".
void* means "any pointer type". You can assign any pointer type without casting. PVOID is void*. In QM can be used byte*, shorter !*.

QM also has "this". Like in C++, it can be used in class member functions. Pass 0 if don't need. Or pass address of some variable.
#11
In fact my function works well as it returns success return value.

But looking closely to the code, the main function is using a loop and an event trigger to fire the callback function , and my code is the raw
procedure, not feeded by any event, so row variable can't be filled in callback function.

So i must code the whole program in QM to hope any success in running main function.

But I learned a lot, and hope many QM users will too.


Forum Jump:


Users browsing this thread: 1 Guest(s)