IonicWind Software

Aurora Compiler => Coding Help - Aurora 101 => Topic started by: J B Wood (Zumwalt) on October 20, 2006, 03:10:59 PM

Title: CreateObject?
Post by: J B Wood (Zumwalt) on October 20, 2006, 03:10:59 PM
What is the equal to this in Aurora?
Title: Re: CreateObject
Post by: Ionic Wind Support Team on October 20, 2006, 05:28:07 PM
?  Not much context there to go on dude.

In Aurora you create an object either on the stack or with the NEW statement.  Pretty sure you already knew that though
Title: Re: CreateObject
Post by: J B Wood (Zumwalt) on October 20, 2006, 11:17:45 PM
VB example:

dim myExcel as object
set myExcel = New CreateObject("Excel.Application")


Title: Re: CreateObject
Post by: Ionic Wind Support Team on October 21, 2006, 02:27:47 AM
It is probably a COM object so you would need the interface definition for it.  Jose Roca could help with his type lib browser.
Title: Re: CreateObject
Post by: Parker on October 21, 2006, 11:12:41 AM
That's late binding, which is a lot harder to do when you're actually writing that code. However you can use Aurora's COM, it'll just look different.
Title: Re: CreateObject
Post by: J B Wood (Zumwalt) on October 21, 2006, 12:54:59 PM
Late binding has major advantages, especially when the user can have different versions of the application, for instance one could have office 97, another 200, another 2003, each have there own class enstansiation, if I late bind, I don't care about a specific com dll, I just attach to what is registered.
Title: Re: CreateObject
Post by: Parker on October 21, 2006, 05:50:51 PM
but it's very complicated.
Title: Re: CreateObject
Post by: Mike Stefanik on November 05, 2006, 01:36:55 AM
Omitting all of the defines and structures, here's basically what COM in Aurora looks like if you want to use late-binding. It's example code from a small test project I wrote with a simple COM server that had an "About" method which displayed a message box.

Here's what the Visual Basic code would look like:


Dim o As Object
Set o = New CreateObject("TestControl.TestClass")
o.About


And here's the corresponding Aurora code:


HRESULT hr;

hr = CoInitializeEx(null, COINIT_APARTMENTTHREADED);
if (FAILED(hr))
{
ÂÃ,  ÂÃ,  // Unable to initialize COM subsystem
ÂÃ,  ÂÃ,  return 0;
}

LPOLESTR pwszProgID = OLESTR("TestControl.TestClass");
GUID CLSID_TestClass;
hr = CLSIDFromProgID(pwszProgID, CLSID_TestClass);
if (FAILED(hr))
{
ÂÃ,  ÂÃ,  // Unable to determine class ID
ÂÃ,  ÂÃ,  return 0;
}

LPOLESTR pwszCLSID = NULL;
StringFromCLSID(CLSID_TestClass, &pwszCLSID);
CoTaskMemFree(pwszCLSID);

IUnknown *pUnknown;
hr = CoCreateInstance(CLSID_TestClass, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, &pUnknown);
if (FAILED(hr))
{
ÂÃ,  ÂÃ,  // Unable to create object instance
ÂÃ,  ÂÃ,  return 0;
}

IDispatch *pIDispatch;
hr = pUnknown->QueryInterface(IID_IDispatch, &pIDispatch);
if (FAILED(hr))
{
ÂÃ,  ÂÃ,  // Unable to obtain interface
ÂÃ,  ÂÃ,  return 0;
}

LPOLESTR pwszMethod = OLESTR("About");
DISPID id;
hr = pIDispatch->GetIDsOfNames(IID_NULL, &pwszMethod, 1, LOCALE_USER_DEFAULT, &id);
delete pwszMethod;
if (FAILED(hr))
{
ÂÃ,  ÂÃ,  // Unable to find method in interface
ÂÃ,  ÂÃ,  return 0;
}

DISPPARAMS params;
ZeroMemory(&params, len(DISPPARAMS));

UINT nArgErr;
hr = pIDispatch->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, &nArgErr);
if (FAILED(hr))
{
ÂÃ,  ÂÃ,  // Unable to invoke the method
ÂÃ,  ÂÃ,  return 0;
}

ULONG dwRef;
dwRef = pIDispatch->Release();


