News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Problem with IShellFolder:BindToObject

Started by jj2007, June 01, 2023, 06:34:52 AM

Previous topic - Next topic

jj2007

Hi folks,

Let's honour Hutch' legacy by doing some coding. I've been searching for a way to zip files without any third party tools, and I found a working solution. Unfortunately it's coded in VB6.

So I tried to translate fafalone's code to assembly, but I am stuck at a certain point: IShellFolder:BindToObject doesn't work, it gives error code 80005000h, which means "generic error".

Attached code is pure Masm32 SDK. Extract all files to a folder and build it. The offending line is

CoInvoke pInterface, IShellFolder.BindToObject, [esi], 0, addr IID_IShellFolder, isfDesktop

I hope somebody has a clue what's wrong. The VB6 version works just fine...

This is the output I get:
pidlZipFolder           005791F8
Operazione completata.
ILCreateFromPathW       0057D650
ILCreateFromPathW       0057D928
ILCreateFromPathW       0057A5C0
ILCreateFromPathW       0057A188
ILCreateFromPathW       0057BA98
SHGetDesktopFolder      00576EFC
IShellFolder interface  00576EFC
BindToObject error      80004005

zedd151


pidlZipFolder           001C7BE8
The system cannot find the file specified.   <<<---- what file? what file???
ILCreateFromPathW       001D2D90
ILCreateFromPathW       001D2A50
ILCreateFromPathW       001DCA28
ILCreateFromPathW       001DF9A0
ILCreateFromPathW       001DFD68
SHGetDesktopFolder      001C0A24
IShellFolder interface  001C0A24
BindToObject error      80004005



That is what I get here... extracted executable and the .txt files ...

Second run (extracted all files this time)
pidlZipFolder           002B25A0
The operation completed successfully.
ILCreateFromPathW       002C71F8
ILCreateFromPathW       002C7440
ILCreateFromPathW       002C7688
ILCreateFromPathW       002C78D0
ILCreateFromPathW       002C7B18
SHGetDesktopFolder      002A0AB4
IShellFolder interface  002A0AB4
BindToObject error      80004005


C:\Users\Administrator\Downloads\ZipFiles>pause
Press any key to continue . . .


Okay, now the same results as you were getting  (whoops on my part)  :rolleyes:


I'll tinker with this in my spare time...

mabdelouahab

QuotepidlZipFolder           004EFF00
The operation completed successfully.
ILCreateFromPathW       004EF580
ILCreateFromPathW       004EF620
ILCreateFromPathW       004EF6C0
ILCreateFromPathW       004EED70
ILCreateFromPathW       004EEE10
SHGetDesktopFolder      004EB0FC
IShellFolder interface  004EB0FC
BindToObject error      80004005

jj2007


zedd151

Okay, so basically what you are trying to do is use Windows 'Send to zip folder' functions, but do it programmatically? Is this correct? I'm trying to wrap my head around this...

jj2007

Quote from: zedd151 on June 01, 2023, 11:46:48 PM
Okay, so basically what you are trying to do is use Windows 'Send to zip folder' functions, but do it programmatically? Is this correct? I'm trying to wrap my head around this...

Yesssss... and as already mentioned, it works perfectly with fafalone's VB6 code. It creates perfect zip archives in milliseconds. But I am stuck at BindToObject :sad:

It doesn't offer the best compression, but that's not the point. Imagine you have an editor, and you want to send your current project to this forum, and you want to do it programmatically through a menu point "Send to Masm32 Forum".

zedd151


Okay. Thats what I thought.




I've stripped the code of everything but what appears to be the essentials for mortals like me to be able to read.  ...
include \masm32\include\masm32rt.inc




ZipThem                 proto :dword, :dword




IShellFolder STRUCT
    QueryInterface      dd ?
    AddRef              dd ?
    Release             dd ?
    ParseDisplayName    dd ?
    EnumObjects         dd ?
    BindToObject        dd ?
    BindToStorage       dd ?
    CompareIDs          dd ?
    CreateViewObject    dd ?
    GetAttributesOf     dd ?
    GetUIObjectOf       dd ?
    GetDisplayNameOf    dd ?
    SetNameOf           dd ?
IShellFolder ENDS




IStorage STRUCT
    QueryInterface      dd ?
    AddRef              dd ?
    Release             dd ?
    CreateStream        dd ?
    OpenStream          dd ?
    CreateStorage       dd ?
    OpenStorage         dd ?
    CopyTo              dd ?
    MoveElementTo       dd ?
    Commit              dd ?
    Revert              dd ?
    EnumElements        dd ?
    DestroyElement      dd ?
    RenameElement       dd ?
    SetElementTimes     dd ?
    SetClass            dd ?
    SetStateBits        dd ?
    Stat                dd ?
IStorage ENDS




