idlers Posted March 16, 2013 Share Posted March 16, 2013 Hi,This is my first post, although I've been using the forums as a fantastic source of inspiration and help for a couple of years. I'm trying to get the SubnetName and SubnetComments back from a dll call to dhcpsapi, but seem to just get pointers to returned strings, and can't work out how to get the actual strings themselves. The function returns a dll structure, which includes the strings inside. I've looked at some other posts which have just made me more confused. Can anyone help? The code takes a string with the dhcp server's ip address, and another string with the subnetID. This is the code I've cobbled together so far, modifying the DHCP.au3 from amel27 It also uses a couple of functions I found on the forums to translate the $subnet string to a binary value, and then to it's int value:expandcollapse popupFunc _DHCP_GetSubnetInfo($sDHCP, $subnet) Local $tEnumSubnetsParms = DllStructCreate("ptr SubnetInfoPtr;DWORD Subnet") Local $infoArray[4]=[0, 0, 0, 0], $tSubnetInfoStr, $tAddress, $aRet, $temp, $tempArray, $tSubnetInfo Local $returnedString ; Translate the $subnet string to a string of 32 bits $tempArray = StringSplit($subnet, ".") For $i = 1 To UBound($tempArray) -1 $temp = $temp & _binary($tempArray[$i]) Next ; Now turn this into an int value to pass to the DHCP server $subnet = _BinToInt($temp) $aRet = DllCall("Dhcpsapi.dll", "int", "DhcpGetSubnetInfo", _ "wstr", $sDHCP, _ "int", $subnet, _ "ptr", DllStructGetPtr($tEnumSubnetsParms, "SubnetInfoPtr") ) If $aRet[0] Then Return 2; SetError(2, $aRet[0]) ; ERR: Any runtime errors ; Debug _ArrayDisplay($aRet) If DllStructGetData($tEnumSubnetsParms,"SubnetInfoPtr")=0 Then Return 1; SetError(1, 0, $infoArray) ; ERR: Not Found $tSubnetInfoStr = DllStructCreate("ptr SubnetAddress;ptr SubnetMask;ptr SubnetName;ptr SubnetComment;ptr PrimaryHost;ptr SubnetState", DllStructGetData($tEnumSubnetsParms,"SubnetInfoPtr")) $tSubnetInfo = DllStructCreate("char[" & DllStructGetData($tSubnetInfoStr, 3) & "]"); , DllStructGetData($tEnumSubnetsParms, "SubnetInfoPtr")) ; Debug If $tSubnetInfoStr = 0 Then MsgBox(0, "E", @error) EndIf ; Let's see what we have MsgBox(0, "G", DllStructGetData($tSubnetInfoStr, 1)) ; Freeing memory DllCall("Dhcpsapi.dll", "none", "DhcpRpcFreeMemory", "ptr", DllStructGetData($tEnumSubnetsParms,"EnumInfoPtr")) Return $infoArray EndFuncThanks so much for any help anyone can give! Link to comment Share on other sites More sharing options...
JohnOne Posted March 17, 2013 Share Posted March 17, 2013 I'm certainly no expert, but in lieu of an answer I'll just make a few observations, and ask a few questions which might clear up a few things for someone who is able to help you.How certain are you that $sDHCP is a unicode string?Param 2 (DHCP_IP_ADDRESS) of DhcpGetSubnetInfo wants a DWORD where you are passing type int (according to msdn page.MSDN says the ID you can pass can be decimal (not integer) so DWORD might be the best option.If param 3 does indeed take a pointer, then that is also the out value which should be a structure of which element should be your SubnetName and element 4 be your SubnetComment, both strings (wstr) to autoit.To be honest I cannot really figure out what you are doing in that function, for example.$tSubnetInfoStr = DllStructCreate(.....)Here you seem to be trying to create your own structure similar to what should have already been returned in param 3 of your dllcall.Like I said, I'm only posting this in lieu of an answer. Hope you get something from it. AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
idlers Posted March 17, 2013 Author Share Posted March 17, 2013 Hi JohnOne, Thanks so much for your reply. I'm pretty certain that the $sDHCP string is correct, as this was copied directly out of the DHCP_EnumSubnets in the DHCP.au3 that amel27. I'm also fairly confident that passing the the ip address as an int is OK, as initially I was getting an error message returned from the DHCP server stating that the subnet was not found. After a bit of tinkering, I am now getting a success message (return code 0), plus the ip address of the server, the subnetID, plus a pointer to something else. From this "something else" (which I believe to be a DHCP_subnetInfo structure), I am managing to extract pointers to other elements, which are different to the pointer that is originally returned by the dllCall. But where I'm getting lost (and probably going around in circles), is how to extract the actual elements from the returned DHCP_subnetInfo structure. There's something there, but I just can't read it properly! As I'm trying to read from a structure, I thought I would have to create another structure to read the elements into, and then extract the subnetName etc from that. But now I'm just confused as neither reading direct from the returned structure, or moving the elements into another one, seem to work. It's my first time trying to use dllcall - maybe I just need to spend some more time using it in other (simpler!) ways to get my head around it... Link to comment Share on other sites More sharing options...
JohnOne Posted March 17, 2013 Share Posted March 17, 2013 (edited) What do you get if you just read the struct element directly? $aRet = DllCall("Dhcpsapi.dll", "int", "DhcpGetSubnetInfo", _ "wstr", $sDHCP, _ "int", $subnet, _ "ptr", DllStructGetPtr($tEnumSubnetsParms, "SubnetInfoPtr") ) If $aRet[0] Then Return 2; SetError(2, $aRet[0]) ; ERR: Any runtime errors If Not IsDllStruct($tEnumSubnetsParms) Then MsgBox(0,0,"Not DllStruct") Exit EndIf MsgBox(0,0,DllStructGetData($tEnumSubnetsParms,3)) Edited March 17, 2013 by JohnOne AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
idlers Posted March 17, 2013 Author Share Posted March 17, 2013 Hmmm...interesting - I just get a message box with a "0" in the title and in the text, so it IS a structure, but it's value can't be displayed that way. Now, that made me wonder if I'm wrong about the subnetInfo being a dll structure...so, I tried adding a test to that, ie after:$tSubnetInfoStr = DllStructCreate("ptr SubnetAddress;ptr SubnetMask;ptr SubnetName;ptr SubnetComment;ptr PrimaryHost;ptr SubnetState", DllStructGetData($tEnumSubnetsParms,"SubnetInfoPtr"))I added this:If IsDllStruct(DllStructGetData($tSubnetInfoStr, 3)) Then MsgBox(0, "", "Yup, it's a structure")Else MsgBox(0, "", "Not a structure")EndIfwhich came back saying that it wasn't a structure - but then the help file for isDllStruct says:Returns 0 if expression is not DllStruct type as return by DllStructCreate.As this has come back from the dhcp server, then it's been created remotely, rather than in AutoIT. Maybe AutoIT can't handle remotely-generated dll structures? Link to comment Share on other sites More sharing options...
idlers Posted March 18, 2013 Author Share Posted March 18, 2013 OK, I've made some progress. I'm now getting the first character of the subnetName, but I'm not sure how to get the rest of the string. Does anyone know what I need to do from here? I tried using DllStructGetSize and a For loop in the hope that would give me the length of the string that the pointer points to, but that only gave me the same character twice. How would I get the length of the string in memory? Thanks for any help! expandcollapse popupFunc _DHCP_GetSubnetInfo1($sDHCP, $subnet) Local $tEnumSubnetsParms = DllStructCreate("ptr SubnetInfoPtr;DWORD Subnet") Local $infoArray[4]=[0, 0, 0, 0], $tSubnetInfoStr, $tAddress, $aRet, $temp, $tempArray, $tSubnetInfo Local $returnedString ; Set the $subnet to correct structure $tempArray = StringSplit($subnet, ".") If @error Then MsgBox(0, @error, "Error creating dll structure") EndIf For $i = 1 To UBound($tempArray) -1 $temp = $temp & _binary($tempArray[$i]) Next $subnet = _BinToInt($temp) $aRet = DllCall("Dhcpsapi.dll", "HANDLE", "DhcpGetSubnetInfo", _ "wstr", $sDHCP, _ "int", $subnet, _ "ptr", DllStructGetPtr($tEnumSubnetsParms, "SubnetInfoPtr") ) If $aRet[0] Then Return 2; SetError(2, $aRet[0]) ; ERR: Any runtime errors If DllStructGetData($tEnumSubnetsParms,"SubnetInfoPtr")=0 Then Return 1; ERR: Not Found $tSubnetInfoStr = DllStructCreate("ptr SubnetAddress;ptr SubnetMask;ptr SubnetName;ptr SubnetComment;ptr PrimaryHost;ptr SubnetState", DllStructGetData($tEnumSubnetsParms,"SubnetInfoPtr")) ; This gives me the first character of the string only - eg "M" $returnedString = DllStructCreate('wchar', DllStructGetData($tSubnetInfoStr, 3)) MsgBox(0, "", DllStructGetData($returnedString, 1)) ; This gives me the first character of the string twice eg "MM" $temp = DllStructCreate('wchar', DllStructGetData($tSubnetInfoStr, 3)) For $i = 1 To DllStructGetSize($temp) $returnedString = $returnedString & DllStructGetData($temp, 1) Next ; Freeing memory DllCall("Dhcpsapi.dll", "none", "DhcpRpcFreeMemory", "ptr", DllStructGetData($tEnumSubnetsParms,"EnumInfoPtr")) MsgBox(0, "1", "placeholder") Return $infoArray EndFunc Link to comment Share on other sites More sharing options...
idlers Posted March 18, 2013 Author Share Posted March 18, 2013 Sorted! This is what I did, in case anyone needs it in the future...Thanks to the following:_binToInt function from Spiff59 taken from _binary function from LimeSeed taken from The function takes a string value for the dhcp server's IP address and a string value for the subnetID, and returns a string with the subnet name from the DHCP scope:expandcollapse popupFunc _DHCP_GetSubnetInfo($sDHCP, $subnetID) Local $tEnumSubnetsParms = DllStructCreate("ptr SubnetInfoPtr;DWORD Subnet") Local $infoArray[4]=[0, 0, 0, 0], $tSubnetInfoStr, $tAddress, $aRet, $temp, $tempArray, $tSubnetInfo Local $returnedString, $stringSize $stringSize = 32 ; Change the subnetID into binary $tempArray = StringSplit($subnetID, ".") For $i = 1 To UBound($tempArray) -1 $temp = $temp & _binary($tempArray[$i]) Next $subnetID = _BinToInt($temp) ; Make the dllCall $aRet = DllCall("Dhcpsapi.dll", "int", "DhcpGetSubnetInfo", _ "wstr", $sDHCP, _ "int", $subnetID, _ "ptr", DllStructGetPtr($tEnumSubnetsParms, "SubnetInfoPtr") ) If $aRet[0] Then Return 0; ERR: Any runtime errors If DllStructGetData($tEnumSubnetsParms,"SubnetInfoPtr")=0 Then Return -1; ERR: Not Found ; Create a new structure to hold all the elements returned in the DHCP_subnet_info structure $tSubnetInfoStr = DllStructCreate("ptr SubnetAddress;ptr SubnetMask;ptr SubnetName;ptr SubnetComment;ptr PrimaryHost;ptr SubnetState", DllStructGetData($tEnumSubnetsParms,"SubnetInfoPtr")) If @error Then MsgBox(0, @error, "Error creating dll structure") EndIf ; Now, pull out the element that we want - SubnetName is the only one implemented here for now ; (1 = SubnetAddress (DHCP_IP_ADDRESS), 2 = SubnetMask(DHCP_IP_MASK), 3 = SubnetName (LPWSTR), 4 = SubnetComment (LPWSTR) , 5 = PrimaryHost(DHCP_HOST_INFO) ; 6 = SubnetState(DHCP_SUBNET_STATE) $temp = DllStructCreate('wchar[' & $stringSize & ']', DllStructGetData($tSubnetInfoStr, 3)) If @error Then MsgBox(0, @error, "Error creating dll structure") EndIf ; Get the data For $i = 1 To $stringSize $returnedString = $returnedString & DllStructGetData($temp, 1, $i) Next ; Freeing memory DllCall("Dhcpsapi.dll", "none", "DhcpRpcFreeMemory", "ptr", DllStructGetData($tEnumSubnetsParms,"EnumInfoPtr")) Return $returnedString EndFunc Func _binary($num) ;converts a number to binary! Local $string dim $string = "" Do $num = $num/2 if(floor($num) = $num) then $string = $string & "0" Else $string = $string & "1" $num -= .5 EndIf Until ($num = 0) While StringLen($string) < 8 $string = $string & "0" WEnd Return _stringreverse($string) EndFunc Func _BinToInt($sValue) Local $iOut = 0, $aValue = StringSplit($sValue, "") For $i = 1 To $aValue[0] $aValue[0] -= 1 If $aValue[$i] = "1" Then $iOut += 2 ^ ($aValue[0]) Next Return Int($iOut) EndFunc JohnOne 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now