Jump to content

Recommended Posts

Posted

In the Files Au3 project, I have implemented IFileOperation to allow copying, deleting, renaming, etc. files and folders on disk. It is all working beautifully right now.

The only (important) thing missing is Undo. The great thing about using IFileOperation for all of these file management ops is that the Shell (explorer.exe) keeps track of all of the Undo stack information.

For example, if I delete, copy or rename something in Files Au3, I can either open File Explorer and press Ctrl+Z to undo the file op performed in Files Au3 or alternatively I can click on the Desktop and press Ctrl+Z.

Since File Explorer itself is not always running (CabinetWClass class), the Desktop most certainly is. So my thought is somehow sending the Ctrl+Z key combo to the Desktop but I don't have much experience with that.

Does anyone know how this could be done?

I don't know whether the key combo would/should be sent to the Progman class, SysListView32 (of the desktop) or if it just gets sent to explorer.exe in general. I know how to get the handle for those classes but I'm just not sure how or where to send Ctrl+Z. I've never sent any key combinations before in any of my previous projects.

Thank you for your time. :)

Posted

I am still stuck on this. I've got the handles for the desktop Progman, SHELLDLL_DefView and SysListView32.

 

Example:

#include <WinAPISysWin.au3>

Local $hProgman = WinGetHandle("[CLASS:Progman]")
ConsoleWrite("Progman hWnd: " & $hProgman & @CRLF)

Local $hSHELLDLL_DefView = _WinAPI_FindWindowEx($hProgman, 0, "SHELLDLL_DefView", "")
ConsoleWrite("SHELLDLL_DefView hWnd: " & $hSHELLDLL_DefView & @CRLF)

Local $aEnumWindows = _WinAPI_EnumWindows(False)
For $n = 1 To UBound($aEnumWindows) - 1
    If $aEnumWindows[$n][1] <> "SysListView32" Then ContinueLoop
    If _WinAPI_GetParent($aEnumWindows[$n][0]) = $hSHELLDLL_DefView Then
        $hSysListView32 = $aEnumWindows[$n][0]
        ExitLoop
    EndIf
Next

ConsoleWrite("Desktop SysListView32 hWnd: " & $hSysListView32 & @CRLF)

;ControlSend($hProgman, "", "[CLASS:SysListView32]", "^z")
ControlSend($hSysListView32, "", ControlGetFocus($hSysListView32), "^z")


Func _WinAPI_FindWindowEx($hParent, $hAfter, $sClass, $sTitle = "")
    Local $ret = DllCall('user32.dll', "hwnd", "FindWindowExW", "hwnd", $hParent, "hwnd", $hAfter, "wstr", $sClass, "wstr", $sTitle)
    If @error Or Not IsArray($ret) Then Return 0
    Return $ret[0]
EndFunc   ;==>_WinAPI_FindWindowEx

 

Posted

It looks like what I have does work if the desktop is in focus. But I was hoping to avoid having to switch windows. I even tried using _WinAPI_SetFocus() but it wasn't enough.

It looks like I'm going to have to find a better way to do this from what I can tell.

Posted

Here we go. This will undo any Copy, Rename, Delete, etc. whether it is from Files Au3, File Explorer, etc.

We do lose focus though but that can easily be brought back.

#include <WinAPISysWin.au3>

Local $hProgman = WinGetHandle("[CLASS:Progman]")
ConsoleWrite("Progman hWnd: " & $hProgman & @CRLF)

Local $hSHELLDLL_DefView = _WinAPI_FindWindowEx($hProgman, 0, "SHELLDLL_DefView", "")
ConsoleWrite("SHELLDLL_DefView hWnd: " & $hSHELLDLL_DefView & @CRLF)

Local $aEnumWindows = _WinAPI_EnumWindows(False)
For $n = 1 To UBound($aEnumWindows) - 1
    If $aEnumWindows[$n][1] <> "SysListView32" Then ContinueLoop
    If _WinAPI_GetParent($aEnumWindows[$n][0]) = $hSHELLDLL_DefView Then
        $hSysListView32 = $aEnumWindows[$n][0]
        ExitLoop
    EndIf
