MattyD Posted Sunday at 12:06 AM Posted Sunday at 12:06 AM (edited) It looks like we need to call IFileOpenDialog::GetResults() - and that returns a shellItem collection. It's possible for the collection to be empty though - so we should check for that with $oItemArr.GetCount() expandcollapse popup#include <WinAPI.au3> #include <GuiConstants.au3> Global $sCLSID_FileOpenDialog = "{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}" Global Const $sIID_IFileOpenDialog = "{d57c7288-d4ad-4768-be02-9d969532d960}" Global Const $sIID_IFileDialogCustomize = "{e6fdd21a-163f-4975-9c8c-a69f1ba37034}" Global Const $sIID_IShellItemArray = "{b63ea76d-1f85-456f-a19c-48159efa858b}" Global Const $sIID_IShellItem = "{43826d1e-e718-42ee-bc55-a1e261c37bfe}" Global Const $tagIFileOpenDialog = _ "Show hresult(hwnd);" & _ "SetFileTypes hresult(uint;ptr);" & _ "SetFileTypeIndex hresult(uint);" & _ "GetFileTypeIndex hresult(uint*);" & _ "Advise hresult(ptr;dword*);" & _ "Unadvise hresult(dword);" & _ "SetOptions hresult(dword);" & _ "GetOptions hresult(dword*);" & _ "SetDefaultFolder hresult(ptr);" & _ "SetFolder hresult(ptr);" & _ "GetFolder hresult(ptr*);" & _ "GetCurrentSelection hresult(ptr*);" & _ "SetFileName hresult(wstr);" & _ "GetFileName hresult(wstr*);" & _ "SetTitle hresult(wstr);" & _ "SetOkButtonLabel hresult(wstr);" & _ "SetFileNameLabel hresult(wstr);" & _ "GetResult hresult(ptr*);" & _ "AddPlace hresult(ptr;dword);" & _ "SetDefaultExtension hresult(wstr);" & _ "Close hresult(hresult);" & _ "SetClientGuid hresult(clsid);" & _ "ClearClientData hresult();" & _ "SetFilter hresult(ptr);" & _ "GetResults hresult(ptr*);" & _ "GetSelectedItems hresult(ptr*);" Global Const $tagIFileDialogCustomize = _ "EnableOpenDropDown hresult(dword);" & _ "AddMenu hresult(dword;wstr);" & _ "AddPushButton hresult(dword;wstr);" & _ "AddComboBox hresult(dword);" & _ "AddRadioButtonList hresult(dword);" & _ "AddCheckButton hresult(dword;wstr;bool);" & _ "AddEditBox hresult(dword;wstr);" & _ "AddSeparator hresult(dword);" & _ "AddText hresult(dword;wstr);" & _ "SetControlLabel hresult(dword;wstr);" & _ "GetControlState hresult(dword;dword*);" & _ "SetControlState hresult(dword;dword);" & _ "GetEditBoxText hresult(dword;ptr*);" & _ "SetEditBoxText hresult(dword;wstr);" & _ "GetCheckButtonState hresult(dword;bool*);" & _ "SetCheckButtonState hresult(dword;bool);" & _ "AddControlItem hresult(dword;dword;wstr);" & _ "RemoveControlItem hresult(dword;dword);" & _ "RemoveAllControlItems hresult(dword);" & _ "GetControlItemState hresult(dword;dword;dword*);" & _ "SetControlItemState hresult(dword;dword;dword);" & _ "GetSelectedControlItem hresult(dword;dword*);" & _ "SetSelectedControlItem hresult(dword;dword);" & _ "StartVisualGroup hresult(dword;wstr);" & _ "EndVisualGroup hresult();" & _ "MakeProminent hresult(dword);" & _ "SetControlItemText hresult(dword;dword;wstr);" Global Const $tagIShellItemArray = _ "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _ "GetPropertyStore hresult(int;clsid;ptr*);" & _ "GetPropertyDescriptionList hresult(ptr;clsid;ptr*);" & _ "GetAttributes hresult(int;int;int*);" & _ "GetCount hresult(uint*);" & _ "GetItemAt hresult(uint;ptr*);" & _ "EnumItems hresult(ptr*);" Global Const $tagIShellItem = _ "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _ "GetParent hresult(ptr*);" & _ "GetDisplayName hresult(int;wstr*);" & _ "GetAttributes hresult(ulong;ulong*);" & _ "Compare hresult(ptr;ulong;int*);" Global Enum $SIGDN_NORMALDISPLAY = 0, _ $SIGDN_PARENTRELATIVEPARSING, _ $SIGDN_DESKTOPABSOLUTEPARSING, _ $SIGDN_PARENTRELATIVEEDITING, _ $SIGDN_DESKTOPABSOLUTEEDITING, _ $SIGDN_FILESYSPATH, _ $SIGDN_URL, _ $SIGDN_PARENTRELATIVEFORADDRESSBAR, _ $SIGDN_PARENTRELATIVE, _ $SIGDN_PARENTRELATIVEFORUI DoFileOpen(0) Func DoFileOpen($hParent) Local $oFileOpen = ObjCreateInterface($sCLSID_FileOpenDialog, $sIID_IFileOpenDialog, $tagIFileOpenDialog) Local $pCustomFileOpen, $tIID_IFileDialogCustomize = _WinAPI_GUIDFromString($sIID_IFileDialogCustomize) $oFileOpen.QueryInterface(DllStructGetPtr($tIID_IFileDialogCustomize), $pCustomFileOpen) Local $oCustomFileOpen = ObjCreateInterface(Ptr($pCustomFileOpen), $sIID_IFileDialogCustomize, $tagIFileDialogCustomize) Local Enum $idVisualGroup = 100, $idCombo, $idItem1, $idItem2, $idItem3 $oCustomFileOpen.StartVisualGroup($idVisualGroup, "&Encoding:") $oCustomFileOpen.AddComboBox($idCombo) $oCustomFileOpen.AddControlItem($idCombo, $idItem1, "Item 1") $oCustomFileOpen.AddControlItem($idCombo, $idItem2, "Item 2") $oCustomFileOpen.AddControlItem($idCombo, $idItem3, "Item 3") $oCustomFileOpen.SetSelectedControlItem($idCombo, $idItem1) $oCustomFileOpen.EndVisualGroup() $oFileOpen.Show($hParent) Local $idSelItem, $sSelItem $oCustomFileOpen.GetSelectedControlItem($idCombo, $idSelItem) ConsoleWrite("SelItemId = " & $idSelItem & @CRLF) Local $pItemArr, $pItem, $sDispName $oFileOpen.GetResults($pItemArr) Local $oItemArr = ObjCreateInterface(Ptr($pItemArr), $sIID_IShellItemArray, $tagIShellItemArray) $oItemArr.GetItemAt(0, $pItem) Local $oItem = ObjCreateInterface(Ptr($pItem), $sIID_IShellItem, $tagIShellItem) $oItem.GetDisplayName($SIGDN_NORMALDISPLAY, $sDispName) ConsoleWrite("SelItem 0 = " & $sDispName & @CRLF) EndFunc PS: I've also updated the "old way" example in the post above just for the exercise. We still shouldn't use it - but I fixed that UI bug by clearing the exstyle on the nested dialog template (it was my mistake, not windows'!) Edited Sunday at 12:08 AM by MattyD WildByDesign 1
WildByDesign Posted Sunday at 11:06 AM Author Posted Sunday at 11:06 AM (edited) 11 hours ago, MattyD said: It looks like we need to call IFileOpenDialog::GetResults() - and that returns a shellItem collection. It's possible for the collection to be empty though - so we should check for that with $oItemArr.GetCount() Thanks Matty. I spent some time on MSDN last night and this morning. COM stuff is not fun, that's for sure. I did not get as far as GetCount. But so far I've used your dialog setup as a base to learn from and switched over to Save As dialog because that is really what is needed in the end. I've replicated the Encoding types from Notepad's Save As dialog and also switched to getting the full system path because we would need full path to save. From what I can tell, the OS does pretty much all of the logic for file type extension, whether or not user adds extension and so on. So that is nice. Here is where I left off: expandcollapse popup#include <WinAPI.au3> #include <GuiConstants.au3> #include <Array.au3> Global Const $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = Ptr(-4) DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "int_ptr", $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) Global Const $sCLSID_FileSaveDialog = "{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}" Global Const $sIID_IFileSaveDialog = "{84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB}" Global Const $sIID_IFileDialogCustomize = "{e6fdd21a-163f-4975-9c8c-a69f1ba37034}" Global Const $sIID_IShellItem = "{43826d1e-e718-42ee-bc55-a1e261c37bfe}" Global Const $tagIFileSaveDialog = _ "Show hresult(hwnd);" & _ "SetFileTypes hresult(uint;ptr);" & _ "SetFileTypeIndex hresult(uint);" & _ "GetFileTypeIndex hresult(uint*);" & _ "Advise hresult(ptr;dword*);" & _ "Unadvise hresult(dword);" & _ "SetOptions hresult(dword);" & _ "GetOptions hresult(dword*);" & _ "SetDefaultFolder hresult(ptr);" & _ "SetFolder hresult(ptr);" & _ "GetFolder hresult(ptr*);" & _ "GetCurrentSelection hresult(ptr*);" & _ "SetFileName hresult(wstr);" & _ "GetFileName hresult(wstr*);" & _ "SetTitle hresult(wstr);" & _ "SetOkButtonLabel hresult(wstr);" & _ "SetFileNameLabel hresult(wstr);" & _ "GetResult hresult(ptr*);" & _ "AddPlace hresult(ptr;dword);" & _ "SetDefaultExtension hresult(wstr);" & _ "Close hresult(hresult);" & _ "SetClientGuid hresult(clsid);" & _ "ClearClientData hresult();" & _ "SetFilter hresult(ptr);" & _ "GetResults hresult(ptr*);" & _ "GetSelectedItems hresult(ptr*);" Global Const $tagIFileDialogCustomize = _ "EnableOpenDropDown hresult(dword);" & _ "AddMenu hresult(dword;wstr);" & _ "AddPushButton hresult(dword;wstr);" & _ "AddComboBox hresult(dword);" & _ "AddRadioButtonList hresult(dword);" & _ "AddCheckButton hresult(dword;wstr;bool);" & _ "AddEditBox hresult(dword;wstr);" & _ "AddSeparator hresult(dword);" & _ "AddText hresult(dword;wstr);" & _ "SetControlLabel hresult(dword;wstr);" & _ "GetControlState hresult(dword;dword*);" & _ "SetControlState hresult(dword;dword);" & _ "GetEditBoxText hresult(dword;ptr*);" & _ "SetEditBoxText hresult(dword;wstr);" & _ "GetCheckButtonState hresult(dword;bool*);" & _ "SetCheckButtonState hresult(dword;bool);" & _ "AddControlItem hresult(dword;dword;wstr);" & _ "RemoveControlItem hresult(dword;dword);" & _ "RemoveAllControlItems hresult(dword);" & _ "GetControlItemState hresult(dword;dword;dword*);" & _ "SetControlItemState hresult(dword;dword;dword);" & _ "GetSelectedControlItem hresult(dword;dword*);" & _ "SetSelectedControlItem hresult(dword;dword);" & _ "StartVisualGroup hresult(dword;wstr);" & _ "EndVisualGroup hresult();" & _ "MakeProminent hresult(dword);" & _ "SetControlItemText hresult(dword;dword;wstr);" Global Const $tagIShellItem = _ "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _ "GetParent hresult(ptr*);" & _ "GetDisplayName hresult(int;ptr*);" & _ "GetAttributes hresult(ulong;ulong*);" & _ "Compare hresult(ptr;ulong;int*);" Global Const $SIGDN_NORMALDISPLAY = 0x00000000 Global Const $SIGDN_PARENTRELATIVEPARSING = 0x80018001 Global Const $SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000 Global Const $SIGDN_PARENTRELATIVEEDITING = 0x80030001 Global Const $SIGDN_DESKTOPABSOLUTEEDITING = 0x8004C000 Global Const $SIGDN_FILESYSPATH = 0x80058000 Global Const $SIGDN_URL = 0x80068000 Global Const $SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x80070001 Global Const $SIGDN_PARENTRELATIVE = 0x80080001 Global Const $SIGDN_PARENTRELATIVEFORUI = 0x80090001 Local $aReturn = DoFileSave(0) If IsArray($aReturn) Then ConsoleWrite("File path and name: " & $aReturn[0] & @CRLF) ConsoleWrite("File encoding: " & $aReturn[1] & @CRLF) EndIf Func DoFileSave($hParent) Local $oFileSave = ObjCreateInterface($sCLSID_FileSaveDialog, $sIID_IFileSaveDialog, $tagIFileSaveDialog) Local $pCustomFileSave, $tIID_IFileDialogCustomize = _WinAPI_GUIDFromString($sIID_IFileDialogCustomize) $oFileSave.QueryInterface(DllStructGetPtr($tIID_IFileDialogCustomize), $pCustomFileSave) Local $oCustomFileSave = ObjCreateInterface(Ptr($pCustomFileSave), $sIID_IFileDialogCustomize, $tagIFileDialogCustomize) Local $sName1 = "Text Documents (*.txt)" Local $sSpec1 = "*.txt" Local $sName2 = "All Files (*.*)" Local $sSpec2 = "*.*" Local $tName1 = DllStructCreate("wchar[" & (StringLen($sName1) + 1) & "]") DllStructSetData($tName1, 1, $sName1) Local $tSpec1 = DllStructCreate("wchar[" & (StringLen($sSpec1) + 1) & "]") DllStructSetData($tSpec1, 1, $sSpec1) Local $tName2 = DllStructCreate("wchar[" & (StringLen($sName2) + 1) & "]") DllStructSetData($tName2, 1, $sName2) Local $tSpec2 = DllStructCreate("wchar[" & (StringLen($sSpec2) + 1) & "]") DllStructSetData($tSpec2, 1, $sSpec2) Local $tFilters = DllStructCreate("ptr;ptr;ptr;ptr") DllStructSetData($tFilters, 1, DllStructGetPtr($tName1)) DllStructSetData($tFilters, 2, DllStructGetPtr($tSpec1)) DllStructSetData($tFilters, 3, DllStructGetPtr($tName2)) DllStructSetData($tFilters, 4, DllStructGetPtr($tSpec2)) $oFileSave.SetFileTypes(2, DllStructGetPtr($tFilters)) $oFileSave.SetFileTypeIndex(1) ; Set Text Documents (*.txt) as default $oFileSave.SetDefaultExtension("txt") Local Enum $idVisualGroup = 100, $idCombo, $idItemANSI, $idItemUTF8, $idItemUTF16LE, $idItemUTF16BE, $idItemUTF8BOM $oCustomFileSave.StartVisualGroup($idVisualGroup, "&Encoding:") $oCustomFileSave.AddComboBox($idCombo) $oCustomFileSave.AddControlItem($idCombo, $idItemANSI, "ANSI") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF16LE, "UTF-16 LE") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF16BE, "UTF-16 BE") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF8, "UTF-8") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF8BOM, "UTF-8 with BOM") $oCustomFileSave.SetSelectedControlItem($idCombo, $idItemUTF8) $oCustomFileSave.EndVisualGroup() $oFileSave.Show($hParent) Local $pItem, $pDispName = 0, $sFullPath = "" $oFileSave.GetResult($pItem) If @error Or Not $pItem Then ConsoleWrite("User cancelled the Save dialog." & @CRLF) Return EndIf Local $aReturn[2] Local $idSelItem, $iEncode $oCustomFileSave.GetSelectedControlItem($idCombo, $idSelItem) Switch $idSelItem Case $idItemANSI $iEncode = $FO_ANSI Case $idItemUTF16LE $iEncode = $FO_UTF16_LE Case $idItemUTF16BE $iEncode = $FO_UTF16_BE Case $idItemUTF8 $iEncode = $FO_UTF8_NOBOM Case $idItemUTF8BOM $iEncode = $FO_UTF8 EndSwitch Local $oItem = ObjCreateInterface(Ptr($pItem), $sIID_IShellItem, $tagIShellItem) $oItem.GetDisplayName($SIGDN_FILESYSPATH, $pDispName) If $pDispName Then Local $tDispName = DllStructCreate("wchar[4096]", $pDispName) $sFullPath = DllStructGetData($tDispName, 1) $aReturn[0] = $sFullPath $aReturn[1] = $iEncode _WinAPI_CoTaskMemFree($pDispName) EndIf $oItem = 0 _WinAPI_FreeMemory($pItem) Return $aReturn EndFunc Edited Sunday at 11:48 AM by WildByDesign Added encoding to return array
WildByDesign Posted Sunday at 11:55 AM Author Posted Sunday at 11:55 AM (edited) 50 minutes ago, WildByDesign said: switched over to Save As dialog because that is really what is needed in the end. Well, I was wildly wrong on this one. I only realized right now that the Notepad Open dialog actually does have an Encoding drop-down with a default Auto-Detect encoding. So it seems that we do need both. Over all the years, I don't think I've ever used the Open dialog in Notepad. That is so strange to think about. Edited Sunday at 11:56 AM by WildByDesign
WildByDesign Posted Sunday at 01:43 PM Author Posted Sunday at 01:43 PM Here is script with Open and Save As dialogs. The part where I left off here is where the bytes need to be scanned to determine the encoding type when Auto-Detect was selected. expandcollapse popup#include <WinAPI.au3> #include <GuiConstants.au3> #include <Array.au3> Global Const $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = Ptr(-4) DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "int_ptr", $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) Global Const $sCLSID_FileSaveDialog = "{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}" Global Const $sIID_IFileSaveDialog = "{84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB}" Global Const $sIID_IFileDialogCustomize = "{e6fdd21a-163f-4975-9c8c-a69f1ba37034}" Global Const $sIID_IShellItem = "{43826d1e-e718-42ee-bc55-a1e261c37bfe}" Global Const $sCLSID_FileOpenDialog = "{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}" Global Const $sIID_IFileOpenDialog = "{d57c7288-d4ad-4768-be02-9d969532d960}" Global Const $sIID_IShellItemArray = "{b63ea76d-1f85-456f-a19c-48159efa858b}" Global Const $tagIFileSaveDialog = _ "Show hresult(hwnd);" & _ "SetFileTypes hresult(uint;ptr);" & _ "SetFileTypeIndex hresult(uint);" & _ "GetFileTypeIndex hresult(uint*);" & _ "Advise hresult(ptr;dword*);" & _ "Unadvise hresult(dword);" & _ "SetOptions hresult(dword);" & _ "GetOptions hresult(dword*);" & _ "SetDefaultFolder hresult(ptr);" & _ "SetFolder hresult(ptr);" & _ "GetFolder hresult(ptr*);" & _ "GetCurrentSelection hresult(ptr*);" & _ "SetFileName hresult(wstr);" & _ "GetFileName hresult(wstr*);" & _ "SetTitle hresult(wstr);" & _ "SetOkButtonLabel hresult(wstr);" & _ "SetFileNameLabel hresult(wstr);" & _ "GetResult hresult(ptr*);" & _ "AddPlace hresult(ptr;dword);" & _ "SetDefaultExtension hresult(wstr);" & _ "Close hresult(hresult);" & _ "SetClientGuid hresult(clsid);" & _ "ClearClientData hresult();" & _ "SetFilter hresult(ptr);" & _ "GetResults hresult(ptr*);" & _ "GetSelectedItems hresult(ptr*);" Global Const $tagIFileOpenDialog = _ "Show hresult(hwnd);" & _ "SetFileTypes hresult(uint;ptr);" & _ "SetFileTypeIndex hresult(uint);" & _ "GetFileTypeIndex hresult(uint*);" & _ "Advise hresult(ptr;dword*);" & _ "Unadvise hresult(dword);" & _ "SetOptions hresult(dword);" & _ "GetOptions hresult(dword*);" & _ "SetDefaultFolder hresult(ptr);" & _ "SetFolder hresult(ptr);" & _ "GetFolder hresult(ptr*);" & _ "GetCurrentSelection hresult(ptr*);" & _ "SetFileName hresult(wstr);" & _ "GetFileName hresult(wstr*);" & _ "SetTitle hresult(wstr);" & _ "SetOkButtonLabel hresult(wstr);" & _ "SetFileNameLabel hresult(wstr);" & _ "GetResult hresult(ptr*);" & _ "AddPlace hresult(ptr;dword);" & _ "SetDefaultExtension hresult(wstr);" & _ "Close hresult(hresult);" & _ "SetClientGuid hresult(clsid);" & _ "ClearClientData hresult();" & _ "SetFilter hresult(ptr);" & _ "GetResults hresult(ptr*);" & _ "GetSelectedItems hresult(ptr*);" Global Const $tagIFileDialogCustomize = _ "EnableOpenDropDown hresult(dword);" & _ "AddMenu hresult(dword;wstr);" & _ "AddPushButton hresult(dword;wstr);" & _ "AddComboBox hresult(dword);" & _ "AddRadioButtonList hresult(dword);" & _ "AddCheckButton hresult(dword;wstr;bool);" & _ "AddEditBox hresult(dword;wstr);" & _ "AddSeparator hresult(dword);" & _ "AddText hresult(dword;wstr);" & _ "SetControlLabel hresult(dword;wstr);" & _ "GetControlState hresult(dword;dword*);" & _ "SetControlState hresult(dword;dword);" & _ "GetEditBoxText hresult(dword;ptr*);" & _ "SetEditBoxText hresult(dword;wstr);" & _ "GetCheckButtonState hresult(dword;bool*);" & _ "SetCheckButtonState hresult(dword;bool);" & _ "AddControlItem hresult(dword;dword;wstr);" & _ "RemoveControlItem hresult(dword;dword);" & _ "RemoveAllControlItems hresult(dword);" & _ "GetControlItemState hresult(dword;dword;dword*);" & _ "SetControlItemState hresult(dword;dword;dword);" & _ "GetSelectedControlItem hresult(dword;dword*);" & _ "SetSelectedControlItem hresult(dword;dword);" & _ "StartVisualGroup hresult(dword;wstr);" & _ "EndVisualGroup hresult();" & _ "MakeProminent hresult(dword);" & _ "SetControlItemText hresult(dword;dword;wstr);" Global Const $tagIShellItemArray = _ "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _ "GetPropertyStore hresult(int;clsid;ptr*);" & _ "GetPropertyDescriptionList hresult(ptr;clsid;ptr*);" & _ "GetAttributes hresult(int;int;int*);" & _ "GetCount hresult(uint*);" & _ "GetItemAt hresult(uint;ptr*);" & _ "EnumItems hresult(ptr*);" Global Const $tagIShellItem = _ "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _ "GetParent hresult(ptr*);" & _ "GetDisplayName hresult(int;ptr*);" & _ "GetAttributes hresult(ulong;ulong*);" & _ "Compare hresult(ptr;ulong;int*);" Global Const $SIGDN_NORMALDISPLAY = 0x00000000 Global Const $SIGDN_PARENTRELATIVEPARSING = 0x80018001 Global Const $SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000 Global Const $SIGDN_PARENTRELATIVEEDITING = 0x80030001 Global Const $SIGDN_DESKTOPABSOLUTEEDITING = 0x8004C000 Global Const $SIGDN_FILESYSPATH = 0x80058000 Global Const $SIGDN_URL = 0x80068000 Global Const $SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x80070001 Global Const $SIGDN_PARENTRELATIVE = 0x80080001 Global Const $SIGDN_PARENTRELATIVEFORUI = 0x80090001 ; Open Dialog Local $sFullPath, $iEncoding Local $aRetOpen = DoFileOpen(0) If IsArray($aRetOpen) Then $sFullPath = $aRetOpen[0] $iEncoding = $aRetOpen[1] ConsoleWrite("File path and name: " & $sFullPath & @CRLF) Switch $iEncoding Case 0 ConsoleWrite("File encoding: Auto-Detect" & @CRLF) ConsoleWrite("TODO: need to scan bytes to determine real encoding." & @CRLF) Case Else ConsoleWrite("File encoding: " & $iEncoding & @CRLF) EndSwitch EndIf ; Save As Dialog Local $aReturn = DoFileSave(0) If IsArray($aReturn) Then ConsoleWrite("File path and name: " & $aReturn[0] & @CRLF) ConsoleWrite("File encoding: " & $aReturn[1] & @CRLF) EndIf Func DoFileSave($hParent) Local $oFileSave = ObjCreateInterface($sCLSID_FileSaveDialog, $sIID_IFileSaveDialog, $tagIFileSaveDialog) Local $pCustomFileSave, $tIID_IFileDialogCustomize = _WinAPI_GUIDFromString($sIID_IFileDialogCustomize) $oFileSave.QueryInterface(DllStructGetPtr($tIID_IFileDialogCustomize), $pCustomFileSave) Local $oCustomFileSave = ObjCreateInterface(Ptr($pCustomFileSave), $sIID_IFileDialogCustomize, $tagIFileDialogCustomize) Local $sName1 = "Text Documents (*.txt)" Local $sSpec1 = "*.txt" Local $sName2 = "All Files (*.*)" Local $sSpec2 = "*.*" Local $tName1 = DllStructCreate("wchar[" & (StringLen($sName1) + 1) & "]") DllStructSetData($tName1, 1, $sName1) Local $tSpec1 = DllStructCreate("wchar[" & (StringLen($sSpec1) + 1) & "]") DllStructSetData($tSpec1, 1, $sSpec1) Local $tName2 = DllStructCreate("wchar[" & (StringLen($sName2) + 1) & "]") DllStructSetData($tName2, 1, $sName2) Local $tSpec2 = DllStructCreate("wchar[" & (StringLen($sSpec2) + 1) & "]") DllStructSetData($tSpec2, 1, $sSpec2) Local $tFilters = DllStructCreate("ptr;ptr;ptr;ptr") DllStructSetData($tFilters, 1, DllStructGetPtr($tName1)) DllStructSetData($tFilters, 2, DllStructGetPtr($tSpec1)) DllStructSetData($tFilters, 3, DllStructGetPtr($tName2)) DllStructSetData($tFilters, 4, DllStructGetPtr($tSpec2)) $oFileSave.SetFileTypes(2, DllStructGetPtr($tFilters)) $oFileSave.SetFileTypeIndex(1) ; Set Text Documents (*.txt) as default $oFileSave.SetDefaultExtension("txt") Local Enum $idVisualGroup = 100, $idCombo, $idItemANSI, $idItemUTF8, $idItemUTF16LE, $idItemUTF16BE, $idItemUTF8BOM $oCustomFileSave.StartVisualGroup($idVisualGroup, "&Encoding:") $oCustomFileSave.AddComboBox($idCombo) $oCustomFileSave.AddControlItem($idCombo, $idItemANSI, "ANSI") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF16LE, "UTF-16 LE") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF16BE, "UTF-16 BE") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF8, "UTF-8") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF8BOM, "UTF-8 with BOM") $oCustomFileSave.SetSelectedControlItem($idCombo, $idItemUTF8) $oCustomFileSave.EndVisualGroup() $oFileSave.Show($hParent) Local $pItem, $pDispName = 0, $sFullPath = "" $oFileSave.GetResult($pItem) If @error Or Not $pItem Then ConsoleWrite("User cancelled the Save dialog." & @CRLF) Return EndIf Local $aReturn[2] Local $idSelItem, $iEncode $oCustomFileSave.GetSelectedControlItem($idCombo, $idSelItem) Switch $idSelItem Case $idItemANSI $iEncode = $FO_ANSI Case $idItemUTF16LE $iEncode = $FO_UTF16_LE Case $idItemUTF16BE $iEncode = $FO_UTF16_BE Case $idItemUTF8 $iEncode = $FO_UTF8_NOBOM Case $idItemUTF8BOM $iEncode = $FO_UTF8 EndSwitch Local $oItem = ObjCreateInterface(Ptr($pItem), $sIID_IShellItem, $tagIShellItem) $oItem.GetDisplayName($SIGDN_FILESYSPATH, $pDispName) If $pDispName Then Local $tDispName = DllStructCreate("wchar[4096]", $pDispName) $sFullPath = DllStructGetData($tDispName, 1) $aReturn[0] = $sFullPath $aReturn[1] = $iEncode _WinAPI_CoTaskMemFree($pDispName) EndIf $oItem = 0 _WinAPI_FreeMemory($pItem) Return $aReturn EndFunc Func DoFileOpen($hParent) Local $oFileOpen = ObjCreateInterface($sCLSID_FileOpenDialog, $sIID_IFileOpenDialog, $tagIFileOpenDialog) Local $pCustomFileOpen, $tIID_IFileDialogCustomize = _WinAPI_GUIDFromString($sIID_IFileDialogCustomize) $oFileOpen.QueryInterface(DllStructGetPtr($tIID_IFileDialogCustomize), $pCustomFileOpen) Local $oCustomFileOpen = ObjCreateInterface(Ptr($pCustomFileOpen), $sIID_IFileDialogCustomize, $tagIFileDialogCustomize) Local Enum $idVisualGroup = 100, $idCombo, $idAutoDetect, $idItemANSI, $idItemUTF8, $idItemUTF16LE, $idItemUTF16BE, $idItemUTF8BOM $oCustomFileOpen.StartVisualGroup($idVisualGroup, "&Encoding:") $oCustomFileOpen.AddComboBox($idCombo) $oCustomFileOpen.AddControlItem($idCombo, $idAutoDetect, "Auto-Detect") $oCustomFileOpen.AddControlItem($idCombo, $idItemANSI, "ANSI") $oCustomFileOpen.AddControlItem($idCombo, $idItemUTF16LE, "UTF-16 LE") $oCustomFileOpen.AddControlItem($idCombo, $idItemUTF16BE, "UTF-16 BE") $oCustomFileOpen.AddControlItem($idCombo, $idItemUTF8, "UTF-8") $oCustomFileOpen.AddControlItem($idCombo, $idItemUTF8BOM, "UTF-8 with BOM") $oCustomFileOpen.SetSelectedControlItem($idCombo, $idAutoDetect) $oCustomFileOpen.EndVisualGroup() $oFileOpen.Show($hParent) Local $aReturn[2] Local $idSelItem, $sSelItem $oCustomFileOpen.GetSelectedControlItem($idCombo, $idSelItem) Switch $idSelItem Case $idAutoDetect $iEncode = 0 Case $idItemANSI $iEncode = $FO_ANSI Case $idItemUTF16LE $iEncode = $FO_UTF16_LE Case $idItemUTF16BE $iEncode = $FO_UTF16_BE Case $idItemUTF8 $iEncode = $FO_UTF8_NOBOM Case $idItemUTF8BOM $iEncode = $FO_UTF8 EndSwitch Local $pItemArr, $pItem, $pDispName = 0, $sFullPath = "" $oFileOpen.GetResults($pItemArr) If @error Or Not $pItemArr Then ConsoleWrite("User cancelled the Open dialog." & @CRLF) Return EndIf Local $oItemArr = ObjCreateInterface(Ptr($pItemArr), $sIID_IShellItemArray, $tagIShellItemArray) $oItemArr.GetItemAt(0, $pItem) Local $oItem = ObjCreateInterface(Ptr($pItem), $sIID_IShellItem, $tagIShellItem) ; This will now properly request and retrieve the absolute file path $oItem.GetDisplayName($SIGDN_FILESYSPATH, $pDispName) If $pDispName Then Local $tDispName = DllStructCreate("wchar[4096]", $pDispName) $sFullPath = DllStructGetData($tDispName, 1) $aReturn[0] = $sFullPath $aReturn[1] = $iEncode _WinAPI_CoTaskMemFree($pDispName) EndIf $oItemArr = 0 $oItem = 0 _WinAPI_FreeMemory($pItemArr) Return $aReturn EndFunc MattyD 1
MattyD Posted Sunday at 11:09 PM Posted Sunday at 11:09 PM Good stuff, Fixed SIGDN_ definitions 👍 Freeing GetDisplayName is also a good pickup. This is absolutely fine - but just a tip, you can generally make filename buffers 260 characters - which is the value of MAX_PATH. $oItem.GetDisplayName($SIGDN_FILESYSPATH, $pDispName) If $pDispName Then Local $tDispName = DllStructCreate("wchar[4096]", $pDispName) $sFullPath = DllStructGetData($tDispName, 1) $aReturn[0] = $sFullPath $aReturn[1] = $iEncode _WinAPI_CoTaskMemFree($pDispName) EndIf This was a brain fart, it can disappear. $oItemArr = 0 $oItem = 0 _WinAPI_FreeMemory($pItemArr) Another good call to error check here. These methods all return HResult - so the error code will be there rather than in @error. But I'd imagine just checking for a valid $pItemArr will probably be enough. $oFileOpen.GetResults($pItemArr) If @error Or Not $pItemArr Then ConsoleWrite("User cancelled the Open dialog." & @CRLF) Return EndIf ;$iResult = $oFileOpen.GetResults($pItemArr) WildByDesign 1
WildByDesign Posted Sunday at 11:44 PM Author Posted Sunday at 11:44 PM (edited) 35 minutes ago, MattyD said: you can generally make filename buffers 260 characters - which is the value of MAX_PATH. Good suggestion and makes sense. I've changed it to 260 characters for both functions now. Is it worthwhile at all to check a system for LongPathsEnabled setting? 35 minutes ago, MattyD said: But I'd imagine just checking for a valid $pItemArr will probably be enough. True, you are right. It does seem to be sufficient. I've made the relevant change for both functions. Thank you for presenting this idea along with some great working code examples and also for checking over my changes. I appreciate your time. Especially when it comes to error checking on this COM stuff because I am not very familiar with it. It looks like this custom Open dialog and Save As dialog should give us exactly what is needed for this Notepad clone project. Edited Sunday at 11:45 PM by WildByDesign
MattyD Posted Sunday at 11:45 PM Posted Sunday at 11:45 PM Quote you can generally make filename buffers 260 characters On second thought, we technically should use _WinAPI_StringLenW in this situation (assuming the string is null-terminated) The method might only allocates enough for the string - and 260 chars will probably overrun this..
MattyD Posted Sunday at 11:54 PM Posted Sunday at 11:54 PM 4 minutes ago, WildByDesign said: Is it worthwhile at all to check a system for LongPathsEnabled setting? I don't think so, by memory the app needs to opt-in to long paths in its manifest. But you may want to check me on this.
WildByDesign Posted Monday at 11:12 AM Author Posted Monday at 11:12 AM @MattyD Can you please check the Auto-Detect functionality in the Open dialog when you have a moment? Thank you. I had to get some help from AI with scanning the bytes. My testing so far with it has checked out OK. But it's not an area that I am familiar with. The Auto-Detect triggers the _DetectFileEncoding function. The idea is to replicate how Notepad handles it exactly. expandcollapse popup#include <WinAPI.au3> #include <GuiConstants.au3> Global Const $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = Ptr(-4) DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "int_ptr", $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) Global Const $sCLSID_FileSaveDialog = "{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}" Global Const $sIID_IFileSaveDialog = "{84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB}" Global Const $sIID_IFileDialogCustomize = "{e6fdd21a-163f-4975-9c8c-a69f1ba37034}" Global Const $sIID_IShellItem = "{43826d1e-e718-42ee-bc55-a1e261c37bfe}" Global Const $sCLSID_FileOpenDialog = "{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}" Global Const $sIID_IFileOpenDialog = "{d57c7288-d4ad-4768-be02-9d969532d960}" Global Const $sIID_IShellItemArray = "{b63ea76d-1f85-456f-a19c-48159efa858b}" Global Const $tagIFileSaveDialog = _ "Show hresult(hwnd);" & _ "SetFileTypes hresult(uint;ptr);" & _ "SetFileTypeIndex hresult(uint);" & _ "GetFileTypeIndex hresult(uint*);" & _ "Advise hresult(ptr;dword*);" & _ "Unadvise hresult(dword);" & _ "SetOptions hresult(dword);" & _ "GetOptions hresult(dword*);" & _ "SetDefaultFolder hresult(ptr);" & _ "SetFolder hresult(ptr);" & _ "GetFolder hresult(ptr*);" & _ "GetCurrentSelection hresult(ptr*);" & _ "SetFileName hresult(wstr);" & _ "GetFileName hresult(wstr*);" & _ "SetTitle hresult(wstr);" & _ "SetOkButtonLabel hresult(wstr);" & _ "SetFileNameLabel hresult(wstr);" & _ "GetResult hresult(ptr*);" & _ "AddPlace hresult(ptr;dword);" & _ "SetDefaultExtension hresult(wstr);" & _ "Close hresult(hresult);" & _ "SetClientGuid hresult(clsid);" & _ "ClearClientData hresult();" & _ "SetFilter hresult(ptr);" & _ "GetResults hresult(ptr*);" & _ "GetSelectedItems hresult(ptr*);" Global Const $tagIFileOpenDialog = _ "Show hresult(hwnd);" & _ "SetFileTypes hresult(uint;ptr);" & _ "SetFileTypeIndex hresult(uint);" & _ "GetFileTypeIndex hresult(uint*);" & _ "Advise hresult(ptr;dword*);" & _ "Unadvise hresult(dword);" & _ "SetOptions hresult(dword);" & _ "GetOptions hresult(dword*);" & _ "SetDefaultFolder hresult(ptr);" & _ "SetFolder hresult(ptr);" & _ "GetFolder hresult(ptr*);" & _ "GetCurrentSelection hresult(ptr*);" & _ "SetFileName hresult(wstr);" & _ "GetFileName hresult(wstr*);" & _ "SetTitle hresult(wstr);" & _ "SetOkButtonLabel hresult(wstr);" & _ "SetFileNameLabel hresult(wstr);" & _ "GetResult hresult(ptr*);" & _ "AddPlace hresult(ptr;dword);" & _ "SetDefaultExtension hresult(wstr);" & _ "Close hresult(hresult);" & _ "SetClientGuid hresult(clsid);" & _ "ClearClientData hresult();" & _ "SetFilter hresult(ptr);" & _ "GetResults hresult(ptr*);" & _ "GetSelectedItems hresult(ptr*);" Global Const $tagIFileDialogCustomize = _ "EnableOpenDropDown hresult(dword);" & _ "AddMenu hresult(dword;wstr);" & _ "AddPushButton hresult(dword;wstr);" & _ "AddComboBox hresult(dword);" & _ "AddRadioButtonList hresult(dword);" & _ "AddCheckButton hresult(dword;wstr;bool);" & _ "AddEditBox hresult(dword;wstr);" & _ "AddSeparator hresult(dword);" & _ "AddText hresult(dword;wstr);" & _ "SetControlLabel hresult(dword;wstr);" & _ "GetControlState hresult(dword;dword*);" & _ "SetControlState hresult(dword;dword);" & _ "GetEditBoxText hresult(dword;ptr*);" & _ "SetEditBoxText hresult(dword;wstr);" & _ "GetCheckButtonState hresult(dword;bool*);" & _ "SetCheckButtonState hresult(dword;bool);" & _ "AddControlItem hresult(dword;dword;wstr);" & _ "RemoveControlItem hresult(dword;dword);" & _ "RemoveAllControlItems hresult(dword);" & _ "GetControlItemState hresult(dword;dword;dword*);" & _ "SetControlItemState hresult(dword;dword;dword);" & _ "GetSelectedControlItem hresult(dword;dword*);" & _ "SetSelectedControlItem hresult(dword;dword);" & _ "StartVisualGroup hresult(dword;wstr);" & _ "EndVisualGroup hresult();" & _ "MakeProminent hresult(dword);" & _ "SetControlItemText hresult(dword;dword;wstr);" Global Const $tagIShellItemArray = _ "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _ "GetPropertyStore hresult(int;clsid;ptr*);" & _ "GetPropertyDescriptionList hresult(ptr;clsid;ptr*);" & _ "GetAttributes hresult(int;int;int*);" & _ "GetCount hresult(uint*);" & _ "GetItemAt hresult(uint;ptr*);" & _ "EnumItems hresult(ptr*);" Global Const $tagIShellItem = _ "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _ "GetParent hresult(ptr*);" & _ "GetDisplayName hresult(int;ptr*);" & _ "GetAttributes hresult(ulong;ulong*);" & _ "Compare hresult(ptr;ulong;int*);" Global Const $SIGDN_NORMALDISPLAY = 0x00000000 Global Const $SIGDN_PARENTRELATIVEPARSING = 0x80018001 Global Const $SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000 Global Const $SIGDN_PARENTRELATIVEEDITING = 0x80030001 Global Const $SIGDN_DESKTOPABSOLUTEEDITING = 0x8004C000 Global Const $SIGDN_FILESYSPATH = 0x80058000 Global Const $SIGDN_URL = 0x80068000 Global Const $SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x80070001 Global Const $SIGDN_PARENTRELATIVE = 0x80080001 Global Const $SIGDN_PARENTRELATIVEFORUI = 0x80090001 ; Open Dialog Local $sFullPath, $iEncoding Local $aRetOpen = DoFileOpen(0) If IsArray($aRetOpen) Then $sFullPath = $aRetOpen[0] $iEncoding = $aRetOpen[1] ConsoleWrite("File path and name: " & $sFullPath & @CRLF) ConsoleWrite("File encoding: " & $iEncoding & @CRLF) EndIf ; Save As Dialog Local $aReturn = DoFileSave(0) If IsArray($aReturn) Then ConsoleWrite("File path and name: " & $aReturn[0] & @CRLF) ConsoleWrite("File encoding: " & $aReturn[1] & @CRLF) EndIf Func DoFileSave($hParent) Local $oFileSave = ObjCreateInterface($sCLSID_FileSaveDialog, $sIID_IFileSaveDialog, $tagIFileSaveDialog) Local $pCustomFileSave, $tIID_IFileDialogCustomize = _WinAPI_GUIDFromString($sIID_IFileDialogCustomize) $oFileSave.QueryInterface(DllStructGetPtr($tIID_IFileDialogCustomize), $pCustomFileSave) Local $oCustomFileSave = ObjCreateInterface(Ptr($pCustomFileSave), $sIID_IFileDialogCustomize, $tagIFileDialogCustomize) Local $sName1 = "Text Documents (*.txt)" Local $sSpec1 = "*.txt" Local $sName2 = "All Files (*.*)" Local $sSpec2 = "*.*" Local $tName1 = DllStructCreate("wchar[" & (StringLen($sName1) + 1) & "]") DllStructSetData($tName1, 1, $sName1) Local $tSpec1 = DllStructCreate("wchar[" & (StringLen($sSpec1) + 1) & "]") DllStructSetData($tSpec1, 1, $sSpec1) Local $tName2 = DllStructCreate("wchar[" & (StringLen($sName2) + 1) & "]") DllStructSetData($tName2, 1, $sName2) Local $tSpec2 = DllStructCreate("wchar[" & (StringLen($sSpec2) + 1) & "]") DllStructSetData($tSpec2, 1, $sSpec2) Local $tFilters = DllStructCreate("ptr;ptr;ptr;ptr") DllStructSetData($tFilters, 1, DllStructGetPtr($tName1)) DllStructSetData($tFilters, 2, DllStructGetPtr($tSpec1)) DllStructSetData($tFilters, 3, DllStructGetPtr($tName2)) DllStructSetData($tFilters, 4, DllStructGetPtr($tSpec2)) $oFileSave.SetFileTypes(2, DllStructGetPtr($tFilters)) $oFileSave.SetFileTypeIndex(1) ; Set Text Documents (*.txt) as default $oFileSave.SetDefaultExtension("txt") Local Enum $idVisualGroup = 100, $idCombo, $idItemANSI, $idItemUTF8, $idItemUTF16LE, $idItemUTF16BE, $idItemUTF8BOM $oCustomFileSave.StartVisualGroup($idVisualGroup, "&Encoding:") $oCustomFileSave.AddComboBox($idCombo) $oCustomFileSave.AddControlItem($idCombo, $idItemANSI, "ANSI") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF16LE, "UTF-16 LE") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF16BE, "UTF-16 BE") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF8, "UTF-8") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF8BOM, "UTF-8 with BOM") $oCustomFileSave.SetSelectedControlItem($idCombo, $idItemUTF8) $oCustomFileSave.EndVisualGroup() $oFileSave.Show($hParent) Local $pItem, $pDispName = 0, $sFullPath = "" $oFileSave.GetResult($pItem) If Not $pItem Then ConsoleWrite("User cancelled the Save dialog." & @CRLF) Return EndIf Local $aReturn[2] Local $idSelItem, $iEncode $oCustomFileSave.GetSelectedControlItem($idCombo, $idSelItem) Switch $idSelItem Case $idItemANSI $iEncode = $FO_ANSI Case $idItemUTF16LE $iEncode = $FO_UTF16_LE Case $idItemUTF16BE $iEncode = $FO_UTF16_BE Case $idItemUTF8 $iEncode = $FO_UTF8_NOBOM Case $idItemUTF8BOM $iEncode = $FO_UTF8 EndSwitch Local $oItem = ObjCreateInterface(Ptr($pItem), $sIID_IShellItem, $tagIShellItem) $oItem.GetDisplayName($SIGDN_FILESYSPATH, $pDispName) If $pDispName Then Local $tDispName = DllStructCreate("wchar[260]", $pDispName) $sFullPath = DllStructGetData($tDispName, 1) $aReturn[0] = $sFullPath $aReturn[1] = $iEncode _WinAPI_CoTaskMemFree($pDispName) EndIf $oItem = 0 _WinAPI_FreeMemory($pItem) Return $aReturn EndFunc Func DoFileOpen($hParent) Local $oFileOpen = ObjCreateInterface($sCLSID_FileOpenDialog, $sIID_IFileOpenDialog, $tagIFileOpenDialog) Local $pCustomFileOpen, $tIID_IFileDialogCustomize = _WinAPI_GUIDFromString($sIID_IFileDialogCustomize) $oFileOpen.QueryInterface(DllStructGetPtr($tIID_IFileDialogCustomize), $pCustomFileOpen) Local $oCustomFileOpen = ObjCreateInterface(Ptr($pCustomFileOpen), $sIID_IFileDialogCustomize, $tagIFileDialogCustomize) Local Enum $idVisualGroup = 100, $idCombo, $idAutoDetect, $idItemANSI, $idItemUTF8, $idItemUTF16LE, $idItemUTF16BE, $idItemUTF8BOM $oCustomFileOpen.StartVisualGroup($idVisualGroup, "&Encoding:") $oCustomFileOpen.AddComboBox($idCombo) $oCustomFileOpen.AddControlItem($idCombo, $idAutoDetect, "Auto-Detect") $oCustomFileOpen.AddControlItem($idCombo, $idItemANSI, "ANSI") $oCustomFileOpen.AddControlItem($idCombo, $idItemUTF16LE, "UTF-16 LE") $oCustomFileOpen.AddControlItem($idCombo, $idItemUTF16BE, "UTF-16 BE") $oCustomFileOpen.AddControlItem($idCombo, $idItemUTF8, "UTF-8") $oCustomFileOpen.AddControlItem($idCombo, $idItemUTF8BOM, "UTF-8 with BOM") $oCustomFileOpen.SetSelectedControlItem($idCombo, $idAutoDetect) $oCustomFileOpen.EndVisualGroup() $oFileOpen.Show($hParent) Local $aReturn[2] Local $idSelItem, $sSelItem $oCustomFileOpen.GetSelectedControlItem($idCombo, $idSelItem) Switch $idSelItem Case $idAutoDetect $iEncode = 0 Case $idItemANSI $iEncode = $FO_ANSI Case $idItemUTF16LE $iEncode = $FO_UTF16_LE Case $idItemUTF16BE $iEncode = $FO_UTF16_BE Case $idItemUTF8 $iEncode = $FO_UTF8_NOBOM Case $idItemUTF8BOM $iEncode = $FO_UTF8 EndSwitch Local $pItemArr, $pItem, $pDispName = 0, $sFullPath = "" $oFileOpen.GetResults($pItemArr) If Not $pItemArr Then ConsoleWrite("User cancelled the Open dialog." & @CRLF) Return EndIf Local $oItemArr = ObjCreateInterface(Ptr($pItemArr), $sIID_IShellItemArray, $tagIShellItemArray) $oItemArr.GetItemAt(0, $pItem) Local $oItem = ObjCreateInterface(Ptr($pItem), $sIID_IShellItem, $tagIShellItem) $oItem.GetDisplayName($SIGDN_FILESYSPATH, $pDispName) If $pDispName Then Local $tDispName = DllStructCreate("wchar[260]", $pDispName) $sFullPath = DllStructGetData($tDispName, 1) $aReturn[0] = $sFullPath If Not $iEncode Then ConsoleWrite("user kept auto detect" & @CRLF) $iEncode = _DetectFileEncoding($sFullPath) EndIf $aReturn[1] = $iEncode _WinAPI_CoTaskMemFree($pDispName) EndIf $oItemArr = 0 $oItem = 0 _WinAPI_FreeMemory($pItemArr) Return $aReturn EndFunc Func _DetectFileEncoding($sFilePath) Local $hFile = FileOpen($sFilePath, 16) If $hFile = -1 Then Return $FO_ANSI Local $bData = FileRead($hFile, 4096) FileClose($hFile) Local $iLen = BinaryLen($bData) If $iLen = 0 Then Return $FO_ANSI ; Check for Byte Order Marks (BOM) If $iLen >= 3 And BinaryMid($bData, 1, 3) == "0xEFBBBF" Then Return $FO_UTF8 If $iLen >= 2 And BinaryMid($bData, 1, 2) == "0xFFFE" Then Return $FO_UTF16_LE If $iLen >= 2 And BinaryMid($bData, 1, 2) == "0xFEFF" Then Return $FO_UTF16_BE ; Heuristic Check Local $i = 1 Local $bHasHighBit = False While $i <= $iLen Local $iByte = Number(BinaryMid($bData, $i, 1)) If $iByte < 128 Then $i += 1 Else $bHasHighBit = True Local $iBytesExpected = 0 If BitAND($iByte, 0xE0) = 0xC0 Then $iBytesExpected = 1 ElseIf BitAND($iByte, 0xF0) = 0xE0 Then $iBytesExpected = 2 ElseIf BitAND($iByte, 0xF8) = 0xF0 Then $iBytesExpected = 3 Else Return $FO_ANSI EndIf If $i + $iBytesExpected > $iLen Then Return $FO_ANSI For $j = 1 To $iBytesExpected $i += 1 Local $iContByte = Number(BinaryMid($bData, $i, 1)) If BitAND($iContByte, 0xC0) <> 0x80 Then Return $FO_ANSI Next $i += 1 EndIf WEnd ; No BOM and no violation -> UTF-8 without BOM ($FO_UTF8_NOBOM) Return $FO_UTF8_NOBOM EndFunc
WildByDesign Posted Monday at 11:46 AM Author Posted Monday at 11:46 AM 11 hours ago, MattyD said: we technically should use _WinAPI_StringLenW in this situation (assuming the string is null-terminated) Sorry, I forgot to mention that I'm not entirely sure how to implement this. From my limited knowledge, I don't think that we even have the string yet at the point where we call DllStructCreate. This is very much above my head and you will understand it better than I do, of course. From DoFileOpen(): If $pDispName Then Local $tDispName = DllStructCreate("wchar[260]", $pDispName) $sFullPath = DllStructGetData($tDispName, 1) $aReturn[0] = $sFullPath If Not $iEncode Then $iEncode = _DetectFileEncoding($sFullPath) EndIf $aReturn[1] = $iEncode _WinAPI_CoTaskMemFree($pDispName) EndIf From DoFileSave(): If $pDispName Then Local $tDispName = DllStructCreate("wchar[260]", $pDispName) $sFullPath = DllStructGetData($tDispName, 1) $aReturn[0] = $sFullPath $aReturn[1] = $iEncode _WinAPI_CoTaskMemFree($pDispName) EndIf I believe that those are the two relevant sections that could potentially use _WinAPI_StringLenW. If you have time, could you please share how that would be implemented?
Solution MattyD Posted Monday at 01:25 PM Solution Posted Monday at 01:25 PM (edited) No worries. I'll answer the second question first, and look at the heuristics tomorrow. 1 hour ago, WildByDesign said: I don't think that we even have the string yet at the point Yep, we certainly do. GetDisplayName creates the string, and to extract it we need to know: Where it is - We're told its at $pDisplayName. How big it is - We do this using StringLenW. It finds the first null character after $pDisplayName. Local $pDispName $oItem.GetDisplayName($SIGDN_FILESYSPATH, $pDispName) ; GetDisplayName creates & fills a buffer. It puts the address in $pDispName, but we still don't know how big it is. If $pDispName Then ; _WinAPI_StringLenW($pDispName) starts at $pDispName, and will keep counting characters until it finds a NULL (ChrW(0)). ; It then returns that count. Local $tDispName = DllStructCreate("wchar[" & _WinAPI_StringLenW($pDispName) & "]", $pDispName) $sFullPath = DllStructGetData($tDispName, 1) ;its our responsibility to free that buffer when we're done with it. _WinAPI_CoTaskMemFree($pDispName) EndIf Edited Monday at 01:37 PM by MattyD wording WildByDesign 1
MattyD Posted Tuesday at 08:00 PM Posted Tuesday at 08:00 PM On 10/5/2026 at 9:12 PM, WildByDesign said: scanning the bytes Not too bad for the UTF8 check - The main issue is this line: If $i + $iBytesExpected > $iLen Then Return $FO_ANSI We haven't necessarily read in the whole file, so this is problematic if the file is > 4096 bytes. Here's something to test the first 96k of the file. expandcollapse popupFunc IsUTF8($hFile) FileSetPos($hFile, 0, $FILE_BEGIN) Local $dChunk, $dByte, $iContBytes Local $iChunkSize = 4096, $iMaxChunks = 24 ;Check first 96k For $i = 1 To $iMaxChunks $dChunk = FileRead($hFile, $iChunkSize) If Not BinaryLen($dChunk) Then ExitLoop For $j = 1 To BinaryLen($dChunk) $dByte = BinaryMid($dChunk, $i, 1) If $iContBytes Then ;Test for: 10nn nnnn If BitAND($dByte, 0xC0) <> 0x80 Then Return False $iContBytes -= 1 ElseIf BitAND($dByte, 0x80) Then ; Test for: 110n nnnn If BitAND($dByte, 0xE0) = 0xC0 Then $iContBytes = 1 ; Test for: 1110 nnnn ElseIf BitAND($dByte, 0xF0) = 0xE0 Then $iContBytes = 2 ; Test for: 1111 0nnn ElseIf BitAND($dByte, 0xF8) = 0xF0 Then $iContBytes = 3 Else Return False EndIf EndIf Next Next Return True EndFunc WildByDesign 1
WildByDesign Posted Wednesday at 10:45 PM Author Posted Wednesday at 10:45 PM On 10/6/2026 at 4:00 PM, MattyD said: Here's something to test the first 96k of the file. Thanks for this updated code. It took me some time to learn more about the various encoding types before I went ahead and put it all together. If you have some time, please test the Open dialog with the Auto-Detect (default) encoding and ensure that it is working correctly. Thanks. expandcollapse popup#include <WinAPI.au3> #include <GuiConstants.au3> Global Const $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = Ptr(-4) DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "int_ptr", $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) Global Const $sCLSID_FileSaveDialog = "{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}" Global Const $sIID_IFileSaveDialog = "{84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB}" Global Const $sIID_IFileDialogCustomize = "{e6fdd21a-163f-4975-9c8c-a69f1ba37034}" Global Const $sIID_IShellItem = "{43826d1e-e718-42ee-bc55-a1e261c37bfe}" Global Const $sCLSID_FileOpenDialog = "{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}" Global Const $sIID_IFileOpenDialog = "{d57c7288-d4ad-4768-be02-9d969532d960}" Global Const $sIID_IShellItemArray = "{b63ea76d-1f85-456f-a19c-48159efa858b}" Global Const $tagIFileSaveDialog = _ "Show hresult(hwnd);" & _ "SetFileTypes hresult(uint;ptr);" & _ "SetFileTypeIndex hresult(uint);" & _ "GetFileTypeIndex hresult(uint*);" & _ "Advise hresult(ptr;dword*);" & _ "Unadvise hresult(dword);" & _ "SetOptions hresult(dword);" & _ "GetOptions hresult(dword*);" & _ "SetDefaultFolder hresult(ptr);" & _ "SetFolder hresult(ptr);" & _ "GetFolder hresult(ptr*);" & _ "GetCurrentSelection hresult(ptr*);" & _ "SetFileName hresult(wstr);" & _ "GetFileName hresult(wstr*);" & _ "SetTitle hresult(wstr);" & _ "SetOkButtonLabel hresult(wstr);" & _ "SetFileNameLabel hresult(wstr);" & _ "GetResult hresult(ptr*);" & _ "AddPlace hresult(ptr;dword);" & _ "SetDefaultExtension hresult(wstr);" & _ "Close hresult(hresult);" & _ "SetClientGuid hresult(clsid);" & _ "ClearClientData hresult();" & _ "SetFilter hresult(ptr);" & _ "GetResults hresult(ptr*);" & _ "GetSelectedItems hresult(ptr*);" Global Const $tagIFileOpenDialog = _ "Show hresult(hwnd);" & _ "SetFileTypes hresult(uint;ptr);" & _ "SetFileTypeIndex hresult(uint);" & _ "GetFileTypeIndex hresult(uint*);" & _ "Advise hresult(ptr;dword*);" & _ "Unadvise hresult(dword);" & _ "SetOptions hresult(dword);" & _ "GetOptions hresult(dword*);" & _ "SetDefaultFolder hresult(ptr);" & _ "SetFolder hresult(ptr);" & _ "GetFolder hresult(ptr*);" & _ "GetCurrentSelection hresult(ptr*);" & _ "SetFileName hresult(wstr);" & _ "GetFileName hresult(wstr*);" & _ "SetTitle hresult(wstr);" & _ "SetOkButtonLabel hresult(wstr);" & _ "SetFileNameLabel hresult(wstr);" & _ "GetResult hresult(ptr*);" & _ "AddPlace hresult(ptr;dword);" & _ "SetDefaultExtension hresult(wstr);" & _ "Close hresult(hresult);" & _ "SetClientGuid hresult(clsid);" & _ "ClearClientData hresult();" & _ "SetFilter hresult(ptr);" & _ "GetResults hresult(ptr*);" & _ "GetSelectedItems hresult(ptr*);" Global Const $tagIFileDialogCustomize = _ "EnableOpenDropDown hresult(dword);" & _ "AddMenu hresult(dword;wstr);" & _ "AddPushButton hresult(dword;wstr);" & _ "AddComboBox hresult(dword);" & _ "AddRadioButtonList hresult(dword);" & _ "AddCheckButton hresult(dword;wstr;bool);" & _ "AddEditBox hresult(dword;wstr);" & _ "AddSeparator hresult(dword);" & _ "AddText hresult(dword;wstr);" & _ "SetControlLabel hresult(dword;wstr);" & _ "GetControlState hresult(dword;dword*);" & _ "SetControlState hresult(dword;dword);" & _ "GetEditBoxText hresult(dword;ptr*);" & _ "SetEditBoxText hresult(dword;wstr);" & _ "GetCheckButtonState hresult(dword;bool*);" & _ "SetCheckButtonState hresult(dword;bool);" & _ "AddControlItem hresult(dword;dword;wstr);" & _ "RemoveControlItem hresult(dword;dword);" & _ "RemoveAllControlItems hresult(dword);" & _ "GetControlItemState hresult(dword;dword;dword*);" & _ "SetControlItemState hresult(dword;dword;dword);" & _ "GetSelectedControlItem hresult(dword;dword*);" & _ "SetSelectedControlItem hresult(dword;dword);" & _ "StartVisualGroup hresult(dword;wstr);" & _ "EndVisualGroup hresult();" & _ "MakeProminent hresult(dword);" & _ "SetControlItemText hresult(dword;dword;wstr);" Global Const $tagIShellItemArray = _ "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _ "GetPropertyStore hresult(int;clsid;ptr*);" & _ "GetPropertyDescriptionList hresult(ptr;clsid;ptr*);" & _ "GetAttributes hresult(int;int;int*);" & _ "GetCount hresult(uint*);" & _ "GetItemAt hresult(uint;ptr*);" & _ "EnumItems hresult(ptr*);" Global Const $tagIShellItem = _ "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _ "GetParent hresult(ptr*);" & _ "GetDisplayName hresult(int;ptr*);" & _ "GetAttributes hresult(ulong;ulong*);" & _ "Compare hresult(ptr;ulong;int*);" Global Const $SIGDN_NORMALDISPLAY = 0x00000000 Global Const $SIGDN_PARENTRELATIVEPARSING = 0x80018001 Global Const $SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000 Global Const $SIGDN_PARENTRELATIVEEDITING = 0x80030001 Global Const $SIGDN_DESKTOPABSOLUTEEDITING = 0x8004C000 Global Const $SIGDN_FILESYSPATH = 0x80058000 Global Const $SIGDN_URL = 0x80068000 Global Const $SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x80070001 Global Const $SIGDN_PARENTRELATIVE = 0x80080001 Global Const $SIGDN_PARENTRELATIVEFORUI = 0x80090001 ; Open Dialog Local $sFullPath, $iEncoding Local $aRetOpen = _DoFileOpen(0) If IsArray($aRetOpen) Then $sFullPath = $aRetOpen[0] $iEncoding = $aRetOpen[1] ConsoleWrite("File path and name: " & $sFullPath & @CRLF) ConsoleWrite("File encoding: " & $iEncoding & @CRLF) EndIf ; Save As Dialog ;Local $aReturn = _DoFileSave(0) ;If IsArray($aReturn) Then ; ConsoleWrite("File path and name: " & $aReturn[0] & @CRLF) ; ConsoleWrite("File encoding: " & $aReturn[1] & @CRLF) ;EndIf Func _DoFileSave($hParent) Local $oFileSave = ObjCreateInterface($sCLSID_FileSaveDialog, $sIID_IFileSaveDialog, $tagIFileSaveDialog) Local $pCustomFileSave, $tIID_IFileDialogCustomize = _WinAPI_GUIDFromString($sIID_IFileDialogCustomize) $oFileSave.QueryInterface(DllStructGetPtr($tIID_IFileDialogCustomize), $pCustomFileSave) Local $oCustomFileSave = ObjCreateInterface(Ptr($pCustomFileSave), $sIID_IFileDialogCustomize, $tagIFileDialogCustomize) Local $sName1 = "Text Documents (*.txt)" Local $sSpec1 = "*.txt" Local $sName2 = "All Files (*.*)" Local $sSpec2 = "*.*" Local $tName1 = DllStructCreate("wchar[" & (StringLen($sName1) + 1) & "]") DllStructSetData($tName1, 1, $sName1) Local $tSpec1 = DllStructCreate("wchar[" & (StringLen($sSpec1) + 1) & "]") DllStructSetData($tSpec1, 1, $sSpec1) Local $tName2 = DllStructCreate("wchar[" & (StringLen($sName2) + 1) & "]") DllStructSetData($tName2, 1, $sName2) Local $tSpec2 = DllStructCreate("wchar[" & (StringLen($sSpec2) + 1) & "]") DllStructSetData($tSpec2, 1, $sSpec2) Local $tFilters = DllStructCreate("ptr;ptr;ptr;ptr") DllStructSetData($tFilters, 1, DllStructGetPtr($tName1)) DllStructSetData($tFilters, 2, DllStructGetPtr($tSpec1)) DllStructSetData($tFilters, 3, DllStructGetPtr($tName2)) DllStructSetData($tFilters, 4, DllStructGetPtr($tSpec2)) $oFileSave.SetFileTypes(2, DllStructGetPtr($tFilters)) $oFileSave.SetFileTypeIndex(1) ; Set Text Documents (*.txt) as default $oFileSave.SetDefaultExtension("txt") Local Enum $idVisualGroup = 100, $idCombo, $idItemANSI, $idItemUTF8, $idItemUTF16LE, $idItemUTF16BE, $idItemUTF8BOM $oCustomFileSave.StartVisualGroup($idVisualGroup, "&Encoding:") $oCustomFileSave.AddComboBox($idCombo) $oCustomFileSave.AddControlItem($idCombo, $idItemANSI, "ANSI") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF16LE, "UTF-16 LE") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF16BE, "UTF-16 BE") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF8, "UTF-8") $oCustomFileSave.AddControlItem($idCombo, $idItemUTF8BOM, "UTF-8 with BOM") $oCustomFileSave.SetSelectedControlItem($idCombo, $idItemUTF8) $oCustomFileSave.EndVisualGroup() $oFileSave.Show($hParent) Local $pItem, $pDispName = 0, $sFullPath = "" $oFileSave.GetResult($pItem) If Not $pItem Then ConsoleWrite("User cancelled the Save dialog." & @CRLF) Return EndIf Local $aReturn[2] Local $idSelItem, $iEncode $oCustomFileSave.GetSelectedControlItem($idCombo, $idSelItem) Switch $idSelItem Case $idItemANSI $iEncode = $FO_ANSI Case $idItemUTF16LE $iEncode = $FO_UTF16_LE Case $idItemUTF16BE $iEncode = $FO_UTF16_BE Case $idItemUTF8 $iEncode = $FO_UTF8_NOBOM Case $idItemUTF8BOM $iEncode = $FO_UTF8 EndSwitch Local $oItem = ObjCreateInterface(Ptr($pItem), $sIID_IShellItem, $tagIShellItem) $oItem.GetDisplayName($SIGDN_FILESYSPATH, $pDispName) If $pDispName Then Local $tDispName = DllStructCreate("wchar[" & _WinAPI_StringLenW($pDispName) & "]", $pDispName) $sFullPath = DllStructGetData($tDispName, 1) $aReturn[0] = $sFullPath $aReturn[1] = $iEncode _WinAPI_CoTaskMemFree($pDispName) EndIf $oItem = 0 _WinAPI_FreeMemory($pItem) Return $aReturn EndFunc ;==>_DoFileSave Func _DoFileOpen($hParent) Local $oFileOpen = ObjCreateInterface($sCLSID_FileOpenDialog, $sIID_IFileOpenDialog, $tagIFileOpenDialog) Local $pCustomFileOpen, $tIID_IFileDialogCustomize = _WinAPI_GUIDFromString($sIID_IFileDialogCustomize) $oFileOpen.QueryInterface(DllStructGetPtr($tIID_IFileDialogCustomize), $pCustomFileOpen) Local $oCustomFileOpen = ObjCreateInterface(Ptr($pCustomFileOpen), $sIID_IFileDialogCustomize, $tagIFileDialogCustomize) Local Enum $idVisualGroup = 100, $idCombo, $idAutoDetect, $idItemANSI, $idItemUTF8, $idItemUTF16LE, $idItemUTF16BE, $idItemUTF8BOM $oCustomFileOpen.StartVisualGroup($idVisualGroup, "&Encoding:") $oCustomFileOpen.AddComboBox($idCombo) $oCustomFileOpen.AddControlItem($idCombo, $idAutoDetect, "Auto-Detect") $oCustomFileOpen.AddControlItem($idCombo, $idItemANSI, "ANSI") $oCustomFileOpen.AddControlItem($idCombo, $idItemUTF16LE, "UTF-16 LE") $oCustomFileOpen.AddControlItem($idCombo, $idItemUTF16BE, "UTF-16 BE") $oCustomFileOpen.AddControlItem($idCombo, $idItemUTF8, "UTF-8") $oCustomFileOpen.AddControlItem($idCombo, $idItemUTF8BOM, "UTF-8 with BOM") $oCustomFileOpen.SetSelectedControlItem($idCombo, $idAutoDetect) $oCustomFileOpen.EndVisualGroup() $oFileOpen.Show($hParent) Local $aReturn[2] Local $idSelItem, $sSelItem $oCustomFileOpen.GetSelectedControlItem($idCombo, $idSelItem) Switch $idSelItem Case $idAutoDetect $iEncode = 0 Case $idItemANSI $iEncode = $FO_ANSI Case $idItemUTF16LE $iEncode = $FO_UTF16_LE Case $idItemUTF16BE $iEncode = $FO_UTF16_BE Case $idItemUTF8 $iEncode = $FO_UTF8_NOBOM Case $idItemUTF8BOM $iEncode = $FO_UTF8 EndSwitch Local $pItemArr, $pItem, $pDispName = 0, $sFullPath = "" $oFileOpen.GetResults($pItemArr) If Not $pItemArr Then ConsoleWrite("User cancelled the Open dialog." & @CRLF) Return EndIf Local $oItemArr = ObjCreateInterface(Ptr($pItemArr), $sIID_IShellItemArray, $tagIShellItemArray) $oItemArr.GetItemAt(0, $pItem) Local $oItem = ObjCreateInterface(Ptr($pItem), $sIID_IShellItem, $tagIShellItem) $oItem.GetDisplayName($SIGDN_FILESYSPATH, $pDispName) If $pDispName Then Local $tDispName = DllStructCreate("wchar[" & _WinAPI_StringLenW($pDispName) & "]", $pDispName) $sFullPath = DllStructGetData($tDispName, 1) $aReturn[0] = $sFullPath If Not $iEncode Then Local $hFile = FileOpen($sFullPath, 16) If $hFile = -1 Then $iEncode = $FO_ANSI Else $iEncode = _GetFileEncodingType($hFile) ConsoleWrite("Auto-detected encoding: " & $iEncode & @CRLF) FileClose($hFile) EndIf EndIf $aReturn[1] = $iEncode _WinAPI_CoTaskMemFree($pDispName) EndIf $oItemArr = 0 $oItem = 0 _WinAPI_FreeMemory($pItemArr) Return $aReturn EndFunc ;==>_DoFileOpen Func _GetFileEncodingType($hFile) FileSetPos($hFile, 0, $FILE_BEGIN) ; Read the first few bytes to check for a Byte Order Mark (BOM) Local $sBOM = FileRead($hFile, 3) If BinaryMid($sBOM, 1, 3) == 0xEFBBBF Then Return $FO_UTF8 ElseIf BinaryMid($sBOM, 1, 2) == 0xFFFE Then Return $FO_UTF16_LE ElseIf BinaryMid($sBOM, 1, 2) == 0xFEFF Then Return $FO_UTF16_BE EndIf ; Reset position to start for regular UTF-8 / ANSI text parsing FileSetPos($hFile, 0, $FILE_BEGIN) Local $dChunk, $dByte, $iContBytes Local $iChunkSize = 4096, $iMaxChunks = 24 ; Check first 96k For $i = 1 To $iMaxChunks $dChunk = FileRead($hFile, $iChunkSize) If Not BinaryLen($dChunk) Then ExitLoop For $j = 1 To BinaryLen($dChunk) $dByte = BinaryMid($dChunk, $j, 1) If $iContBytes Then If BitAND($dByte, 0xC0) <> 0x80 Then Return $FO_ANSI $iContBytes -= 1 ElseIf BitAND($dByte, 0x80) Then If BitAND($dByte, 0xE0) = 0xC0 Then $iContBytes = 1 ElseIf BitAND($dByte, 0xF0) = 0xE0 Then $iContBytes = 2 ElseIf BitAND($dByte, 0xF8) = 0xF0 Then $iContBytes = 3 Else Return $FO_ANSI EndIf EndIf Next Next Return $FO_UTF8_NOBOM EndFunc ;==>_GetFileEncodingType
MattyD Posted 9 hours ago Posted 9 hours ago Just be careful in this section: The double-equals does a string comparison. We end up testing for "15711167" here because 0xEFBBBF becomes String(0xEFBBBF). On 10/8/2026 at 8:45 AM, WildByDesign said: If BinaryMid($sBOM, 1, 3) == 0xEFBBBF Then What you had earlier works, otherwise just compare binary with binary. If BinaryMid($sBOM, 1, 3) == "0xEFBBBF" Then If BinaryMid($sBOM, 1, 3) = Binary("0xEFBBBF") Then I think the next step would be to build some BOM-Less UTF16 tests, rather than just returning ANSI if our UTF-8 test fails. It seems like there's a few tests that people use: UTF16-LE: Check for lots of nulls at odd bytes. (Works for western languages, but bad test for Chinese/Japanese/Korean) UTF16-BE: Check for lots of nulls at even bytes. (again, no good for CJK) Look for line ending patterns/space characters. (No good if the text has none!) CJK detection: Check if pairs of bytes fall consistently within certain ranges. Also a bit off-topic: But this should be removed from the script too.. The garbage collector will free the object automatically once its refcount goes to 0. $oItemArr = 0 $oItem = 0 _WinAPI_FreeMemory($pItemArr)
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