Like Parker said, it's complicated. You're basically using COM the same way that you would in C, and even using trivial objects becomes a non-trivial exercise.
Title: Re: CreateObject
Post by: Ionic Wind Support Team on November 05, 2006, 02:34:21 AM
Well you can make it easier.  C++ creates a container class when you use a custom ole control.  That class contains all of the Invoke methods wrapped into class method calls.  Which is doable in Aurora.

You can also use the TypeLib browser (http://www.forum.it-berater.org/index.php?topic=7.0) to generate the interface definitions and use CoCreateInstance to get a pointer to the interface. Saves a lot of typing and the code generated is very useful.

Title: Re: CreateObject
Post by: Mike Stefanik on November 05, 2006, 02:55:55 AM
He specifically mentioned late binding, which means you can't use vtable interfaces; you have to use GetIDsOfNames (getting the dispatch IDs for the methods that you want to call) and then use Invoke. Of course, you could create your own wrapper class that implemented each method, called Invoke, etc. but you're still in for a lot of coding. For the kind of "ease of use" that you have with COM objects in VB, there'd need to be direct support for them in the compiler. In other words, for late binding support to COM objects, the compiler would have to allow the use of class methods that are completely undefined at compile time, and dynamically package up the arguments and call Invoke.

object o = CreateObject("TestControl.TestClass");
o->About();


Upon seeing an undefined method, the compiler would need to blow code like what I have above, rather than generate an error. Of course, if there was no "About" method, then you'd get an error at runtime.
Title: Re: CreateObject
Post by: Ionic Wind Support Team on November 05, 2006, 03:43:18 AM
Or create a little helper class that does the lookup and uses a variable number of parameters in a method named "Call" or something.

CObject o;
o.Create("TestControl.TestClass");
o.Call("About");
o.Call("SetHandle",1, h);

Wouldn't be too hard to implement.  I did something similar using the AtlAxWin class in IBasic.  This is part of the 'Invoke' method for that demo.


SUB InvokeMethod(iFace as IDispatch,name as STRING,numargs as INT,...),VARIANT
POINTER pArgs,pArgs2,pTemp,pStr:pArgs = VA_START(numargs)
UINT puArgErr:puArgErr = 0
INT dispID,x
STRING method,strTemp
POINTER pMethod:pMethod = method
MultiByteToWideChar(0,0,name,-1,method,125)
variant result
DISPPARAMS param
param.rgvarg = NULL
param.cArgs = 0
param.cNamedArgs = 0
param.rgdispidNamedArgs = NULL
SET_INTERFACE iFace,IDispatch
IF iFace->GetIDsOfNames(NULL,&pMethod,1,NULL,dispID)>=0
'create the argument list
IF numargs
pArgs2 = pArgs + (4 * numargs)
param.cArgs = numargs
param.rgvarg = NEW(VARIANT,numargs)
FOR x=0 to numargs-1
param.#<VARIANT>rgvarg[x].vt = #<WORD>pArgs
pTemp = param.#<VARIANT>rgvarg[x].item
SELECT #<WORD>pArgs & 0xFFF
CASE VT_I1
CASE& VT_UI1
#<CHAR>pTemp = #<CHAR>pArgs2
pArgs2 += 4


Which in Aurora could be simplified down a bit since the class would have the interface pointer returned by the Create method.

Title: Re: CreateObject
Post by: Ionic Wind Support Team on November 05, 2006, 03:46:37 AM
We should suggest it to Sapero ;)  He seems to really enjoy that kind of programming.  Betcha he could whip out a CObject class in a few hours.
Title: Re: CreateObject?
Post by: JR on November 05, 2006, 11:42:00 AM
I have just uploaded a new version of the TypeLib Browser that fixes a few small bugs:



http://www.forum.it-berater.org/index.php?topic=420.0
Title: Re: CreateObject?
Post by: Mike Stefanik on November 05, 2006, 11:54:56 AM
Thanks, it's a great tool for folks who need to work with COM in Aurora.
Title: Re: CreateObject
Post by: JR on November 05, 2006, 12:11:56 PM
Quote from: Jonathan (zumwalt) Wood on October 21, 2006, 12:54:59 PM
Late binding has major advantages, especially when the user can have different versions of the application, for instance one could have office 97, another 200, another 2003, each have there own class enstansiation, if I late bind, I don't care about a specific com dll, I just attach to what is registered.

This is not what late binding means. The only difference between late binding and early binding is that, when using late binding, an additional call to the GetIDsOfNames method should be performed to retrieve the DispID (dispatch identifier) of the method or property before calling Invoke. Compilers supporting Automation natively retrieve the DispID at compile file and hardcode it in the call to Invoke.

