News:

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

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

dedndave

i've been reading up a little on COM....

it would seem that the shell is a "dual interface"
that is, it may be accessed via IDispatch, or via the shell functions
from what i gather, the IDispatch methods target "variable type" languages, such as scripts
VB scripts and java scripts use IDispatch

so, it would seem that adeyblue has the right idea for what we want
however - that's not to say that it can't be done via IDispatch

a good analogy might be using DialogBoxParam and a bunch of structures to create a dialog box,
as opposed to using a resource template, and letting the OS do it

still playing with IDispatch - i want to see if i can figure it out - lol

peter_asm

I was poking through zipfldr.dll again and noticed various objects used to work with ZIP files inherit from ITransferHelper, ITransferAdviseSink and ITransferSource2 which is undocumented

seen this too : http://blog.airesoft.co.uk/2012/10/dropping-like-files-zipping-without-libraries/

jj2007

Quote from: peter_asm on May 30, 2014, 07:45:04 AMseen this too : http://blog.airesoft.co.uk/2012/10/dropping-like-files-zipping-without-libraries/

That is adeyblue's blog, see reply #40. Does anybody have a Microsoft account?
QuoteThe sad thing is of course that the zip compatibility is crap; http://blogs.msdn.com/b/michkap/archive/2012/01/04/10252916.aspx etc

dedndave

i checked it the other day
it's a dead link
you can create a hotmail acct to sign into MS - it's free

dedndave

it's Michael Kaplan
you can google and find that they are refering to zipping UNICODE filenames
the locale identifier may cause issues (zip in one locale, unzip in another)
seems to me, you could set the locale id to 0   :P

jj2007

Here is a sample for testing...

I can handle it with the new UnzipFile macro, but it's a bit clumsy. Curious to see if Windows knows about Unicode ;)

dedndave

i had a little time to play, today

as i mentioned before - there is a lot of documentation on creating a COM interface
it almost seems easier than using one - lol
but, one of the things i noticed was that IDispatch interfaces aren't necessarily limited to the 7 functions
the first 3 are IUnknown, which is a subset of IDispatch, which is a subset.... and so on

IDispatch STRUCT
  METHOD(QueryInterface,   _this:LPVOID,riid:LPVOID,ppvObj:LPVOID)
  METHOD(AddRef,           _this:LPVOID)
  METHOD(Release,          _this:LPVOID)
  METHOD(GetTypeInfoCount, _this:LPVOID,pctinfo:UINT)
  METHOD(GetTypeInfo,      _this:LPVOID,iTInfo:UINT,lcid:LCID,ppTInfo:LPVOID)
  METHOD(GetIDsOfNames,    _this:LPVOID,riid:LPVOID,rgszNames:LPOLESTR,cNames:UINT,lcid:LCID,rgDispId:LPVOID)
  METHOD(dInvoke,          _this:LPVOID,dispIdMember:DWORD,riid:LPVOID,lcid:LCID,wFlags:DWORD,pDispParams:LPVOID,pVarResult:LPVOID,pExcepInfo:LPVOID,puArgErr:UINT)
IDispatch ENDS


what i learned was, because we are using "Shell.Application",
what we are actually getting is an IShellDispatch interface vTable
and - with different versions of OS, service pack, CommonCtrls, and .NET, you get different versions of IShellDispatch
using XP SP3, .NET 3.5, and without referencing CommCtrls 6.0, i get an IShellDispatch4 vTable
these can be acquired directly with
IID_IShellDispatch  GUID <0D8F015C0h,0C278h,11CEh,<0A4h,9Eh,44h,45h,53h,54h,0,0>>
IID_IShellDispatch2 GUID <0A4C6892Ch,3BA9h,11D2h,<9Dh,0EAh,0,0C0h,4Fh,0B1h,61h,62h>>
IID_IShellDispatch3 GUID <177160CAh,0BB5Ah,411Ch,<84h,1Dh,0BDh,38h,0FAh,0CDh,0EAh,0A0h>>
IID_IShellDispatch4 GUID <0EFD84B2Dh,4BCFh,4298h,<0BEh,25h,0EBh,54h,2Ah,59h,0FBh,0DAh>>
IID_IShellDispatch5 GUID <866738B9h,6CF2h,4DE8h,<87h,67h,0F7h,94h,0EBh,0E7h,4Fh,4Eh>>
IID_IShellDispatch6 GUID <286E6F1Bh,7113h,4355h,<95h,62h,96h,0B7h,0E9h,0D6h,4Ch,54h>>


