[COM] How to enumerate IEnumNetworkConnections in a more "native" way?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
qwerty12
Posts: 468
Joined: 04 Mar 2016, 04:33
Contact:

[COM] How to enumerate IEnumNetworkConnections in a more "native" way?

26 Mar 2016, 09:33

Sorry for my odd titling, I guess what I'm trying to say is: I can't figure out how to get to the network connections as returned by INetworkListManager::GetNetworkConnections. If I try naïvely enumerating, depending on whether I'm looking at the key or value and if I'm forcing it with ComObject, I get either: nothing, "No valid COM Object" or AutoHotkey crashing:

Code: Select all

#NoEnv

NetworkListManager := ComObjCreate("{DCB00C01-570F-4A9B-8D69-199FDBA5723B}")
IEnumNetworkConnections := NetworkListManager.GetNetworkConnections()
for key, val in IEnumNetworkConnections
{
	rgelt := ComObject(9, key, 1)
	INetwork := rgelt.GetNetwork()
	if (INetwork) {
		MsgBox % INetwork.GetName()
		ObjRelease(INetwork)
	}
}
I get the same result as the above if I call _NewEnum and try this:

Code: Select all

NetworkListManager := ComObjCreate("{DCB00C01-570F-4A9B-8D69-199FDBA5723B}")
IEnumNetworkConnections := NetworkListManager.GetNetworkConnections()._NewEnum() ; Uses IEnumNetworkConnections->get__NewEnum() ?
if IsObject(IEnumNetworkConnections)
    while IEnumNetworkConnections.Next(Key, Value)
    {
		INetwork := Value.GetNetwork()
		if (INetwork) {
			MsgBox % INetwork.GetName()
			ObjRelease(INetwork)
		}
    }
ComObjType() says the VarType for Key is 13 (VT_UNKNOWN) and says nothing for Value.

If I try calling IEnumNetworkConnections::Next, I do not have much success there either:

Code: Select all

NetworkListManager := ComObjCreate("{DCB00C01-570F-4A9B-8D69-199FDBA5723B}")
IEnumNetworkConnections := NetworkListManager.GetNetworkConnections()
VarSetCapacity(var, 1024, 0) ; lazily making the size large enough for now just to rule out one source of error
vref := ComObject(9 | 0x4000, &var) ; VT_DISPATCH | VT_BYREF
Next := IEnumNetworkConnections.Next(1, vref, 0) ; Does the last argument suffice for a NULL pointer, or must ComObject be used again? AHK doesn't bring up any error messages so I assume so...
INetwork := Next.GetNetwork()
if (INetwork) {
	MsgBox % INetwork.GetName() ; doesn't show
}

INetwork := vref.GetNetwork() ; no valid COM object!
if (INetwork) {
	MsgBox % INetwork.GetName()
}

INetwork := var.GetNetwork()
if (INetwork) {
	MsgBox % INetwork.GetName() ; doesn't show
}

If I give up and just go back to calling the method in the VTable directly, everything works (as seen below), but when everything here implements IDispatch or IEnumVariant, I feel like I'm missing out on something by not fully utilising the native AutoHotkey functionality that maps to those.

Code: Select all

#NoEnv
NetworkListManager := ComObjCreate("{DCB00C01-570F-4A9B-8D69-199FDBA5723B}")
IEnumNetworkConnections := NetworkListManager.GetNetworkConnections()
IEnumNetworkConnections_ptr := ComObjValue(IEnumNetworkConnections)
if (IEnumNetworkConnections_ptr)
{
	while (DllCall(NumGet(NumGet(IEnumNetworkConnections_ptr+0)+8*A_PtrSize), "Ptr", IEnumNetworkConnections_ptr, "UInt", 1, "Ptr*", rgelt, "Ptr", 0) == 0) ; IEnumNetworkConnections::Next
	{
		rgelt := ComObject(9, rgelt, 1)
		INetwork := rgelt.GetNetwork()
		if (INetwork) {
			MsgBox % INetwork.GetName() ; Actually shows the profile name of the network I'm connected to
			ObjRelease(INetwork)
		}
		ObjRelease(rgelt)
	}
}