Being able to use the same code with different versions of a component involves the use of a version independent ProgID (program identifier), if the component supports it, which is the same ProgID that the version dependent one without the version number, e.g. Excel.Application.10 is a version dependent ProgID and only will work with version 10 of Excel, whereas Excel.Application will work with any version. But this is not always as wonderful as it looks, because if you are using a method available in version 10 but not in lesser versions, your application will fail if the user has not version 10 installed. Microsoft is now increasingly using side-by-side installations, so you can have different versions of a component installed at the same time.

No matter which syntax you use to create an instance of the component, it ends in a call to CoCreateInstance, that in turn is a wrapper for CoGetClassObject. The returned pointer (in fact the address of a pointer to the virtual table of the object, that is, a pointer to a pointer), can be used both to call the methods and properties directly or through the Invoke method of the IDispatch interface.  With Aurora, using direct calls is more straightforward, although some components such Excel, that have been designed to work with scripting languages, have many optional variant parameters that you can omit when using a language that supports automation but that, when using direct calls, you have to pass a variant of type VT_ERROR filled with the constant value DISP_E_PARAMNOTFOUND.
Title: Re: CreateObject?
Post by: J B Wood (Zumwalt) on November 05, 2006, 12:47:06 PM
wow
Title: Re: CreateObject
Post by: Mike Stefanik on November 05, 2006, 12:52:41 PM
Quote from: JosÃÆ'Ã,© Roca on November 05, 2006, 12:11:56 PM
The only difference between late binding and early binding is that, when using late binding, an additional call to the GetIDsOfNames method should be performed to retrieve the DispID (dispatch identifier) of the method or property before calling Invoke. Compilers supporting Automation natively retrieve the DispID at compile file and hardcode it in the call to Invoke.

The other difference is the use of Invoke, rather than calling the method directly through the vtable interface. And technically speaking, a compiler that hardcodes the dispatch ID (i.e.: resolves it at compile time and just stores the ID, rather than resolving the method name at runtime) is behaving incorrectly. With late binding, the only thing that the compiler should store is a table of the method names; the dispatch IDs should always be determined dynamically. In other words, with late binding the object should be treated in exactly the same way that it would be in a scriptable environment.
Title: Re: CreateObject?
Post by: JR on November 05, 2006, 01:46:35 PM
Quote
The other difference is the use of Invoke, rather than calling the method directly through the vtable interface.

I was talking of the difference betweel early and late binding, not between late binding and direct calls.

Quote
And technically speaking, a compiler that hardcodes the dispatch ID (i.e.: resolves it at compile time and just stores the ID, rather than resolving the method name at runtime) is behaving incorrectly.

With early binding, the compiler can check if your call is correct because it knows about the parameters and also provides better performance not only because doesn't need to call GetIDsOfNames, but because having checked the correctness of the syntax and the parameters doesn't need to call VariantChangeType to coerce the passed values. However, most implementations of Automation rely on DispInvoke, so this last optimization isn't performed. Only components that have dynamic properties need late binding.

Quote
With late binding, the only thing that the compiler should store is a table of the method names; the dispatch IDs should always be determined dynamically. In other words, with late binding the object should be treated in exactly the same way that it would be in a scriptable environment.

Yes, of course. I think that you are misunderstanding me or that I haven't explained it well. The compiler hardcodes the DispIDs when using early binding.
Title: Re: CreateObject?
Post by: J B Wood (Zumwalt) on November 05, 2006, 09:48:10 PM
I just need something that works.
All this is great info, but gets me nowhere :)
I am not educated enough.
Title: Re: CreateObject?
Post by: sapero on November 06, 2006, 04:11:52 AM
Following Paul's suggestion, the first version is here ;D
For the demo I've used windows media player, assuming you have any standard(directshow) audio or video file.
The main methods are:
Create(wstring *progID) - creates the object from registered ProgID like "somelibrary.listview"
CreateFromResult(CInvoker *from) - creates the object from result of a call from other CInvoker instance.
Can be explained as CInvoker1 = CInvoker2.get(objectX)
GetInterfaceName() - usefull to search for methods in typelibrary browser
get(wstring *property,opt void *ppValue=NULL) - get a property
put(...) - put a property (wstring propertyname, ? value)
invoke(...) - call a method (wstring methodname, ...)

