Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 12/24/2020 in all areas

  1. I was in need of an IPC (Interprocess communication) between system, admin and user levels, and ended up writing this UDF to suit my wantings. Hope you find it useful too. Works from WinXP/Server2003 to the now current Win10/Server2016. It communicates between any mix of x32, x64, Admin, User. In the zip file, there is the UDF and an example: FMIPC(v0.2018.04.04).zip Special thanks to @RTFC for the help in the support forum
    1 point
  2. The Running Object Table (ROT) is a system global table where objects can register themselves. This makes the objects accessible in processes other than the process where the object was created. IRunningObjectTable and related interfaces provides access to register and maintain objects in the ROT. ThreadsOther threads related to ROT objects: Non-blocking data display functions IPC Techniques through ROT Objects AutoIt and Perl integration through ROT objects Access AutoIt by trancexx is about executing AutoIt commands in other programming languages. The AutoIt command is executed by calling a Call method of the ROT object. The example is based on the AutoItObject UDF. Posts (2021-01-03)This is a list of the most interesting posts below: Usage section with typical examples of the use of ROT objects with the following subsections: Passing array between AutoIt programs Passing array between AutoIt and VBScript Passing data through ROT Objects Executing Object Methods through VBScript VBScript (2021-01-03)VBScript is used as a consistent programming language to demonstrate the ROT technique for communicating between AutoIt and other languages. This is a list of the VBScript posts: Passing array between AutoIt and VBScript (in middle of post) Executing Object Methods through VBScript BasicRegister an objectExamples\1) Basic\0) ROT_RegisterObject.au3 #include <Array.au3> #include "..\..\Includes\IRunningObjectTable.au3" Example() Func Example() Local $sNameId = "DataTransferObject" & ROT_CreateGUID() Local $iHandle = ROT_RegisterObject( Default, $sNameId ) ; Default => Object = Dictionary object If Not $iHandle Then Return ConsoleWrite( "ROT_RegisterObject ERR" & @CRLF ) ConsoleWrite( "ROT_RegisterObject OK" & @CRLF ) Local $aROT_List = ROT_Enumerate() _ArrayDisplay( $aROT_List, "ROT_RegisterObject" ) EndFunc Output in _ArrayDisplay looks like this: DataTransferObject-{05DCB964-FD4B-40EC-A95A-999491347D20} $sNameId (similar to ProgID) is the identification of the ROT object and is used in the ObjGet() function to access the object in this way: Local $oDataTransferObject = ObjGet( "DataTransferObject-{05DCB964-FD4B-40EC-A95A-999491347D20}" ) ROT_CreateGUID() is used to make $sNameId unique. See below. ROT_RegisterObject() is the function that registers the object in the ROT. The Dictionary object is the actual object that is registered in the ROT. The Add method allows you to add a new key/item pair to the object. The key is often a string. The item property can be any COM compatible data type which includes most AutoIt data types. An exception is the DllStruct type which must be converted to a compatible type. Because many different data types can be used in the item property and the item can be identified through a key, the Dictionary object is generally applicable for many different purposes. More information about registering objects in the ROT can be found in this Microsoft documentation. ROT_Enumerate() enumerate the objects, that are registered in the ROT. The program that registers an object in the ROT plays the role of server. One or more programs that access the ROT object with the ObjGet() function play the role of clients. The ROT object is only available as long as the server program is running or until the server program deletes the object with the ROT_Revoke() function. You can find examples of using the functions in Examples\1) Basic\. ROT objects (2020-07-11)The Dictionary object is the default object in the ROT_RegisterObject() function. The object that's passed to this function is the actual object that's registered in the ROT. The Dictionary object works fine when passing data between AutoIt scripts, between AutoIt and VBScript, and between AutoIt and Perl. However, situations may easily arise where it can be an advantage to pass data with a very simple object with just a single property. There are several options for creating such a simple object. This can be done through C# and VB.NET code, as demonstrated in Using C# and VB Code in AutoIt through .NET Framework. And it can be done through the AutoItObject UDF. Examples\4) ROT Objects\ contains examples for creating the ROT object in these three ways. Client.au3 is the same script in all examples: #include <Array.au3> Example() Func Example() Local $sNameId = "DataTransfer" Local $oDataTransfer = ObjGet( $sNameId ) Local $aArray = $oDataTransfer.Item _ArrayDisplay( $aArray ) EndFunc Create object with C# code CSharp\Server.au3: #include "..\..\..\Includes\IRunningObjectTable.au3" #include "..\DotNetAll.au3" Example() Func Example() Local $aArray[1000][10] For $i = 0 To 1000 - 1 For $j = 0 To 10 - 1 $aArray[$i][$j] = $i & "/" & $j Next Next Local $oNetCode = DotNet_LoadCScode( FileRead( "Object.cs" ), "System.dll" ) Local $oCSObject = DotNet_CreateObject( $oNetCode, "CSObjClass" ) $oCSObject.Item = $aArray Local $sNameId = "DataTransfer" ROT_RegisterObject( Ptr( $oCSObject ), $sNameId ) RunWait( @AutoItExe & " /AutoIt3ExecuteScript " & "Client.au3" ) EndFunc CSharp\Object.cs: using System; public class CSObjClass { public object Item { get; set; } } Create object with VB.NET code VB.NET\Server.au3: #include "..\..\..\Includes\IRunningObjectTable.au3" #include "..\DotNetAll.au3" Example() Func Example() Local $aArray[1000][10] For $i = 0 To 1000 - 1 For $j = 0 To 10 - 1 $aArray[$i][$j] = $i & "/" & $j Next Next Local $oNetCode = DotNet_LoadVBcode( FileRead( "Object.vb" ), "System.dll" ) Local $oVBObject = DotNet_CreateObject( $oNetCode, "VBObjClass" ) $oVBObject.Item = $aArray Local $sNameId = "DataTransfer" ROT_RegisterObject( Ptr( $oVBObject ), $sNameId ) RunWait( @AutoItExe & " /AutoIt3ExecuteScript " & "Client.au3" ) EndFunc VB.NET\Object.vb: Imports System Public Class VBObjClass Public Property Item As Object End Class In AutoIt/Perl integration, the very first attempts were performed with the VB.NET object. Check for recognition of the ROT object with this Client.pl script (copied from the AutoIt/Perl example) : use strict; use Win32::OLE; my $oObj = Win32::OLE->GetObject( "DataTransfer" ); Win32::OLE->EnumAllObjects( sub { my $Object = shift; my $Class = Win32::OLE->QueryObjectType( $Object ); printf "Object = %s, Class = %s\n", $Object, $Class; } ); Gave the following output: Object = Win32::OLE=HASH(0x72a51c), Class = _VBObjClass ; VB.NET object Object = Win32::OLE=HASH(0x71b5a8), Class = IDictionary ; Dictionary object Create object with AutoItObject AutoItObject\Server.au3: #include "..\..\..\Includes\IRunningObjectTable.au3" #include "AutoitObject.au3" Example() Func Example() Local $aArray[1000][10] For $i = 0 To 1000 - 1 For $j = 0 To 10 - 1 $aArray[$i][$j] = $i & "/" & $j Next Next _AutoItObject_StartUp() Local $oObject = NewObject(), $sNameId = "DataTransfer" ROT_RegisterObject( Ptr( $oObject ), $sNameId ) Local $oDataTransfer = ObjGet( $sNameId ) $oDataTransfer.Item = $aArray RunWait( @AutoItExe & " /AutoIt3ExecuteScript " & "Client.au3" ) _AutoItObject_Shutdown() EndFunc Func NewObject() Local $oClassObject = _AutoItObject_Class() $oClassObject.AddProperty( "Item" ) Return $oClassObject.Object EndFunc Unique objectsWhen using ROT objects in real code, there is a particular question that needs to be addressed. The question is how to make sure that $sNameId, which clients use to access the object with the ObjGet() function, actually identifies a unique object. Running a server program twice in succession can easily create two ROT objects with the same $sNameId. But how do you actually access the ROT object that was created first and the ROT object that was created last? The answer to the question is to make sure that $sNameId also becomes unique so that you can distinguish between the two objects. To that end, the ROT_CreateGUID() function is created (copy of _WinAPI_CreateGUID()). The function can ensure a unique $sNameId as shown in the example above. The problem and solution is demonstrated in Examples\1) Basic\2) Multiple ROT objects.au3. Time stampsUsing the NoteChangeTime() and GetTimeOfLastChange() methods of the IRunningObjectTable interface, you can set and get timestamps on a ROT object. But these timestamps do not seem particularly useful. Therefore, the methods are not implemented. The UDFThe IRunningObjectTable UDF, Includes\IRunningObjectTable.au3, is a very small UDF with less than 150 lines of code: #include-once ; --- Interface definitions --- Global Const $sIID_IRunningObjectTable = "{00000010-0000-0000-C000-000000000046}" Global Const $dtag_IRunningObjectTable = _ "Register hresult(dword;ptr;ptr;dword*);" & _ "Revoke hresult(dword);" & _ "IsRunning hresult(ptr);" & _ "GetObject hresult(ptr;ptr*);" & _ "NoteChangeTime hresult(dword;struct*);" & _ "GetTimeOfLastChange hresult(ptr;ptr*);" & _ "EnumRunning hresult(ptr*);" Global Const $ROTFLAGS_REGISTRATIONKEEPSALIVE = 0x1 Global Const $ROTFLAGS_ALLOWANYCLIENT = 0x2 Global Const $sIID_IEnumMoniker = "{00000102-0000-0000-C000-000000000046}" Global Const $dtag_IEnumMoniker = _ "Next hresult(ulong;ptr*;ulong*);" & _ "Skip hresult(ulong);" & _ "Reset hresult();" & _ "Clone hresult(ptr*);" Global Const $sIID_IPersist = "{0000010C-0000-0000-C000-000000000046}" Global Const $dtag_IPersist = _ "GetClassID hresult(ptr*);" Global Const $sIID_IPersistStream = "{00000109-0000-0000-C000-000000000046}" Global Const $dtag_IPersistStream = $dtag_IPersist & _ "IsDirty hresult();" & _ "Load hresult(ptr);" & _ "Save hresult(ptr;bool);" & _ "GetSizeMax hresult(uint*);" Global Const $sIID_IMoniker = "{0000000F-0000-0000-C000-000000000046}" Global Const $dtag_IMoniker = $dtag_IPersistStream & _ "BindToObject hresult();" & _ "BindToStorage hresult();" & _ "Reduce hresult();" & _ "ComposeWith hresult();" & _ "Enum hresult();" & _ "IsEqual hresult();" & _ "Hash hresult();" & _ "IsRunning hresult(ptr;ptr;ptr);" & _ "GetTimeOfLastChange hresult(ptr;ptr;ptr);" & _ "Inverse hresult();" & _ "CommonPrefixWith hresult();" & _ "RelativePathTo hresult();" & _ "GetDisplayName hresult(ptr;ptr;wstr*);" & _ "ParseDisplayName hresult();" & _ "IsSystemMoniker hresult(ptr*);" ; --- Windows API functions --- Func ROT_GetRunningObjectTable() Return DllCall( "Ole32.dll", "long", "GetRunningObjectTable", "dword", 0, "ptr*", 0 )[2] EndFunc Func ROT_CreateFileMoniker( $sNameId ) Return DllCall( "Ole32.dll", "long", "CreateFileMoniker", "wstr", $sNameId, "ptr*", 0 )[2] EndFunc Func ROT_CreateBindCtx() Return DllCall( "Ole32.dll", "long", "CreateBindCtx", "dword", 0, "ptr*", 0 )[2] EndFunc ; --- UDF functions --- ; Failure: Returns 0 ; Success: Returns $iHandle ; Registers an object and its identifying moniker in the ROT Func ROT_RegisterObject( $pObject, $sNameId, $iFlags = $ROTFLAGS_REGISTRATIONKEEPSALIVE ) If $pObject = Default Then Local $oDict = ObjCreate( "Scripting.Dictionary" ) $pObject = Ptr( $oDict ) EndIf If Not $pObject Or Not $sNameId Then Return 0 Local $oRunningObjectTable = ObjCreateInterface( ROT_GetRunningObjectTable(), $sIID_IRunningObjectTable, $dtag_IRunningObjectTable ) If Not IsObj( $oRunningObjectTable ) Then Return 0 Local $pMoniker = ROT_CreateFileMoniker( $sNameId ) If Not $pMoniker Then Return 0 Local $iHandle $oRunningObjectTable.Register( $iFlags, $pObject, $pMoniker, $iHandle ) Return $iHandle ? $iHandle : 0 EndFunc ; Returns unique GUID as string ; Copied from _WinAPI_CreateGUID Func ROT_CreateGUID() Local Static $tGUID = DllStructCreate( "struct;ulong Data1;ushort Data2;ushort Data3;byte Data4[8];endstruct" ) DllCall( "Ole32.dll", "long", "CoCreateGuid", "struct*", $tGUID ) Return "-" & DllCall( "Ole32.dll", "int", "StringFromGUID2", "struct*", $tGUID, "wstr", "", "int", 65536 )[2] EndFunc ; Failure: Returns 0 ; Success: Returns $aROT_List ; Enumerates objects and identifying monikers in the ROT Func ROT_Enumerate() Local $oRunningObjectTable = ObjCreateInterface( ROT_GetRunningObjectTable(), $sIID_IRunningObjectTable, $dtag_IRunningObjectTable ) If Not IsObj( $oRunningObjectTable ) Then Return 0 Local $pEnumMoniker $oRunningObjectTable.EnumRunning( $pEnumMoniker ) Local $oEnumMoniker = ObjCreateInterface( $pEnumMoniker, $sIID_IEnumMoniker, $dtag_IEnumMoniker ) If Not IsObj( $oEnumMoniker ) Then Return 0 Local $pMoniker, $oMoniker, $pBindCtx, $sMonikerName, $i = 0 Local $oDict = ObjCreate( "Scripting.Dictionary" ) While( $oEnumMoniker.Next( 1, $pMoniker, NULL ) = 0 ) $pBindCtx = ROT_CreateBindCtx() $oMoniker = ObjCreateInterface( $pMoniker, $sIID_IMoniker, $dtag_IMoniker ) $oMoniker.GetDisplayName( $pBindCtx, NULL, $sMonikerName ) $oDict.Add( "Key" & $i, $sMonikerName ) $i += 1 WEnd Local $aROT_List = $oDict.Items() Return $aROT_List EndFunc ; Failure: Returns 0 ; Success: Returns 1 ; Removes an object and its identifying moniker from the ROT Func ROT_Revoke( $iHandle ) If Not $iHandle Then Return 0 Local $oRunningObjectTable = ObjCreateInterface( ROT_GetRunningObjectTable(), $sIID_IRunningObjectTable, $dtag_IRunningObjectTable ) If Not IsObj( $oRunningObjectTable ) Then Return 0 Return Not $oRunningObjectTable.Revoke( $iHandle ) * 1 EndFunc 7z-fileThe 7z-file contains source code for the UDF and examples. You need AutoIt 3.3.12 or later. Tested on Windows 7 and Windows 10. Comments are welcome. Let me know if there are any issues. IRunningObjectTable.7z
    1 point
  3. pixelsearch

    CSV file editor

    Hi everybody The script below (901f) allows to wander easily through a listview, selecting any item or subitem by using the 4 direction keys. The Enter key is also managed and allows to fire an event (as double-click does) With the help of mikell (many thanks !) and after several tests based on 1000 rows & 6 columns, we succeeded to code a clear WM_NOTIFY function, which is simple (though solid) and should be reusable without any modification in other scripts dealing with basic listviews (we didn't use or check any particular style for the listview) Trapping the Enter key has been done by using a dummy control + Accelerators, though we spent the whole last week trapping it in another way, using Yashied's Wsp.dll (without any problem) . Finally we choosed the dummy control option... to have a smaller code. Version 901f (Nov 11, 2019) : the pic below shows how the selected subitem appears, with its specific background colour (light blue) Version 901f code : #include <GUIConstantsEx.au3> #include <GuiListView.au3> #include <WindowsConstants.au3> #include <WinAPIvkeysConstants.au3> Global $hGUI = GUICreate("Wandering through ListView (901f)", 460, 500) Global $idListView = GUICtrlCreateListView _ (" Col 0 | Col 1| Col 2| Col 3", 15, 60, 430, 400) Global $hListView = GuiCtrlGetHandle($idListView) For $iRow = 0 To 99 $sRow = StringFormat("%2s", $iRow) GUICtrlCreateListViewItem( _ "Row " & $sRow & " / Col 0 |" & _ "Row " & $sRow & " / Col 1 |" & _ "Row " & $sRow & " / Col 2 |" & _ "Row " & $sRow & " / Col 3", $idListView) Next Global $g_iColumnCount = _GUICtrlListView_GetColumnCount($idListView) -1 Global $g_iItem = -1, $g_iSubItem = -1 ; item/subitem selected in ListView control Global $idDummy_Dbl_Click = GUICtrlCreateDummy() Global $idDummy_Enter = GUICtrlCreateDummy() Global $aAccelKeys[1][2] = [["{ENTER}", $idDummy_Enter]] GUISetAccelerators($aAccelKeys) GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") GUISetState(@SW_SHOW) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE GUIDelete($hGUI) Exit Case $idDummy_Dbl_Click MsgBox($MB_TOPMOST, "Double-click activated cell", _ "Row " & $g_iItem & " / Col " & $g_iSubItem) Case $idDummy_Enter If _WinAPI_GetFocus() = $hListView And $g_iItem > -1 Then MsgBox($MB_TOPMOST, "Enter activated cell", _ "Row " & $g_iItem & " / Col " & $g_iSubItem) EndIf EndSwitch WEnd ;============================================ Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam Local $tNMHDR, $hWndFrom, $iIDFrom, $iCode $tNMHDR = DllStructCreate($tagNMHDR, $lParam) $hWndFrom = DllStructGetData($tNMHDR, "hWndFrom") $iCode = DllStructGetData($tNMHDR, "Code") Static $bMouseDown = False, $bNotXP = Not (@OSVersion = "WIN_XP") Switch $hWndFrom Case $hListView Switch $iCode Case $NM_CUSTOMDRAW Local $tCustDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam) Local $iDrawStage = DllStructGetData($tCustDraw, "dwDrawStage") If $iDrawStage = $CDDS_PREPAINT Then Return $CDRF_NOTIFYITEMDRAW If $iDrawStage = $CDDS_ITEMPREPAINT Then Return $CDRF_NOTIFYSUBITEMDRAW Local $iItem = DllStructGetData($tCustDraw, "dwItemSpec") Local $iSubItem = DllStructGetData($tCustDraw, "iSubItem") Local $iColor = 0xFF000000 ; this is $CLR_DEFAULT in ColorConstants.au3 If $iItem = $g_iItem And $iSubItem = $g_iSubItem Then $iColor = 0xFFFFC0 ; light blue for 1 subitem (BGR) EndIf DllStructSetData($tCustDraw, "clrTextBk", $iColor) Return $CDRF_NEWFONT Case $LVN_KEYDOWN If $bMouseDown Or $g_iItem = -1 Then Return 1 ; don't process Local $tInfo = DllStructCreate($tagNMLVKEYDOWN, $lParam) Local $iVK = DllStructGetData($tInfo, "VKey") Switch $iVK Case $VK_RIGHT If $g_iSubItem < $g_iColumnCount Then $g_iSubItem += 1 If $bNotXP Then _GUICtrlListView_RedrawItems($hListview, $g_iItem, $g_iItem) EndIf Case $VK_LEFT If $g_iSubItem > 0 Then $g_iSubItem -= 1 If $bNotXP Then _GUICtrlListView_RedrawItems($hListview, $g_iItem, $g_iItem) EndIf Case $VK_SPACE ; spacebar would select the whole row Return 1 EndSwitch Case $NM_RELEASEDCAPTURE $bMouseDown = True Local $iItemSave = $g_iItem Local $aHit = _GUICtrlListView_SubItemHitTest($hListView) $g_iItem = $aHit[0] $g_iSubItem = $aHit[1] If $g_iItem = -1 And $iItemSave > -1 Then _GUICtrlListView_RedrawItems($hListview, $iItemSave, $iItemSave) EndIf Case $LVN_ITEMCHANGED Local $tInfo = DllStructCreate($tagNMLISTVIEW, $lParam) Local $iNewState = DllStructGetData($tInfo, "NewState") Switch $iNewState Case BitOr($LVIS_FOCUSED, $LVIS_SELECTED) $g_iItem = DllStructGetData($tInfo, "Item") _GUICtrlListView_SetItemSelected($hListview, $g_iItem, False) EndSwitch Case $NM_CLICK, $NM_RCLICK $bMouseDown = False Case $NM_DBLCLK $bMouseDown = False If $g_iItem > -1 Then GUICtrlSendToDummy($idDummy_Dbl_Click) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY Version 901k (Dec 16, 2019) What started with a simple "wander through listview" has turned now to a functional CSV file editor, which can be useful to modify your CSV files with AutoIt : Here are the instructions to use the script, based on a CSV file starting like this : street,city,zip,state,beds,baths,sq__ft,type,sale_date,price,latitude,longitude 3526 HIGH ST,SACRAMENTO,95838,CA,2,1,836,Residential,Wed May 21 00:00:00 EDT 2008,59222,38.631913,-121.434879 51 OMAHA CT,SACRAMENTO,95823,CA,3,1,1167,Residential,Wed May 21 00:00:00 EDT 2008,68212,38.478902,-121.431028 ... 1) Import options : comma delimited (default) No need to change anything if your CSV is comma delimited (other options are Semicolon delimited, Tab delimited) 2) Import options : First row = headers (default = checked) * Keep it checked if the 1st row of your imported file contains headers (that's the case in our example) * UNcheck it if the 1st row contains data, making listview headers appear like this : Col 0 | Col 1 | Col 2 ... 3) Import your CSV file : Only now the listview will be created dynamically. As soon as it is populated, GUI becomes resizable/maximizable, which can be helpful during modifications of a listview containing many columns. 4) Selection color : light blue (default) You can change the selected cell background color by clicking the "Selection color" button : this will open Windows color picker. 5) Editing a listview cell : done by Enter key (or double-click), this is how the edited cell will appear : * Please note that the edited background color (green in the pic) depends on each computer theme. It is not related to the selected background we discussed in 4) * Validate your modification with Enter key, or cancel the modification (revert) with Escape Key 6) Edit Font size : 15 (default) 15 was good in the precedent pic, the edited cell had its content "RIO LINDA" perfectly aligned with all other cells (on my computer). Here again, the font height required depends on each computer : if you want the edited font to be bigger (or smaller), just use the updown control. 7) Chained Edit ? (default = No) * "No" => when you finish editing a cell (Enter key), the same cell stays selected. * "Horizontally" => If checked, edition will automatically continue with the cell on its right. * "Vertically" => If checked, edition will automatically continue with the cell below. This feature can be very useful when you modify cells of a whole colum (vertically) or cells by row (horizontally) 8 ) Inserting a blank line (not in Gui) : press the "Ins" key : 9) Deleting a line (not in Gui) : press the "Del" key : 10) Export CSV file : Filename automatically suggested for export will be : Filename import & actual date & actual time, for example : Import name = "Sales Results.csv" => suggested Export name = "Sales Results_2019-12-16 16:00:59.csv" Version 901m (Dec 18, 2019) Yesterday, mikell suggested to import the csv file by dropping it directly into the GUI, good idea This new version 901m allows it. Now there are 2 ways to import the csv file : * Import button * Drag and drop into the large droppable zone, as shown in the pic below (this zone will be reused to create the listview at same coords) Version 901n (Dec 20, 2019) As t0nZ got tons of csv files, pipe "|" separated, here is a new version allowing this 4th separator Version 901p (Dec 25, 2019) New functionality : now you can drag headers to reorder columns. It may help some users who need it while editing their file. Exported CSV file will be saved according to the new columns order. Version 901r (Dec 29, 2019) New functionality : Numeric sort on any column (right click on column header) It is recommended to backup (export) your file before sorting, just in case you need a copy of it, unsorted. Version 901s (Dec 30, 2019) 1 functionality added : String sort (right click on column header) Numeric sort is alright in most cases, but sometimes we also need a String sort like shown in the following picture. Both ways of sorting (numeric and string) are found in this new release. Version 901t (Jan 3, 2020) 3 functionalities added Rename Header , Insert Column , Delete Column (right click on column header to display its context menu) Version 901u (Jan 6, 2020) 1 functionality added : Natural sort. Thanks to jchd for the idea and Melba23 for his function ArrayMultiColSort() included in the script. Though this natural sort isn't fully implemented, it should work when numbers precede letters (see pic below or better, try it on the "street" column found in the downloadable csv test file below) Natural sort duration + listview update are fast, maybe because of the new function _BufferCreate() described here and now added to the script. Version 901w (Jan 10, 2020) Two functionalities added : 1) Close File button, which allows to import other csv file(s) during the same session 2) Import speed has been improved because the listview control is now populated directly by an Array and not anymore by GUICtrlCreateListViewItem() This explains why, in this version, there are no more Control id's for listview items, allowing to empty the listview content in a snap with this line of code : _SendMessage($g_hListView, $LVM_DELETEALLITEMS) That's what it took to add the Close File button and import several csv files during the same session, avoiding id leaks. Please report if any issue is encountered. Version 901x (Jan 14, 2020) One minor functionality added : number of rows is now displayed just under the listview, it may be handy sometimes. Other minor changes included (natural sort speed improved) Credits : Many thanks to Czardas for his function _CSVSplit() and guinness for his function _SaveCSV(), guys you did a great job. Thanks to Musashi : your suggestions and time passed on testing beta versions of the script, that was really helpful and challenging. Not sure I would have ended this script without your detailed reports. Mikell : the 1st step above (901f) that we wrote together, it all started from here. Your knowledge and kindness are legendary ! Not forgetting all other persons who were inspiring : LarsJ, Melba23, jpm, that list could be endless... Download link : version 901x - Jan 14, 2020 (minor update on Jan 15) 901x - CSV file editor.au3 Test csv file (986 rows/12cols) : Sacramento real estate transactions.csv
    1 point
  4. Excellent Amazing This is what I wanted Thank you Champion
    1 point
  5. Hmm I also know that this assertion is not exactly true But I'm surprised you didn't suggest such a solution $s = "Movie (0000) (part1000) (2002)" $r = StringSplit(StringMid($s, 1, StringInStr($s, "(", 0, -1)-1) & @crlf & StringMid($s, StringInStr($s, "(", 0, -1)+1, 4), @crlf, 3) _ArrayDisplay($r)
    1 point
  6. ; enable "www.facebook.com" #RequireAdmin #include <Array.au3> $sURL = "www.facebook.com" $sHostsFile = @WindowsDir & "\system32\drivers\etc\hosts" $iReadonly = StringInStr(FileGetAttrib($sHostsFile), "R") If $iReadonly Then FileSetAttrib($sHostsFile, "-R") $aFile = FileReadToArray($sHostsFile) For $i = @extended - 1 To 0 Step -1 If StringInStr($aFile[$i], $surl) Then _ArrayDelete($aFile, $i) Next FileDelete($sHostsFile) FileWrite($sHostsFile,_ArrayToString($aFile,@CRLF)) If $iReadonly Then FileSetAttrib($sHostsFile, "+R")
    1 point
  7. well still without WM_SIZE, it doesn't flicker that much. or are there problems to simply use GuiCtrlSetPos()? a mix from both that works well for me ( win7 64-bit ) nevermind i got the problem with bigger pictures but it works if the Base Stats are at desktopsize #include <GUIConstants.au3> #include <GDIPlus.au3> #include <WinAPISysWin.au3> _GDIPlus_Startup() Local Const $BASE_WIDTH = @DesktopWidth, $BASE_HEIGHT = @DesktopHeight - 65 Global $hImage = _GDIPlus_ImageLoadFromFile("Image.jpg") Global $iImageWidth = _GDIPlus_ImageGetWidth($hImage), $iImageHeight = _GDIPlus_ImageGetHeight($hImage) _ReduceLargeImage($hImage, $iImageWidth, $iImageHeight) Local $aPos[] = [$iImageWidth, $iImageHeight] If $iImageWidth > $BASE_WIDTH Or $iImageHeight > $BASE_HEIGHT Then $aPos = _EvaluateSize($BASE_WIDTH, $BASE_HEIGHT, $iImageWidth, $iImageHeight) EndIf Global $hGUI = GUICreate("", $aPos[0], $aPos[1], -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX, $WS_THICKFRAME)) GUISetBkColor(0x000000) Global $idPic = GUICtrlCreatePic("", 0, 0, $aPos[0], $aPos[1]) _SetImagetoCtrl($idPic, $hImage, $aPos[0], $aPos[1]) AdlibRegister("_ResizeImage", 5) GUISetState() While 1 Local $nMsg = GUIGetMsg() Switch $nMsg Case -3 Exit EndSwitch WEnd Func _ReduceLargeImage(ByRef $hImage, ByRef $iImageWidth, ByRef $iImageHeight) If $iImageWidth <= @DesktopWidth Or $iImageHeight <= @DesktopHeight Then Return Local $aPos = _EvaluateSize(@DesktopWidth, @DesktopHeight, $iImageWidth, $iImageHeight) Local $hResize = _GDIPlus_ImageResize($hImage, $aPos[0], $aPos[1]) _GDIPlus_ImageDispose($hImage) $hImage = $hResize $iImageWidth = $aPos[0] $iImageHeight = $aPos[1] EndFunc ;==>_ReduceLargeImage Func _EvaluateSize($iBaseWidth, $iBaseHeight, $iActualWidth, $iActualHeight) Local $iVal = $iBaseWidth / $iActualWidth * $iActualHeight If $iVal <= $iBaseHeight Then Return StringSplit($iBaseWidth & "|" & $iVal, "|", $STR_NOCOUNT) $iVal = $iBaseHeight / $iActualHeight * $iActualWidth Return StringSplit($iVal & "|" & $iBaseHeight, "|", $STR_NOCOUNT) EndFunc ;==>_EvaluateSize Func _SetImagetoCtrl($idPic, $hImage, $iWidth, $iHeight) Local $hResize = _GDIPlus_ImageResize($hImage, $iWidth, $iHeight) Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hResize) _GDIPlus_ImageDispose($hResize) _WinAPI_DeleteObject(GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)) _WinAPI_DeleteObject($hHBitmap) EndFunc ;==>_SetImagetoCtrl Func _ResizeImage() Local $tRECT = _WinAPI_GetClientRect($hGUI) Local $iWidth = $tRECT.right - $tRECT.left + 1 Local $iHeight = $tRECT.bottom - $tRECT.top + 1 If $iWidth > $iImageWidth And $iHeight > $iImageHeight Then Local $aPos[] = [$iImageWidth, $iImageHeight] Else Local $aPos = _EvaluateSize($iWidth, $iHeight, $iImageWidth, $iImageHeight) EndIf Local $aIMGpos = ControlGetPos($hGUI, "", $idPic) If $aIMGpos[0] <> Int(($iWidth - $aPos[0]) / 2) Or $aIMGpos[1] <> Int(($iHeight - $aPos[1]) / 2) Or Int($aPos[0]) <> $aIMGpos[2] Or Int($aPos[1]) <> $aIMGpos[3] Then GUICtrlSetPos($idPic, Int(($iWidth - $aPos[0]) / 2), Int(($iHeight - $aPos[1]) / 2), $aPos[0], $aPos[1]) EndFunc ;==>_ResizeImage
    1 point
  8. @Aelc and @beginner10. I tested with a large image (3.2k x 1.8k) and there is effectively a tad more lag. One solution I found is to resize the base image to fit screen dimensions. It helps for sure. Func _ReduceLargeImage (ByRef $hImage, ByRef $iImageWidth, ByRef $iImageHeight) If $iImageWidth <= @DesktopWidth Or $iImageHeight <= @DesktopHeight Then Return Local $aPos = _EvaluateSize(@DesktopWidth, @DesktopHeight, $iImageWidth, $iImageHeight) Local $hResize = _GDIPlus_ImageResize($hImage, $aPos[0], $aPos[1]) _GDIPlus_ImageDispose($hImage) $hImage = $hResize $iImageWidth = $aPos[0] $iImageHeight = $aPos[1] EndFunc Use this function in main : Local Const $BASE_WIDTH = 800, $BASE_HEIGHT = 600 Global $hImage = _GDIPlus_ImageLoadFromFile("Image.jpg") Global $iImageWidth = _GDIPlus_ImageGetWidth($hImage), $iImageHeight = _GDIPlus_ImageGetHeight($hImage) _ReduceLargeImage ($hImage, $iImageWidth, $iImageHeight) Local $aPos[] = [$iImageWidth, $iImageHeight] .....
    1 point
  9. Executing Object Methods through VBScriptIn IPC Techniques through ROT Objects (Data types section) the AutoIt data types have been tested based on the example for the VarGetType() function in the help file. The data types are sent from Sender to Receiver with these results: $aArray : Array variable type. $dBinary : Binary variable type. $bBoolean : Bool variable type. $pPtr : Int32 variable type. $hWnd : Int32 variable type. $iInt : Int32 variable type. $fFloat : Double variable type. $oObject : Object variable type. $sString : String variable type. $tStruct : Not recognized as a valid variable type. $vKeyword : Keyword variable type. fuMsgBox : Not recognized as a valid variable type. $fuFunc : Not recognized as a valid variable type. $fuUserFunc : Not recognized as a valid variable type. Note that an AutoIt object is a data type that is sent correctly from one process to another through a ROT Object. What does it mean that an object is sent correctly from one process to another? This means that the object instance (the specific representation of the object) of the receiving process is exactly the same as the object instance of the sending process. The object of receiver and sender is simply the same object. It's the implementation of the ROT Object that ensures that the object of receiver and sender is the same. If an object $oHexEdit is sent from AutoIt code to VBScript code in this way: Local $sDictionaryData = "DictionaryData" ROT_RegisterObject( Default, $sDictionaryData ) ; Default => Object = Dictionary object Local $oROTobj = ObjGet( $sDictionaryData ) ; Dictionary object $oROTobj( "oHexEdit" ) = $oHexEdit and received in the VBScript code in this way: Dim oROTobj, oHexEdit Set oROTobj = GetObject( "DictionaryData" ) Set oHexEdit = oROTobj( "oHexEdit" ) then the $oHexEdit object in the AutoIt code and oHexEdit object in the VBScript code is the same object. Type mismatch errorWhat can all this be used for? This is an example of a Hex Editor ActiveX control based on this CodeProject article. A simple AutoIt implementation can look like this (HexEdit0.au3) #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 Opt( "MustDeclareVars", 1 ) #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> Example() Func Example() ; Create GUI GUICreate( "Hex Editor", 420, 420 ) ; Create COM error handler Local $oMyError = ObjEvent( "AutoIt.Error", "MyErrFunc" ) ; Create Com object Local $oHexEdit = ObjCreate( "HEXEDIT.HexEditCtrl.1" ) If Not IsObj( $oHexEdit ) Then Return ConsoleWrite( "$oHexEdit ERR" & @CRLF ) ConsoleWrite( "$oHexEdit OK" & @CRLF ) ; Create ActiveX control GUICtrlCreateObj( $oHexEdit, 10, 10, 400, 400 ) ; Show GUI GUISetState() ; Load HexEditDlg.exe into ActiveX control Local $hFile = FileOpen( "HexEditDlg.exe", 16 ), $dBinary = FileRead( $hFile ), $i = FileClose( $hFile ) ; 16 = $FO_BINARY $oHexEdit.SetData( $dBinary, 0 ) ; Loop While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd #forceref $oMyError, $i EndFunc Func MyErrFunc( $oError ) ConsoleWrite(@ScriptName & " (" & $oError.scriptline & ") : ==> COM Error intercepted !" & @CRLF & _ @TAB & "err.number is: " & @TAB & @TAB & "0x" & Hex($oError.number) & @CRLF & _ @TAB & "err.windescription:" & @TAB & $oError.windescription & @CRLF & _ @TAB & "err.description is: " & @TAB & $oError.description & @CRLF & _ @TAB & "err.source is: " & @TAB & @TAB & $oError.source & @CRLF & _ @TAB & "err.helpfile is: " & @TAB & $oError.helpfile & @CRLF & _ @TAB & "err.helpcontext is: " & @TAB & $oError.helpcontext & @CRLF & _ @TAB & "err.lastdllerror is: " & @TAB & $oError.lastdllerror & @CRLF & _ @TAB & "err.scriptline is: " & @TAB & $oError.scriptline & @CRLF & _ @TAB & "err.retcode is: " & @TAB & "0x" & Hex($oError.retcode) & @CRLF & @CRLF) EndFunc The HexEdit ActiveX control must be registered in an elevated Command Prompt with HexEditorOcx\register.bat included in the 7z-file below. HexEditDlg.exe is the test file that is loaded into the ActiveX control. Also contained in the 7z-file. You can also download it all directly from the CodeProject article. HexEditDlg.exe is the demo project. When you run the script in SciTE with F5 you'll see the following COM error in the console: $oHexEdit OK HexEdit0.au3 (30) : ==> COM Error intercepted ! err.number is: 0x80020005 err.windescription: Type mismatch. err.description is: err.source is: err.helpfile is: err.helpcontext is: err.lastdllerror is: 0 err.scriptline is: 30 err.retcode is: 0x00000000 Line 30 is this line: $oHexEdit.SetData( $dBinary, 0 ) The error is due to the binary data in $dBinary not being transferred correctly to the SetData() method. The first lines of the implementation of the SetData() method in HexEditCtl.cpp (not included in the 7z-file but can be downloaded from the article) looks like this: SCODE CHexEditCtrl::SetData(VARIANT FAR* pData, long dwStartAddr) { if ( ( pData->vt != (VT_ARRAY | VT_UI1) && pData->vt != (VT_ARRAY | VT_I1) ) || ::SafeArrayGetDim(pData->parray) != 1) VARIANT FAR* pData and pData->vt == (VT_ARRAY | VT_UI1) means that the first parameter in Setdata() must be a pointer to a variant, where the data field in the variant can contain a pointer to a safearray of bytes. A safearray of bytes is also referred to as a bytearray. In AutoIt, a bytearray is represented by the Binary data type. Since there are no other data types in AutoIt that correspond to a bytearray, there is actually not really anything to do about the error. The internal AutoIt code is capable of transferring the vast majority of parameter data types to an object method in the correct way. However, there are still several examples of parameter data types being passed incorrectly resulting in a data type mismatch error. And here the VBScript code comes into play. The VBScript language is coded by Microsoft, and Microsoft obviously knows how to pass data to an object method. The idea is to transfer both the $oHexEdit object and the binary data in $dBinary to a VBScript through a ROT Object and then execute the SetData() method directly in the VBScript. Executing VBScript codeHexEdit1.au3: #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 Opt( "MustDeclareVars", 1 ) #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include "IRunningObjectTable.au3" Example() Func Example() ; Create GUI GUICreate( "Hex Editor", 420, 420 ) ; Create COM error handler Local $oMyError = ObjEvent( "AutoIt.Error", "MyErrFunc" ) ; Create Com object Local $oHexEdit = ObjCreate( "HEXEDIT.HexEditCtrl.1" ) If Not IsObj( $oHexEdit ) Then Return ConsoleWrite( "$oHexEdit ERR" & @CRLF ) ConsoleWrite( "$oHexEdit OK" & @CRLF ) ; Create ActiveX control GUICtrlCreateObj( $oHexEdit, 10, 10, 400, 400 ) ; Show GUI GUISetState() ; Load HexEditDlg.exe into ActiveX control Local $hFile = FileOpen( "HexEditDlg.exe", 16 ), $dBinary = FileRead( $hFile ), $i = FileClose( $hFile ) ; 16 = $FO_BINARY Local $sDictionaryData = "DictionaryData" ROT_RegisterObject( Default, $sDictionaryData ) ; Default => Object = Dictionary object Local $oROTobj = ObjGet( $sDictionaryData ) ; Dictionary object $oROTobj( "oHexEdit" ) = $oHexEdit $oROTobj( "dBinary" ) = $dBinary RunWait( 'wscript.exe "HexEdit1.vbs"' ) ; Loop While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd #forceref $oMyError, $i EndFunc Func MyErrFunc( $oError ) ConsoleWrite(@ScriptName & " (" & $oError.scriptline & ") : ==> COM Error intercepted !" & @CRLF & _ @TAB & "err.number is: " & @TAB & @TAB & "0x" & Hex($oError.number) & @CRLF & _ @TAB & "err.windescription:" & @TAB & $oError.windescription & @CRLF & _ @TAB & "err.description is: " & @TAB & $oError.description & @CRLF & _ @TAB & "err.source is: " & @TAB & @TAB & $oError.source & @CRLF & _ @TAB & "err.helpfile is: " & @TAB & $oError.helpfile & @CRLF & _ @TAB & "err.helpcontext is: " & @TAB & $oError.helpcontext & @CRLF & _ @TAB & "err.lastdllerror is: " & @TAB & $oError.lastdllerror & @CRLF & _ @TAB & "err.scriptline is: " & @TAB & $oError.scriptline & @CRLF & _ @TAB & "err.retcode is: " & @TAB & "0x" & Hex($oError.retcode) & @CRLF & @CRLF) EndFunc HexEdit1.vbs: Dim oROTobj, oHexEdit, dBinary Set oROTobj = GetObject( "DictionaryData" ) Set oHexEdit = oROTobj( "oHexEdit" ) dBinary = oROTobj( "dBinary" ) oHexEdit.SetData dBinary, 0 The ActiveX control in the AutoIt GUI is updated directly through the code in the VBScript: Hopefully someone will take up the challenge and implement a more complete Hex Editor. This is just a Hex Viewer. 7z-fileThe 7z-file contains all the necessary code and data. You need AutoIt 3.3.12 or later. Tested on Windows 7 and Windows 10. HexEdit is a 32 bit control. The code only runs as 32 bit code. Comments are welcome. Let me know if there are any issues. ObjectMethods.7z
    1 point
  10. Ascer

    google OCR with Autoit

    @lordsocke Im not sure if this code will works since to enable OCR interface you have to pay for it Anyway this code represent: vision.images.annotate ; Enter your api key here. Local $GOOGLE_API_KEY = "XXXXXX-XXXXXXXXXXX_XXXXXXXXXXX" ; Enter path to image. Image like white background and black text example. Local $IMAGE_PATH = @ScriptDir & "\OCR.png" ; Create Object for out/in comming connections. Local $oHttp = ObjCreate("winhttp.winhttprequest.5.1") ; Check if some error durinig creation object. If Not IsObj($oHttp) Then ConsoleWrite("+++ Error 1. Failed to create object." & @CRLF) Exit EndIf ; Create POST request to google OCR Local $sRequest = "https://vision.googleapis.com/v1/images:annotate?key=" & $GOOGLE_API_KEY ; Open request. $oHttp.Open("POST", $sRequest , False) ; Set request header - we want received packets in json format $oHTTP.SetRequestHeader("Content-Type", "application/json") ; Load image and read. Local $sImage = FileOpen(FileRead($IMAGE_PATH)) ; Check for errors. If @error Then ConsoleWrite("+++ Error 2. Failed to load image. Make sure about valid path." & @CRLF) Exit EndIf ; Convert image to base64 IMPORTANT! If not works try this way: base64($sImage, True, True) $sImage = base64($sImage) ; Check for errors. If @error or $sImage = "" Then ConsoleWrite("+++ Error 3. Failed convert image to base 64." & @CRLF) Exit EndIf ; Create structure in JSON format Local $sJson $sJson &= "{" $sJson &= '"requests": [' $sJson &= "{" $sJson &= '"image": {' $sJson &= '"content": "' & $sImage & '"' $sJson &= '},' $sJson &= '"features": [' $sJson &= "{" $sJson &= '"type": "TEXT_DETECTION"' $sJson &= "}" $sJson &= "]" $sJson &= "}" $sJson &= "]" $sJson &= "}" ConsoleWrite("Sending request please wait..." & @CRLF) ; Send our request $oHttp.Send($sJson) ;======================= ; Sending process... ; AutoIt freeze now. ; Wait until finish ;======================= ; Get request back status and output text Local $iStatus = $oHttp.Status Local $sOutput = $oHttp.ResponseText ; Check respond status If $iStatus <> 200 Then ConsoleWrite("+++ Error 4. Invaild respond status: " & $iStatus & @CRLF) Else ConsoleWrite("++ Successfully send request." & @CRLF) EndIf ConsoleWrite("OUTPUT:" & @CRLF & $sOutput & @CRLF) ;============================================================================================================================== ; Function: base64($vCode [, $bEncode = True [, $bUrl = False]]) ; ; Description: Decode or Encode $vData using Microsoft.XMLDOM to Base64Binary or Base64Url. ; IMPORTANT! Encoded base64url is without @LF after 72 lines. Some websites may require this. ; ; Parameter(s): $vData - string or integer | Data to encode or decode. ; $bEncode - boolean | True - encode, False - decode. ; $bUrl - boolean | True - output is will decoded or encoded using base64url shema. ; ; Return Value(s): On Success - Returns output data ; On Failure - Returns 1 - Failed to create object. ; ; Author (s): (Ghads on Wordpress.com), Ascer ;=============================================================================================================================== Func base64($vCode, $bEncode = True, $bUrl = False) Local $oDM = ObjCreate("Microsoft.XMLDOM") If Not IsObj($oDM) Then Return SetError(1, 0, 1) Local $oEL = $oDM.createElement("Tmp") $oEL.DataType = "bin.base64" If $bEncode then $oEL.NodeTypedValue = Binary($vCode) If Not $bUrl Then Return $oEL.Text Return StringReplace(StringReplace(StringReplace($oEL.Text, "+", "-"),"/", "_"), @LF, "") Else If $bUrl Then $vCode = StringReplace(StringReplace($vCode, "-", "+"), "_", "/") $oEL.Text = $vCode Return $oEL.NodeTypedValue EndIf EndFunc ;==>base64
    1 point
×
×
  • Create New...