ObjRelease(IEnumNetworkConnections)
ObjRelease(NetworkListManager)
Sorry for the many examples. Being able to know how to actually use the native enumeration facilities on the COM objects that support it would be the most beneficial to me.

Thanks.
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

26 Mar 2016, 17:51

Try this:

Code: Select all

for INetwork in ComObjCreate("{DCB00C01-570F-4A9B-8D69-199FDBA5723B}").GetNetworks(1)
	MsgBox % INetwork.GetName()
qwerty12
Posts: 468
Joined: 04 Mar 2016, 04:33
Contact:

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

26 Mar 2016, 17:57

Oh, wow, looking at how needlessly long my non-working examples were, I feel silly... That works great; thank you, HotKeyIt!

EDIT: Thanks, lexikos, as always, for your detailed posts. I'll know what to do the next I play with COM again. Making another post just to say "thanks" seems like a waste of everyone's time, so I'll just edit this one...
Last edited by qwerty12 on 26 Mar 2016, 21:45, edited 1 time in total.
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

26 Mar 2016, 21:12

qwerty12 wrote:rgelt := ComObject(9, key, 1)
As you said, ComObjType returns VT_UNKNOWN. That means key is a ComObject wrapper containing an IUnknown interface pointer. You can't invoke it directly (key.GetNetwork()) because invocation is something you do via the IDispatch interface, i.e. VT_DISPATCH.

ComObject(9, key, 1) is not valid, because key is a wrapper object, not a value that you can wrap, nor an integer/pointer:
Value
The value to wrap. Currently only integer and pointer values are supported.
When you have a variant (ComObject) of type VT_UNKNOWN, the correct way to attempt to turn it into a "usable" (VT_DISPATCH) object is:

Code: Select all

    pdsp := ComObjQuery(key, "{00020400-0000-0000-C000-000000000046}") ; IID_IDispatch
    rgelt := ComObject(9, pdsp, 1)
(Plus error-checking, if needed.)
ComObjType() says the VarType for Key is 13 (VT_UNKNOWN) and says nothing for Value.
Of course, the documentation will tell you that Value is a number, not a ComObject.
For COM objects, Key contains the value returned by IEnumVARIANT::Next() and Value contains a number which represents its variant type.
Source: For-loop
"Key" and "Value" are just variable names and typically reflect what they're used for, but an object's enumerator can put whatever it wants into those variables. COM object enumerators do not return key-value pairs.

Rather strange that GetNetworkConnections()'s enumerator returns VT_UNKNOWN values while GetNetworks(1) returns VT_DISPATCH.
User avatar
DataLife
Posts: 447
Joined: 29 Sep 2013, 19:52

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

14 May 2018, 18:29

HotKeyIt wrote:Try this:

Code: Select all

for INetwork in ComObjCreate("{DCB00C01-570F-4A9B-8D69-199FDBA5723B}").GetNetworks(1)
	MsgBox % INetwork.GetName()
HotKeyit,
Sometimes the above code returns ???

I am not able to reproduce this issue, but I have someone using one of my programs in Sweden and he is seeing this ???

Any idea what is happening? Is there a foreign character being returned that INetwork.GetName() can not handle?
Check out my scripts. (MyIpChanger) (ClipBoard Manager) (SavePictureAs)
All my scripts are tested on Windows 10, AutoHotkey 32 bit Ansi unless otherwise stated.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

14 May 2018, 19:10

All my scripts are tested on Windows 10, AutoHotkey 32 bit Ansi unless otherwise stated.
- Did you compile the script as ANSI?
- Has the user tried running your script with AHK Unicode?
- An idea that may or may not work: if it works differently in AHK ANSI/Unicode, you could try rewriting the code in a pure style using the interfaces directly, using Ptr/WStr pointing to a buffer and then StrGet.
E.g. the code would look something like this, DllCall with: pointer to interface's verb table + n*A_PtrSize (for the nth method), pointer to interface, other parameters.

Code: Select all

