-
[RESOLVED] Drag & Drop file from compressed folder
I have a VB 6 application that has a form that successfully catches the drop of files from an explorer window. However, if the explorer window is showing the contents of a compressed folder(zip) I am unable to drop this on my form.
Does anyone know if it is possible for me to handle this and if so what I would need to do.
Thanks:ehh:
-
Re: Drag & Drop file from compressed folder
there may well be better (proper) ways to do what you require, but as no one has suggested any, you can test this, but it has some limitations
1. if there are more than 1 shell window open to a zip file you will not know which the item is dragged from
2. it will only work for a single dragged file, but you can detect that multiple files were dragged
vb Code:
Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single)
On Error GoTo zip
fname = Data.Files(1)
Exit Sub
zip:
Set sh = CreateObject("shell.application")
For Each sw In sh.windows
' Debug.Print sw.locationurl
If Right(sw.locationname, 4) = ".zip" Then
fname = Replace(Replace(Mid(sw.locationurl, 9), "/", "\"), "%20", " ") & "\" & sw.document.focuseditem.Name
Exit For
End If
Next
End Sub
-
Re: Drag & Drop file from compressed folder
Thanks, I think that would work. However, I don't think I can rely on only a single shell window being open. I either need to handle this correctly or not permit the operation.
Given the lack of responses or answers from googling, I guess its not something people generally support.
Thanks for the idea though.:)
-
Re: Drag & Drop file from compressed folder
If it's any help, neither Visual C# 2010 Express nor WinRAR supported this in my testing. If they don't I doubt you'll find a program that does.
-
Re: Drag & Drop file from compressed folder
you can test if there are multiple shell windows open to zip files, then give warning, that operation can not be processed, same with multiple files, give warning then fail
-
Re: Drag & Drop file from compressed folder
What I know; may be someone else can fill in the gaps
If the drag drop is coming from an Explorer window the class name of the window will be 'CabinetWClass' from;
Code:
Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Function GetWindowClass(ByVal hWnd As Long) As String
' Return the class name of the specified window
Dim sClass As String
sClass = Space$(256)
GetClassName hWnd, sClass, 255
GetWindowClass = Left$(sClass, InStr(sClass, vbNullChar) - 1)
End Function
where hwnd is supplied by a call to;
Declare Function GetForegroundWindow Lib "user32" () As Long
..because the foreground window must be the one being dragged from.
Data.GetFormat(-16248) gives me True for file(s) dragged from a compressed folder instead of the normal Data.GetFormat(vbCFFiles) when files are dragged from a normal one. This suggests use of a RegisterClipboardFormat, and a RegisterClipboardFormat that is already registered because the Windows Shell already knows how to drag and drop a compressed file to an uncompressed folder and unzip it on the fly.
It is possible to;
byteData() = Data.GetData(-16248)
and get a little sense out of the converted string, but it is spoilt by trash characters.
When dragging and dropping files from Outlook email attachements the magic argument supplied to the RegisterClipboardFormat API must be "FileGroupDescriptor", that does not appear to work for files being dragged from compressed folders. A magic string is required for data format -16248 and some rules for processing thereafter.
The Windows Shell .CopyHere Method is zip aware so will automatically zip/ unzip as files they are Copied/ dragged between Compressed/ UnCompressed folders
-
Re: Drag & Drop file from compressed folder
it may be the clipboard format to use would be CFSTR_FILEDESCRIPTOR
does the getforegroundwindow return the drag source or target window?
can not test till later
-
Re: Drag & Drop file from compressed folder
>does the getforegroundwindow return the drag source or target window?
The drag source, because you have clicked on it, and so given it focus, to begin the drag.
-
Re: Drag & Drop file from compressed folder
Thats given me a few pointers, seems that using the code below I can now recognize a drop from a compressed folder or a zip. Although I have not yet been able to decode the FileGroupDescriptor.
I can get the foreground window, the source for the drop. Is it possible to call the CopyHere method on it directly as then I would not need to try a decode the list of files.
Code:
Private Const CFSTR_FILEGROUPDESCRIPTORW As String = "FileGroupDescriptorW"
Private hCF_FileGroupDescriptorW As Long
Private Sub Form_Load()
hCF_FileGroupDescriptorW = &H8000 Or RegisterClipboardFormat(CFSTR_FILEGROUPDESCRIPTORW) And &H7FFF&
end sub
Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single)
If Data.GetFormat(hCF_FileGroupDescriptorW) Then
Endif
end sub
-
Re: Drag & Drop file from compressed folder
Quote:
Is it possible to call the CopyHere method on it directly
i guess you can copyhere the selected file (one file) or all files from the folder, but i do not know how you can return all selected files to copy
-
Re: Drag & Drop file from compressed folder
This looks promising;
Code:
Option Explicit
Private Declare Function RegisterClipboardFormat Lib "user32" Alias "RegisterClipboardFormatA" (ByVal lpString As String) As Long
Private Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
'typedef struct _FILEGROUPDESCRIPTOR {
' UINT cItems;
' FILEDESCRIPTOR fgd[1];
'} FILEGROUPDESCRIPTOR, *LPFILEGROUPDESCRIPTOR;
'typedef struct _FILEDESCRIPTOR {
' DWORD dwFlags;
' CLSID clsid;
' SIZEL sizel;
' POINTL pointl;
' DWORD dwFileAttributes;
' FILETIME ftCreationTime;
' FILETIME ftLastAccessTime;
' FILETIME ftLastWriteTime;
' DWORD nFileSizeHigh;
' DWORD nFileSizeLow;
' TCHAR cFileName[MAX_PATH];
'} FILEDESCRIPTOR, *LPFILEDESCRIPTOR;
Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim ICF_FILE As Long
Dim CF_FILE As Integer
Dim bdata() As Byte
Dim sNameString As String
Dim filename(), j%, i%, msg$, nfilesingroup%
ICF_FILE = RegisterClipboardFormat("FileGroupDescriptorW")
' lCF_FILE is a Long and has to be converted to an Integer for use with GetFormat like this;
MoveMemory CF_FILE, ICF_FILE, 2
'or apparently like this;
'CF_FILE = Val("&H" & Hex(lCF_FILE))
If Data.GetFormat(CF_FILE) Then
bdata() = Data.GetData(CF_FILE)
'the 1st byte in the strct_FileGroupDescriptorW returns the number of files
nfilesingroup = bdata(1)
sNameString = StrConv(bdata, vbUnicode)
sNameString = Mid$(sNameString, 3)
ReDim filename(1 To nfilesingroup)
For i = 1 To Len(sNameString) - 100 Step (UBound(bdata) - 4) / nfilesingroup 'typically 592 which equates with the length of a struct_FILEDESCRIPTOR
j = j + 1
filename(j) = Mid(sNameString, i + 74) ' the offset of the filename in the struct_FILEDESCRIPTOR
filename(j) = Left$(filename(j), InStr(filename(j), Chr$(0) & Chr$(0)) - 1)
filename(j) = Replace$(filename(j), Chr$(0), "")
msg$ = msg$ & filename(j) & vbCr
Next
MsgBox nfilesingroup & " files dropped" & vbCr & msg$
End If
End Sub
-
Re: Drag & Drop file from compressed folder
I have a solution that now works. It required me to use the olelib.tlb obtained from http://www.mvps.org/emorcillo/en/code/vb6/index.shtml. This gave me access to the IDataObject and also the various structures.
Code:
Private CF_FILECONTENTS As Integer
Private CF_FILEGROUPDESCRIPTOR As Integer
Private CF_FILEGROUPDESCRIPTORW As Integer
Private Sub Form_Load()
' Get the clipboard formats
CF_FILECONTENTS = RegisterClipboardFormat("FileContents") And &H7FFF& Or &H8000
CF_FILEGROUPDESCRIPTOR = RegisterClipboardFormat("FileGroupDescriptor") And &H7FFF& Or &H8000
CF_FILEGROUPDESCRIPTORW = RegisterClipboardFormat("FileGroupDescriptorW") And &H7FFF& Or &H8000
End Sub
Private Sub iGrid1_OLEDragDrop( _
ByRef Data As DataObject, _
ByRef Effect As Long, _
ByRef Button As Integer, _
ByRef Shift As Integer, _
ByRef X As Single, _
ByRef Y As Single)
Dim hWindow As Long
Dim i As Integer
Dim tFMT As FORMATETC
Dim tSTGM As STGMEDIUM
Dim tFGD As FILEGROUPDESCRIPTORW
Dim tFD As FILEDESCRIPTORW
Dim lptr As Long
Dim oShell As Shell
Dim oShellWindow As Object
Dim boolGotWindow As Boolean
Dim strFile As String
If Data.GetFormat(CF_FILEGROUPDESCRIPTORW) Then
hWindow = GetForegroundWindow
Set oShell = New Shell
'Find the source shell window for the drag.
For Each oShellWindow In oShell.Windows
If oShellWindow.hwnd = hWindow Then
boolGotWindow = True
Exit For
End If
Next
If boolGotWindow Then
'Get an uncounted reference to the IDataObject
Call MoveMemory(myDataObject, ByVal ObjPtr(Data) + 16, 4)
'Use the IDataObject interface
With tFMT
.cfFormat = CF_FILEGROUPDESCRIPTORW
.dwAspect = DVASPECT_CONTENT
.lIndex = -1
.TYMED = TYMED_HGLOBAL
End With
If myDataObject.GetData(tFMT, tSTGM) = S_OK Then
'Get the pointer to the data
lptr = GlobalLock(tSTGM.Data)
'Copy the data to the UDT
MoveMemory tFGD, ByVal lptr, Len(tFGD)
For i = 0 To tFGD.cItems - 1
'Get the FILEDESCRIPTOR for the files
MoveMemory tFD, ByVal lptr + 4& + Len(tFD) * i, Len(tFD)
strFile = _
Replace(Replace(Mid(oShellWindow.locationurl, 9), "/", "\"), "%20", " ") & _
"\" & _
Left$(tFD.cFileName, InStr(tFD.cFileName, vbNullChar) - 1)
Call oShell.NameSpace(myFolderPath).CopyHere(strFile)
Next
'Release the pointer
GlobalUnlock tSTGM.Data
'Release the data
ReleaseStgMedium tSTGM
End If
'Release the IDataObject
'You can't use Set = Nothing because the reference is not counted
Call MoveMemory(myDataObject, 0&, 4)
End If
End If
End Sub
-
Re: [RESOLVED] Drag & Drop file from compressed folder
Good. That code makes mine look like a bit of a hack but here is my final just for info...
Code:
Option Explicit
Private Declare Function RegisterClipboardFormat Lib "user32" Alias "RegisterClipboardFormatA" (ByVal lpString As String) As Long
Private Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetForegroundWindow Lib "user32" () As Long
'needs a reference to Shell Controls and Automation
'typedef struct _FILEGROUPDESCRIPTOR {
' UINT cItems;
' FILEDESCRIPTOR fgd[1];
'} FILEGROUPDESCRIPTOR, *LPFILEGROUPDESCRIPTOR;
'typedef struct _FILEDESCRIPTOR {
' DWORD dwFlags;
' CLSID clsid;
' SIZEL sizel;
' POINTL pointl;
' DWORD dwFileAttributes;
' FILETIME ftCreationTime;
' FILETIME ftLastAccessTime;
' FILETIME ftLastWriteTime;
' DWORD nFileSizeHigh;
' DWORD nFileSizeLow;
' TCHAR cFileName[MAX_PATH];
'} FILEDESCRIPTOR, *LPFILEDESCRIPTOR;
Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim ICF_FILE As Long
Dim CF_FILE As Integer
Dim bdata() As Byte
Dim sNameString As String
Dim filename As String, Msg As String, Sourcepath As String
Dim j As Integer, i As Integer, nfilesingroup As Integer
Dim hWindow As Long
Dim boolGotWindow As Boolean
Dim oShell As Shell, oShellWindow As Object
hWindow = GetForegroundWindow
Set oShell = New Shell
'Find the source shell window for the drag.
For Each oShellWindow In oShell.Windows
If oShellWindow.hwnd = hWindow Then
boolGotWindow = True
Sourcepath = Replace(Replace(Mid(oShellWindow.locationurl, 9), "/", "\"), "%20", " ")
Exit For
End If
Next
If boolGotWindow Then
ICF_FILE = RegisterClipboardFormat("FileGroupDescriptorW")
' lCF_FILE is a Long and has to be converted to an Integer for use with GetFormat like this;
CF_FILE = Val("&H" & Hex(ICF_FILE)) 'or like this MoveMemory CF_FILE, ICF_FILE, 2
If Data.GetFormat(CF_FILE) Then
bdata() = Data.GetData(CF_FILE)
'the 2 bytes in the strct_FileGroupDescriptorW returns the number of files
nfilesingroup = bdata(1) + 256 * bdata(2)
sNameString = StrConv(bdata, vbUnicode)
sNameString = Mid$(sNameString, 3)
For i = 1 To Len(sNameString) - 100 Step (UBound(bdata) - 4) / nfilesingroup 'typically 592 which equates with the length of a struct_FILEDESCRIPTOR
filename = Mid(sNameString, i + 74) ' the offset of the filename in the struct_FILEDESCRIPTOR
filename = Left$(filename, InStr(filename, Chr$(0) & Chr$(0)) - 1) 'the name is terminated by 2 acsii zeros
filename = Replace$(filename, Chr$(0), "") 'the letters in the name have ascii zeroes between them
filename = Sourcepath & "\" & filename
oShell.NameSpace(CurDir$).CopyHere (filename)
Msg$ = Msg$ & filename & vbCr
Next
MsgBox nfilesingroup & " files dropped and copied to Cdir" & vbCr & Msg$
End If
End If
End Sub
-
Re: [RESOLVED] Drag & Drop file from compressed folder
A small qwirk; Once you have selected files in Explorer the selection remains there when the ForeGround window changes to some other window; maybe our app's window. It is then still possible to drag the selection from the Explorer window to our target window WITHOUT the Explorer window becoming the ForeGround window again; in cases like this our ForeGround window logic at the start of our routines is looking flaky; no errors it just drops through after If boolGotWindow Then
-
Re: [RESOLVED] Drag & Drop file from compressed folder
Yes I noticed that when going through in debug, the foreground window was that of the IDE not the shell. When checking through the window handles I was going to see if I could determine if the window was a shell/explorer. Ideally would need to find the source of the drag from the drop, but not sure there is a way to find that from the IDataObject. I have the file names from the IDataObject but don't know from which folder (namespace) without finding the shell.
-
Re: [RESOLVED] Drag & Drop file from compressed folder
Maybe I shouldn't be trying to find the source shell. But rather should be trying to get the file contents from a storage stream in the data object. Then creating the file and copying the stream into it. Although I don't seem to be able to google any suitable examples of doing this.
-
Re: Drag & Drop file from compressed folder
Ah, this doesn't work if the compressed/zip folder has sub folders as the shell window location name does not have the full name for the sub folder.
-
Re: Drag & Drop file from compressed folder
>Ah, this doesn't work...
Do you mean the whole thing or just the stream thing you were discussing in your last post?
I don't seem to have a problem copying files from sub folders within the zip when they are plain folders or even zips within a zip; just as long as they are displayed in the foreground window.
-
Re: Drag & Drop file from compressed folder
-
Re: Drag & Drop file from compressed folder
Haven't got the stream stuff to work.
Problem is the shell window location.
If I navigate to the zipped file, the location name is shown as,
"C:\PCMD Backups\PCMD V3.5.182.zip"
If I then go down into a sub folder, the location name is,
PCMD V3.5.182/Docs
So my copy fails as I no longer have the full path name for the compressed folder and its sub folder.
-
Re: Drag & Drop file from compressed folder
Thanks LeandroA
But I know the destination folder, its the source folder I need.
-
Re: Drag & Drop file from compressed folder
you can match the shell window to the foreground window
vb Code:
hw = getforgroundwindow
for each sw in sh.windows
if sw.hwnd = hw then exit for
next
-
Re: Drag & Drop file from compressed folder
Andy ref post #20 - I am not getting that behaviour. LocationUrl is returning the full path for me, although I have not tested it with a filename containing that many dots. Filenames with more than one dot can be challenging at the best of times, see how it goes without them.
Westconn1 - Contary to what I said in post #6 we estabished in post #14 that it is possible to drag a selection from an Explorer window which is not the foreground window.
-
Re: Drag & Drop file from compressed folder
Andy ref post #20 - I am not getting that behaviour under Vista or Windows 7, but I DO under XP; so weird!
I was wondering if this could be affected by the Users Folder Options but I've switched around a few of them like 'show full path in title bar' with no success.
-
Re: Drag & Drop file from compressed folder
shellwindow.document.focuseditem.path
any help?
-
Re: Drag & Drop file from compressed folder
>shellwindow.document.focuseditem.path
There seems to be a fair example of that at http://stackoverflow.com/questions/2...xplorer-window. But it seems to suffer from the same problem when we are in a Sub Folder under XP; the path preceding the Folder name goes missing. Incidentally it goes missing from the Explorer window's Caption too. The technique does not seem to help to identify the Explorer window being dragged from either.
-
Re: Drag & Drop file from compressed folder
No, everything seems just relative to the compressed folder.
I think I am more convinced I should be trying to handle the stream for the file as then I would have no worry about the source. I just don't seem to be able to find a working example of it. ANd the bits I have tried just give an error.
I seem to be able to access the data object, with CFSTR_FILECONTENTS and get a STGMEDIUM for the file. But I cannot seem to process this as a stream. I can't believe that someone hasn't done this before even in .net etc.
-
Re: Drag & Drop file from compressed folder
Quote:
I think I am more convinced I should be trying to handle the stream for the file as then I would have no worry about the source.
probably correct
but it looks like you can get the path by
vb Code:
With sw.document.focuseditem.GetFolder.parentfolder.self
MsgBox .Parent.self.Path & "\" & .Path
End With
-
Re: Drag & Drop file from compressed folder
Unfortunately that still only gives a path relative to the compressed folder.
And also as pointed out, the foreground window may not be the source window. Although, so far that seems to be good enough.
-
Re: Drag & Drop file from compressed folder
I think it is completely possible to get the file's data and then write that data to another file somewhere. But moving it would require deletion of original & unless you come up with a idiot-proof method of locating the source path (including any subpaths within the compressed folder), then ???
The data itself (CF_FILECONTENTS) can be retrieved via an IStream (TYMED_ISTREAM) or IStorage (TYMED_ISTORAGE) object via a TLB or hard-to-use DispCallFunc API. The data should not be available via an TYMED_GLOBAL from what I've read: Windows will use IStream/IStorage. Another app might use TYMED_GLOBAL though.
Edited: Can this one be queried from the data object also? CFSTR_SHELLIDLIST
If so, maybe it can be used to transfer files via a PIDL (SHGetPathFromIDList API)
:: CFSTR_SHELLIDLIST string is "Shell IDList Array"
Follow-up. Out of curiosity, I tried it. No joy, so CFSTR_SHELLIDLIST isn't viable.
-
Re: Drag & Drop file from compressed folder
Quote:
Unfortunately that still only gives a path relative to the compressed folder
that code was returning the full path when i was testing
-
Re: Drag & Drop file from compressed folder
Just FYI. VB only + API (no TLB) method of retrieving file content from compressed folders
Read comments in code. Create new project, one form & paste code. Drag file(s) from compressed folder to test. Caution. This was not tested to the extremes
Code:
*** removed. Updated and replaced in post #39 below
- FYI: I tried to call IStream::Stat method to get stream size vs getting file descriptors. But call kept returning error-not implemented.
Some useful links I used to create above code
TYMED values & release authority: http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx
IDataObject vTable: http://www.tenouk.com/visualcplusmfc...oleobject.html
IStream vTable: http://www.tenouk.com/visualcplusmfc...p/statstg.html
-
Re: Drag & Drop file from compressed folder
Thanks Lavolpe, I shall try that.
I was trying the stream with TYMED_ISTREAM, but was failing on the Stat call with an error.
-
Re: Drag & Drop file from compressed folder
Quote:
Originally Posted by
LaVolpe
Just FYI. VB only + API (no TLB) method of retrieving file content from compressed folders
Read comments in code. Create new project, one form & paste code. Drag file(s) from compressed folder to test. Caution. This was not tested to the extremes
Edited: Some more notes
- Not compatible with files > 1GB (nFileSizeHigh<>0). If to be supported, create target file with CreateFile API and read stream directly to the file with no byte array intermediary. Search forum for VB file support ~2GB
- FYI: I tried to call IStream::Stat method to get stream size vs getting file descriptors. But call kept returning error-not implemented.
Thanks,Lavolpe. It works (tested on Win7 after compiled) on ANSI (even though winzip also not support Unicode). I remember you have come out of droped unicode files routine few years ago.
Please refine the code to support Unicode and allow 2GB above.:)
-
Re: Drag & Drop file from compressed folder
Working here too (only tested on Vista so far), thanks Lavolpe.
-
Re: Drag & Drop file from compressed folder
Quote:
Originally Posted by
Jonney
Thanks,Lavolpe. It works (tested on Win7 after compiled) on ANSI. I remember you have come out of droped unicode files routine few years ago.
Please refine the code to support Unicode and allow 2GB above.:)
I can only assume it does support unicode. The cFileName comes in @ 2-bytes per char, not 1. However, I cannot create a unicode-compatible compressed folder on my XP machine. Error keeps occurrring: 'The compression cannot be performed for file or directory. [filename] contains characters in its name that Compressed (zipped) Folders cannot store: [then lists the unicode characters]". My version of Winzip won't zip up those either.
If anything, the code I posted won't support ANSI, but then again, compressed folders can't be created on ANSI systems, can they? Isn't that option for XP and above only?
For others: I'll leave it to you to support +~2GB files....
Edited: See post #39 for updatd code & should handle very large files
-
2 Attachment(s)
Re: Drag & Drop file from compressed folder
Quote:
Originally Posted by
LaVolpe
I can only assume it does support unicode. The cFileName comes in @ 2-bytes per char, not 1. However, I cannot create a unicode-compatible compressed folder on my XP machine. Error keeps occurrring: 'The compression cannot be performed for file or directory. [filename] contains characters in its name that Compressed (zipped) Folders cannot store: [then lists the unicode characters]". My version of Winzip won't zip up those either.
If anything, the code I posted won't support ANSI, but then again, compressed folders can't be created on ANSI systems, can they? Isn't that option for XP and above only?
I attached files with Unicode filename for you testing.
-
1 Attachment(s)
Re: Drag & Drop file from compressed folder
Thanx, I'll give it a go.
Note that the routine I gave won't do folders within a folder that is zipped. In other words if compressed folder has inside of it a compressed folder that contains a file & you want to extract the inner folder, you will get 2 files extracted: the inner compressed folder (0 bytes), then the file. So to save, you'd have to create the subfolder first, then the file within that subfolder if you wanted to keep the folder structure. I'm playing with updating the above code to do that.
Edited: Jonney, she's a pretty lady! It worked fine. I was able to extract the data and write it to a file. The file was created with CreateFile API to support unicode characters.
Note: When I saved the zip to my drive, unicode characters changed too, but data remained ok
Attachment 82057
-
1 Attachment(s)
Re: Drag & Drop file from compressed folder
Ok, here is the newest re-write of the code. Things I've changed...
1) Data is not written to a byte array. It is written directly to file via a mapped file
2) Creates subfolders if dragging compressed folders within compressed folders
3) Creates files/subfolders using unicode-aware APIs
4) Theoretically handles +2GB files. I'll leave that to someone else to test. Very large files are handled via a loop using a pre-defined maximum chunk size. That chunk size is currently set at approximately 100MB, but you can change it higher or lower.
For testing. Create new blank form, paste attached code & run after changing the target path in Form_OLEDragDrop.
Read comments in code
Edited Yet Again. Dang copy & paste error. All fixed below :o
Either re-download or make following change:
Routine: Long2Size
Change from: LongLow = CLngLong2Size - 4294967295@) - 1&
Change to: LongLow = CLng(Long2Size - 4294967295@) - 1&
See post #48 for more comments, suggested enhancements/improvements.
GO BEARS!!!!
-
Re: Drag & Drop file from compressed folder
Quote:
Originally Posted by
LaVolpe
Note: When I saved the zip to my drive, unicode characters changed too, but data remained ok
Attachment 82057
It seems it is not fault in your code.The compressed folder is shown and extracted by Winzip class and Winzip is not unicode compatible. (?)
-
Re: Drag & Drop file from compressed folder
Jonney thanx for the info on the 2 typos. I've updated the code in post #39.
To all. The code will correctly extract/uncompress files/folders dragged from within a compressed folder
-
1 Attachment(s)
Re: Drag & Drop file from compressed folder
Jonney,
What utility/version did you use to Zip the folder/files?
With WinZip 14 I am not getting Unicode filenames with your ZippedUniFiles.zip.
If I Zip a folder here (WinZip 14) with Unicode filenames they are OK.
Also get Unicode filenames with WinRar and 7Zip.
From http://www.winzip.com/whatsnew112.htm :
WinZip prior to 11.2 does not support Unicode characters in filenames.
For Unicode support, the Zip file must be created and opened with a zip utility that supports the Unicode extensions to the Zip file format such as WinZip 11.2
-
Re: Drag & Drop file from compressed folder
What utility/version did you use to Zip the folder/files?
--- Winzip 9
With WinZip 14 I am not getting Unicode filenames with your ZippedUniFiles.zip.
If I Zip a folder here (WinZip 14) with Unicode filenames they are OK.
Also get Unicode filenames with WinRar and 7Zip.
-- I downloaded and installed Winzip 15 on my Win7. It still doesn't support.
a. Locale = 1033 (English)
Step 1: Compressed a folder with filename in Chinese Characters using Winzip V15
Step 2: I can see right filename in Winzip windows
Step 3: Run Lavolpe's project, Failed to show Original filename with weird characters
Step 4: Change locale = 2052 (Chinese PRC) and restart Win7
Step 4: Run Lavolpe's project, Failed to show Original filename with wrong characters mixed Chinese. But interestingly if the compressed zip file contained another zip file,that zip file show right chinese characters in Winzip window or unzipped without demage.
b. Locale = 2052 (Chinese,PRC)
Step 1: Compressed a folder with filename in Chinese Characters using Winzip V15
Step 2: I can see right filename in Winzip windows
Step 3: Run Lavolpe's project, show right filenames
Step 4: Change locale = 1033(English) and restart Win7
Step 4: Run Lavolpe's project, Failed to show Original filename with weird characters. But interestingly if the compressed zip file contained another zip file,that zip file show right chinese characters in Winzip window or unzipped without demage.
From http://www.winzip.com/whatsnew112.htm :
WinZip prior to 11.2 does not support Unicode characters in filenames.
For Unicode support, the Zip file must be created and opened with a zip utility that supports the Unicode extensions to the Zip file format such as WinZip 11.2
--- Winzip v15 seems not 100% unicode compatible even it can zip/unzip files with Unicode filenames.I am not clear why the treeview of windows explorer can show winzip compressed folder but why winRAR can't??? It is done by Windows Explorer or Winzip?
If it was done by Windows Explorer,it is explorer problem in unicode;If it was done by Winzip,it is Winzip problem in unicode. Just a GUESS.
-
Re: Drag & Drop file from compressed folder
Can you reupload ZippedUniFiles.zip using WinZip 15?
I think Explorer is showing MBCS Chinese characters when locale is 1033(English).
-
2 Attachment(s)
Re: Drag & Drop file from compressed folder
Quote:
Originally Posted by
DrUnicode
Can you reupload ZippedUniFiles.zip using WinZip 15?
I think Explorer is showing MBCS Chinese characters when locale is 1033(English).
It appears to be MBCS in locale=1033.
I upload the files in locale=1033 and 2052.
-
Re: Drag & Drop file from compressed folder
The correct folder name is ChrW$(&H4E2D) & ChrW$(&H6587)
Explorer (Locale 1033) shows this as Íð+-
So is Explorer just extracting the Zip filenames using legacy code and doesn't support "Unicode extensions to the Zip file format".
I see that Chilkat Zip C / C++ Library "Supports Unicode filename zip file format extensions".
http://www.chilkatsoft.com/zip-library.asp
Also Xceed Zip Compression Library "Stores and retrieves the latest zip file format extensions, allowing Unicode filenames and NT file attributes, extra time stamps, and security permissions to be stored in the zip file.".
http://xceed.com/Zip_ActiveX_Features.html
-
Re: Drag & Drop file from compressed folder
Thanks LaVolpe
That works great. Can happily copy files out of compressed folder with subfolders to my application. No longer have to worry about foreground windows and finding the source shell.
When copying like this do you think it should used the same creation time etc for the copied file as that of the original?
-
Re: [RESOLVED] Drag & Drop file from compressed folder
It's up to you. If you want to, that data is part of the file descriptor and you can use the API SetFileTime (example at bottom of that link).
Reference post #39 for the code being talked about.
Edited. As a matter of completeness, there are 2 holes in that code
1) I don't immediately know how to move, vs. copy, the file from a compressed folder during/after drag-drop. Knowing/fixing that would make the routine more complete. Prior to this thread, I never even used compressed folders. So all this was new to me.
2) It is possible to get data via IStorage vs IStream, though I haven't been able to test that as I'm always getting IStream even if I ask for IStorage. If someone knows how we can get Windows to give us IStorage, I can add appropriate code for that. Writing data to file with IStorage could be far simpler than using IStream. Additionally, if Windows adds IStorage vs. IStream, then code will just ignore it. Code would be more complete with IStorage handling.
Not a hole, but something each should do depending on their requirements. Several places in that code, I left comments/spots for error handling. Specific errors should be handled
a) Folder failed to be created with CreateDirectoryW. Possible reasons: already exists (ignore error), anything else: handle it & stop processing files
-- optional: test for folder's existance before calling CreateDirectoryW
b) Target file fails to be created. Possible reasons: no drive space, no permissions, existing file/folder to overwrite is read-only/locked. Handle it & stop processing files
c) Failed to create a mapped file or view of mapped file. Possible reasons: chunk size too big? Handle it & stop processing files
d) Failed to read stream. lRead <> [number of bytes attemped to read] or varRtn<>0. Possible reasons: unknown. Handle it & stop processing files
e) File contents not passed as IStream (files vs. directories). Possible reason: File placed in Data object as HGlobal or IStorage. Handle these with separate code, i.e.
Code:
Select Case fMedium.TYMED
Case TYMED_ISTREAM
Case TYMED_HGLOBAL
Case TYMED_ISTORAGE ' value is 8
Case Else
' handle the exception
End Select
Room for enhancement. There are 2 places in that code where one can create/call a Public Event if the code were added to a class. That public event could be used for progress. Just a suggestion/idea.
1) Within GetDroppedCompressedFiles routine's loop. You could forward which file number & total files being processed and current file name
2) Within the SaveSteamToFile. If chunking the stream, you could return percentage (bytesWritten/FileSize) of file being processed & file name
3) I'd suggest changing GetDroppedCompressedFiles to a function that returns true/false & test for the CF_FILECONTENTS & CF_FILEGROUPDESCRIPTORW in the OLEDragDrop before calling GetDroppedCompressedFiles. What's the point of calling it if those aren't in the Data object?
-
Re: [RESOLVED] Drag & Drop file from compressed folder
I chose to set the last write time (modified) time to that of the original file as this is what seems to happen on a normal cut and paste. creation and last accessed times are set to the current time.
Yes, not sure about the move versus copy. If its a normal file drop, then setting the copy of move effect flags causes the source to tidy up. i.e. only ever have to copy the file, setting only the move effect flag (and clearing the copy one) causes the source to delete the file after the drop. This is what the documentation suggests.
However, this does not seem to happen if the effect is set to move, the source does not delete the file. Although I one point during my testing I was sure it did.
-
Re: [RESOLVED] Drag & Drop file from compressed folder
For all. MSDN provides some conflicting information described below which may effect release of the IStream after transferring file data.
Souce page. Notice conflicting comments highlighted in blue below
Quote:
Originally Posted by MSDN TYMED_ISTREAM
The storage medium is a stream object identified by an IStream pointer. Use ISequentialStream::Read to read the data. If the STGMEDIUM punkForRelease member is not NULL, the destination process should use Release to release the stream component.
Quote:
Originally Posted by MSDN Remarks for post-drag/drop
The provider of the medium indicates its choice of ownership scenarios in the value it provides in the STGMEDIUM structure. A NULL value for the pUnkForRelease member indicates that the receiving body of code owns and can free the medium.
And from MSDN's page for ReleaseStgMedium function, this.
Quote:
Originally Posted by MSDN
The provider indicates that the receiver of the medium is responsible for freeing the medium by specifying NULL for the punkForRelease structure member.
Majority wins? If you agree, the code in post #39 should be modified as so
Routine: GetDroppedCompressedFiles
Change from: If fMedium.pUnkForRelease <> 0 Then ' are we to release the stream?
Change to: If fMedium.pUnkForRelease = 0 Then ' are we to release the stream?
Note: No issues noted and may be that Windows Explorer checks if the stream was released and releases it if not ??? But I wouldn't bet my career on it without knowing for sure.
-
Re: [RESOLVED] Drag & Drop file from compressed folder
The provider indicates that the receiver of the medium is responsible for freeing the medium by specifying NULL for the punkForRelease structure member. Then the receiver calls ReleaseStgMedium, which makes a call as described in the following table depending on the type of storage medium being freed.
So yes I believe you are right and if it is null, then we have to release it.
Although any vaguely similar code examples I find seem to release it regardless.
-
Re: [RESOLVED] Drag & Drop file from compressed folder
Quote:
Originally Posted by
andy-w
...Although any vaguely similar code examples I find seem to release it regardless.
The issue with using OPC (other people's code). Many coders are lazy and don't want to research how something works; they just use it as is. I, personally, have no problem going to MSDN and researching. That's how I determined the inconsistencies with their statements above. I originally wrote the code based on the TYMED_ISTREAM statements which said to not release it if it is Null. What made me question it was that I was releasing TYMED_HGLOBAL if it was Null -- why the difference? That was enough to make me dig deeper.
-
Re: [RESOLVED] Drag & Drop file from compressed folder
Quote:
Originally Posted by
LaVolpe
I, personally, have no problem going to MSDN and researching...
why the difference? That was enough to make me dig deeper.
I suggest Lavolpe posting a new thread for this great pieces of code and add the thread in your signature.
-
Re: [RESOLVED] Drag & Drop file from compressed folder
I was thinking of posting it in the CodeBank, but am not satisfied yet. I wanted to do some more testing (XP & Vista) to see if Windows ever passes compressed file(s) by IStorage or HGlobal.
Oh, and regarding OPC... not many coders out there understand the core API I am using to access COM interface methods. If someone really wants to understand why the code works and how the API calls trigger the interface methods, they need to understand the API first of all. Then they need to understand how Interfaces are laid out in memory (their VTables specifically). And how inheritance of other interfaces affect the VTable offsets. Low-level stuff in that code. Understanding it may be a challenge at first. It was for me when I first started to mess with that core API a few years ago. And regarding VTables of COM Interfaces, MSDN changed their pages again and list interface methods alphabetically instead of VTable order. One will have to find a good trusted site to get quick lists of VTable orders now.
Edited. Or one could just rewrite the code using a TLB and supported interfaces. Then the low-level API approach would not be needed at all.