Why put and invoke are cdecl? cdecl calling conversion allows to pass any type of value in proper size without (de)referencing pointers etc.
So put(L"int", 6) or put(L"double", 1.2) or put(L"name", L"blah") will always work correctly.

Number and types of arguments are retrieved from object typelibrary, so you must know how many arguments the method requires.
Method get and invoke are storing return value in a VARIANT class variable - you can access this variable and read the type and value.

Method get can return this value directly by reference - get(L"duration", &double_duration), but you must know what the property returns.
Some types are extra handled here to copy exact number of bytes: byte,word,int,double,int64 and wstring
A bool is always converted to/from ole VARIANT_TRUE/VARIANT_FALSE to standard bool (also int).
A wstring is converted to/from BSTR, if you call get where BSTR is returned - be sure to set the second argument to a wstring buffer (or NULL)
All other types are defaulted to 4-byte in size.
Not all VARIANT types are correctly handled here (BRECORD or DECIMAL)
#include "CInvoker.inc"
#typedef HWND int
#typedef HRESULT int
#use "atl.lib"

// the file to be played
#define VIDEO_PATH L"file:///G:\video\rtl animals.avi" // or mp3,wav

declare import, AtlAxAttachControl(IUnknown* pControl, HWND hWnd, IUnknown* ppUnkContainer),HRESULT;
declare import, AtlAxWinInit(),BOOL;

class CWnd : CWindow
{
declare virtual OnClose() {Destroy();}
}



//------------------------------------------------------
sub main()
{
CWnd win;

CInvoker player;
CInvoker controls;
CInvoker media;
CInvoker settings;

// Create accepts progID like "MSDataListLib.DataCombo" or "MSComctlLib.ListViewCtrl"
if (!player.Create(L"WMPlayer.OCX"))
MessageBox(0, "failed to create object!", "", 16)
else
{
win.Create(0,0,800,600,0x10CF0040,0, "MediaPlayer demo - " + player.GetInterfaceName(),NULL);
AtlAxWinInit();
AtlAxAttachControl(player.m_object, win.m_hwnd, NULL);

player.get(L"controls");
controls.CreateFromResult(player); // grab IWMPControls from player.m_retval

player.get(L"settings");
settings.CreateFromResult(player); // grab IWMPSettings from player.m_retval

settings.put(L"autoStart", TRUE); // FALSE works too

if (!player.put(L"URL",VIDEO_PATH))
MessageBox(win,"failed to open clip", "");

if (player.get(L"URL"))
MessageBox(win,sprint("url:",player.GetResultAsString()), "");


controls.invoke(L"play"); // pause,stop,fastForward,fastReverse ...

player.get(L"currentMedia");
media.CreateFromResult(player); // grab IWMPMedia from player.m_retval

int w,h;
double duration;
if media.get(L"imageSourceWidth", &w)
&& media.get(L"imageSourceHeight", &h)
&& media.get(L"duration", &duration)
MessageBox(win,sprint("video size: ",w,"x",h,"\nduration:",duration), "");

while (win.m_hwnd) {wait();}
}
return;
}


invoke and get return values you can convert to string using GetResultAsString()

//edit: added callback mechanism
Title: Re: CreateObject?
Post by: J B Wood (Zumwalt) on November 06, 2006, 07:05:34 AM
Sweet! Going to give this puppy a try today :) THANKS
Title: Re: CreateObject?
Post by: Steven Picard on November 06, 2006, 07:48:33 AM
Wow!  I'm going to play around with this when I get a chance.  8)
Title: Re: CreateObject?
Post by: J B Wood (Zumwalt) on November 06, 2006, 09:37:43 AM
typelibviewer crashes on my machine:

AppName: typelibviewer.exe    AppVer: 0.0.1.705    ModName: user32.dll
ModVer: 5.1.2600.2622    Offset: 0001204f
Title: Re: CreateObject?
Post by: Mike Stefanik on November 06, 2006, 09:49:45 AM
I have the same issue, it crashes shortly after it loads. Have you tried the latest version of the typelib browser from JosÃÆ'Ã,©?

http://www.forum.it-berater.org/index.php?topic=420.0
Title: Re: CreateObject?
Post by: sapero on November 06, 2006, 11:38:08 AM
The exe was compressed with older version of pecompact2, maybe it was the crash issue. On my two XP it was running clean as packed and unpacked version.
I've changed it to unpacked and added source. This tool uses scintilla too ;D
Yes, i know JosÃÆ'Ã,©'s browser and have the latest version, but as every programmer will my own.
After running it does only enumerate all controls and typelibs from the registry.