VarSetCapacity(WIN32_FIND_DATA, 592)
VarSetCapacity(vTarget, 260*2)
DllCall(NumGet(NumGet(pSL+0) + 3*A_PtrSize), Ptr,pSL, WStr,vTarget, Int,260, Ptr,&WIN32_FIND_DATA, UInt,0x4) ;IShellLink::GetPath
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
DataLife
Posts: 447
Joined: 29 Sep 2013, 19:52

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

14 May 2018, 23:21

jeeswg wrote:
All my scripts are tested on Windows 10, AutoHotkey 32 bit Ansi unless otherwise stated.
- Did you compile the script as ANSI?
- Has the user tried running your script with AHK Unicode?
- An idea that may or may not work: if it works differently in AHK ANSI/Unicode, you could try rewriting the code in a pure style using the interfaces directly, using Ptr/WStr pointing to a buffer and then StrGet.
E.g. the code would look something like this, DllCall with: pointer to interface's verb table + n*A_PtrSize (for the nth method), pointer to interface, other parameters.

Code: Select all

VarSetCapacity(WIN32_FIND_DATA, 592)
VarSetCapacity(vTarget, 260*2)
DllCall(NumGet(NumGet(pSL+0) + 3*A_PtrSize), Ptr,pSL, WStr,vTarget, Int,260, Ptr,&WIN32_FIND_DATA, UInt,0x4) ;IShellLink::GetPath
I compiled with 32 bit Ansi.
I can install the AutoHotkey unicode version and compile to see if that fixes it. My user does not use AHK.

I have no idea about all that other stuff, I.E....pure stle, Ptr/WStr, buffer, StrGet.

I have no problem compiling as Unicode if that fixes the issue.
thanks
Check out my scripts. (MyIpChanger) (ClipBoard Manager) (SavePictureAs)
All my scripts are tested on Windows 10, AutoHotkey 32 bit Ansi unless otherwise stated.
gregster
Posts: 8990
Joined: 30 Sep 2013, 06:48

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

14 May 2018, 23:58

Sometimes the above code returns ???
Does this happen when there are swedish characters in the network name? Then, I would guess ANSI is the problem...
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

22 May 2018, 18:39

- I installed Visual Studio which created this folder: C:\Program Files (x86)\Windows Kits\8.1, with lots of .h files in it.
- You can search the .h files for names and numbers. Note however that the numbers, commonly separated by hyphens, could be separated in different ways.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
TLM
Posts: 1608
Joined: 01 Oct 2013, 07:52
Contact:

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

22 May 2018, 19:15

thank you I had a feeling it was there or in windows sdk but I don't have access to either of them on this box
will check that out :)
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

27 May 2018, 19:00

- I was able to retrieve the text by using the interface directly. You could try compiling the script as both ANSI and Unicode, and see if your user has better luck.
- Note: this issue is also discussed here:
Ansi VS Unicode - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=49437
- The script works, but I don't use vtables too often so I would appreciate anyone checking over my (short) script.
- All of the information I used was from here:
C:\Program Files (x86)\Windows Kits\8.1\Include\um\netlistmgr.h
And from the MSDN pages for: INetworkListManager, IEnumNetworks and INetwork.
- I have some notes on handling interfaces here:
jeeswg's objects tutorial - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=29232

Code: Select all

q:: ;list networks
;source: netlistmgr.h
CLSID_NetworkListManager := "{DCB00C01-570F-4A9B-8D69-199FDBA5723B}"
IID_INetworkListManager := "{DCB00000-570F-4A9B-8D69-199FDBA5723B}"
pNLM := ComObjCreate(CLSID_NetworkListManager, IID_INetworkListManager)

;NLM_ENUM_NETWORK_CONNECTED := 0x1
;NLM_ENUM_NETWORK_DISCONNECTED := 0x2
;NLM_ENUM_NETWORK_ALL := 0x3
DllCall(vtable(pNLM,7), Ptr,pNLM, Int,0x3, PtrP,pEN) ;INetworkListManager::GetNetworks

while !DllCall(vtable(pEN,8), Ptr,pEN, UInt,1, PtrP,pN, UIntP,0) ;IEnumNetworks::Next
{
	DllCall(vtable(pN,7), Ptr,pN, PtrP,pNetworkName) ;INetwork::GetName
	vOutput .= StrGet(pNetworkName, "UTF-16") "`r`n"
	ObjRelease(pN)
}
ObjRelease(pEN), ObjRelease(pNLM)
Clipboard := vOutput
MsgBox, % vOutput
return

