www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - (help) automation on windows

reply "Carlos Santander B." <csantander619 gmail.com> writes:
I fond some reference on how to do late binding and automation (it's 
cool when you know the right terms... at least I hope they're right...), 
so I have this D code right now:

//----------------------------------------
void main()
{
     wchar * prog="InternetExplorer.Application";
     wchar * member="Visible";

     LCID defaultLCID = GetUserDefaultLCID();

     HRESULT hr = CoInitialize(null);
     printf("1:%d\n",hr);

     CLSID bu;
     hr=CLSIDFromProgID(prog, &bu);
     printf("2:%d\n",hr);

     IDispatch* pIDispatch;
     hr = CoCreateInstance(&bu, null, CLSCTX_SERVER, &IID_IDispatch,cast 
(void**)&pIDispatch);
     printf("3:%d\n",hr);

     DISPID dispid;
     hr = pIDispatch.GetIDsOfNames(cast(REFIID) &IID_NULL, &member, 1, 
defaultLCID, &dispid);
     printf("4:%d\n",hr);

     VARIANTARG myArg;
     myArg.n1.n2.vt = VT_I4|VT_BYREF;
     myArg.n1.n2.n3.lVal = 1;

     DISPPARAMS param;
     param.cArgs=1;
     param.rgvarg=&myArg;

     VARIANT * result=new VARIANT;

     hr = pIDispatch.Invoke(dispid, cast(REFIID) &IID_NULL, defaultLCID, 
DISPATCH_METHOD,
         &param, result, null, null);
     printf("5:%d\n",hr);

     //Sleep(2000);

     CoUninitialize();
}
//----------------------------------------

The idea is to do something like (pseudo-code):

app=new InternetExplorer.Application();
app.Visible=1; //or app.Visible(1), I don't know

But the call to GetIDsOfNames (between printfs 3 and 4) produces an 
access violation. Any ideas?

The C++ version does a bit better: the Invoke call returns -2147024809, 
whatever that means.

(BTW, I'm using the core32 library for all that IDispatch stuff, even if 
the one I have is a bit outdated)

_______________________
Carlos Santander Bernal
Mar 09 2005
parent reply "John C" <johnch_atms hotmail.com> writes:
"Carlos Santander B." <csantander619 gmail.com> wrote in message 
news:d0nuj0$eds$1 digitaldaemon.com...
I fond some reference on how to do late binding and automation (it's cool 
when you know the right terms... at least I hope they're right...), so I 
have this D code right now:

 //----------------------------------------
 void main()
 {
     wchar * prog="InternetExplorer.Application";
     wchar * member="Visible";

     LCID defaultLCID = GetUserDefaultLCID();

     HRESULT hr = CoInitialize(null);
     printf("1:%d\n",hr);

     CLSID bu;
     hr=CLSIDFromProgID(prog, &bu);
     printf("2:%d\n",hr);

     IDispatch* pIDispatch;
     hr = CoCreateInstance(&bu, null, CLSCTX_SERVER, &IID_IDispatch,cast 
 (void**)&pIDispatch);
     printf("3:%d\n",hr);

     DISPID dispid;
     hr = pIDispatch.GetIDsOfNames(cast(REFIID) &IID_NULL, &member, 1, 
 defaultLCID, &dispid);
     printf("4:%d\n",hr);

If you create a WebBrowser object instead, with IID_IWebBrowser2, you should be able to directly call put_Visible(VARIANT_TRUE).
     VARIANTARG myArg;
     myArg.n1.n2.vt = VT_I4|VT_BYREF;
     myArg.n1.n2.n3.lVal = 1;

     DISPPARAMS param;
     param.cArgs=1;
     param.rgvarg=&myArg;

     VARIANT * result=new VARIANT;

     hr = pIDispatch.Invoke(dispid, cast(REFIID) &IID_NULL, defaultLCID, 
 DISPATCH_METHOD,
         &param, result, null, null);
     printf("5:%d\n",hr);

     //Sleep(2000);

     CoUninitialize();
 }
 //----------------------------------------

 The idea is to do something like (pseudo-code):

 app=new InternetExplorer.Application();
 app.Visible=1; //or app.Visible(1), I don't know

 But the call to GetIDsOfNames (between printfs 3 and 4) produces an access 
 violation. Any ideas?

 The C++ version does a bit better: the Invoke call returns -2147024809, 
 whatever that means.

 (BTW, I'm using the core32 library for all that IDispatch stuff, even if 
 the one I have is a bit outdated)

 _______________________
 Carlos Santander Bernal 

Mar 09 2005
parent reply "Carlos Santander B." <csantander619 gmail.com> writes:
John C wrote:
 
 
 If you create a WebBrowser object instead, with IID_IWebBrowser2, you should 
 be able to directly call put_Visible(VARIANT_TRUE).
 
 

I guess I should've said that: it's supposed to be like that. I mean, if later I want to replace "InternetExplorer.Application" with something else, that's all I should change, without having to worry about GUIDs. Same for "Visible". The goal is late binding. But thanks, though. _______________________ Carlos Santander Bernal
Mar 09 2005
parent reply "John C" <johnch_atms hotmail.com> writes:
"Carlos Santander B." <csantander619 gmail.com> wrote in message 
news:d0o2ht$i82$1 digitaldaemon.com...
 John C wrote:
 If you create a WebBrowser object instead, with IID_IWebBrowser2, you 
 should be able to directly call put_Visible(VARIANT_TRUE).

I guess I should've said that: it's supposed to be like that. I mean, if later I want to replace "InternetExplorer.Application" with something else, that's all I should change, without having to worry about GUIDs. Same for "Visible". The goal is late binding. But thanks, though. _______________________ Carlos Santander Bernal

Could this line be the source of the problem? IDispatch* pIDispatch; Change it to IDispatch pIDispatch; It worked for me. By the way, when you call Invoke, try using "DISPATCH_PROPERTYPUT" instead of "DISPATCH_METHOD". Hope this helps.
Mar 09 2005
parent reply "Carlos Santander B." <csantander619 gmail.com> writes:
John C wrote:
 
 Could this line be the source of the problem?
 
     IDispatch* pIDispatch;
 
 Change it to
 
     IDispatch pIDispatch;
 
 It worked for me. By the way, when you call Invoke, try using 
 "DISPATCH_PROPERTYPUT" instead of "DISPATCH_METHOD".
 
 Hope this helps. 
 
 

Thanks, that worked. Partially. "Invoke" returns -1073741819. It doesn't matter if I use DISPATCH_METHOD or DISPATCH_PROPERTYPUT. Regarding that, is there a way to know (automagically, programmatically) when to use DISPATCH_PROPERTYPUT, DISPATCH_METHOD, DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUTREF? Maybe by the result of calling GetIDsOfNames? _______________________ Carlos Santander Bernal
Mar 09 2005
parent reply "John C" <johnch_atms hotmail.com> writes:
"Carlos Santander B." <csantander619 gmail.com> wrote in message 
news:d0o9va$pgh$1 digitaldaemon.com...
 John C wrote:
 Could this line be the source of the problem?

     IDispatch* pIDispatch;

 Change it to

     IDispatch pIDispatch;

 It worked for me. By the way, when you call Invoke, try using 
 "DISPATCH_PROPERTYPUT" instead of "DISPATCH_METHOD".

 Hope this helps.

Thanks, that worked. Partially. "Invoke" returns -1073741819. It doesn't matter if I use DISPATCH_METHOD or DISPATCH_PROPERTYPUT. Regarding that, is there a way to know (automagically, programmatically) when to use DISPATCH_PROPERTYPUT, DISPATCH_METHOD, DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUTREF? Maybe by the result of calling GetIDsOfNames?

Conveniently, IDispatch has a GetTypeInfo method that returns an ITypeInfo interface. ITypeInfo::GetFuncDesc returns a FUNCDESC structure containing an INVOKEKIND enumeration, which is defined as follows: typedef enum tagINVOKEKIND { INVOKE_FUNC = DISPATCH_METHOD, INVOKE_PROPERTYGET = DISPATCH_PROPERTYGET, INVOKE_PROPERTYPUT = DISPATCH_PROPERTYPUT, INVOKE_PROPERTYPUTREF = DISPATCH_PROPERTYPUTREF } INVOKEKIND; That looks like what you need. Or you could try calling Invoke() with each flag in turn until you get S_OK. If you don't get S_OK after trying all flags, then throw an exception saying the method or property doesn't exist. I think this how scripting languages do late binding for automation objects. By the way, MSDN says "when you use IDispatch::Invoke() with DISPATCH_PROPERTYPUT you have to specially initialize the cNamedArgs and rgdispidNamedArgs elements of your DISPPARAMS structure with the following: DISPID dispidNamed = DISPID_PROPERTYPUT; dispparams.cNamedArgs = 1; dispparams.rgdispidNamedArgs = &dispidNamed;" I found an example on Microsoft's support site (it's for Excel, but you can adapt it for other automation objects): http://support.microsoft.com/kb/181473/EN-US/
 _______________________
 Carlos Santander Bernal 

Mar 10 2005
parent reply "Carlos Santander B." <csantander619 gmail.com> writes:
John C wrote:
 
 Conveniently, IDispatch has a GetTypeInfo method that returns an ITypeInfo 
 interface. ITypeInfo::GetFuncDesc returns a FUNCDESC structure containing an 
 INVOKEKIND enumeration, which is defined as follows:
 
     typedef enum tagINVOKEKIND {
        INVOKE_FUNC = DISPATCH_METHOD,
        INVOKE_PROPERTYGET = DISPATCH_PROPERTYGET,
        INVOKE_PROPERTYPUT = DISPATCH_PROPERTYPUT,
        INVOKE_PROPERTYPUTREF = DISPATCH_PROPERTYPUTREF
     } INVOKEKIND;
 
 That looks like what you need.
 
 Or you could try calling Invoke() with each flag in turn until you get S_OK. 
 If you don't get S_OK after trying all flags, then throw an exception saying 
 the method or property doesn't exist. I think this how scripting languages 
 do late binding for automation objects.
 
 By the way, MSDN says "when you use IDispatch::Invoke() with 
 DISPATCH_PROPERTYPUT you have to specially initialize the cNamedArgs and 
 rgdispidNamedArgs elements of your DISPPARAMS structure with the following:
 
     DISPID dispidNamed = DISPID_PROPERTYPUT;
     dispparams.cNamedArgs = 1;
     dispparams.rgdispidNamedArgs = &dispidNamed;"
 
 I found an example on Microsoft's support site (it's for Excel, but you can 
 adapt it for other automation objects): 
 http://support.microsoft.com/kb/181473/EN-US/
 
 
