Revision: 14593 http://harbour-project.svn.sourceforge.net/harbour-project/?rev=14593&view=rev Author: druzus Date: 2010-05-25 22:04:04 +0000 (Tue, 25 May 2010)
Log Message: ----------- 2010-05-26 00:03 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/contrib/hbwin/Makefile + harbour/contrib/hbwin/hbolesrv.c + added inproc OLE server implementation. It allows to create OLE/ACTIVEX COM server in Harbour. Such OLE server allows can be used by programs written in any languages supporting OLE automation (also in other Harbour applications) User ole server code should be linked as DLL which later can be register in MS-Windows by regsvr32.exe program, i.e.: regsvr32 myolesrv.dll The OLE server code should contain DLLMAIN() PRG function which is executed just after loading OLE inproc DLL server as server from other application and also by regsrv32.exe during registration and unregistration procedure. It has to initialize at least OLE server ID and name usinf WIN_OleServerInit(). + added new PRG function which intitialize OLE server: WIN_OleServerInit( <cClassID>, <cServerName>, ; [ <hAction> | <oAction> | <bAction> | <sAction> ], ; [ <lHashClone> | <lAcceptAll> ] ) -> <lServerActive> <cClassID> is registered OLE server class GUID <cServerName> is OLE server class name <hAction> is optional parameter with hash array containing messages and instance variables used by OLE server. The keys in hash array are strings with message names and values are actions. Codeblock and symbol items means that given message is a method call and any other value means that it's variable. By default the same hash array is shared between all objects created by registered server. It's important when hash array contains values which are neither codeblock nor symbol items so they are not used as method but rather as instance variables because such instance variables are shared between OLE objects. Setting 4-th parameter <lHashClone> to .T. causes that each objects receives it's own copy of <hAction> item so instance variables inside hash array are also local to OLE object. Alternatively programmer can use <bAction> or <sAction> to create seprate copy of hash array for each object, i.e.: bAction := {|| hb_hClone( hValue ) } When hash array contains symbol item (@funcName()) then when it's executed by OLE object message it's possible to access the hash array bound with given OLE object using QSelf() function. It maybe useful if hash array contains instance variables and programmer wants to access them. Please remember that using hash array which was initialized to keep original assign order by HB_HKEEPORDER( <hAction>, .T. ) before adding its items you can define strict message numbers (DISPIDs), i.e.: hAction := {=>} HB_HKEEPORDER( hAction, .T. ) hAction[ "OPEN" ] := @myole_open() // DISPID=1 hAction[ "CLOSE" ] := @myole_close() // DISPID=2 hAction[ "SAVE" ] := @myole_save() // DISPID=3 hAction[ "LOAD" ] := @myole_load() // DISPID=4 hAction[ "PRINT" ] := @myole_print() // DISPID=5 (see example in olesrv2.prg) <oAction> is optional parameter with Harbour object which is used as base for all newly created OLE objects. All messages (method and instance variables) supported explicitly by <oAction> object (except ONERROR message redirecting) are inherited by OLE objects. Each newly created OLE object uses the same <oAction> object so its instance variables are shared between all of them. If programmer wants to create separate Harbour object for each OLE object then he should use <bAction> or <sAction>, i.e.: bAction := {|| myClass():new() } <bAction> is optional parameter with codeblock executed when new OLE object is created. It should return hash array or Harbour object which will be used as base for newly created OLE object. <sAction> is optional parameter with function symbol. This function is executed when new OLE object is created and should return hash array or Harbour object which is used as base for newly created OLE object. If the 3-rd parameter is <oAction>, <bAction> or <sAction> then it's possible to also set 4-th parameter <lAcceptAll> to .T. and in such case <xAction> parameter is used in different way. Newly created OLE object accepts any massage names invoking for each of them EVAL() message which is sent to <xAction> with OLE message name inserted as the 1-st item to OLE object parameters. It allows to create OLE server which will accept unknown messages redirecting them to some other code, i.e.: if netio_connect( cServer,,, cPasswd ) WIN_OleServerInit( cClassID, cServerName, @netio_funcExec(), .T. ) endif initialize OLE server which redirects all messages to default netio connection establish by netio_connect(). If 3-rd parameter is not given then all HVM functions becomes OLE methods and HVM memvars (public and private variables) are OLE object instance variables so they are shared with all OLE objects created by this interface. It works just like xHarbour.com OLE server described at http://xharbour.com/index.asp?page=add_on_oleserver&show_sub=7&show_i=1 ; TODO: add support for MT RPC servers. Current implementation cannot be safely used in MT programs creating OLE objects and executing their methods simultaneously in different threads without additional user code which will serialize these operations. ; TODO: replace message handler API in WIN_AxGetControl()/ __AxRegisterHandler() which uses only fixed method IDs and do not support method names with above one so user can easy create activex controls which support message names. This modificaiton will force updating user and 3-rd party code but IMO should be done. Current interface is simply too much limited to keep it. ; Possible TODO: add support for user defined fixed message numbers (DISPIDs) which are not continuous small numbers so users cannot easy use hash arrays with strict order. Is such functionality necessary? Can someone with ActiveX experience say sth about it? Above implementation has undocumented feature: it supports hash arrays with keys using numbers only which can be used like in __AxRegisterHandler() but I haven't decided yet I should keep, extend or remove such functionality. Please make real life test. I do not have any practice with MS-Windows and OLE and most of above code I wrote using only documentation so I'm very interesting in real test results and user opinions about it. If some important functionality is missing then please inform me about it. BTW There are some 3-rd party activex implementation for [x]Harbour, i.e. xharbour.com or FiveWin ones. Maybe someone familiar with them can create PRG compatibility layer for Harbour. I cannot do that myself because I do not know that products and their PRG API used in OLE/COM/ActiveX implementations but if someone can describe it then I can help in such implementation. + harbour/contrib/hbwin/hbolesrv.def + harbour/contrib/hbwin/hbolesrv-mgw.def + harbour/contrib/hbwin/hbolesrv-ow.def + added .DEF link files which are necessary to correctly export inproc OLE server DLL functions. It's possible that other compilers or even different versions of the same compilers may use different a little bit different .DEF files. I tested above with BCC5.5, MinGW 3.4.5 and OpenWatcom 1.8. + harbour/contrib/hbwin/test/olesrv1.prg + harbour/contrib/hbwin/test/olesrv1.hbp + harbour/contrib/hbwin/test/oletst1.prg + harbour/contrib/hbwin/test/oletst1.hbp + added example of NETIO-RPC OLE server code with Harbour (PRG) client. This server redirects all messages sent to its OLE objects to remote HBNETIO server as function calls. It understands the following messages: CONNECT() - creates connection to the server, parameters like in NETIO_CONNECT() and NETIO_GETCONNECTION() functions DISCONNECT() - closes current connection PROCEXISTS() - works like NETIO_PROCEXISTS() PROCEXEC() - works like NETIO_PROCEXEC() PROCEXECW() - works like NETIO_PROCEXECW() FUNCEXEC() - works like NETIO_FUNCEXEC() All other messages are redirected directly to RPS server as function calls. CONNECT() message should be executed by client to create connection to the server. Each NETIO-RPC OLE object uses its own connection which should be initialized. If CONNECT() is executed more then once the current connection is closed. DISCONNECT() is executed automatically when OLE object is destroyed so it's not necessary to call it explicitly. Please use hbmk2 and olesrv1.hbp to compile OLE server. OLE inproc servers have to export some DLL entry functions which are defined in .def files which have to be passed to linker. Before client code can be tested the server has to be registered. The server can be registered in given MS-Windows system using regsvr32.exe command. To register the server use: regsvr32 olesrv1.dll and to unregister: regsvr32 /u olesrv1.dll + harbour/contrib/hbwin/test/olesrv2.prg + harbour/contrib/hbwin/test/olesrv2.hbp + harbour/contrib/hbwin/test/oletst2.prg + harbour/contrib/hbwin/test/oletst2.hbp + added very simple example of OLE server using hash array with strict item order (associative hash array) to define OLE objects with fixed message numbers (DISPIDs) Remember about registering the server by 'regsvr32 olesrv2.dll' + harbour/contrib/hbwin/test/olesrv3.prg + harbour/contrib/hbwin/test/olesrv3.hbp + harbour/contrib/hbwin/test/oletst3.prg + harbour/contrib/hbwin/test/oletst3.hbp + harbour/contrib/hbwin/test/oletst3.bas + added example of OLE server code with Harbour (PRG) and Visual Basic (BAS) clients. This server redirects all messages sent to its OLE objects to HVM functions and messages to HVM memver (public and private) variables This server should work as xHarbour.com OLE servers described at: http://xharbour.com/index.asp?page=add_on_oleserver&show_sub=7&show_i=1 The server and clients code are nearly the same so users can easy compare them. Remember about registering the server by 'regsvr32 olesrv2.dll' Modified Paths: -------------- trunk/harbour/ChangeLog trunk/harbour/contrib/hbwin/Makefile Added Paths: ----------- trunk/harbour/contrib/hbwin/hbolesrv-mgw.def trunk/harbour/contrib/hbwin/hbolesrv-ow.def trunk/harbour/contrib/hbwin/hbolesrv.c trunk/harbour/contrib/hbwin/hbolesrv.def trunk/harbour/contrib/hbwin/tests/olesrv1.hbp trunk/harbour/contrib/hbwin/tests/olesrv1.prg trunk/harbour/contrib/hbwin/tests/olesrv2.hbp trunk/harbour/contrib/hbwin/tests/olesrv2.prg trunk/harbour/contrib/hbwin/tests/olesrv3.hbp trunk/harbour/contrib/hbwin/tests/olesrv3.prg trunk/harbour/contrib/hbwin/tests/oletst1.hbp trunk/harbour/contrib/hbwin/tests/oletst1.prg trunk/harbour/contrib/hbwin/tests/oletst2.hbp trunk/harbour/contrib/hbwin/tests/oletst2.prg trunk/harbour/contrib/hbwin/tests/oletst3.bas trunk/harbour/contrib/hbwin/tests/oletst3.hbp trunk/harbour/contrib/hbwin/tests/oletst3.prg This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. _______________________________________________ Harbour mailing list (attachment size limit: 40KB) Harbour@harbour-project.org http://lists.harbour-project.org/mailman/listinfo/harbour