and, the vTables progress like this...
;IUnknown methods (3)

    AddRef
    QueryInterface
    Release

;IDispatch methods (4)

    GetIDsOfNames
    GetTypeInfo
    GetTypeInfoCount
    Invoke

;IShellDispatch properties (2)

    Application
    Parent

;IShellDispatch methods (21)

    NameSpace
    BrowseForFolder
    Windows
    Open
    Explore
    MinimizeAll
    UndoMinimizeALL
    FileRun
    CascadeWindows
    TileVertically
    TileHorizontally
    ShutdownWindows
    Suspend
    EjectPC
    SetTime
    TrayProperties
    Help
    FindFiles
    FindComputer
    RefreshMenu
    ControlPanelItem

;IShellDispatch2 methods (9)

    IsRestricted
    ShellExecute
    FindPrinter
    GetSystemInformation
    ServiceStart
    ServiceStop
    IsServiceRunning
    CanStartStopService
    ShowBrowserBar

;IShellDispatch3 method (1)

    AddToRecent

;IShellDispatch4 methods (4) (visible in XP SP3 without Common Controls 6.0)

    WindowsSecurity
    ToggleDesktop
    ExplorerPolicy
    GetSetting

IShellDispatch5 method (1) (suspect visible with Common Controls 6.0 and/or some level of .NET)

    WindowSwitcher

IShellDispatch6 method (1) (suspect visible with Windows 8 and/or some level of .NET)

    SearchCommand


i'm not really sure what's required to get the later versions
but, it doesn't matter, because we're primarily interested in NameSpace


the other thing i learned today was how to build a C++ program using Visual C++ 2005 Express
not being much on compilers, that's a big step for me   :P
tomorrow, i'll be able to play some more

dedndave

