Archive: Can't remove folder


Can't remove folder
I'm creating a installer for a modification to a game which created a program group in the Start Menu.

(Some of you might remember me posting about this issue long ago. Sorry to drag it up again.)

Now I understand that NSIS doesn't support unicode, so I've decided to turn to the System plug-in, and use API functions to remove said shortcuts.

But the folder still remains. I've resorted to using 8.3 filename conventions since I'm not that well educated in using the System plugin to string together elaberate filenames.

Before I go on:
$SMPROGRAMS I'm using SetShellVarContext all since the game creates items in the All Users group. and I have a check for Admin privledges.

WIND-A~$6 The $6 is just a number that goes from 1-4 to catch the most obvious instances. The long pathname is Wind - a breath of heart - Re***65306;gratitude (the colon being unicode, hence why I have to resort to using 8.3 convention to address it.)

WIND-A~1.LNK 8.3 filename for the following Wind - a breath of heart - Re***65306;gratitude.lnk

This works:

System::Call "kernel32::RemoveDirectoryW(w '\\?\$SMPROGRAMS\minori\lala' )"

System::Call "kernel32::RemoveDirectoryW(w '\\?\$SMPROGRAMS\minori\BLAHBL~1' )"


as does this:
System::Call "kernel32::DeleteFileW(w '$SMPROGRAMS\minori\WIND-A~$6\$2' )"

$2 being the filename output from a FindFirst search.

And to get rid of the Shortcut containing unicode, this works:
System::Call "kernel32::DeleteFileW(w '\\?\$SMPROGRAMS\minori\WIND-A~$6\WIND-A~1.LNK' )"



But to get rid of the (now) empty folder, this does not work:
System::Call "kernel32::RemoveDirectoryW(w '\\?\$SMPROGRAMS\minori\WIND-A~$6\' )"


Any advice will be greatly appreciated.
Thank you very much for your time.

I ran into similar situation. For me, I cannot delete the folder because one of my process was holding it for some reason. I terminated the process, but it did not determinated, therefore, it didn't work.

Good Luck.


Make sure that your uninstaller's working directory is not set to the folder you are trying to delete.

You can add a SetOutPath command just before the folder delete to set the output path to another folder.

Also, are you using the /REBOOTOK flag?

Example:


; This assumes that the folder you are trying to delete is NOT $TEMP...
SetOutPath "$TEMP"
RMDir /r /REBOOTOK "C:\path_to_folder"

; at this point, check the reboot flag to determine whether or not to reboot
IfRebootFlag 0 +2
MessageBox MB_OK "Some files/folders were in use and will be removed when you restart."

Comperio, I don't think you understand my situation.
The whole reason I'm using an API call is because I cannot use NSIS's "RMDir", because the folder contains a unicode character. Therefore /REBOOTOK isn't much help : (

My SetOuPath isn't the folder I'm trying to delete, but thank you for suggesting.

No processes are holding/using the folder (to my knowledge, after rebooting, shutting down all but core services [even explorer], the folder remains)

Yes I can remove the folder via normal Shell/Command prompt methods.

Thank you for your time thus far.


What if you put a Sleep 1000 before it.

-Stu


I think I see what you are getting at.
You mean after deleting the folder contents, to sleep before deleting the folder?

To make sure that wasn't the case, I've tested the code when the folder was already empty.
If that was not what you were implying, please elaborate, hee hee.


Hmm, I'm wondering if using the SHFileOperation will work for me, since it's recursive by nature, AND supports the use of wildcards. (I could put a wildcard in where the unicode character lies.)

The only problem I'm having with this route, is that I cannot get structures working properly : (
I can't even get the example structures in the System plug-in readme to work.

If someone could give me some pointers where I might be going wrong, I would be very grateful.

Here's the stuff I've tried:

StrCpy $2 "C:\blah\*.txt"
System::Call "*(i '$HWNDPARENT', t 'FO_DELETE', t '$2', i 0, i 0, i 0, i 0, i 0 )i.s"
System::Call "shell32::SHFileOperation(i r0)"
System::Free $0


Here's the info from the MSDN for SHFileOperation and the info for the struct that needs to be passed to it SHFILEOPSTRUCT

Thank you very much for your time : )

Name "Output"
OutFile "Output.exe"

!define FO_MOVE 0x0001
!define FO_COPY 0x0002
!define FO_DELETE 0x0003
!define FO_RENAME 0x0004

!define FOF_MULTIDESTFILES 0x0001
!define FOF_CONFIRMMOUSE 0x0002
!define FOF_SILENT 0x0004 # don't create progress/report
!define FOF_RENAMEONCOLLISION 0x0008
!define FOF_NOCONFIRMATION 0x0010 # Don't prompt the user.
!define FOF_WANTMAPPINGHANDLE 0x0020 # Fill in SHFILEOPSTRUCT.hNameMappings
!define FOF_ALLOWUNDO 0x0040
!define FOF_FILESONLY 0x0080 # on *.*, do only files
!define FOF_SIMPLEPROGRESS 0x0100 # means don't show names of files
!define FOF_NOCONFIRMMKDIR 0x0200 # don't confirm making any needed dirs
!define FOF_NOERRORUI 0x0400 # don't put up error UI
!define FOF_NOCOPYSECURITYATTRIBS 0x0800 # dont copy NT file Security Attributes
!define FOF_NORECURSION 0x1000 # don't recurse into directories.