IStream STRUCT
    QueryInterface      dd ?
    AddRef              dd ?
    Release             dd ?
    _Read               dd ?
    _Write              dd ?
    _Seek               dd ?
    SetSize             dd ?
    CopyTo              dd ?
    Commit              dd ?
    Revert              dd ?
    LockRegion          dd ?
    UnlockRegion        dd ?
    Stat                dd ?
    Clone               dd ?
IStream ENDS




wRec$ macro arg
  push ecx
  invoke MultiByteToWideChar, 65001, 0, arg, -1, offset wRecBuffer, 1000
  pop ecx
  EXITM <offset wRecBuffer>
endm




.data
    f0              db "Testfile1.txt", 0
    f1              db "Testfile2.txt", 0
    f2              db "Testfile3.txt", 0
    f3              db "Testfile4.txt", 0
    f4              db "Testfile5.txt", 0
    files2Zip       dd f0, f1, f2, f3, f4, 0
    wRecBuffer      db 1000 dup(?)
    fullpath$       db 1000 dup(?)
    _pszZipFolder$  db "..\ThisFolder", 0
    pszZipFolder$   dd _pszZipFolder$
    _pszZipFile$    db "Test.zip", 0
    pszZipFile$     dd _pszZipFile$




.code




start:
    invoke ZipThem, chr$("."), addr files2Zip ; the dot means "current folder"
    exit




.code




ZipThem proc sZipPath$:dword, pszToZip:dword
local pidlZipFolder, isfDesktop, isf
local pidlToZip[999]
    push esi
    push edi
    push ebx
    mov esi, pszToZip
    lea edi, pidlToZip
    push edi
    xor ebx, ebx
    mov eax, pszZipFolder$
    mov ecx, offset fullpath$
    push ecx
    invoke GetFullPathNameW, wRec$(sZipPath$), 1000, ecx, 0
    pop ecx
    mov pidlZipFolder, rv(ILCreateFromPathW, ecx)
   
  .While 1
    lodsd
  .Break .if !eax
    mov ecx, offset fullpath$
    push ecx
    invoke GetFullPathNameW, wRec$(eax), 1000, ecx, 0
    pop ecx
    invoke ILCreateFromPathW, ecx
    stosd
    inc ebx
  .Endw

    pop esi
    lea edi, isfDesktop
    invoke SHGetDesktopFolder, addr isfDesktop
    mov eax, isfDesktop
  @out:
    pop ebx
    pop edi
    pop esi
    ret
ZipThem endp




end start

Let me know if it is missing anything ...


I've removed the console & print code, and of course the 'deb' code and everything else that is not referenced in the essential code. I think I have done it properly. This will allow stepping in olly without the other 'noise' so hopefully I can understand better what exactly is goin on with the code.


If I have made errors by omissions, post a clean (no deb or console stuff, just the algo) code.  :biggrin:  And a batch file to assemble with. The code posted assembles, but I do not know if you had any link options set so I simply assembled it.




okay I see something... The CoInvoke.inc file has more to do with than making the console window. (GuidFromString, etc)  Hmmm.
lemme revise what I had done...  I don't like the pesky console window open while debugging, and dont really need to print anything either. I just want to follow the essential code.  :undecided:

zedd151

I've done some searching for "how does windows zip files and folders" but only thing that comes up is guides for neophytes on how to use the 'send to compressed...' feature.   :badgrin:  I will next search in sourceforge and github, perhaps someone has coded up something in C or C++ ...


Else another option is to trace how Windows Explorer does it. I might have to use Windows xp for that adventure, less bloat in general there. If I can figure out how to do that, that is.   :biggrin:


I would think that there might be a GUID error somewhere maybe. ?


Well all I can say is that you've come up with an interesting exercise.  :biggrin:

zedd151

I've found this here http://masm32.com/board/index.php?topic=3215.msg34255#msg34255 that looks interesting. its a cpp file but...



you could probably get the gist of what that program does and how by looking at the code in olly.


edit to add, I can't get that program to work as expected...  :sad:

zedd151

okay I got it to work, but the program and zip file (to add to) and the file (to add) had to be in the same location.
Path parsing error? I dunno. But Ill play with it a little more...  :biggrin:


storagezip.exe C:\users\administrator\desktop\test.zip C:\users\administrator\desktop\x.ss I made an error in the path. It works as expected.


The zip file can either exist and the file will be added, or if the zip file doesnt exist will create it and compress the file to it.


That is part of the functionality you want, yes?


I don't know how to extract to folder though I have tried. Maybe you will have better luck  :thup:
Just noticed that it is one of your own threads.


for more research ...
http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/d3e347cc-f4dc-44a6-8f84-977f958d89c6/manipulating-zipfldrdll-to-create-a-compressed-folder?forum=windowsgeneraldevelopmentissues



Quote
This is a code snippet to UNZIP a .zip file to a folder.