Added: callback mechanism for controls:
class CWMPEvents : CInvoker
{
// [...] defined all virtual methods
}

CWMPEvents::OnClick(word nButton, word nShiftState, int fX, int fY)
{
MessageBox(0,"OnClick","");
}

sub main()
{
CWMPEvents player;
player.Create(L"WMPlayer.OCX");
player.Advise();
...
}


The Advise method assumes that 'player' instance  implements all methods for current control declared as virtual methods.
All here goes automatically: events guid is requested from typelibrary, eventsink is connected, IDispatch converts Invoke calls to your methods.
IDispatch::Invoke has been renamed to Invoke2 :)
Only VARIANT_TRUE and VARIANT_FALSE are converted to BOOL, BSTR is pushed unchanged, but you can use it as wstring.

In CWMPEvents.inc you can find all event classes for WMP, only one class is "created" - CWMPEvents

Compile this new example (and change video path), then click the player :)
Title: Re: CreateObject?
Post by: JR on November 06, 2006, 12:55:12 PM
Works better now. Have to made a change to mine. I haven't done anything with Aurora since July and wasn't aware that support for enumerations has been added.
Title: Re: CreateObject?
Post by: JR on November 06, 2006, 01:06:37 PM
BTW I'm assuming that optional parameters can only be omitted if all of them are at the end of the parameters list, so when using a declaration like the one below we have to pass all the parameters because the last one is not optional. With VB you can omit them using ",,", but if I'm not wrong you can't do the same with Aurora. Am I right?


declare virtual Execute(/*[out][opt]*/opt VARIANT* RecordsAffected, /*[in][opt]*/opt VARIANT* Parameters, /*[in][opt][hasdefault]*/opt long Options, _Recordset* ppRetval),HRESULT;

Title: Re: CreateObject?
Post by: Ionic Wind Support Team on November 06, 2006, 01:11:48 PM
Yes the optional parameters in Aurora are much like the ones in C++.  Actually you can define a function that has optional paramters before the end of the parameter list, you just cant use them from Aurora. 

Title: Re: CreateObject?
Post by: sapero on November 06, 2006, 01:37:48 PM
The opt keyword didn't mean you can push NULL as optional VARIANT, it must be a valid variant pointer, but the variant can be set to empty.
Same with optional BSTR - if default value is L"" you can not push null.
JosÃÆ'Ã,©, maybe you know how to get the default value from optional parameters? I do have iviewers source (http://msdn2.microsoft.com/en-us/library/w9yyfff5(VS.80).aspx) (small oleview), but cannot find where it is :)
Title: Re: CreateObject?
Post by: JR on November 06, 2006, 02:09:07 PM
Oh, yes. My browser shows the default value in the comments.

This is the (PowerBASIC) code I'm using:


   LOCAL pex AS PARAMDESCEX PTR              ' // Pointer to a PARAMDESCEX structure

   ...
   ...

   ' -------------------------------------------------------------------------------
   ' Default value
   ' -------------------------------------------------------------------------------
   strDefaultValue = ""
   IF (@ppParam[x].u.uparamdesc.wParamFlags AND %PARAMFLAG_FHASDEFAULT) = %PARAMFLAG_FHASDEFAULT THEN
      ' // Pointer to a PARAMDESCEX structure
      pex = @ppParam[x].u.uparamdesc.pparamdescex
      ' // Vartype
      vt = @pex.vardefaultvalue.vt
      IF vt = %VT_BSTR THEN
         ' // Get the content of the unicode string
         bstrLen = SysStringByteLen(BYVAL @pex.varDefaultValue.vd.bstrVal)
         IF bstrLen THEN
            strDefaultValue = $DQ & ACODE$(PEEK$(@pex.varDefaultValue.vd.bstrVal, bstrLen)) & $DQ
         ELSE
            strDefaultValue = $DQ & $DQ
         END IF
      ELSE
         ' // Get the integer value
         IF udt_LibDoc.syskind = %SYS_WIN16 THEN
            strDefaultValue = FORMAT$(@pex.varDefaultValue.vd.iVal)
         ELSE
            SELECT CASE vt
               CASE %VT_BOOL
                  strDefaultValue = FORMAT$(@pex.varDefaultValue.vd.boolVal)
               CASE %VT_I2, %VT_INT
                  strDefaultValue = FORMAT$(@pex.varDefaultValue.vd.iVal)
               CASE %VT_UI1, %VT_I1
                  strDefaultValue = FORMAT$(@pex.varDefaultValue.vd.bVal)
               CASE %VT_R4
                  strDefaultValue = FORMAT$(@pex.varDefaultValue.vd.fltVal)
               CASE %VT_R8
                  strDefaultValue = FORMAT$(@pex.varDefaultValue.vd.dblVal)
               CASE %VT_CY, %VT_I8, %VT_UI8
                  strDefaultValue = FORMAT$(@pex.varDefaultValue.vd.cyVal)
               CASE %VT_DATE
                  strDefaultValue = FORMAT$(@pex.varDefaultValue.vd.date)
               CASE ELSE
                 strDefaultValue = FORMAT$(@pex.varDefaultValue.vd.lVal)
            END SELECT
         END IF
      END IF
   END IF
   IF LEN(strDefaultValue) THEN TV_InsertItem(@pmd.hTreeView2, hChildNode, "Default value = " & strDefaultValue)
   ' -------------------------------------------------------------------------------