_______________________
Carlos Santander Bernal 


It works! Thanks, again! _______________________ Carlos Santander Bernal
Mar 10 2005
parent reply "Carlos Santander B." <csantander619 gmail.com> writes:
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 digitalmars.D/18805, I hope the URL is ok): //---------------------------------------------------------------- AXO ie=new AXO("InternetExplorer.Application"); try { VARIANTARG a1, a2, a3, a4; a1.n1.n2.vt=20; a2.n1.n2.vt=6008; a3.n1.n2.vt=0; a4.n1.n2.vt=17; VARIANTARG myArg; myArg.n1.n2.vt = VT_BSTR; myArg.n1.n2.n3.bstrVal = "about:blank"; ie.call("Navigate",a4,a3,a2,a1,myArg); myArg.n1.n2.vt = VT_UI4; myArg.n1.n2.n3.lVal = 850; ie.set("Width",myArg); myArg.n1.n2.n3.lVal = 710; ie.set("Height",myArg); myArg.n1.n2.n3.lVal = 10; ie.set("Top",myArg); myArg.n1.n2.n3.lVal = 10; ie.set("Left",myArg); myArg.n1.n2.vt = VT_BOOL; myArg.n1.n2.n3.boolVal = 0; ie.set("ToolBar",myArg); ie.set("MenuBar",myArg); ie.set("StatusBar",myArg); myArg.n1.n2.n3.boolVal = 1; ie.set("Visible",myArg); VARIANT tmp = ie.get("Visible"); bool isVisible = cast(bool) tmp.n1.n2.n3.boolVal; } finally ie.call("Quit"); //---------------------------------------------------------------- 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. So, again, some help would be nice. _______________________ Carlos Santander Bernal
Mar 11 2005
next sibling parent reply "John C" <johnch_atms hotmail.com> writes:
"Carlos Santander B." <csantander619 gmail.com> wrote in message 
news:d0tjun$15ie$1 digitaldaemon.com...
 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 digitalmars.D/18805, I hope the URL is ok): //---------------------------------------------------------------- AXO ie=new AXO("InternetExplorer.Application"); try { VARIANTARG a1, a2, a3, a4; a1.n1.n2.vt=20; a2.n1.n2.vt=6008; a3.n1.n2.vt=0; a4.n1.n2.vt=17; VARIANTARG myArg; myArg.n1.n2.vt = VT_BSTR; myArg.n1.n2.n3.bstrVal = "about:blank"; ie.call("Navigate",a4,a3,a2,a1,myArg); myArg.n1.n2.vt = VT_UI4; myArg.n1.n2.n3.lVal = 850; ie.set("Width",myArg); myArg.n1.n2.n3.lVal = 710; ie.set("Height",myArg); myArg.n1.n2.n3.lVal = 10; ie.set("Top",myArg); myArg.n1.n2.n3.lVal = 10; ie.set("Left",myArg); myArg.n1.n2.vt = VT_BOOL; myArg.n1.n2.n3.boolVal = 0; ie.set("ToolBar",myArg); ie.set("MenuBar",myArg); ie.set("StatusBar",myArg); myArg.n1.n2.n3.boolVal = 1; ie.set("Visible",myArg); VARIANT tmp = ie.get("Visible"); bool isVisible = cast(bool) tmp.n1.n2.n3.boolVal; } finally ie.call("Quit"); //---------------------------------------------------------------- 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. So, again, some help would be nice.

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.) 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.
 _______________________
 Carlos Santander Bernal 

