Jump to content

Please explain the DllStructCreate(Struct, Pointer) syntax!

Recommended Posts

From the documentation of DllStructCreate(), it can be called using the following syntax:

DllStructCreate(Struct, Pointer)
Struct A string representing the structure to create (See Remarks).
Pointer [optional] If supplied the struct will not allocate memory but use the pointer supplied.

Would somebody here explain the usage of Pointer parameter clearly with some examples?

Thank's in advance.

Edited by tukangusil7
Link to post
Share on other sites

basically you are giving a reference to an already created data structure you are just defining what it contains to AutoIt

below is an entirely contrived example but it gives you the idea, typically the pointer would be returned from an API function

$tInit = DllStructCreate("BYTE[8]")
DllStructSetData($tInit, 1, 0xFF, 1)
DllStructSetData($tInit, 1, 0xEE, 2)
DllStructSetData($tInit, 1, 0xDD, 3)
DllStructSetData($tInit, 1, 0xCC, 4)
DllStructSetData($tInit, 1, 0x11, 5)
DllStructSetData($tInit, 1, 0x22, 6)
DllStructSetData($tInit, 1, 0x33, 7)
DllStructSetData($tInit, 1, 0x44, 8)

$tInitPtr = DllStructCreate("BYTE[4]", DllStructGetPtr($tInit)) ; Using a pointer $tInit
For $i = 1 To 4 ; Show Contents
    ConsoleWrite("0x" & Hex(DllStructGetData($tInitPtr, 1, $i)) & @CRLF)

; Setting the data here affects the original data
DllStructSetData($tInitPtr, 1, 0xBB, 1)
DllStructSetData($tInitPtr, 1, 0xAA, 2)
DllStructSetData($tInitPtr, 1, 0x99, 3)
DllStructSetData($tInitPtr, 1, 0x88, 4)

For $i = 1 To 4
    ConsoleWrite("0x" & Hex(DllStructGetData($tInit, 1, $i)) & @CRLF)

;lets start at second element (DllStructGetPtr($tInit) + 0 ) is initial (first) element
$tInitPtr = DllStructCreate("BYTE[4]", DllStructGetPtr($tInit) + 1)
For $i = 1 To 4
    ConsoleWrite("0x" & Hex(DllStructGetData($tInitPtr, 1, $i)) & @CRLF)

;lets start at third element
$tInitPtr = DllStructCreate("BYTE[4]", DllStructGetPtr($tInit) + 2)
For $i = 1 To 4
    ConsoleWrite("0x" & Hex(DllStructGetData($tInitPtr, 1, $i)) & @CRLF)

;lets start at fourth element
$tInitPtr = DllStructCreate("BYTE[4]", DllStructGetPtr($tInit) + 3)
For $i = 1 To 4
    ConsoleWrite("0x" & Hex(DllStructGetData($tInitPtr, 1, $i)) & @CRLF)


Link to post
Share on other sites


the "struct" reserves some memory, and the "pointer" points to the first adress of this memory.

Here an (not season related^^)  example which demonstrates the usage of the so called "memory" (which belongs to NOTHING! (meaning the datatypes) )

;create struct
$struct =dllstructcreate("int;float[4];dword")

;fill struct with data

;read some data from struct at offset 4


Link to post
Share on other sites
  • Moderators