BTW be aware that sometimes an alias is returned as the parameter type. For example, for the ADO library, your browser declares ppRetval as PositionEnum_Param, but the name of the enumeration is PositionEnum. PositionEnum_Param is an alias for PositionEnum.


declare virtual get_AbsolutePosition(PositionEnum_Param* ppRetval),HRESULT;


You will have to retrieve the aliases and use defines.
Title: Re: CreateObject?
Post by: JR on November 06, 2006, 02:46:37 PM
The .u. in

pex = @ppParam
Title: Re: CreateObject?
Post by: sapero on November 07, 2006, 07:13:57 AM
Thanks JosÃÆ'Ã,©, i've tried in same way, but always got exceptions.
Today testing the PARAMDESCEX under MS compiler i've found a bug in structure packing:
//oaidl.h (SDK)
// somewhere #include "pack8"
typedef struct tagPARAMDESCEX
{
    ULONG cBytes;
    VARIANTARG varDefaultValue;
} PARAMDESCEX;

My definition was: struct PARAMDESCEX,8 but offset from cBytes to varDefaultValue was still 4 bytes instead 8.
So a hack cBytes[2] helped.
Structure packing works only for 1,2,4 but 8 not.
Title: Re: CreateObject?
Post by: J B Wood (Zumwalt) on November 07, 2006, 07:57:36 AM
My machines still bomb on the viewer.
I'll see if my dll is outdated.
Title: Re: CreateObject?
Post by: JR on November 07, 2006, 08:39:25 AM
Quote
My definition was: struct PARAMDESCEX,8 but offset from cBytes to varDefaultValue was still 4 bytes instead 8.
So a hack cBytes[2] helped.
Structure packing works only for 1,2,4 but 8 not.

I had the same problem. See my structure definition for PowerBASIC:


' ========================================================================================
' PARAMDESCEX Structure
' Contains information about the default value of the parameter.
' Note: cBytes returns 24 bytes as the size of the structure. I have had to add a dowrd
' as a filler to get it to work with PowerBasic.
' ========================================================================================

TYPE PARAMDESCEX
   cBytes AS DWORD                    ' size of this struct
   filler AS DWORD
   varDefaultValue AS VARIANTAPI      ' default value of this parameter
END TYPE

Title: Re: CreateObject?
Post by: sapero on November 11, 2006, 02:30:54 PM
I've uploaded newer version with fixed invoke method. You can now pass a VARIANT as parameter, as ilustrated in CBrowser example.
Added examples:
- DHTMLEdit - very simple HTML editor
- Speech - click it! :)
- WebBrowser - uses older version of browser control
- WebBrowser2

Both browser examples are supporting popups, opening new windows as owned, not in IE
Title: Re: CreateObject?
Post by: Earn on November 12, 2006, 09:20:10 AM
sapero,

This is great stuff.  I'll need to study it much to see how it all works.

The WebBrowser2 example, however, crashes with an access violation when I close the app.

Thanks Earn.
Title: Re: CreateObject?
Post by: sapero on November 12, 2006, 11:14:52 AM
It crashes too if you open and close new window, then click any URL in the first window :-X