You can use the reverse thing for makking .zip files.




bool UnZipFolder(LPCTSTR zipFile,LPCTSTR destination)
   {


    DWORD     strlen = 0;
    HRESULT     hResult;
    IShellDispatch *pISD;
    Folder  *pToFolder = NULL;
    Folder  *pFromFolder = NULL;
    FolderItems *pFolderItems = NULL;
    FolderItem *pItem = NULL;
   
    VARIANT   vDir, vFile, vOpt;
    BSTR  strptr1, strptr2;
    CoInitialize(NULL);
   
    bool bReturn = false;
   
    hResult = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
     IID_IShellDispatch, (void **)&pISD);
   
    if(FAILED(hResult))
    {
     return bReturn;
    }
   
    VariantInit(&vOpt);
    vOpt.vt = VT_I4;
    vOpt.lVal = 16+4;     // Do not display a progress dialog box ~ This will not work properly!
   
   
    CString strZipFile(zipFile);
    CString strDestination(destination);
    strptr1 = strZipFile.AllocSysString();
    strptr2 = strDestination.AllocSysString();
   
    VariantInit(&vFile);
    vFile.vt = VT_BSTR;
    vFile.bstrVal = strptr1;
    hResult = pISD->NameSpace(vFile, &pFromFolder); 
   
    VariantInit(&vDir);
    vDir.vt = VT_BSTR;
    vDir.bstrVal = strptr2;
   
    hResult = pISD->NameSpace(vDir, &pToFolder);
   
    if(S_OK == hResult)
    {
     hResult = pFromFolder->Items(&pFolderItems);
     if(SUCCEEDED(hResult))
     {
      long lCount = 0;
      pFolderItems->get_Count(&lCount);
      IDispatch* pDispatch = NULL;
      pFolderItems->QueryInterface(IID_IDispatch,(void**)&pDispatch);
      VARIANT vtDispatch;
      VariantInit(&vtDispatch);
      vtDispatch.vt = VT_DISPATCH;
      vtDispatch.pdispVal = pDispatch;
           
      //cout << "Extracting files ...\n";
      hResult = pToFolder->CopyHere(vtDispatch,vOpt);
      if(hResult != S_OK) return false;





      //Cross check and wait until all files are zipped!
      FolderItems* pToFolderItems;
      hResult = pToFolder->Items(&pToFolderItems);
     
      if(S_OK == hResult)
      {
       long lCount2 = 0;   
             
       hResult = pToFolderItems->get_Count(&lCount2);
       if(S_OK != hResult)
       {
        pFolderItems->Release();
        pToFolderItems->Release();
        SysFreeString(strptr1);
        SysFreeString(strptr2);
        pISD->Release();
        CoUninitialize();
        return false;
       }
       //Use this code in a loop if you want to cross-check the items unzipped.
       /*if(lCount2 != lCount)
       {
        pFolderItems->Release();
        pToFolderItems->Release();
        SysFreeString(strptr1);
        SysFreeString(strptr2);
        pISD->Release();
        CoUninitialize();
        return false;
       }*/
       
       bReturn = true;
      }     
     
      pFolderItems->Release();
      pToFolderItems->Release();
     }
     
     pToFolder->Release();
     pFromFolder->Release();
    }
   
    //cout << "Over!\n";
    SysFreeString(strptr1);
    SysFreeString(strptr2);
    pISD->Release();
   
    CoUninitialize();
    return bReturn;
   }





Monday, October 6, 2008 10:52 AM

ma22du

zedd151


Quote from: zedd151 on June 02, 2023, 01:41:32 AM
I've found this here http://masm32.com/board/index.php?topic=3215.msg34255#msg34255 that looks interesting.


Apparently this program only creates zip files. But it does that quite nicely and as expected. (so far)    At least I havent been able to unzip with it. 


Aha! a similar error as in your proggy