this works, but it seems like a lot of code   :P
it's a starting point
the empty zip file and folders must exist
int _tmain(int argc, _TCHAR* argv[])
{
    DWORD strlen = 0;
    char szFrom[] = "C:\\ZipTest\\ZipIt",
         szTo[] = "C:\\ZipTest\\New\\New.zip";
    HRESULT hResult;
    IShellDispatch *pISD;
    Folder *pToFolder = NULL;
    VARIANT vDir, vFile, vOpt;
    BSTR strptr1, strptr2;

    CoInitialize(NULL);

    hResult = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void **)&pISD);

    if  (SUCCEEDED(hResult) && pISD != NULL)
    {
        strlen = MultiByteToWideChar(CP_ACP, 0, szTo, -1, 0, 0);
        strptr1 = SysAllocStringLen(0, strlen);
        MultiByteToWideChar(CP_ACP, 0, szTo, -1, strptr1, strlen);

        VariantInit(&vDir);
        vDir.vt = VT_BSTR;
        vDir.bstrVal = strptr1;
        hResult = pISD->NameSpace(vDir, &pToFolder);

        if  (SUCCEEDED(hResult))
        {
            strlen = MultiByteToWideChar(CP_ACP, 0, szFrom, -1, 0, 0);
            strptr2 = SysAllocStringLen(0, strlen);
            MultiByteToWideChar(CP_ACP, 0, szFrom, -1, strptr2, strlen);

            VariantInit(&vFile);
            vFile.vt = VT_BSTR;
            vFile.bstrVal = strptr2;

            VariantInit(&vOpt);
            vOpt.vt = VT_I4;
            vOpt.lVal = 4;          // Do not display a progress dialog box

            hResult = NULL;
            printf("Copying %s to %s ...\n", szFrom, szTo);
            hResult = pToFolder->CopyHere(vFile, vOpt); //NOTE: this appears to always return S_OK even on error
            /*
             * 1) Enumerate current threads in the process using Thread32First/Thread32Next
             * 2) Start the operation
             * 3) Enumerate the threads again
             * 4) Wait for any new threads using WaitForMultipleObjects
             *
             * Of course, if the operation creates any new threads that don't exit, then you have a problem.
             */
                 if (hResult == S_OK) {
                     //NOTE: hard-coded for testing - be sure not to overflow the array if > 5 threads exist
                     HANDLE hThrd[5];
                     HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPALL ,0);  //TH32CS_SNAPMODULE, 0);
                     DWORD NUM_THREADS = 0;
                     if (h != INVALID_HANDLE_VALUE) {
                         THREADENTRY32 te;
                         te.dwSize = sizeof(te);
                         if (Thread32First(h, &te)) {
                             do {
                                 if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID)) ) {
                                     //only enumerate threads that are called by this process and not the main thread
                                     if((te.th32OwnerProcessID == GetCurrentProcessId()) && (te.th32ThreadID != GetCurrentThreadId()) ){
                                         //printf("Process 0x%04x Thread 0x%04x\n", te.th32OwnerProcessID, te.th32ThreadID);
                                         hThrd[NUM_THREADS] = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
                                         NUM_THREADS++;
                                    }
                                }
                                te.dwSize = sizeof(te);
                            } while (Thread32Next(h, &te));
                        }
                        CloseHandle(h);

                        printf("waiting for all threads to exit...\n");
                        //Wait for all threads to exit
                        WaitForMultipleObjects(NUM_THREADS, hThrd , TRUE , INFINITE);

                        //Close All handles
                        for ( DWORD i = 0; i < NUM_THREADS ; i++ ){
                            CloseHandle( hThrd[i] );
                        }
                    } //if invalid handle
                } //if CopyHere() hResult is S_OK

            SysFreeString(strptr2);
            pToFolder->Release();
        }

        SysFreeString(strptr1);
        pISD->Release();
    }

    CoUninitialize();

    printf ("Press ENTER to exit\n");
    getchar();
    return 0;

}


while reading, i came across this function that looked interesting
the descriptions are sometimes misleading, though

SHGetInstanceExplorer
http://msdn.microsoft.com/en-us/library/windows/desktop/bb762186%28v=vs.85%29.aspx

GoneFishing

I think that SHGetInstanceExplorer is called from the shell extension / component's  side .
I didn't know that we can get thread handle from its ID and thus can use WaitForMultipleObjects function.
MSDN has a warning about its usage in Remarks:
QuoteUse caution when calling the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked.

CopyHere method doesn't return any value so it's our job to check if the copy operation was successful .

I don't understand this line of code:
Quoteif (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID)) ) {
Could anybody explain its meaning?

qWord

Quote from: vertograd on June 02, 2014, 10:00:31 PMI don't understand this line of code:
Quoteif (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID)) ) {
Could anybody explain its meaning?
Quote from: msdnThe calling application must set the dwSize member of THREADENTRY32 to the size, in bytes, of the structure. Thread32First changes dwSize to the number of bytes written to the structure. This will never be greater than the initial value of dwSize, but it may be smaller. If the value is smaller, do not rely on the values of any members whose offsets are greater than this value.
I'm really curious under which conditions the structure is only partially filled, even it seems like some backward compatibility issue...
MREAL macros - when you need floating point arithmetic while assembling!

GoneFishing


adeyblue

Quote from: qWord on June 02, 2014, 10:49:26 PM
Quote from: msdnThe calling application must set the dwSize member of THREADENTRY32 to the size, in bytes, of the structure. Thread32First changes dwSize to the number of bytes written to the structure. This will never be greater than the initial value of dwSize, but it may be smaller. If the value is smaller, do not rely on the values of any members whose offsets are greater than this value.
I'm really curious under which conditions the structure is only partially filled, even it seems like some backward compatibility issue...

There are none (so far). The struct has been the same size from Win95 to 8.1, and all the thread funcs do is basically open a memory mapped file and memcpy the relevant struct.

Quote from: dedndave
hResult = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void **)&pISD);
If you don't mind Microsoft's ominous, but so far untrue words (it still exists and works fine in 8.1). You can skip hitting the registry and all of ole32's funkiness with:

