March 13, 2005
Carlos Santander B. wrote:
> Carlos Santander B. wrote:
> 
>>
>> It works! Thanks, again!
>>
> 
> (progress update and another request for help)
> 
> PROPERTYGET and PROPERTYPUT work. PROPERTYPUTREF, I don't know, because I haven't tried and I don't know how to try. METHOD without parameters also works. With parameters, however, it's not as good.
> 
> So far, this code works (adapted from Justin's code in http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/18805, I hope the URL is ok):

Not that I should receive any credit for the code which I blantantly ripped off of jicman. ;)

...

> Works, except for the Navigate call. Going through the parameters I found their VARTYPEs, so that's why I set them, but I have no idea what they should receive. Also, I'm aware some methods are optional (Navigate has 4, I assume the only required is the URL), but only passing one doesn't work either.

I'm hoping John C's observations are helpful because I don't have any ideas.

I would like to congratulate you, though. It looks to me like you'd figured out the truly hard part and only the nagging details remain. Good job!

-- 
Justin (a/k/a jcc7)
http://jcc_7.tripod.com/d/
March 13, 2005
J C Calvarese wrote:
> 
> 
> I'm hoping John C's observations are helpful because I don't have any ideas.
> 
> I would like to congratulate you, though. It looks to me like you'd figured out the truly hard part and only the nagging details remain. Good job!
> 

Thanks. "The key is in the details" (or is the problem, or the issue?)