Next

ConsoleWrite("Desktop SysListView32 hWnd: " & $hSysListView32 & @CRLF)

_WinAPI_SetForegroundWindow($hSysListView32)
_WinAPI_SetFocus($hSysListView32)

ControlSend($hSHELLDLL_DefView, "", "[CLASS:SysListView32]", "^z")
;ControlSend($hSysListView32, "", ControlGetFocus($hSysListView32), "^z")


Func _WinAPI_FindWindowEx($hParent, $hAfter, $sClass, $sTitle = "")
    Local $ret = DllCall('user32.dll', "hwnd", "FindWindowExW", "hwnd", $hParent, "hwnd", $hAfter, "wstr", $sClass, "wstr", $sTitle)
    If @error Or Not IsArray($ret) Then Return 0
    Return $ret[0]
EndFunc   ;==>_WinAPI_FindWindowEx

 

  • Solution
Posted
6 minutes ago, Nine said:

FWIW, you could simply :

That is nice! Thank you. :)

The same goal is achieved but with something like 90% less lines of code. Works perfectly.

That also reminds me that I really need to stop overlooking the built-in AutoIt functions.

Posted (edited)

Sorry but both variants don't work for me (for my system). German Windows 11 (newest).
Maybe I did something wrong, but what is did is the following:

  1. Open a Windows Explorer window
  2. Move a file from one folder into another
  3. Test by CTRL+Z and CTRL+Y within the Windows Explorer window - works fine
  4. Repeat 1. + 2.
  5. Use the scripts - without success

I checked the classes for Desktop which is "Progman".
I also used the taskbar "Shell_TrayWnd" which should also work (as my understanding is), but no it doesn't.

What could cause the issue? I don't believe it depends on Windows 11 language version.

I also tested it on a "Windows Server 2019 Datacenter" without success 😒 .

Best regards
Sven

Edited by SOLVE-SMART

==> AutoIt related: 🔗 Organization AutoIt Community🔗 GitHub, 🔗 Discord Server, 🔗 Cheat Sheet🔗 autoit-webdriver-boilerplate

Spoiler

🌍 Au3Forums

🎲 AutoIt (en) Cheat Sheet

📊 AutoIt limits/defaults

💎 Code Katas: [...] (comming soon)

🎭 Collection of GitHub users with AutoIt projects

🐞 False-Positives

🔮 Me on GitHub

💬 Opinion about new forum sub category

📑 UDF wiki list

✂ VSCode-AutoItSnippets

📑 WebDriver FAQs

👨‍🏫 WebDriver Tutorial (coming soon)

Posted
8 minutes ago, SOLVE-SMART said:
  • Open a Windows Explorer window
  • Move a file from one folder into another
  • Test by CTRL+Z and CTRL+Y within the Windows Explorer window - works fine
  • Repeat 1. + 2.
  • Use the scripts - without success

Can you try to move the file into another folder again, then minimize or close File Explorer, click anywhere on the desktop background and press Ctrl+Z?

Let me know if that works. It's definitely something that we need to figure out. Although since it uses class names, those are the same on all languages so I'm not exactly sure why it isn't working on yours. 

Posted

Update:
I recognized a non-deterministic behavior. I believe it is a timing based issue.

Your suggestion worked three times in a raw, then not at all, then sometimes again.
I try several Sleep command combination to get to the point where the issue is, but so far only your @WildByDesign variant works sometimes.

The code snippets of @Nine doesn't work so far, but I try it on the different Windows System (server system) to confirm my observation.
I will let you know when I found the issue.

Best regards
Sven

==> AutoIt related: 🔗 Organization AutoIt Community🔗 GitHub, 🔗 Discord Server, 🔗 Cheat Sheet🔗 autoit-webdriver-boilerplate

Spoiler

🌍 Au3Forums