hResult = SHCoCreateInstance(NULL, &CLSID_Shell, NULL, IID_IShellDispatch, (void **)&pISD);

dedndave

you can create it directly

IFNDEF CLSCTX_INPROC_SERVER
    CLSCTX_INPROC_SERVER EQU 1
ENDIF

        .DATA

CLSID_Shell         GUID <13709620h,0C279h,11CEh,<0A4h,9Eh,44h,45h,53h,54h,0,0>>
IID_IShellDispatch  GUID <0D8F015C0h,0C278h,11CEh,<0A4h,9Eh,44h,45h,53h,54h,0,0>>

        .DATA?

pvShell  LPVOID ?

        .CODE

        INVOKE  CoInitialize,NULL
        INVOKE  CoCreateInstance,offset CLSID_Shell,NULL,CLSCTX_INPROC_SERVER,offset IID_IShellDispatch,offset pvShell

dedndave

once you have it, you just need some proper vTable structures   :biggrin:

let's start with qWord's METHOD macro

;METHOD macro by qWord

METHOD  MACRO   name,args:VARARG
        LOCAL   _type1,_type2
        _type1  TYPEDEF PROTO args
        _type2  TYPEDEF PTR _type1
        EXITM   <name _type2 ?>
        ENDM


then, IUnknown and IDispatch

;IUnknown interface vTable (structure)

IUnknown STRUCT
  METHOD(QueryInterface, _this:LPVOID,riid:LPVOID,ppvObj:LPVOID)
  METHOD(AddRef,         _this:LPVOID)
  METHOD(Release,        _this:LPVOID)
IUnknown ENDS

;IDispatch interface vTable (structure)

IDispatch STRUCT
    IUnknown                 <>
  METHOD(GetTypeInfoCount, _this:LPVOID,pctinfo:LPVOID)
  METHOD(GetTypeInfo,      _this:LPVOID,iTInfo:UINT,lcid:LCID,ppTInfo:LPVOID)
  METHOD(GetIDsOfNames,    _this:LPVOID,riid:LPVOID,rgszNames:LPOLESTR,cNames:UINT,lcid:LCID,rgDispId:LPVOID)
  METHOD(dInvoke,          _this:LPVOID,dispIdMember:DWORD,riid:LPVOID,lcid:LCID,wFlags:DWORD,pDispParams:LPVOID,pVarResult:LPVOID,pExcepInfo:LPVOID,puArgErr:LPVOID)
IDispatch ENDS


because we created an IShellDispatch interface...

;IShellDispatch interface vTable (structure)
;       vDir VARIANT struct = vtDir:DWORD,vD0:DWORD,vstrDir:LPVOID,vDV0:DWORD
;vRootFolder VARIANT struct = vtRoot:DWORD,vR0:DWORD,vstrRoot:LPVOID,vRV0:DWORD