Section
StrCpy $1 "C:\blah\*.txt"
System::Call "*(i '$HWNDPARENT', i ${FO_DELETE}, t '$1', i 0, i ${FOF_SILENT}|${FOF_NOCONFIRMATION}, i 0, i 0, i 0)i .r0"
System::Call "shell32::SHFileOperation(i r0)"
System::Free $0
SectionEnd

Wow!
Thank you so much Instructor. It works perfectly!

I had no idea it was supposed to be used like this, heh.
Thank you once again.
I'm very grateful!


Using UNICODE in File/foldernames on Windows? O_o wtf
its absolutly a DONT


I have been using the code suggested by Instructor in the same situation as Clammerz had: I need to delete a start menu folder that contains a unicode character. The folder is called "Fate/stay night", with the forward slash in unicode.

Up until recently Instructor's example has worked just fine, but I cannot get it to work in Windows Vista. FindFirst and FindNext can find the folder name without trouble, but calling SHFileOperation has no effect at all. Can someone think of a reason why?

The MSDN page for SHFileOperation can be found at hxxp://msdn2.microsoft.com/en-us/library/bb762164.aspx


I came up with a hacky way to create unicode strings, but seems to work fine.

!macro MakeUnicodePathWithSpecialChar outvar prefix unicodechar suffix
push $0
push $1
StrLen $0 '${prefix}'
StrLen $1 '${suffix}'
IntOp $0 $0 * 2
IntOp $1 $1 + 1 ;\0
IntOp $1 $1 * 2
System::Call /NoUnload "*(&w$0 '${prefix}',&i2 ${unicodechar}, &w$1 '${suffix}')i.s"
Exch 2
pop $0
pop $1
pop ${outvar}
!macroend


!define BasePath "D:\unsorted\dev"

!insertmacro MakeUnicodePathWithSpecialChar $0 "\\?\${BasePath}\foo" 0xFF0F "bar"
System::Call /NoUnload "kernel32::CreateDirectoryW(i$0,i0)"
System::Call /NoUnload 'user32::MessageBoxW(i $hwndparent,i $0,w "Will now delete:",i0)'
System::Call /NoUnload "kernel32::RemoveDirectoryW(i $0 )"
System::Free $0

If you go with the short name solution, you don't even need the System plug-in. RMDir and Delete will be able to find and delete the files by using their short names.

RMDir is even capable of deleting files with Unicode names as long as the directory doesn't have Unicode in it. So if you have the short name of the folder, you can simply use RMDir /r.


Unfrtunately, the short filename for Fate/stay night ends up as Fate/~1... I tried Anders' solution, and the result is as sad as it is annoying: Vista is able to create/remove a directory called Fate/stay night, but it's not able to remove the garbled version (in English locale) of the Japanese-created folder.


Then it's probably the FAQ:

http://nsis.sourceforge.net/Shortcut..._Windows_Vista


Just in case its not the vista all user folder problem, I went all out...

Deletes the folder "foo/bar" (and its contents) in ${BasePath}, UNICODE all the way, and again, works fine on my system


!define BasePath "D:\unsorted\dev"
!define FindMask "foo*bar"
Section
System::Call /NoUnload '*(i,&i8,&i8,&i8,i0,i0,i0,i0,&w260,&w14,&i20)i.r0' ;&i20=dummy data
System::Call /NoUnload 'kernel32::FindFirstFileW(w "${BasePath}\${FindMask}",i $0)i.r1'
IntOp $3 $0 + 44 ;WIN32_FIND_DATA.cFileName
;System::Call /NoUnload 'user32::MessageBoxW(i $hwndparent,i $3,w "yo",i0)'
StrLen $R0 "${BasePath}\"
IntOp $R0 $R0 * 2
System::Call /NoUnload 'kernel32::lstrlenW(i $3)i.R1'
IntOp $R1 $R1 * 2
System::Call /NoUnload '*(&w$R0 "${BasePath}\",&i$R1 0,&i4 0)i.r4' ;make "${BasePath}\${FindMask}\0\0" buffer
System::Call /NoUnload 'kernel32::lstrcatW(i $4,i $3)i.R1'
;System::Call /NoUnload 'user32::MessageBoxW(i $hwndparent,i $4,w "yo",i0)'
System::Call "*(i '$HWNDPARENT', i 0x3,i $4, i 0, i 0x14, i 0, i 0, i 0)i.r9"
System::Call "shell32::SHFileOperationW(i r9)"
System::Free $9 ;pSHFILEOPSTRUCT
System::Free $4 ;SHFILEOPSTRUCT.pFrom buffer
FindClose $1
System::Free $0 ;pWIN32_FIND_DATA

SectionEnd


..and 0 error checking, might want to check the return value of FindFirstFileW and make sure its not -1

and the short version

!define BasePath "D:\unsorted\dev"
!define FindMask "foo*bar"
Section
StrLen $9 "${BasePath}\${FindMask}"
IntOp $9 $9 * 2
System::Call /NoUnload '*(&w$9 "${BasePath}\${FindMask}",&i4 0)i.r4'
System::Call "*(i '$HWNDPARENT', i 0x3,i $4, i 0, i 0x14, i 0, i 0, i 0)i.r9"
System::Call "shell32::SHFileOperationW(i r9)"
System::Free $9 ;pSHFILEOPSTRUCT
System::Free $4 ;SHFILEOPSTRUCT.pFrom buffer
SectionEnd