// update to previous post:
The method Advise has now one optional parameter - name of events interface. Usefull if the class has more eventsinls.
Method Attach - added optional IID* parameter - if your object implements more than one interface you can connect to other, instead default interface.

// debug/testing:
Added GetInvokeArguments(wstring wszmethod) - if you need parameter types, it is located in separate module and is not linked if not used.
Same with GetErrorDesc(m_hr) (separate module, but shared with GetInvokeArguments) - returns printable error description for failed invoke call.
This method describes only IDispatch::Invoke, all other error strings you can find in winerror.inc.
Title: Re: CreateObject?
Post by: Steven Picard on November 13, 2006, 09:01:01 AM
I played around with this a little bit and I think this would be great as a standard part of Aurora. Any chance of that happening?  I guess that decision is really up to Sapero and Paul but it is something I would like to see happen.
Title: Re: CreateObject?
Post by: Mike Stefanik on November 13, 2006, 12:20:25 PM
Native support for COM (servers and clients), along with things like having variants be an intrinsic type, would be wonderful features for Aurora. On the other hand, at this point I don't think anything significant should be done that would delay its release. In my opinion, Aurora is already well past a commercial 1.0 release, aside from the documentation which needs to be finished. The focus now should be on wrapping things up. And as every developer knows, the last 5% of a project is 95% of the work.
Title: Re: CreateObject?
Post by: Steven Picard on November 13, 2006, 12:39:15 PM
I don't entirely disagree with you but since Sapero has already done much of the work I see no reason why not to include it as a standard part of Aurora.  It would be nice to be there from day one.  Just my opinion of course. :)
Title: Re: CreateObject?
Post by: Mike Stefanik on November 13, 2006, 12:44:17 PM
The problem is a) it's more documentation, and b) it would be included in a half-baked state. What sapero has done is very useful, but it doesn't translate into comprehensive COM support for the language.
Title: Re: CreateObject?
Post by: Steven Picard on November 13, 2006, 12:49:14 PM
Quote from: Mike Stefanik on November 13, 2006, 12:44:17 PM
The problem is a) it's more documentation

I thought that was Paul's most favorite thing to do. :D Just kidding.
Title: Re: CreateObject?
Post by: sapero on November 15, 2006, 08:08:29 AM
I'm currently working on a tool where you can select a ocx control from the registry, select a coclass, interface and sink-methods, then after clicking magic button you get complete project with wrapped methods and ... window :)
For now it can create project (.awp file) and class source and include.
I hope tomorrow it will be uploaded as alpha 1.
Title: Re: CreateObject?
Post by: Steven Picard on November 15, 2006, 08:17:12 AM
I'm very much looking forward to this!!  :D
Title: Re: CreateObject?
Post by: J B Wood (Zumwalt) on November 15, 2006, 08:35:37 AM
Your not the only one....
Title: Re: CreateObject?
Post by: sapero on November 20, 2006, 06:00:05 AM
Ok, here it is!
Lol, create application with only one click ;DÂÃ,  I'm sure you find bugs and get it crashed while browsing ocx controls with bugs.
One bug i have found in OO defrag control (and mailed the developer) - while unloading unused dlls (CoFreeUnusedLibraries) the application just closes (ExitProcess is called or stack overflow).

Standard project files and external libraries are extracted from resource (all packed in single cab file, api=SetupIterateCabinet)
In next release it will be changed to allow modifications in template source file.
Main dialog looks like property sheet but has only one page, the button 'Next' creates the project and runs the application if checked.
Second page will be added to initially set control properties or call methods...

The state of checkbox "define unknown variable types" is ignored, an extra include file with dumped enums/structs is created as needed.

CInvoker has been updated:
1. put() is now cdecl and accepts any number of parameters,
2. putref() added (cdecl)

To Paul: i've got many times error while assembling: undefined symbol __imp_lstrcpyW, while using the w2s() function.
This simple line helped:#emit extern __imp_lstrcpyW
Title: Re: CreateObject?
Post by: J B Wood (Zumwalt) on November 20, 2006, 06:27:55 AM
wooohooo no other language can boast this!
YOU ROCK
Title: Re: CreateObject?
Post by: ExMember001 on November 20, 2006, 01:18:58 PM
yep awesome work!
thanks for sharing  ;D