C:\Users\Administrator\Desktop>storagezip.exe test.zip "sudoku gui 5"
Zipping of 26401 bytes of 'basic3.asm' returned 0
Zipping of 534528 bytes of 'basic3.exe' returned 0
Zipping of 709 bytes of 'current state.txt' returned 0
Zipping of 766 bytes of 'mainicon.ico' returned 0
Zipping of 1417 bytes of 'makeit.bat' returned 0
Zipping of 362998 bytes of 'back.bmp' returned 0
Zipping of 138 bytes of 'can.bmp' returned 0
Zipping of 338 bytes of 'can1.bmp' returned 0
Zipping of 342 bytes of 'can2.bmp' returned 0
Zipping of 346 bytes of 'can3.bmp' returned 0
Zipping of 350 bytes of 'can4.bmp' returned 0
Zipping of 350 bytes of 'can5.bmp' returned 0
Zipping of 346 bytes of 'can6.bmp' returned 0
Zipping of 338 bytes of 'can7.bmp' returned 0
Zipping of 350 bytes of 'can8.bmp' returned 0
Zipping of 346 bytes of 'can9.bmp' returned 0
Zipping of 1256 bytes of 'can1hi.bmp' returned 0
Zipping of 1256 bytes of 'can2hi.bmp' returned 0
Zipping of 1256 bytes of 'can3hi.bmp' returned 0
Zipping of 1256 bytes of 'can4hi.bmp' returned 0
Zipping of 1256 bytes of 'can5hi.bmp' returned 0
Zipping of 1256 bytes of 'can6hi.bmp' returned 0
Zipping of 1256 bytes of 'can7hi.bmp' returned 0
Zipping of 1256 bytes of 'can8hi.bmp' returned 0
Zipping of 1256 bytes of 'can9hi.bmp' returned 0
Zipping of 1256 bytes of 'canhi.bmp' returned 0
Zipping of 766 bytes of 'mainicon.ico' returned 0x80070005   ; <---
Couldn't zip 'pix\mainicon.ico' because of error 0x80070005   ; <---
Zipping of 439 bytes of 'manifest.xml' returned 0
Zipping of 2154 bytes of '1.bmp' returned 0
Zipping of 2166 bytes of '2.bmp' returned 0
Zipping of 2166 bytes of '3.bmp' returned 0
Zipping of 2166 bytes of '4.bmp' returned 0
Zipping of 2166 bytes of '5.bmp' returned 0
Zipping of 2166 bytes of '6.bmp' returned 0
Zipping of 2166 bytes of '7.bmp' returned 0
Zipping of 2166 bytes of '8.bmp' returned 0
Zipping of 2166 bytes of '9.bmp' returned 0
Zipping of 570 bytes of 'white.bmp' returned 0
Zipping of 2166 bytes of '1bold.bmp' returned 0
Zipping of 2166 bytes of '2bold.bmp' returned 0
Zipping of 2166 bytes of '3bold.bmp' returned 0
Zipping of 2166 bytes of '4bold.bmp' returned 0
Zipping of 2166 bytes of '5bold.bmp' returned 0
Zipping of 2166 bytes of '6bold.bmp' returned 0
Zipping of 2166 bytes of '7bold.bmp' returned 0
Zipping of 2166 bytes of '8bold.bmp' returned 0
Zipping of 2166 bytes of '9bold.bmp' returned 0
Zipping of 12344 bytes of '1boldhi.bmp' returned 0
Zipping of 12344 bytes of '2boldhi.bmp' returned 0
Zipping of 12344 bytes of '3boldhi.bmp' returned 0
Zipping of 2166 bytes of '4boldhi.bmp' returned 0
Zipping of 12344 bytes of '5boldhi.bmp' returned 0
Zipping of 12344 bytes of '6boldhi.bmp' returned 0
Zipping of 12344 bytes of '7boldhi.bmp' returned 0
Zipping of 12344 bytes of '8boldhi.bmp' returned 0
Zipping of 12344 bytes of '9boldhi.bmp' returned 0
Zipping of 12344 bytes of '1hi.bmp' returned 0
Zipping of 12344 bytes of '2hi.bmp' returned 0
Zipping of 12344 bytes of '3hi.bmp' returned 0
Zipping of 12344 bytes of '4hi.bmp' returned 0
Zipping of 12344 bytes of '5hi.bmp' returned 0
Zipping of 12344 bytes of '6hi.bmp' returned 0
Zipping of 12344 bytes of '7hi.bmp' returned 0
Zipping of 12344 bytes of '8hi.bmp' returned 0
Zipping of 12344 bytes of '9hi.bmp' returned 0
Zipping of 12342 bytes of 'hi.bmp' returned 0
Zipping of 3189 bytes of 'rsrc.old.rc' returned 0
Zipping of 574 bytes of 'select.bmp' returned 0
Zipping of 2271 bytes of 'rsrc.rc' returned 0




C:\Users\Administrator\Desktop>pause
Press any key to continue . . .

Quote
0x80070005 obviously a different error code

It zipped the rest of the files, in spite of the error for the icon file.

jj2007

Quote from: zedd151 on June 02, 2023, 02:08:07 AM
okay I got it to work, but the program and zip file (to add to) and the file (to add) had to be in the same location.
Path parsing error? I dunno. But Ill play with it a little more...  :biggrin:

Great, thanks. Right now I have no time, but asap I'll look into it :thumbsup:

zedd151

Quote from: jj2007 on June 02, 2023, 04:29:06 AM
Great, thanks. Right now I have no time, but asap I'll look into it :thumbsup:


Looking at that code either the .cpp source or the executable in ollydbg might give you a hint of where your code is going wrong.


Funny thing is that it is in one of your old threads from several years ago. Perhaps you were experimenting with the same thing then? Maybe you already have the old code?