IShellDispatch STRUCT
    IDispatch                <>
  METHOD(Application,      _this:LPVOID,ppid:LPVOID)
  METHOD(Parent,           _this:LPVOID,ppid:LPVOID)
  METHOD(NameSpace,        _this:LPVOID,vtDir:DWORD,vD0:DWORD,vstrDir:LPVOID,vDV0:DWORD,ppsdf:LPVOID)
  METHOD(BrowseForFolder,  _this:LPVOID,Hwnd:DWORD,lpTitle:LPVOID,Options:DWORD,vtRoot:DWORD,vR0:DWORD,vstrRoot:LPVOID,vRV0:DWORD,ppsdf:LPVOID)
  METHOD(Windows,          _this:LPVOID,ppid:LPVOID)
  METHOD(Open,             _this:LPVOID,vtDir:DWORD,vD0:DWORD,vstrDir:LPVOID,vDV0:DWORD)
  METHOD(Explore,          _this:LPVOID,vtDir:DWORD,vD0:DWORD,vstrDir:LPVOID,vDV0:DWORD)
  METHOD(MinimizeAll,      _this:LPVOID)
  METHOD(UndoMinimizeALL,  _this:LPVOID)
  METHOD(FileRun,          _this:LPVOID)
  METHOD(CascadeWindows,   _this:LPVOID)
  METHOD(TileVertically,   _this:LPVOID)
  METHOD(TileHorizontally, _this:LPVOID)
  METHOD(ShutdownWindows,  _this:LPVOID)
  METHOD(Suspend,          _this:LPVOID)
  METHOD(EjectPC,          _this:LPVOID)
  METHOD(SetTime,          _this:LPVOID)
  METHOD(TrayProperties,   _this:LPVOID)
  METHOD(Help,             _this:LPVOID)
  METHOD(FindFiles,        _this:LPVOID)
  METHOD(FindComputer,     _this:LPVOID)
  METHOD(RefreshMenu,      _this:LPVOID)
  METHOD(ControlPanelItem, _this:LPVOID,bstrDir:LPVOID)
IShellDispatch ENDS


when you call the IShellDispatch::NameSpace method, it returns a "folder object".
the folder object is another IDispatch interface - from which we can call the CopyHere method

;IShellDispatch::NameSpace Folder object interface vTable (structure)
;   vItem VARIANT struct = vtItem:DWORD,vI0:DWORD,vdwItem:DWORD,vIV0:DWORD
;vOptions VARIANT struct = vtOpt:DWORD,vO0:DWORD,vdwOpt:LPVOID,vOV0:DWORD

Folder STRUCT
    IDispatch            <>
  METHOD(getTitle,     _this:LPVOID,pbs:LPVOID)
  METHOD(Application,  _this:LPVOID,ppid:LPVOID)
  METHOD(Parent,       _this:LPVOID,ppid:LPVOID)
  METHOD(ParentFolder, _this:LPVOID,ppsf:LPVOID)
  METHOD(Items,        _this:LPVOID,ppid:LPVOID)
  METHOD(ParseName,    _this:LPVOID,bstrName:LPVOID,ppid:LPVOID)
  METHOD(NewFolder,    _this:LPVOID,bstrName:LPVOID,vtOpt:DWORD,vO0:DWORD,vdwOpt:LPVOID,vOV0:DWORD)
  METHOD(MoveHere,     _this:LPVOID,vtItem:DWORD,vI0:DWORD,vdwItem:DWORD,vIV0:DWORD,vtOpt:DWORD,vO0:DWORD,vdwOpt:LPVOID,vOV0:DWORD)
  METHOD(CopyHere,     _this:LPVOID,vtItem:DWORD,vI0:DWORD,vdwItem:DWORD,vIV0:DWORD,vtOpt:DWORD,vO0:DWORD,vdwOpt:LPVOID,vOV0:DWORD)
  METHOD(GetDetailsOf, _this:LPVOID,vtItem:DWORD,vI0:DWORD,vdwItem:DWORD,vIV0:DWORD,iColumn:DWORD,pbs:LPVOID)
Folder ENDS


now that we have proper vTable definitions, we just need a little work with VARIANT structures,
and, of course, a way to know when it's done zipping   :t

i was having a hard time figuring out how to call the NameSpace and CopyHere methods
now that i have those figured out, things should get a little easier   :biggrin:

EDIT: updated IShellDispatch and Folder vTable structures to allow VARIANT's as DWORD's
EDIT: modified "Title" to "getTitle" in Folder vTable to avoid use of reserved keyword
modified "Title" to "lpTitle" in IShellDispatch, BrowseForFolder arguments - same reason

dedndave

reports all over the web say that "CopyHere options don't work"
probably because they are passing the flags directly as an integer
it's a pointer to a VT_I4 VARIANT structure   :biggrin: