News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Number and type of arguments required for call to C library

Started by jj2007, May 21, 2014, 10:21:19 PM

Previous topic - Next topic

GoneFishing

Quote from: dedndave on June 03, 2014, 10:57:11 AM
reports all over the web say that "CopyHere options don't work"
...
http://msdn.microsoft.com/en-us/library/windows/desktop/bb787866(v=vs.85).aspx:
QuoteNote  In some cases, such as compressed (.zip) files, some option flags may be ignored by design.

dedndave

these seem to be pertinent for zipping files/folders
there may be more

(content removed, see next post)

dedndave

added a couple more
IFNDEF FOF_SILENT
  FOF_SILENT            EQU 4     ;Do not display a progress dialog box.
ENDIF

IFNDEF FOF_RENAMEONCOLLISION
  FOF_RENAMEONCOLLISION EQU 8     ;Give the file being operated on a new name if a file with the target name already exists.
ENDIF

IFNDEF FOF_NOCONFIRMATION
  FOF_NOCONFIRMATION    EQU 10h   ;Respond with "Yes to All" for any dialog box that is displayed.
ENDIF

IFNDEF FOF_SIMPLEPROGRESS
  FOF_SIMPLEPROGRESS    EQU 100h  ;Display a progress dialog box but do not show the file names.
ENDIF

IFNDEF FOF_NOCONFIRMMKDIR
  FOF_NOCONFIRMMKDIR    EQU 200h  ;Do not confirm the creation of a new directory if the operation requires one to be created.
ENDIF

IFNDEF FOF_NOERRORUI
  FOF_NOERRORUI         EQU 400h  ;Do not display a user interface if an error occurs.
ENDIF

dedndave

ok - big mistake on my part
a pointer to the VARIANT structure is not passed
the entire VARIANT structure is passed
no wonder it looked so confusing   :redface:

i will have to update my interface vTable structures
for asm code, it's best to define it as dwords, so it will take a little work

dedndave

updated the IShellDispatch and Folder vTable structures in Reply #103

now, we are ready to rock and roll   :biggrin:

no wonder everything kept crashing
the stack was probably out of balance
we PUSH'ed too few parms (the worst kind of imbalance)

dedndave

it works - and it zips the files
i just have to figure out why my UNICODE aware hex routine is adding an extra space   :lol:
then, i'll post an EXE with source
                     Stack Pointer:  0012FFC4
                  CoCreateInstance: Success
IShellDispatch::NameSpace(Target): Success
          Folder::CopyHere(Source): (no return value)
                   Folder::Release: Success
           IShellDispatch::Release: Success
                     Stack Pointer:  0012FFC4

Press any key to continue ...

dedndave

doh !
i forgot the -1   :biggrin:
    INVOKE  awConOut,lengthof sz0000-1,offset sz0000

here it is.....
you will have to create a folder structure
  C:\ZipTest
      \New
      \ZipIt
          Test1.txt
          \Test
              Test2.txt

Test1.txt and Test2.txt are small text files
you can put whatever you like into the ZipIt folder
but, i am only using a 5 second delay to let it finish
the resulting ZIP file will be C:\ZipTest\New\New.zip

now, i can work on detecting when it's done

by the way - it builds and runs as UNICODE or ANSI

EDIT: changed some UNICODE Aware stuff - no functional changes
EDIT: more uneventful UNICODE Aware updates

adeyblue

Since peter_asm posted an example of finding the thread and waiting for it, here's a version that uses the shell notifications:

#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <shldisp.h>
#include <shlobj.h>
#include <ole2.h>
#include <cstdio>

#define CHECK_FAIL(x) \
    { \
        HRESULT hr = (x); \
        if(FAILED(hr)) \
        { \
            printf(#x " failed with error %#x\n", hr); \
            goto exit; \
        } \
    }

const UINT g_zipFinMsg = WM_APP + 0x50;

LRESULT __stdcall ZipWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HANDLE hExitHandle = NULL;
    switch(msg)
    {
        case WM_CREATE:
        {
            LPCREATESTRUCT pCS = reinterpret_cast<LPCREATESTRUCT>(lParam);
            hExitHandle = static_cast<HANDLE>(pCS->lpCreateParams);
        }
        break;
        case g_zipFinMsg:
        {
            SetEvent(hExitHandle);
            DestroyWindow(hwnd);
        }
        break;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

void CreateZipFile(PCWSTR pZip)
{
    CloseHandle(CreateFile(pZip, STANDARD_RIGHTS_WRITE, 0, NULL, OPEN_ALWAYS, 0x80, NULL));
}

HWND CreateZipWaitWnd(HANDLE hEvent)
{
    WNDCLASSEX wndClass = {sizeof(wndClass), 0};
    wndClass.lpfnWndProc = &ZipWndProc;
    wndClass.hInstance = GetModuleHandle(NULL);
    wndClass.lpszClassName = L"ZipWnd";
    RegisterClassEx(&wndClass);
    return CreateWindowEx(
        0,
        wndClass.lpszClassName,
        L"",
        WS_OVERLAPPEDWINDOW,
        1,
        1,
        1,
        1,
        HWND_MESSAGE,
        NULL,
        wndClass.hInstance,
        hEvent
    );
}

BSTR GetFullZipPath(PCWSTR pZip)
{
    DWORD charsReq = GetFullPathName(pZip, 0, NULL, 0);
    BSTR zipPath = SysAllocStringLen(NULL, charsReq);
    GetFullPathName(pZip, charsReq, zipPath, NULL);
    return zipPath;
}

void ScriptyZip(PCWSTR pZip, PCWSTR pItemsToZip)
{
    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

    IShellDispatch* pShellDisp = NULL;
    Folder* pZipFolder = NULL, *pOutFolder = NULL;
    FolderItems* pThingsToZip = NULL;

    BSTR zipFile = GetFullZipPath(pZip);
    CreateZipFile(zipFile);
    BSTR outputDir = SysAllocString(pItemsToZip);

    VARIANT varZip = {VT_BSTR}; varZip.bstrVal = zipFile;
    VARIANT varOutDir = {VT_BSTR}; varOutDir.bstrVal = outputDir;
    VARIANT varDispItems = {VT_DISPATCH};
    VARIANT varCopyOpts = {VT_UI4};

    HRESULT hRes = SHCoCreateInstance(NULL, &CLSID_Shell, NULL, IID_IShellDispatch, (void**)&pShellDisp);
    // Folder object for the zip file
    CHECK_FAIL(pShellDisp->NameSpace(varZip, &pZipFolder));
    // Folder object for the output folder
    CHECK_FAIL(pShellDisp->NameSpace(varOutDir, &pOutFolder));
    // Get the items in the folder
    CHECK_FAIL(pOutFolder->Items(&pThingsToZip));

    varDispItems.pdispVal = pThingsToZip;

    // create the window and setup the shell notification before
    // CopyHere so we can catch even the quickest of operations
    HANDLE hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    HWND hwndWaitWindow = CreateZipWaitWnd(hExitEvent);
    if(!(hExitEvent && hwndWaitWindow))
    {
        goto exit;
    }
    SHChangeNotifyEntry entry = {ILCreateFromPath(pZip), FALSE};
    ULONG regId = SHChangeNotifyRegister(
        hwndWaitWindow,
        SHCNRF_InterruptLevel | SHCNRF_ShellLevel,
        SHCNE_CREATE | SHCNE_UPDATEITEM,
        g_zipFinMsg,
        1,
        &entry
    );
    pZipFolder->CopyHere(varDispItems, varCopyOpts);
    DWORD ret;
    while((ret = MsgWaitForMultipleObjects(1, &hExitEvent, FALSE, INFINITE, QS_ALLINPUT)) <= 1)
    {
        // exit event set
        if(ret == 0)
        {
            break;
        }
        // message received
        else
        {
            MSG msg;
            while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
            {
                DispatchMessage(&msg); // don't need TranslateMessage
            }
        }
    }
    SHChangeNotifyDeregister(regId);
    ILFree((LPITEMIDLIST)entry.pidl);

exit:
    if(hExitEvent)
    {
        CloseHandle(hExitEvent);
    }
    if(pThingsToZip)
    {
        pThingsToZip->Release();
    }
    if(pZipFolder)
    {
        pZipFolder->Release();
    }
    if(pOutFolder)
    {
        pOutFolder->Release();
    }
    if(pShellDisp)
    {
        pShellDisp->Release();
    }
    SysFreeString(zipFile);
    SysFreeString(outputDir);
    CoUninitialize();
}

int wmain(int argc, wchar_t** argv)
{
    if(argc != 3)
    {
        return puts("Usage: ScriptyZip file.zip c:\\dir\\or\\file\\to.add");
    }
    else
    {
        ScriptyZip(argv[1], argv[2]);
    }
    return 0;
}

dedndave


Gunther

You have to know the facts before you can distort them.

jj2007

Quote from: dedndave on June 04, 2014, 12:30:28 PM
updated the attachment in Reply #111

Win7-32: Creates New.zip at 22 bytes (after pointing bstrPathTarget and szZipFile to existing folders) but fails for IShellDispatch.NameSpace :(

So it works for you, Gunther?

@adeyblue: pShellDisp->NameSpace(varOutDir, &pOutFolder) failed with error 0x80004005 :(

Gunther

Jochen,

Quote from: jj2007 on June 04, 2014, 04:36:39 PM
So it works for you, Gunther?

at least with my old XP box.

                     Stack Pointer: 0013FFC4
                  CoCreateInstance: Success
IShellDispatch::NameSpace(Target): 00000001
           IShellDispatch::Release: Success
                     Stack Pointer: 0013FFC4

Press any key to continue...


I can test it with Win7-64 not before Friday, because I'm currently on the island of RĂ¼gen (with bad internet access :().

Gunther 
You have to know the facts before you can distort them.

sinsi

Working here (after a change - hard coded paths dave?), creates a 791KB new.zip
Windows 8.1 Pro x64


                     Stack Pointer: 0018FF90
                  CoCreateInstance: Success
IShellDispatch::NameSpace(Target): Success
          Folder::CopyHere(Source): (no return value)
                   Folder::Release: Success
           IShellDispatch::Release: Success
                     Stack Pointer: 0018FF90

🍺🍺🍺

GoneFishing

Dave,
Did you test CopyHere's option flags ?
I'm curious which of them work for zip folders.

dedndave

no - i didn't test them yet
but - i zipped the contents of masm32\include (longer time delay), and with the current flagset - no progress dialog, as desired

as for the hard-coded paths, yes
i wanted to spend time figuring out how the COM stuff worked
not spend time writing a fancy program - lol

the way it's written, you create the following folders
C:\ZipTest
C:\ZipTest\New
C:\ZipTest\ZipIt

the stuff you put into the ZipIt folder will be zipped
so, for test purposes, i put a text file, and a folder containing a text file into the ZipIt folder