🎲 AutoIt (en) Cheat Sheet

📊 AutoIt limits/defaults

💎 Code Katas: [...] (comming soon)

🎭 Collection of GitHub users with AutoIt projects

🐞 False-Positives

🔮 Me on GitHub

💬 Opinion about new forum sub category

📑 UDF wiki list

✂ VSCode-AutoItSnippets

📑 WebDriver FAQs

👨‍🏫 WebDriver Tutorial (coming soon)

Posted (edited)
23 minutes ago, SOLVE-SMART said:

I recognized a non-deterministic behavior. I believe it is a timing based issue.

Your suggestion worked three times in a raw, then not at all, then sometimes again.
I try several Sleep command combination to get to the point where the issue is, but so far only your @WildByDesign variant works sometimes

That is very interesting behavior. We definitely need to get this sorted out.

Does the script get the handles in the ConsoleWrite 100% of the time? Or does it sometimes fail to return a handle?

Edited by WildByDesign
Posted

I restarted my computer. Now I don't have any issue anymore 😤 - welcome to Windows 😅 .
@Nines approach is still not working, but the WinAPI way works so far without any additional "Sleep" actions.

Still strange, that it doesn't worked on the Windows Server system, but this one is within a Citrix VDI (virtual desktop infrastructure). Maybe there was a correlation between my system and the virtualized one, before I restarted my system/computer. No it works on both OS variants.

I knwo that I can undo or redo several steps and this also works fine, thankfully now.

Best regards
Sven

==> AutoIt related: 🔗 Organization AutoIt Community🔗 GitHub, 🔗 Discord Server, 🔗 Cheat Sheet🔗 autoit-webdriver-boilerplate

Spoiler

🌍 Au3Forums

🎲 AutoIt (en) Cheat Sheet

📊 AutoIt limits/defaults

💎 Code Katas: [...] (comming soon)

🎭 Collection of GitHub users with AutoIt projects

🐞 False-Positives

🔮 Me on GitHub

💬 Opinion about new forum sub category

📑 UDF wiki list

✂ VSCode-AutoItSnippets

📑 WebDriver FAQs

👨‍🏫 WebDriver Tutorial (coming soon)

Posted
15 minutes ago, SOLVE-SMART said:

@Nines approach is still not working, but the WinAPI way works so far without any additional "Sleep" actions.

This could be because on his you have to switch ^a to ^z likely as he was being careful.

Posted

I did both. Playing around with ^a (select all) and ^z (undo). Non of them works in the short version (Nine).
But I am quite sure, this must have be related to my system, because the AutoIt code is okay and make sence.

I usually run x64, so I am still confused a bit. Today I cannot further investigate, but tomorrow I will have a fresh look.

Best regards
Sven

==> AutoIt related: 🔗 Organization AutoIt Community🔗 GitHub, 🔗 Discord Server, 🔗 Cheat Sheet🔗 autoit-webdriver-boilerplate

Spoiler

🌍 Au3Forums

🎲 AutoIt (en) Cheat Sheet

📊 AutoIt limits/defaults

💎 Code Katas: [...] (comming soon)

🎭 Collection of GitHub users with AutoIt projects

🐞 False-Positives

🔮 Me on GitHub

💬 Opinion about new forum sub category

📑 UDF wiki list

✂ VSCode-AutoItSnippets

📑 WebDriver FAQs

👨‍🏫 WebDriver Tutorial (coming soon)

Posted

Try that Sven :

Local $hProgman = WinGetHandle("[CLASS:Progman]")
Local $hCurrent = WinGetHandle("[ACTIVE]")
WinActivate($hProgman)
WinWaitActive($hProgman)
Send("^a")
WinActivate($hCurrent)

I know Send is misliked.  It is just a cultural bias on the forum.  When you know that a specific window is active, Send is a more robust way to transmit characters.  Some windows will not accept KB messages, but will accept LLKB.  Notice that the last WinActivate will temporarily hide the selection.  You can comment it out if you wish to.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...