Mar 12 2005
parent reply "Carlos Santander B." <csantander619 gmail.com> writes:
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
Mar 12 2005
parent reply "John C" <johnch_atms hotmail.com> writes:
"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.
Mar 13 2005
next sibling parent reply "Carlos Santander B." <csantander619 gmail.com> writes:
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
Mar 13 2005
parent reply "John C" <johnch_atms hotmail.com> writes:
"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).
Mar 13 2005
parent =?iso-8859-1?Q?Robert_M=2E_M=FCnch?= <robert.muench robertmuench.de> writes:
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
Apr 07 2005
prev sibling parent jicman <jicman_member pathlink.com> writes:
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.

Mar 13 2005
prev sibling next sibling parent reply jicman <jicman_member pathlink.com> writes:
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é


Carlos Santander B. says...
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 digitalmars.D/18805, I hope the URL is ok): //---------------------------------------------------------------- AXO ie=new AXO("InternetExplorer.Application"); try { VARIANTARG a1, a2, a3, a4; a1.n1.n2.vt=20; a2.n1.n2.vt=6008; a3.n1.n2.vt=0; a4.n1.n2.vt=17; VARIANTARG myArg; myArg.n1.n2.vt = VT_BSTR; myArg.n1.n2.n3.bstrVal = "about:blank"; ie.call("Navigate",a4,a3,a2,a1,myArg); myArg.n1.n2.vt = VT_UI4; myArg.n1.n2.n3.lVal = 850; ie.set("Width",myArg); myArg.n1.n2.n3.lVal = 710; ie.set("Height",myArg); myArg.n1.n2.n3.lVal = 10; ie.set("Top",myArg); myArg.n1.n2.n3.lVal = 10; ie.set("Left",myArg); myArg.n1.n2.vt = VT_BOOL; myArg.n1.n2.n3.boolVal = 0; ie.set("ToolBar",myArg); ie.set("MenuBar",myArg); ie.set("StatusBar",myArg); myArg.n1.n2.n3.boolVal = 1; ie.set("Visible",myArg); VARIANT tmp = ie.get("Visible"); bool isVisible = cast(bool) tmp.n1.n2.n3.boolVal; } finally ie.call("Quit"); //---------------------------------------------------------------- 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. So, again, some help would be nice. _______________________ Carlos Santander Bernal

Mar 12 2005
parent reply "Carlos Santander B." <csantander619 gmail.com> writes:
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
Mar 12 2005
parent Petr <nainkaaa mail.ru> writes:
Deleaker ( http://deleaker.com/ ) is the best tool for memory leaks detection
and localization in C++
Apr 19 2010
prev sibling parent reply J C Calvarese <jcc7 cox.net> writes:
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 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/
Mar 12 2005
next sibling parent "Carlos Santander B." <csantander619 gmail.com> writes:
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
Mar 12 2005
prev sibling parent jicman <jicman_member pathlink.com> writes:
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 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/

Mar 13 2005