vtable(ptr, n) {
    ; NumGet(ptr+0) returns the address of the object's virtual function
    ; table (vtable for short). The remainder of the expression retrieves
    ; the address of the nth function's address from the vtable.
    return NumGet(NumGet(ptr+0), n*A_PtrSize)
}
- Hope this helps. Btw DataLife, nice avatar. Cheers.

- [EDIT:] Btw, to get the vtable information for interface 'XXX' I look up 'XXXVtbl' in the relevant .h (header) file, and parse the information manually.
- E.g. for the INetworkListManager interface, I looked up INetworkListManagerVtbl in netlistmgr.h.
C:\Program Files (x86)\Windows Kits\8.1\Include\um\netlistmgr.h
- Is there are a more direct way to do this? Or a large collection of lists somewhere?
- Here are the lists that I produced, but it's not easy to confirm that they're correct unless I test multiple methods manually via DllCall.

Code: Select all

;INetworkListManagerVtbl
;0 QueryInterface
;1 AddRef
;2 Release
;3 GetTypeInfoCount
;4 GetTypeInfo
;5 GetIDsOfNames
;6 Invoke
;7 GetNetworks
;8 GetNetwork
;9 GetNetworkConnections
;10 GetNetworkConnection
;11 get_IsConnectedToInternet
;12 get_IsConnected
;13 GetConnectivity
;14 SetSimulatedProfileInfo
;15 ClearSimulatedProfileInfo

;IEnumNetworksVtbl
;0 QueryInterface
;1 AddRef
;2 Release
;3 GetTypeInfoCount
;4 GetTypeInfo
;5 GetIDsOfNames
;6 Invoke
;7 get__NewEnum
;8 Next
;9 Skip
;10 Reset
;11 Clone

;INetworkVtbl
;0 QueryInterface
;1 AddRef
;2 Release
;3 GetTypeInfoCount
;4 GetTypeInfo
;5 GetIDsOfNames
;6 Invoke
;7 GetName
;8 SetName
;9 GetDescription
;10 SetDescription
;11 GetNetworkId
;12 GetDomainType
;13 GetNetworkConnections
;14 GetTimeCreatedAndConnected
;15 get_IsConnectedToInternet
;16 get_IsConnected
;17 GetConnectivity
;18 GetCategory
;19 SetCategory
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
DataLife
Posts: 447
Joined: 29 Sep 2013, 19:52

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

10 Jun 2018, 15:55

thanks jeeswg
I have compiled that as ansi and unicode and sent them to my user in Sweden. I am waiting on his reply with screenshots.
thanks for the compliment on my avatar.
DataLife
Check out my scripts. (MyIpChanger) (ClipBoard Manager) (SavePictureAs)
All my scripts are tested on Windows 10, AutoHotkey 32 bit Ansi unless otherwise stated.
User avatar
DataLife
Posts: 447
Joined: 29 Sep 2013, 19:52

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

10 Jun 2018, 17:54

DataLife wrote:thanks jeeswg
I have compiled that as ansi and unicode and sent them to my user in Sweden. I am waiting on his reply with screenshots.
thanks for the compliment on my avatar.
DataLife
jeeswg,
I got the results back, and using the vTable Dll method did not change anything.
I don't think the problem is retrieving the networks, I think it is displaying them properly.
As you can see below there is a difference when I compile as Ansi or Unicode.
I am stumped as to why some of his networks show properly and others do not. This tells me that AutoHotkey can not display the characters properly so it replaces them with ??? and other strange characters. Please see the 3 screen shots below.

This guy is in Sweden. I pulled some info from his system. Can you think of any other info I can pull from his system that may help figure this out?
https://www.dropbox.com/s/btq73oqvbg6ie ... o.PNG?dl=0

Ansi results of jeeswg's suggested code
https://www.dropbox.com/s/bi3s1vj319t9q ... i.png?dl=0