_______________________
Carlos Santander Bernal
March 13, 2005
John C wrote:
> 
> Documentation on this stuff is sparse (as you've no doubt gathered). But if I remember correctly, the parameters for Navigate() are as follows:
> 
>     url [VT_BSTR, bstrVal]
>     flags [VT_UI4, lVal (see BrowserNavConstants)]
>     targetFrameName [VT_BSTR, bstrVal]
>     postData [VT_ARRAY | VT_VARIANT of VT_UI1, parray]
>     headers [VT_BSTR, bstrVal]
>     cancel [VT_BOOL | VT_BYREF, pboolVal]
> 
> (Note that "cancel" isn't available as a parameter in early binding.)

Thanks. I'll try that to see how it goes. The problem (still) is being generic: I'm just trying with IE, but I want it to be 100% functional with any ActiveX object.

> 
> Without seeing the code behind your set() methods, it's difficult to know why it's failing. Your rgvarg array's elements have to be in reverse order, but I think you're doing that anyway.
> 
> 

set() isn't the problem. call() is:

    VARIANT call(char [] member,...)
    {
        INVOKEKIND ik=INVOKE_FUNC;
        DISPID dispid = findMember(member,ik);

        if (!(dispid in methods))
            throw new Exception("can only call methods");

        VARIANTARG [] myArgs = makeArray(_arguments,_argptr);

        DISPPARAMS param;
        param.cArgs=myArgs.length;
        param.rgvarg=myArgs.ptr;

        VARIANT result;
        HRESULT hr = pIDispatch.Invoke(dispid, cast(REFIID) &IID_NULL, defaultLCID, ik, &param, &result, null, null);
        return result;
    }

and makeArray() is:

    VARIANTARG [] makeArray(TypeInfo [] args, void* ptr)
    {
        VARIANTARG [] array;
        array.length = args.length;

        for (uint i;i<args.length;++i)
        {
            if (args[i] == typeid(VARIANTARG))
                array [i] = va_arg!(VARIANTARG)(ptr);
            else
                throw new Exception( "Expected arguments of type VARIANTARG" );
        }

        return array;
    }

The problem seems to be after the findMember() call, because calling Quit (no parameters) works fine.

_______________________
Carlos Santander Bernal
March 13, 2005
jicman wrote:
> Carlos,
> 
> I am very interested in this project.  Here is a JScript program that does a lot
> with COMs.  It uses IE, Excel and MySQL COM calls.  I wish I can help you more
> but I am out of the country on business.  I will keep on watching the posts on
> this subject.  Thanks.
> 
> josé
> 
> 

Thanks, I think that could work as a test case.

_______________________
Carlos Santander Bernal
March 13, 2005
J C Calvarese says...
>
>Carlos Santander B. wrote:
>> Carlos Santander B. wrote:
>> 
>>>
>>> It works! Thanks, again!
>>>
>> 
>> (progress update and another request for help)
>> 
>> PROPERTYGET and PROPERTYPUT work. PROPERTYPUTREF, I don't know, because I haven't tried and I don't know how to try. METHOD without parameters also works. With parameters, however, it's not as good.
>> 
>> So far, this code works (adapted from Justin's code in http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/18805, I hope the URL is ok):
>
>Not that I should receive any credit for the code which I blantantly ripped off of jicman. ;)

Which I, purposely, grab from a Microsoft site.  Though, I did have to suffer translating it to JScript, since it was VBScript!  But, code it's never stolen. Just copied and pasted. ja ja ja ja (That's me, laughing in Spanish!  By the way, it sounds just like ha ha ha ha.  For you see, in Spanish, the j sounds like an h. Ja ja ja ja ja)


>> Works, except for the Navigate call. Going through the parameters I found their VARTYPEs, so that's why I set them, but I have no idea what they should receive. Also, I'm aware some methods are optional (Navigate has 4, I assume the only required is the URL), but only passing one doesn't work either.
>
>I'm hoping John C's observations are helpful because I don't have any ideas.
>
>I would like to congratulate you, though. It looks to me like you'd figured out the truly hard part and only the nagging details remain. Good job!
>
>-- 
>Justin (a/k/a jcc7)
>http://jcc_7.tripod.com/d/


March 13, 2005
"Carlos Santander B." <csantander619@gmail.com> wrote in message news:d10aai$12dk$1@digitaldaemon.com...
> John C wrote:
>>
>> Documentation on this stuff is sparse (as you've no doubt gathered). But if I remember correctly, the parameters for Navigate() are as follows:
>>
>>     url [VT_BSTR, bstrVal]
>>     flags [VT_UI4, lVal (see BrowserNavConstants)]
>>     targetFrameName [VT_BSTR, bstrVal]
>>     postData [VT_ARRAY | VT_VARIANT of VT_UI1, parray]
>>     headers [VT_BSTR, bstrVal]
>>     cancel [VT_BOOL | VT_BYREF, pboolVal]
>>
>> (Note that "cancel" isn't available as a parameter in early binding.)
>
> Thanks. I'll try that to see how it goes. The problem (still) is being generic: I'm just trying with IE, but I want it to be 100% functional with any ActiveX object.
>
>>
>> Without seeing the code behind your set() methods, it's difficult to know why it's failing. Your rgvarg array's elements have to be in reverse order, but I think you're doing that anyway.
>>
>>
>
> set() isn't the problem. call() is:
>
>     VARIANT call(char [] member,...)
>     {
>         INVOKEKIND ik=INVOKE_FUNC;
>         DISPID dispid = findMember(member,ik);
>
>         if (!(dispid in methods))
>             throw new Exception("can only call methods");
>
>         VARIANTARG [] myArgs = makeArray(_arguments,_argptr);
>
>         DISPPARAMS param;
>         param.cArgs=myArgs.length;
>         param.rgvarg=myArgs.ptr;
>
>         VARIANT result;
>         HRESULT hr = pIDispatch.Invoke(dispid, cast(REFIID) &IID_NULL,
> defaultLCID, ik, &param, &result, null, null);
>         return result;
>     }
>
> and makeArray() is:
>
>     VARIANTARG [] makeArray(TypeInfo [] args, void* ptr)
>     {
>         VARIANTARG [] array;
>         array.length = args.length;
>
>         for (uint i;i<args.length;++i)
>         {
>             if (args[i] == typeid(VARIANTARG))
>                 array [i] = va_arg!(VARIANTARG)(ptr);
>             else
>                 throw new Exception( "Expected arguments of type
> VARIANTARG" );
>         }
>
>         return array;
>     }
>
> The problem seems to be after the findMember() call, because calling Quit (no parameters) works fine.

After a fair amount of trial and error, I've got it working.

    /*------------------------ activex.d -------------------------*/

    module test.activex;

    private import std.stdarg;

    static this() {
        CoInitialize(null);
    }

    static ~this() {
        CoUninitialize();
    }

    public class ActiveXObject {

        private IDispatch disp_;

        public this(char[] progId) {
            CLSID clsid;
            CLSIDFromProgID(toUTF16z(progId), &clsid);
            CoCreateInstance(&clsid, null, CLSCTX_SERVER, &IID_IDispatch,
(void**)&_disp);
        }

        public VARIANT call(char[] member, ...) {
            DISPID memberId = findMember(member);

            VARIANT[] args = makeArray(_arguments, _argptr);
            DISPPARAMS params;
            params.rgvarg = agrs.ptr;
            params.cArgs = args.length;

            VARIANT result;
            disp_.Invoke(memberId, &IID_NULL, GetUserDefaultLCID(),
DISPATCH_METHOD, &params, &result, null, null);
            return result;
        }

        public void set(wchar[] member, VARIANT value) // omitted
        public VARIANT get(wchar[] member) // omitted

        private DISPID findMember(char[] member) {
            // Simplified version
            wchar* pszMember = toUTF16z(member);
            DISPID dispidResult;
            disp_.GetIDsOfNames(&IID_NULL, &pszMember, 1,
GetUserDefaultLCID(), &dispidResult);
            return dispidResult;
        }

        private VARIANT[] makeArray(TypeInfo[] argTypes, void* ptr) {
            int argsLength = argTypes.length;
            VARIANT[] args;
            foreach (TypeInfo argType; argTypes) {
                if (argType == typeid(VARIANT))
                    args ~= va_arg!(VARIANT)(ptr);
            }
            return args;
        }

    }

    /*-------------------------- test.d -------------------------*/

    module test.app;

    private import test.activex;

    int main() {
        ActiveXObject axObject= new
ActiveXObject("InternetExplorer.Application");

        VARIANT variantTrue;
        variantTrue.vt = VT_BOOL;
        variantTrue.boolVal = -1; // VARIANT_TRUE

        VARIANT variantFalse;
        variantFalse.vt = VT_BOOL;
        variantFalse.boolVal = 0; // VARIANT_FALSE

        axObject.set("ToolBar", variantFalse);
        axObject.set("Visible", variantTrue);

        VARIANT url;
        url.vt = VT_BSTR;
        // Must call SysAllocString() to allocate a BSTR
        url.bstrVal = SysAllocString("about:blank");

        axObject.call("Navigate", VARIANT.init, VARIANT.init, VARIANT.init,
VARIANT.init, url);

        // Now free the BSTR
        SysFreeString(url.bstrVal);

        return 0;
    }


I can't see that you're doing anything radically different, apart from using the wrong value for VARIANT_TRUE and not allocating your BSTRs with SysAllocString(). If you're still having problems after trying it, let me know and I'll send you my source files.

Good luck.


March 13, 2005
John C wrote:
> 
>     /*------------------------ activex.d -------------------------*/
> 
>     module test.activex;
> 
>     private import std.stdarg;
> 
>     static this() {
>         CoInitialize(null);
>     }
> 
>     static ~this() {
>         CoUninitialize();
>     }
> 
>     public class ActiveXObject {
> 
>         private IDispatch disp_;
> 
>         public this(char[] progId) {
>             CLSID clsid;
>             CLSIDFromProgID(toUTF16z(progId), &clsid);
>             CoCreateInstance(&clsid, null, CLSCTX_SERVER, &IID_IDispatch, (void**)&_disp);
>         }
> 
>         public VARIANT call(char[] member, ...) {
>             DISPID memberId = findMember(member);
> 
>             VARIANT[] args = makeArray(_arguments, _argptr);
>             DISPPARAMS params;
>             params.rgvarg = agrs.ptr;
>             params.cArgs = args.length;
> 
>             VARIANT result;
>             disp_.Invoke(memberId, &IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, &params, &result, null, null);
>             return result;
>         }
> 
>         public void set(wchar[] member, VARIANT value) // omitted
>         public VARIANT get(wchar[] member) // omitted
> 
>         private DISPID findMember(char[] member) {
>             // Simplified version
>             wchar* pszMember = toUTF16z(member);
>             DISPID dispidResult;
>             disp_.GetIDsOfNames(&IID_NULL, &pszMember, 1, GetUserDefaultLCID(), &dispidResult);
>             return dispidResult;
>         }
> 
>         private VARIANT[] makeArray(TypeInfo[] argTypes, void* ptr) {
>             int argsLength = argTypes.length;
>             VARIANT[] args;
>             foreach (TypeInfo argType; argTypes) {
>                 if (argType == typeid(VARIANT))
>                     args ~= va_arg!(VARIANT)(ptr);
>             }
>             return args;
>         }
> 
>     }
> 
>     /*-------------------------- test.d -------------------------*/
> 
>     module test.app;
> 
>     private import test.activex;
> 
>     int main() {
>         ActiveXObject axObject= new ActiveXObject("InternetExplorer.Application");
> 
>         VARIANT variantTrue;
>         variantTrue.vt = VT_BOOL;
>         variantTrue.boolVal = -1; // VARIANT_TRUE
> 
>         VARIANT variantFalse;
>         variantFalse.vt = VT_BOOL;
>         variantFalse.boolVal = 0; // VARIANT_FALSE
> 
>         axObject.set("ToolBar", variantFalse);
>         axObject.set("Visible", variantTrue);
> 
>         VARIANT url;
>         url.vt = VT_BSTR;
>         // Must call SysAllocString() to allocate a BSTR
>         url.bstrVal = SysAllocString("about:blank");
> 
>         axObject.call("Navigate", VARIANT.init, VARIANT.init, VARIANT.init, VARIANT.init, url);
> 
>         // Now free the BSTR
>         SysFreeString(url.bstrVal);
> 
>         return 0;
>     }
> 
> 
> I can't see that you're doing anything radically different, apart from using the wrong value for VARIANT_TRUE and not allocating your BSTRs with SysAllocString(). If you're still having problems after trying it, let me know and I'll send you my source files.
> 
> Good luck. 
> 
> 

SysAllocString did the trick. Thanks! Uh, and using 1 instead of -1 does work. But thanks again!

It's funny that your activex module is basically identical to what I have.

_______________________
Carlos Santander Bernal
March 13, 2005
"Carlos Santander B." <csantander619@gmail.com> wrote in message news:d11n8k$2cd2$1@digitaldaemon.com...
>
> SysAllocString did the trick. Thanks! Uh, and using 1 instead of -1 does work. But thanks again!
>
> It's funny that your activex module is basically identical to what I have.
>

And by clever use of subclassing, the syntax you proposed in your initial post is almost possible:

    public final abstract class InternetExplorer {
        public final class Application : ActiveXObject {
            public this() {
                super("InternetExplorer.Application");
            }
        }
    }

    public final abstract class Excel {
        public final class Application : ActiveXObject {
            public this() {
                super("Excel.Application");
            }
        }
    }

    ActiveXObject ieObject = new InternetExplorer.Application;
    ActiveXObject excelObject = new Excel.Application;

Just make the ActiveXObject class abstract and its constructor protected, and you've got a fairly safe idiom to guard users from creating invalid objects ("Notepad.Application" etc, which doesn't exist).


March 13, 2005
Will you zip these files and post them again?  Sorry and thanks.

jic

John C says...
>
>"Carlos Santander B." <csantander619@gmail.com> wrote in message news:d10aai$12dk$1@digitaldaemon.com...
>> John C wrote:
>>>
>>> Documentation on this stuff is sparse (as you've no doubt gathered). But if I remember correctly, the parameters for Navigate() are as follows:
>>>
>>>     url [VT_BSTR, bstrVal]
>>>     flags [VT_UI4, lVal (see BrowserNavConstants)]
>>>     targetFrameName [VT_BSTR, bstrVal]
>>>     postData [VT_ARRAY | VT_VARIANT of VT_UI1, parray]
>>>     headers [VT_BSTR, bstrVal]
>>>     cancel [VT_BOOL | VT_BYREF, pboolVal]
>>>
>>> (Note that "cancel" isn't available as a parameter in early binding.)
>>
>> Thanks. I'll try that to see how it goes. The problem (still) is being generic: I'm just trying with IE, but I want it to be 100% functional with any ActiveX object.
>>
>>>
>>> Without seeing the code behind your set() methods, it's difficult to know why it's failing. Your rgvarg array's elements have to be in reverse order, but I think you're doing that anyway.
>>>
>>>
>>
>> set() isn't the problem. call() is:
>>
>>     VARIANT call(char [] member,...)
>>     {
>>         INVOKEKIND ik=INVOKE_FUNC;
>>         DISPID dispid = findMember(member,ik);
>>
>>         if (!(dispid in methods))
>>             throw new Exception("can only call methods");
>>
>>         VARIANTARG [] myArgs = makeArray(_arguments,_argptr);
>>
>>         DISPPARAMS param;
>>         param.cArgs=myArgs.length;
>>         param.rgvarg=myArgs.ptr;
>>
>>         VARIANT result;
>>         HRESULT hr = pIDispatch.Invoke(dispid, cast(REFIID) &IID_NULL,
>> defaultLCID, ik, &param, &result, null, null);
>>         return result;
>>     }
>>
>> and makeArray() is:
>>
>>     VARIANTARG [] makeArray(TypeInfo [] args, void* ptr)
>>     {
>>         VARIANTARG [] array;
>>         array.length = args.length;
>>
>>         for (uint i;i<args.length;++i)
>>         {
>>             if (args[i] == typeid(VARIANTARG))
>>                 array [i] = va_arg!(VARIANTARG)(ptr);
>>             else
>>                 throw new Exception( "Expected arguments of type
>> VARIANTARG" );
>>         }
>>
>>         return array;
>>     }
>>
>> The problem seems to be after the findMember() call, because calling Quit (no parameters) works fine.
>
>After a fair amount of trial and error, I've got it working.
>
>    /*------------------------ activex.d -------------------------*/
>
>    module test.activex;
>
>    private import std.stdarg;
>
>    static this() {
>        CoInitialize(null);
>    }
>
>    static ~this() {
>        CoUninitialize();
>    }
>
>    public class ActiveXObject {
>
>        private IDispatch disp_;
>
>        public this(char[] progId) {
>            CLSID clsid;
>            CLSIDFromProgID(toUTF16z(progId), &clsid);
>            CoCreateInstance(&clsid, null, CLSCTX_SERVER, &IID_IDispatch,
>(void**)&_disp);
>        }
>
>        public VARIANT call(char[] member, ...) {
>            DISPID memberId = findMember(member);
>
>            VARIANT[] args = makeArray(_arguments, _argptr);
>            DISPPARAMS params;
>            params.rgvarg = agrs.ptr;
>            params.cArgs = args.length;
>
>            VARIANT result;
>            disp_.Invoke(memberId, &IID_NULL, GetUserDefaultLCID(),
>DISPATCH_METHOD, &params, &result, null, null);
>            return result;
>        }
>
>        public void set(wchar[] member, VARIANT value) // omitted
>        public VARIANT get(wchar[] member) // omitted
>
>        private DISPID findMember(char[] member) {
>            // Simplified version
>            wchar* pszMember = toUTF16z(member);
>            DISPID dispidResult;
>            disp_.GetIDsOfNames(&IID_NULL, &pszMember, 1,
>GetUserDefaultLCID(), &dispidResult);
>            return dispidResult;
>        }
>
>        private VARIANT[] makeArray(TypeInfo[] argTypes, void* ptr) {
>            int argsLength = argTypes.length;
>            VARIANT[] args;
>            foreach (TypeInfo argType; argTypes) {
>                if (argType == typeid(VARIANT))
>                    args ~= va_arg!(VARIANT)(ptr);
>            }
>            return args;
>        }
>
>    }
>
>    /*-------------------------- test.d -------------------------*/
>
>    module test.app;
>
>    private import test.activex;
>
>    int main() {
>        ActiveXObject axObject= new
>ActiveXObject("InternetExplorer.Application");
>
>        VARIANT variantTrue;
>        variantTrue.vt = VT_BOOL;
>        variantTrue.boolVal = -1; // VARIANT_TRUE
>
>        VARIANT variantFalse;
>        variantFalse.vt = VT_BOOL;
>        variantFalse.boolVal = 0; // VARIANT_FALSE
>
>        axObject.set("ToolBar", variantFalse);
>        axObject.set("Visible", variantTrue);
>
>        VARIANT url;
>        url.vt = VT_BSTR;
>        // Must call SysAllocString() to allocate a BSTR
>        url.bstrVal = SysAllocString("about:blank");
>
>        axObject.call("Navigate", VARIANT.init, VARIANT.init, VARIANT.init,
>VARIANT.init, url);
>
>        // Now free the BSTR
>        SysFreeString(url.bstrVal);
>
>        return 0;
>    }
>
>
>I can't see that you're doing anything radically different, apart from using the wrong value for VARIANT_TRUE and not allocating your BSTRs with SysAllocString(). If you're still having problems after trying it, let me know and I'll send you my source files.
>
>Good luck.
>
>


April 07, 2005
On Sun, 13 Mar 2005 20:38:42 +0100, John C <johnch_atms@hotmail.com> wrote:

> And by clever use of subclassing, the syntax you proposed in your initial post is almost possible:

Hi, I'm just trying to play using D (version 0.120) for COM programming. Can someone please send a complete working example? Or send me a ZIP file? That would be great!! I tried fiddling around with all pieces here but didn't made it yet.

Thanks a lot.

-- 
Robert M. Münch
Management & IT Freelancer
http://www.robertmuench.de