Any explanation that refers to IKEA furniture cannot, by definition, be considered "simple"! ;)


Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:


ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Luigi
      A simple function to print a DllStruct on AutoIt.

      #include <StringConstants.au3> #include <Array.au3> Func DllStructPrint($str, $tag) Local $ret = "" If IsDllStruct($str) Then $tag = StringLower($tag) Local $arr1, $arr2 $arr1 = StringSplit($tag, ";", $STR_NOCOUNT) Local $aLabel[1] For $ii = 0 To UBound($arr1, 1) - 1 If Not ($arr1[$ii] = "struct") And Not ($arr1[$ii] = "endstruct") Then $arr2 = StringSplit($arr1[$ii], " ", $STR_NOCOUNT) If IsArray($arr2) Then _ArrayAdd($aLabel, $arr2[1]) EndIf Next For $ii = 1 To UBound($aLabel, 1) - 1 $ret &= $aLabel[$ii] & "=" & DllStructGetData($str, $aLabel[$ii]) Next ElseIf IsArray($str) Then $ret &= "[" & @LF Local $iSize = UBound($str, 1) - 1 For $ii = 0 To $iSize $ret &= " " & DllStructPrint($str[$ii], $tag) & ($ii = $iSize ? "" : ",") & @LF Next $ret &= "]" & @LF EndIf Return $ret EndFunc ;==>DllStructPrint Local $tag = "Struct;byte key;EndStruct" Local $str1 = DllStructCreate($tag) $str1.key = Random(100, 999) Local $str2 = DllStructCreate($tag) $str2.key = Random(100, 999) Local $str3 = DllStructCreate($tag) $str3.key = Random(100, 999) Local $arr[2] $arr[0] = $str2 $arr[1] = $str3 Local $var1 = DllStructPrint($str1, $tag) ConsoleWrite($var1 & @LF) Local $var2 = DllStructPrint($arr, $tag) ConsoleWrite($var2 & @LF)  
      OUTPUT: key=189 [ key=155, key=62 ]  
    • By supersonic
      Hi -
      Currently I'm playing around with Windows Credential Manager. I'm trying to access it with DllCall("advapi32.dll", ...) using the functions 'CredWriteW', 'CredReadW' and 'CredDeleteW'. All well. Another function I have to deal with is 'CredEnumerateW': https://docs.microsoft.com/en-us/windows/desktop/api/wincred/nf-wincred-credenumeratew/ .
      That's the test code I have so far:
      #include <Array.au3> #include <String.au3> Local $tCredentialsCount = DllStructCreate("DWORD;") Local $tPointerToArrayOfPointers = DllStructCreate("PTR;") ; Local $tPointerToArrayOfPointers = DllStructCreate(_StringRepeat("PTR;", 200)) ; ??? Local $aResult = DllCall("advapi32.dll", "BOOL", "CredEnumerateW", _ "WSTR", Null, "DWORD", 1, "DWORD", DllStructGetPtr($tCredentialsCount), "PTR", DllStructGetPtr($tPointerToArrayOfPointers)) If (Not @error) Then Local $iCredentialsCount = DllStructGetData($tCredentialsCount, 1) _ArrayDisplay($aResult, $iCredentialsCount) Local $hPointerToArrayOfPointers = DllStructGetData($tPointerToArrayOfPointers, 1) MsgBox(0, "$hPointerToArrayOfPointers", $hPointerToArrayOfPointers) ; Fails... For $i = 1 To 10 ; $iCredentialsCount MsgBox(0, $i & "___" & (($i * 2) - 1), DllStructGetData($tPointerToArrayOfPointers, ($i * 2) - 1)) Next $tCredentialsCount = 0 $tPointerToArrayOfPointers = 0 DllCall("advapi32.dll", "NONE", "CredFreeW", "PTR", $hPointerToArrayOfPointers) EndIf The DllCall seems to function properly - I get a valid count of credentials (on my computer ~ 133) and a pointer "to array of pointers".
      What is meant by "array of pointers"?
      Microsoft says: Pointer to an array of pointers to credentials. The returned credential is a single allocated block. Any pointers contained within the buffer are pointers to locations within this single allocated block.
      How to access these pointers... Contained within the buffer???
      Any information you can provide me would be greatly appreciated.
    • By tukangusil7
      _Security__GetTokenInformation() returns a struct containing raw bytes that represents the requested token information.
      Take for example, if _Security__GetTokenInformation()  called with  $iClass parameter is set to $TokenUser, the function returns raw bytes that represents a TOKEN_USER struct, which is defined as follows:
      typedef struct _TOKEN_USER { SID_AND_ATTRIBUTES User; } TOKEN_USER, *PTOKEN_USER; Subsequently, the SID_AND_ATTRIBUTES struct is defined as follows:
      typedef struct _SID_AND_ATTRIBUTES {   PSID  Sid;   DWORD Attributes; } SID_AND_ATTRIBUTES, *PSID_AND_ATTRIBUTES; Problems
      Since SID has variable length, I suppose that interpreting the returned bytes as SID_AND_ATTRIBUTES struct won't be easy as usual.
      Please inspect my GetTokenInfoUser function below.
      Have I got a correct value of Attributes member of SID_AND_ATTRIBUTES struct? If I have got the correct value, is my approach efficient? #include <Security.au3> #include <WinAPIHObj.au3> #include <Array.au3> Opt("MustDeclareVars", 1) Func GetTokenInfoUser($hToken) Do ; _Security__GetTokenInformation() returns a struct containing bytes that represents the ; requested token information. Local $tRawTokenInfo = _Security__GetTokenInformation($hToken, $TokenUser) If @error Then MsgBox($MB_SYSTEMMODAL, _WinAPI_GetLastError(), "_Security__GetTokenInformation() fails.") ExitLoop EndIf Local $pRawTokenInfo = DllStructGetPtr($tRawTokenInfo) ; Since SID has variable length, I do not know how to interpret the raw bytes as SID_AND_ATTRIBUTES ; struct unless the SID length is known. Local $tagPtrSid = "align 4; PTR Sid" Local $tPtrSid = DllStructCreate($tagPtrSid, $pRawTokenInfo) Local $pSid = DllStructGetData($tPtrSid, 1) If Not _Security__IsValidSid($pSid) Then ; Just to make sure $pSid is a pointer to a valid SID MsgBox($MB_SYSTEMMODAL, "", "The SID is invalid.") ExitLoop EndIf Local $iSidBytesLen = _Security__GetLengthSid($pSid) ; The length of the binary SID, in bytes ; After the SID length is known, the raw bytes are interpreted as SID_AND_ATTRIBUTES struct Local $tagSID_AND_ATTRIBUTES = "align 4; PTR Sid; BYTE[" & $iSidBytesLen & "]; ULONG Attributes" Local $tSID_AND_ATTRIBUTES = DllStructCreate($tagSID_AND_ATTRIBUTES, $pRawTokenInfo) ; Return the results Local $avResults[2] $avResults[0] = $pSid $avResults[1] = DllStructGetData($tSID_AND_ATTRIBUTES, "Attributes") Return $avResults Until False Return SetError(1, 0, 0) EndFunc ; GetTokenInfoUser Func Main() Do Local $hToken = _Security__OpenProcessToken(_WinAPI_GetCurrentProcess(), $TOKEN_QUERY) If Not $hToken Then MsgBox($MB_SYSTEMMODAL, _WinAPI_GetLastError(), "_Security__OpenProcessToken() fails.") ExitLoop EndIf Local $avResults = GetTokenInfoUser($hToken) If @error Then ExitLoop _ArrayDisplay($avResults) ; Display the results of GetTokenInfoUser() If $hToken Then _WinAPI_CloseHandle($hToken) Return Until False If $hToken Then _WinAPI_CloseHandle($hToken) EndFunc ; Main Main() Thanks in advance.
    • By tukangusil7
      When the type of a registry value given by RegQueryValueEx() is REG_RESOURCE_LIST constant (i.e. 8), the data received in the lpData (out) parameter is a pointer to a variable of type CM_RESOURCE_LIST struct.
      According to MSDN, CM_RESOURCE_LIST struct is defined as follows:
      typedef struct _CM_RESOURCE_LIST { ULONG Count; CM_FULL_RESOURCE_DESCRIPTOR List[1]; } *PCM_RESOURCE_LIST, CM_RESOURCE_LIST; Additionally, CM_FULL_RESOURCE_DESCRIPTOR struct is defined as follows:
      typedef struct _CM_PARTIAL_RESOURCE_LIST { USHORT Version; USHORT Revision; ULONG Count; CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1]; } CM_PARTIAL_RESOURCE_LIST, *PCM_PARTIAL_RESOURCE_LIST; Finally, CM_PARTIAL_RESOURCE_DESCRIPTOR struct is defined like that (long enough to be posted here).
      I have no idea how to create these kind of structs in AutoIt.
      Please tell me how to write them in AutoIt just until the second struct (CM_FULL_RESOURCE_DESCRIPTOR).
    • By c.haslam
      In the code that follows, it appears that DllStructCreate() is not allocating memory in
      $tag = 'byte val['&$iLength&']' . . Static Local $tvalue = DllStructCreate($tag) Running the code below, the problem does not show, but it does show in a much longer script: there _GDIPlus_ImageSaveToFile only writes about 30K bytes when it should write about 1MB, which it does when the code is
      $tag = 'char val['&$iLength&']' . . Static Local $tvalue = DllStructCreate($tag) It should write about 1 MB.
      I suggest caution in running the code below. On my PC, it caused a second instance of SciTE to appear at the top left of the Desktop, showing only the title bar, with a width of only approximately 200 pixels! Then rebooting the PC showed this at login. Further, double-clicking on the SciTE shortcut on the Desktop showed SciTE in the same way! (After running Regedit, and searching for SciTE, the shortcut behaves normally.)
      I would appreciate help in determining whether or not there is a bug in DLLStructCreate, preferably a way which does not clobber Windows. Of course, It is possible that there is a bug in my code.
      I have made $tvalue Static in the hope that this might make the code run properly. Doing this did not help.
      My code is based on code written by Authenticity and ChrisL.
      #include <GDIPlus.au3> #include <Array.au3> Opt('MustDeclareVars',1) ; Property Item structure Global Const $tagGDIPPROPERTYITEM = _ "uint id;" & _ ; ID of this property "ulong length;" & _ ; Length of the property value, in bytes "word type;" & _ ; Type of the value, as one of TAG_TYPE_XXX constants "ptr pvalue;" ; pointer to property value ; Image property types constants ; Ref: https://www.media.mit.edu/pia/Research/deepview/exif.html Global Const $GDIP_PROPERTYTAGTYPEUBYTE = 1 Global Const $GDIP_PROPERTYTAGTYPEASCII = 2 Global Const $GDIP_PROPERTYTAGTYPEUSHORT = 3 Global Const $GDIP_PROPERTYTAGTYPEULONG = 4 Global Const $GDIP_PROPERTYTAGTYPEURATIONAL = 5 Global Const $GDIP_PROPERTYTAGTYPESBYTE = 6 Global Const $GDIP_PROPERTYTAGTYPEUNDEFINED = 7 Global Const $GDIP_PROPERTYTAGTYPESSHORT = 8 Global Const $GDIP_PROPERTYTAGTYPESLONG = 9 Global Const $GDIP_PROPERTYTAGTYPESRATIONAL = 10 Global Const $GDIP_PROPERTYTAGTYPESFLOAT = 11 Global Const $GDIP_PROPERTYTAGTYPEDFLOAT = 12 main() Func main() _GDIPlus_Startup() Local $hImage = _GDIPlus_ImageLoadFromFile('H:\temp\AP test data\DSC00824 - Copy.jpg') Local $ar = _GDIPlus_ImageGetAllPropertyItemsEx($hImage) Local $propsAr[UBound($ar,1)-1][5],$vec,$j=-1 For $i = 1 To $ar[0][0] If $ar[$i][3]<>0 Then ; pValue -- for Sony! $j += 1 $propsAr[$j][0] = $ar[$i][0] ; id $propsAr[$j][1] = $ar[$i][1] ; length $propsAr[$j][2] =$ar[$i][2]; type $vec = _GDIPlus_ImageGetPropertyItemValue($ar[$i][1],$ar[$i][2],$ar[$i][3]) $propsAr[$j][3] = $vec[0] ; val1 Switch $ar[$i][2] Case 5,10 ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL $propsAr[$j][4] = $vec[1] Case Else $propsAr[$j][4] = '' EndSwitch EndIf Next ReDim $propsAr[$j+1][5] For $i = 0 To UBound($propsAr,1)-1 Switch $propsAr[$i][2] ; type Case 5,10 ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL _GDIPlus_ImageSetPropertyItemEx($hImage,$propsAr[$i][0],$propsAr[$i][1], _ $propsAr[$i][2],$propsAr[$i][3],$propsAr[$i][4]) Case Else _GDIPlus_ImageSetPropertyItemEx($hImage,$propsAr[$i][0],$propsAr[$i][1], _ $propsAr[$i][2],$propsAr[$i][3]) EndSwitch Next _GDIPlus_ImageSaveToFile($hImage,'H:\b\1.jpg') _GDIPlus_ImageDispose($hImage) _GDIPlus_Shutdown() EndFunc Func _GDIPlus_ImageGetAllPropertyItemsEx($hImage) Local $iI, $iCount, $tBuffer, $pBuffer, $iBuffer, $tPropertyItem, $aSize, $aPropertyItems[1][1], $aResult $aSize = _GDIPlus_ImageGetPropertySize($hImage) If @error Then Return SetError(@error, @extended, -1) $iBuffer = $aSize[0] $tBuffer = DllStructCreate("byte[" & $iBuffer & "]") $pBuffer = DllStructGetPtr($tBuffer) $iCount = $aSize[1] $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetAllPropertyItems", "hwnd", $hImage, "uint", $iBuffer, "uint", $iCount, "ptr", $pBuffer) If @error Then Return SetError(@error, @extended, -1) If $aResult[0] Then Return SetError(10, $aResult[0], False) ReDim $aPropertyItems[$iCount + 1][4] $aPropertyItems[0][0] = $iCount For $iI = 1 To $iCount $tPropertyItem = DllStructCreate($tagGDIPPROPERTYITEM, $pBuffer) $aPropertyItems[$iI][0] = DllStructGetData($tPropertyItem, "id") $aPropertyItems[$iI][1] = DllStructGetData($tPropertyItem, "length") $aPropertyItems[$iI][2] = DllStructGetData($tPropertyItem, "type") $aPropertyItems[$iI][3] = DllStructGetData($tPropertyItem, "pvalue") $pBuffer += DllStructGetSize($tPropertyItem) Next Return $aPropertyItems EndFunc Func _GDIPlus_ImageGetPropertyItemValue($iLength, $iType, $pValue) Static Local $tvalue Switch $iType Case 1,6 ; $GDIP_PROPERTYTAGTYPEUBYTE,$GDIP_PROPERTYTAGTYPESBYTE $tvalue = DllStructCreate('byte val',$pValue) Case 2 ; $GDIP_PROPERTYTAGTYPEASCII $tvalue = DllStructCreate('char val['&$iLength&']',$pValue) Case 3 ; $GDIP_PROPERTYTAGTYPEUSHORT $tvalue = DllStructCreate('ushort val',$pValue) Case 4 ; $GDIP_PROPERTYTAGTYPEULONG $tvalue = DllStructCreate('ulong val',$pValue) Case 5 ; $GDIP_PROPERTYTAGTYPEURATIONAL $tvalue = DllStructCreate('ulong val1;ulong val2',$pValue) Case 7 ; $GDIP_PROPERTYTAGTYPEUNDEFINED ; undefined, per specification, but may be a long but is sometimes a string $tvalue = DllStructCreate('byte val['&$ilength&']',$pValue) ; see _GDIPlus_ImageSetPropertyItemEx ;~ $tvalue = DllStructCreate('char val['&$ilength&']',$pValue) Case 8 ; $GDIP_PROPERTYTAGTYPESSHORT $tvalue = DllStructCreate('short val',$pValue) Case 9 ; $GDIP_PROPERTYTAGTYPEULONG $tvalue = DllStructCreate('ulong val',$pValue) Case 10 ; $GDIP_PROPERTYTAGTYPESRATIONAL $tvalue = DllStructCreate('ulong val1;ulong val2',$pValue) Case 11 ; $GDIP_PROPERTYTAGTYPESFLOAT $tvalue = DllStructCreate('float val',$pValue) Case 12 ; $GDIP_PROPERTYTAGTYPEDFLOAT $tvalue = DllStructCreate('double val',$pValue) EndSwitch If @error Then Return SetError(@error,0,-1) Switch $iType Case 5,10 ; $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL Local $aRet[2] $aRet[0] = DllStructGetData($tvalue,'val1') $aRet[1] = DllStructGetData($tvalue,'val2') Case Else Local $aRet[1] $aRet[0] = DllStructGetData($tvalue,'val') EndSwitch Return $aRet EndFunc Func _GDIPlus_ImageGetPropertySize($hImage) Local $aSize[2], $aResult $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetPropertySize", "hwnd", $hImage, "uint*", 0, "uint*", 0) If @error Then Return SetError(@error, @extended, -1) $aSize[0] = $aResult[2] $aSize[1] = $aResult[3] Return $aSize EndFunc ;==>_GDIPlus_ImageGetPropertySize Func _GDIPlus_ImageSetPropertyItemEx($hImage,$id,$iLength,$iType,$value1,$value2=-1) Local $tProp = DllStructCreate($tagGDIPPROPERTYITEM) DllStructSetData($tProp,'id',$id) DllStructSetData($tProp,'type',$itype) DllStructSetData($tProp,'length',$ilength) Local $tag Switch $iType Case $GDIP_PROPERTYTAGTYPEUBYTE,$GDIP_PROPERTYTAGTYPESBYTE $tag = 'byte val' Case $GDIP_PROPERTYTAGTYPEASCII $tag = 'char val['&$iLength&']' Case $GDIP_PROPERTYTAGTYPEUSHORT $tag = 'ushort val' Case $GDIP_PROPERTYTAGTYPEULONG $tag = 'ulong val' Case $GDIP_PROPERTYTAGTYPEURATIONAL $tag = 'ulong val1;ulong val2' Case $GDIP_PROPERTYTAGTYPEUNDEFINED ; undefined, per specification, but may be a long but is sometimes a string $tag = 'byte val['&$iLength&']' ; causes saving to jpeg to write junk ;~ $tag = 'char val['&$iLength&']' Case $GDIP_PROPERTYTAGTYPESSHORT $tag = 'short val' Case $GDIP_PROPERTYTAGTYPEULONG $tag = 'ulong val' Case $GDIP_PROPERTYTAGTYPESRATIONAL $tag = 'long val1;long val2' Case $GDIP_PROPERTYTAGTYPESFLOAT $tag = 'float val' Case $GDIP_PROPERTYTAGTYPEDFLOAT $tag = 'double val' EndSwitch Static Local $tvalue = DllStructCreate($tag) Switch $iType Case $GDIP_PROPERTYTAGTYPEURATIONAL,$GDIP_PROPERTYTAGTYPESRATIONAL DllStructSetData($tvalue,'val1',$value1) DllStructSetData($tvalue,'val2',$value2) Case Else DllStructSetData($tvalue,1,$value1) EndSwitch DllStructSetData($tProp,'pvalue',DllStructGetPtr($tvalue)) Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipSetPropertyItem", "hwnd", $hImage, "ptr", _ DllStructGetPtr($tProp)) If @error Then Return SetError(@error, @extended, -1) If $aResult[0] Then Return SetError(10, $aResult[0], -1) Return $aResult[0] = 0 EndFunc I have seen $iLength be as much as 37 KB for $GDIP_PROPERTYTAGTYPEUNDEFINED.
      Is there is a bug, how can this be demonstrated to the developers in a few lines of code (without clobbering Windows)?
  • Create New...