now i just need to understand what is an ocx control and how to use that properly ...  ;)
Title: Re: CreateObject?
Post by: Rock Ridge Farm (Larry) on November 20, 2006, 02:26:35 PM
How do I compile this - I get lots of errors.
Title: Re: CreateObject?
Post by: Rock Ridge Farm (Larry) on November 20, 2006, 06:33:22 PM
This thing is really cool - 3 or 4 years I might understand it.
Title: Re: CreateObject?
Post by: Mike Stefanik on November 20, 2006, 07:36:36 PM
Just so you know, the source is incomplete (lots of references to things that aren't included in the zip file) and the executable GP faults on Windows XP (at least on my system).

It looks like a wild pointer, trying to read memory at address 0xffffffef. Also looks like the stack is corrupted.
Title: Re: CreateObject?
Post by: sapero on November 21, 2006, 03:53:24 AM
The included source is only the real stuff - main program and small typelib helper class set, It uses the windows headers so if i would upload all, the zip would be 3 MB.
Mike - when and what crashes? The output executable can crash right after opening main window, the atl ocx container has an bug.
After replacing the atl with custom ocx container it was running ok.
Main program can crash by combobox subclass proc - replaced CallWindowProc with direct call to combo wndproc, it works on XP but needs more initialization.

I'm running two different XP - on laptop i like to code, desktop is connected to internet but has ultra slow P4 with L4 dead (2Y old).
First time the program was tested on desktop conputer - no controls found :), so XP is not equal XP.
The actual version has GDI leaks in OnDrawItem, and some heap leaks in writer part.

Has anyone tested this on older systems like 98/ME?
Title: Re: CreateObject?
Post by: sapero on November 21, 2006, 07:41:33 AM
I've uploaded newer version with fixed leaks, included resources and internal extras like unicode functions + extended Sean's stringify tools.

And here you find the custom ocx container - it uses a lot of com classes, but is very simple. Can host only windowed controls (with IOleWindow).
Works with browser, macromedia flash realplayer, wmp, system-monitor... and is ready for extending for new interfaces without recompilling.
Supports also "external" for javascript, and drag-drop extensions.
The host is implemented inside CInvoker2 and is initialized with CInvoker2::Create2

While running control "Microsoft Forms 2.0 MultiPage" hosted by ATL - it will crash, but hosted with this tool - will run propertly.
Title: Re: CreateObject?
Post by: Mike Stefanik on November 21, 2006, 09:31:11 AM
It still crashes on my system, right as it's loading up. The dialog displays, and as soon as the progress bar is hidden, it GP faults. It looks like the problem may be somewhere in EnumControlsThread(), after you hide the IDC_PROGRESS control. Offhand, the first I noticed is that you're not initializing the m_bitmaps member to a value, and you're not checking to see if it's actually valid when you start iterating through that loop. In any case, like I said in my previous post, it looks like you have a wild pointer in there.

Title: Re: CreateObject?
Post by: JR on November 21, 2006, 09:40:11 AM
There is a buggy versiol of ATL.DLL that crashes in XP. I use ATL71.DLL that works fine.
Title: Re: CreateObject?
Post by: Mike Stefanik on November 21, 2006, 10:08:08 AM
In this particular case the stack trace doesn't show calls to ATL.dll (nothing like AtlModuleLoadTypeLib, etc.), it's actually crashing inside User32.dll, although the stack does look munged.
Title: Re: CreateObject?
Post by: sapero on November 21, 2006, 12:16:13 PM
The main class is created with new() so all is initialized to NULL, i know the new() function uses GlobalAlloc with GMEM_ZEROINIT flag, same with AllocHeap.
Mike, you can fake the last selected control to "nothing" by setting HKCU\Software\Sapero\OcxWrapÂÃ,  LastControlClsid=16* 0xFF
After enumerating it will not find/select this clsid, and will not load anything

I have created a debug version (compile capable):
ocxwrap_debug: http://www.mytempdir.com/1075162
And before Paul updates new sdk includes, grab the nevest pack from http://rapidshare.com/files/4610026/aurora.include.21.11.2006.zip.html
Open the project and start debug session.

Ah so, unpack this project to c:\debug, it was here compiled
And lol, before you recompile this - remove parameters from main() and the 'if' - you do not have modified startup library :)
Title: Re: CreateObject?
Post by: Shannara on December 31, 2006, 08:28:15 PM
I think that link might be down. I couldnt find a download on the resulting page :( The link near the top of this thread page's exe crashes all the time. At the beginning when it's loading the top combobox, is when it happens. Have anybody got this working? Or have resulting code when they run this against the msscript.ocx control on their system?