Unicode results of jeeswg's suggested code
https://www.dropbox.com/s/4a3n8a2advy62 ... e.png?dl=0

thank you very much for your help
Datalife
Check out my scripts. (MyIpChanger) (ClipBoard Manager) (SavePictureAs)
All my scripts are tested on Windows 10, AutoHotkey 32 bit Ansi unless otherwise stated.
User avatar
Flipeador
Posts: 1204
Joined: 15 Nov 2014, 21:31
Location: Argentina
Contact:

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

10 Jun 2018, 18:56

Hello DataLife,
I just uploaded a sample if you want to try: https://mega.nz/#!XUhija4Z!FnyInDm82DQU ... tGIeR7b-dY.
Note: I deleted the comment and I published it again with the correct file.
DataLife wrote:Should I have saved my script as Unicode or UTF8 before compiling with the Unicode version of Autohotkey?
Use UTF-8 with BOM.
User avatar
DataLife
Posts: 447
Joined: 29 Sep 2013, 19:52

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

10 Jun 2018, 23:10

Flipeador wrote:Hello DataLife,
I just uploaded a sample if you want to try: https://mega.nz/#!XUhija4Z!FnyInDm82DQU ... tGIeR7b-dY.
Note: I deleted the comment and I published it again with the correct file.
DataLife wrote:Should I have saved my script as Unicode or UTF8 before compiling with the Unicode version of Autohotkey?
Use UTF-8 with BOM.
I downloaded your sample. Was that sample saved as UTF-8 with BOM and compiled as unicode?

I saved my script as UTF-8 with BOM and compiled as unicode and sent it to my user in Sweden. I am waiting on his reply to see if it fixed the display issue.
thanks
DataLife
Check out my scripts. (MyIpChanger) (ClipBoard Manager) (SavePictureAs)
All my scripts are tested on Windows 10, AutoHotkey 32 bit Ansi unless otherwise stated.
just me
Posts: 9442
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

11 Jun 2018, 08:35

Hi DataLife,

for an additional test you can use jeeswg's script and change

Code: Select all

	vOutput .= StrGet(pNetworkName, "UTF-16") "`r`n"
to

Code: Select all

	vOutput .= StrGet(pNetworkName, "CP0") "`r`n"
to see whether there are identifiable ANSI strings stored somewhere in Sweden.
User avatar
DataLife
Posts: 447
Joined: 29 Sep 2013, 19:52

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

11 Jun 2018, 13:59

just me wrote:Hi DataLife,

for an additional test you can use jeeswg's script and change

Code: Select all

	vOutput .= StrGet(pNetworkName, "UTF-16") "`r`n"
to

Code: Select all

	vOutput .= StrGet(pNetworkName, "CP0") "`r`n"
to see whether there are identifiable ANSI strings stored somewhere in Sweden.
Should I save as UTF-8 with BOM and compile as Ansi or Unicode?

I ran jeeswg's code with your changes. The output showed 1 letter per line. What should I expect when my user in Sweden runs this code?
Check out my scripts. (MyIpChanger) (ClipBoard Manager) (SavePictureAs)
All my scripts are tested on Windows 10, AutoHotkey 32 bit Ansi unless otherwise stated.
User avatar
Flipeador
Posts: 1204
Joined: 15 Nov 2014, 21:31
Location: Argentina
Contact:

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

11 Jun 2018, 21:37

Would not it be better to send several test files compressed in ZIP?.
I recommend using AHK Unicode and always save your scripts in UTF-8 with BOM, that is the solution. I do not think CP0 (Ansi) is correct, the string is UTF-16 (Unicode). That is the reason why only one letter is displayed.
just me
Posts: 9442
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [COM] How to enumerate IEnumNetworkConnections in a more "native" way?

12 Jun 2018, 06:10

Flipeador wrote:I do not think CP0 (Ansi) is correct, the string is UTF-16 (Unicode).
It should be Unicode, but what is shown for the user in Sweden doesn't look like reasonable Unicode. One option would be ANSI. Otherwise it might be an arbitrary number read as Unicode.

BTW: More than 2700 different network connections! How did your user do that?

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 299 guests