I'm trying out OmniXML after years of working with the default msxml implementation.
I have several xml structures (some of which are pretty massive) for which I originally created a binding using the Delphi wizard. The binding was then edited manually to fix errors and what not.
First question: is there a (somewhat) easy way to create such a binding for OmniXML? I suspect not, but you never know... I started editing my structures by hand to try and make the interfaces and classes fit into omniXML, but it is quite a bit of (very tedious) work
Second question: In some of the demos, and online, it would seem that the "data binding" (for want of a better term) is done by inheriting the classes defined in OmniXMLPorperties (TGpXMLxxxx). So I started toying with that. Is there an advantage, at least in my case, to defining my data-binding this way as opposed to trying to recycle the one created by the wizard?
Thanks!
PS: In case it matters, I'm using Delphi XE2
Delphi's native XML Data Binding is not tied to any particular XML DOM vendor implementation. It is based on TXMLDocument and related interfaces, which then access vendor-specific DOM interfaces internally.
On Windows, MSXML is the default DOM vendor used. On Mac OSX, ADOM/OpenXML is the default DOM vendor used. But you can change which DOM vendor is used. You just have to assign the DOM vendor's name to the global DefaultDOMVendor variable in the Xml.XmlDom.pas unit, and make sure a corresponding DOM implementation has been registered via RegisterDOMVendor() (for MSXML and ADOM/OpenXML, simply add the corresponding DOM implementation unit in your uses clause - Xml.Win.msxmldom for MSXML, Xml.adomxmldom for ADOM/OpenXML - as they call RegisterDOMVendor() internally).
So in this case, you would simple find (or make) a DOM implementation wrapper for OmniXML so it can plug into TXMLDocument, then register it with RegisterDOMVendor(), and set the DefaultDOMVendor variable to the registered DOM name.
Related
i am using Delphi XE4 to create a Voip program. i am using an outdated VOIP SDK From a company called BigSpeed which is no longer around the current code points to the following path 'C:\Program Files (x86)\BigSpeed Voice SDK\' where the active x controls are stored.
LIBID_bsVoiChatCln: TGUID = '{D2A88515-99E0-4EEE-A030-E5D2AB306A03}';
IID_IbsVoiChatClnX: TGUID = '{5055A626-56A1-4E58-A461-000A69CA3E03}';
DIID_IbsVoiChatClnXEvents: TGUID = '{665DB561-22D3-4624-B55B-4416309A2E03}';
CLASS_bsVoiChatClnX: TGUID = '{BE761C1E-1F6C-46F8-A99B-0AB29C9B2D03}';
How can i create a new GUID and have the program access the active x controls from a new directory.
You don't want to create new GUIDs. The GUIDs are the identifiers of that component. All you want to do, as far as I can tell from the question and your comments, is to register the DLL at a different location.
The ActiveX DLL almost certainly uses self-registration. This means that you can put the DLL somewhere else and register it there. For instance, suppose the DLL is located in:
C:\MyFolder\MyDll.dll
Then you could register it by executing this command:
regsvr32 C:\MyFolder\MyDll.dll
Looks like you do not understand (or do not explain) relations between your program, the library and the GUIDs.
How can i create a new GUID and
1) GUID is just a 128-bit random number. So you can "create new GUID" simply by editing its hexadecimal string. Or you can press Ctrl+Shift+G in Delphi source editor in designtime. In runtime you can use CreateGUID function of SysUtils unit.
http://docwiki.embarcadero.com/CodeExamples/XE5/en/UsingGUIDs_(Delphi)
http://docwiki.embarcadero.com/Libraries/XE2/en/System.SysUtils.CreateGUID
http://en.wikipedia.org/wiki/GUID
But i don't think creating new GUID will do you any good. If anything, it should mean explicitly declared incompatibility with old GUIDs (hence incompatibility with VOIP library)
from a new directory.
2) Why do you think your VoIP library is arranged as a set of ActiveX control ? Just because there are GUIDs there? Not any text file with GUIDs inside would be ActiveX.
ActiveX are specifically arranged Windows servers, that are registered in the registry so that any program could call them. Sometimes you can register them after the fact, if the installer failed it.
http://en.wikipedia.org/wiki/Activex
http://en.wikipedia.org/wiki/Regsvr32
http://support.microsoft.com/?id=207132
So you should read manuals for your library whether they constitute ActiveX or not, and if they do, how to register them in Windows (should be done by the library installer)
If installer does not provide for it, then you can not be sure that the library can work from a different place. Not only your program needs a connection to it, but also the library itself may need connection to its other parts.
have the program access the active x controls
3) If your library really conforms to ActiveX specifications and if it was correctly installed (registered) then you can just import them into Delphi IDE and drop them onto the form like you drop tables and dialogs.
http://docwiki.embarcadero.com/RADStudio/XE3/en/Import_Component_Wizard
http://delphi.about.com/library/howto/htaddactivex.htm
http://www.delphisources.ru/pages/faq/master-delphi-7/content/LiB0125.html
4) if you do not want to drop your VoIP component onto the form, then you can try to create it in runtime with CoCreateInstance. But first you have to read some tutorial about Microsoft COM for beginners. You may miss some advanced concepts, but you should understand the most basic things like how interfaces are similar to and different from classes, how their lifetime is managed, how COM runtime is initialized and finalized for your program and so on.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686615.aspx
http://delphi.about.com/library/weekly/aa121404a.htm
http://www.delphikingdom.ru/asp/viewitem.asp?catalogid=1135
How to use CoCreateInstance() to get a com object?
https://stackoverflow.com/search?q=%5Bdelphi%5D+cocreateinstance
all the MS Office related examples in c:\RAD Studio\9.0\OCX\Servers\
5) you may also try to bypass the proper Windows ways of locating and loading the server and try to do it yourself, using DllGetClassObject routines in proper DLLs. If the library is permissive, it will work. But if it does rely on Windows-provided services that has a potential for all kinds of crashes and unmet expectations.
https://www.google.com/search?client=opera&q=CoCreateInstance+and+DllGetClassObject&sourceid=opera&ie=utf-8&oe=utf-8&channel=suggest
http://msdn.microsoft.com/en-us/library/windows/desktop/ms680760.aspx
How do I use a COM DLL with LoadLibrary in C++
DllGetClassObject return "No such interface supported" while CoCreateInstance can find it successful
If my memory serves me, You can find examples of that approach in early HTML Help units for delphi. Microsoft HTML Help provides for both late binding using CoCreateInstance and runtime ActiveX servers registry, or early binding towards htmlhlp.ocx treated as DLL. Early versions of HTML Help API for Delphi provided for both options. But i may be wrong here.
I just discovered TWebBrowserEx in the Delphi XE source. When I google it, I get zero hits! Anyone have insight on where this component came from, and on what the purpose is?
You can find the source in $(BDS)\Source\Internet\WebBrowserEx.pas. If you open that file, there is a large section of comments at the top giving links to the documentation for the interfaces inside.
The component is usually called TWebBrowser – no doubt this is a variant. Perhaps they renamed it to avoid clashes with existing TWebBrowser components.
TWebBrowser is an OCX wrapper around IWebBrowser2. It's very hard to imagine that TWebBrowserEx is implemented in any other way.
The documentation is on MSDN but you'll get better hits searching for TWebBrowser. The best source of information is Brian Cryer's site.
Note that once you get into programming the DOM (through the Document property) it becomes highly dynamic and so what documentation there is takes quite a bit of getting used to if you are used to more static class interfaces.
UPDATE
According to #jachguate, TWebBrowserEx derives from TWebBrowser and adds a bunch of extra interfaces. I don't believe this changes anything substantial in the answer. The documentation sources are still going to be as listed above.
The one that is installed into the IDE for use at designtime is called TWebBrowser, and it is implemented in SHDocVw.pas.
I thought there is no such class name as TWebBrowserEx in any file in Delphi XE VCL source folder. What file are you looking at and where is it located?
You might be interested in the TEmbeddedWB component from www.bsalsa.com. I found that it works a lot better for me than the standard TWebBrowser.
Update: So it does exist. Whoa. It seems to be an inner class defined inside this unit, used as a field inside TCustomWebBrowserComponent, which seems to be a base class you would extend.
After this question, I need to know what principles should be followed in order to make an encapsulation of a class in a dll compatible to other version of Delphi.
I made a class using generics feature in RAD2010 and make a dll which has a function that return an instance of it. When I tried to use the dll using BDS2006 or Delphi 6, the DLL didn't work as expected. But if I use RAD2010 in other computer, there is no issue. Is it caused by using the feature that not available in previous Delphi version (the stack<> stuffs?)?
For string matters, I already follow the comment guidance in the library file, that I put ShareMem in both library first uses clause and my project. And I have copied borlndmm.dll from RAD2010 to the same folder where I tried the DLL using BDS2006. It didn't crash, but it didn't work es expected. A function return an empty string when in RAD2010 environment it worked very well.
Once again, I have a question : what principles should be followed in order to make an encapsulation of a class in a dll compatible to other version of Delphi? Thank you in advance. (For encapsulating functions in a dll when no OOP is used, I have no issued for other version of Delphi).
The definition of a string changed with D2009. If you want to make string communication safe, use a PAnsiChar or a WideString.
The basic rule of communication through DLLs is to not use anything specific to Delphi, so no Delphi strings and no TObject descendants. Interfaces, records and COM types work fine, though.
You ask:
Once again, I have a question : what principles should be followed in order to make an encapsulation of a class in a dll compatible to other version of Delphi?
and there is only one: Don't do it. You can't do it. Either you write a DLL, then use idioms and data types that can safely be used in DLLs, which precludes (among other things) classes.
Or you write a BPL, then you can safely export classes, use strings and such, but you are tied to the same Delphi version. This limitation is of technical nature, so writing a DLL will not work around it. There may be tricks to overcome this, and there may be different Delphi versions that use the same class layout so that it works, but you must not tie your public DLL interface to such implementation details.
Stick with only fundamental types. If you use interfaces, create them using the type library editor so your constrained by the compatible types by the start. A good rule of thumb is to look at the windows API and try to emulate its calling conventions.
You can use classes in your DLL, you just can't expose them as such. A good idiom that works well for DLL's is the handle concept. Your DLL creates an object and returns a handle to that object. When you need to work with that object again, you pass a function in the DLL a handle. Just remember that your DLL needs to be completely responsible for the memory and lifetime of the object. Its a trivial process to create DLL functions to expose the pieces of the class that you will need access too.
From the Delphi side, you can then write a proxy wrapper which hides the handle from the user. For events you can use a callback method. Basically you pass non object function pointers to the dll, which then invokes the function on the event. A quick overview of this process is available on Delphi 3000.
I am looking to add the capability for users to write plugins to the program I have developed in Delphi. The program is a single executable with no DLLs used.
This would allow the user community to write extensions to my program to access the internal data and add capabilities that they may find useful.
I've seen the post at: Suggestions for Adding Plugin Capability? but its answers don't seem transferrable to a Delphi program.
I would like, if possible, to add this capability and keep my application as a single executable without any DLLs or additional modules required.
Do you know of any resources, components or articles that would suggest how to best do this in Delphi, or do you have your own recommendation?
The first question I would ask is, do you need the plugins to access the UI of your host application, or add any UI elements of their own? Or will the plugins be limited to querying and/or supplying data to your host app?
The latter is much easier and opens up two possibilities. Others have already mentioned DLLs, which is the first way to go. Certain caveats apply - in general you should be interfacing with a dll using only the data types that are used in Windows API. THat way you can be sure that the plugin DLLs will understand your data types, no matter what language/compiler they were created in. (So for example, use PChars, not strings. Do not as a rule pass Delphi classes such as TStream to a DLL. This will appear to work in some cases, but is unsafe in general, because even if the DLL was compiled in Delphi, it may have been a different version of the compiler, with a slightly different idea of what TStream is). Google for using DLLs in Delphi, and you'll find plenty more tips.
Another way that hasn't been mentioned yet is to enable scripting in your application itself. There are several very capable 3rd-party scripting engines, both commercial and free, and most of them allow you to exchange Delphi objects with the script. Some of these libraries support only Pascal as the scripting language, others will let you use Basic (perhaps better for beginner users) or other languages. See for example RemObjects Pascal Script (free) at http://www.remobjects.com/free.aspx .
My favorite scripting solution at the moment is Python for Delphi (P4D, also free) from http://mmm-experts.com/Products.aspx?ProductID=3 It can interface beautifully with your classes via RTTI, and allows you to execute Python code in your Delphi app, as well as use Delphi classes in Python scripts. Given the popularity of Python, this may be a viable solution if you want to attract developers to your project. However, every user will need to have a Python distribution installed.
It seems to me that the barrier to entry, from the point of view of potential plugin writers, is lower if you use scripting than if you choose DLLs.
Now, back to my initial question: things get much more complicated if you need the plugins to interact with your user interface, e.g. by placing controls on it. In general, DLLs cannot be used to do this. The Borland/CodeGear-sanctioned way is to use packages (BPLs). With BPLs, you can access and instantiate classes offered by a plugin as if they were declared in your host application. The catch is, all BPLs must be compiled with the same exact version and build of Delphi that your main application is. In my opinion this makes packages completely impractical, since it's hard to expect that all the potential plugin writers around the world will be using the same version of Delphi you are. A major pitfall.
To get around this, I have experimented with a different approach: keep using DLLs, and develop a syntax for the plugin to describe the UI it needs, then create the UI yourself in the host app. (XML is a convenient way to express the UI, since you get the concept of parenting / nesting for free.) The UI description syntax can include callbacks to the DLL triggered when the contents or state of the control changes. This method will restrict plugins to the set of VCL controls your application already uses or has registered, though. And it's not a one-nighter job, while BPLs certainly are.
Google for "Delphi plugin framework", too. There are some ready-made solutions, but as far as I know they usually use BPLs, with their limited usefulness.
Actually, the accepted answer to the question you cite is quite appropriate for Delphi as well. Your plug-ins will be DLLs, and you can dictate that they should export a function with a certain name and signature. Then, your program will load the DLL (with LoadLibrary) and get the address of the function (with GetProcAddress). If the DLL doesn't load, or the function isn't there, then the DLL is not a plug-in for your application.
After you have the address for the DLL, you can call it. You can pass the function an interface to something that represents the parts of your application that you wish to expose. You can also require that the function return an interface with methods that your application will call at various times.
When testing your plug-in system, it will be wise to write a plug-in yourself with a language other than Delphi. That way, you can be more confident that you haven't inadvertently required everyone to use Delphi.
At first I went for BPL and DLL base plugins. And found them hard to mantain.
If you use BPL system, then you need to match BPL version with EXE version. This includes Delphi updates which can break something. I found out (the hard way) that if I need to include all my plugins with every release, there is no point in having plugins at all.
Then I switched to plain DLL plugins. But that system just complicated code base. And that's not a good thing.
While crusing the net I found out Lua embedded script language, and delivered with it. Lua is 150K DLL, embedding bytecode compiler, interpreter and very simple and smart dynamic programing language.
My plugins are simple lua scripts. Easily mantaind and made. There are premade Delphi examples, so you can export any class or procedure as Lua table or function. GUI or not. For example I had TurboPower Abbrevia in my app for zipping. I exported my zipping class to lua, and all plugins now can call zip('.', 'dir.zip') and unzip(). Then I switched to 7zip and only implemented old class to use 7zip. All plugins work as they did, with support for new zip('.', 'dir.7z').
I made TLuaAction which calls Execute(), Update(), Hint() procedure from its script.
Lua allso have it's own plugin system that makes it easy to add funcionality to it. Eg luacom make is easy to use COM automation, luainterface allows calling .net from lua.
See luaforge for more. There is Lua IDE made in Delphi, with source.
I tried to make an overview of all such options some time ago. Together with my readers/commenters we built this list:
DLL/BPL loaded from the program.
DLL/BPL loaded from a sandbox (which could be another copy of the program or a specialized "server" application and which communicates with the main program via messages/sockets/msmq/named pipes/mailslots/memory mapped files).
COM (in any of its variants).
DDE (please not).
External program that communicates via stanard input/output.
External program that communicates via files (file name is a parameter to the program).
External program that works via drop folder (useful for batch processing).
External program that communicates with windows messages/windows sockets/msmq/named pipes/mailslots/memory mapped files/database publish-subscribe.
The most universal method of adding plug-in capability is to use COM. A good book to get you started on the road is Delphi Com Programming by Eric Harmon. While it was originally written for Delphi versions 3 through 5, the books contents are still valid with the latest versions of Delphi.
Personally, I have used this technique along with active scripting to allow end user customization.
I'm using plug-ins to implement most of the functionality in the game engine I'm building. The main EXE is made up of a script engine, a plug-in manager, some basic graphics routines and not much else. I'm using TJvPluginManager from the JEDI VCL library. It's a very good manager, and it can add just about anything you want to your program. Check out the demos included with the package to see how it works. The only downside is that it adds a lot of JCL/JVCL code to your program, but that's not really an issue if you're already using other JVCL components.
If plugins will be developed in Delphi or C++ builder, use packages + interfaces. Delphi OTA is a good example for that.
If plugins will be language independent, COM is a good way to go.
Addition: If you won't use COM, u may need to provide SDKs for each language. And datatype handling between different languages can be pain(for example delphi string type). Delphi COM support is excellent, u don't need to worry about kind of details. Those are mostly impilicit with Delphi COM support. Don't try to invent the wheel again. I'm surprised why people doesn't tend to mention about it.
I found an article by Tim Sullivan:
Implementing Plug-Ins for Your Delphi Applications
You could have a look at Hydra from Remobjects. Not only will this allow you to add plugins, but also to mix win32 and .net.
I read this article and find the concept of Virtual Library Interfaces nice for runtime loading of DLLs. However it seems that they aren't available for Win32. Is this true? And if so: Why? I don't see what would tie the idea to .NET.
EDIT: I'm mostly rephrasing here what Rob already wrote. :-)
I'm not after plugins or similar - it's about plain old Win32 DLLs. What appeals to me is the idea to let the compiler deal with all the details of loading a DLL at runtime - no need to call GetProcAddress for every function in the DLL etc.
It seems to me like the three answers so far have completely missed the point of your question. That, or I have. You're asking why Win32 Delphi doesn't have something like the magical Supports function that Hallvard's article talks about, aren't you? Namely, a function that, given the name of a DLL and the type information of an interface, returns an object that implements that interface using the standalone functions exported from the DLL.
Hydra seems to be all about calling .Net code from a Win32 program, not about importing functions from a DLL. TJvPluginManager requires that the plug-in DLLs export a special self-registration function that the manager will call when it loads the DLL, and the function must return an instance of the TJvPlugin class, so the plug-in DLL must be written in Delphi or C++ Builder. The Supports function, on the other hand, works with any DLL written in any language. You could use it on kernel32, if you wanted.
I don't know why Win32 Delphi doesn't have such a thing. Maybe CodeGear didn't see much demand for it since Delphi and Turbo Pascal had already gone for so long without it.
It's certainly possible to write a function that works like that, and I don't expect it would be any harder to write than the .Net version must have been, unless Microsoft's .Net libraries already provide most of the pieces and Delphi just wraps them up into a convenient-to-call function that looks like the several other overloaded versions of Supports that Delphi has had for years.
There would be a few steps to implementing that function in Win32. (I'm providing only a sketch of what's necessary because I don't have a running copy of Delphi handy right now. Ask nicely, and maybe I'll find more details.) First, you'd need to make sure that type information for an interface held, at a minimum, the undecorated names of its methods. Then, Supports would need to generate a function stub for each method in the interface (besides _AddRef, _Release, and QueryInterface). The stub would go something like this, assuming the calling convention is stdcall:
asm
// Pop the return address,
// discard the "this" pointer,
// and restore the return address
pop eax
pop ecx
push eax
jmp AddressOfFunction
end;
As Supports generated each stub, it would fill in the actual function address, gotten from calling GetProcAddress with the name of the corresponding interface method. The stdcall calling convention is easy to wrap like that; cdecl is a little cumbersome; register is a pain in the neck.
Once it has all the stubs generated, it would need to generate an "object" that looks like it implements the given interface. It doesn't have to be an actual class. At compile time, Supports doesn't know the layout of the interface it's going to be asked to implement, so having a class wouldn't accomplish much.
The final step is to provide implementations of the _AddRef, _Release, and QueryInterface. _AddRef would be unremarkable; _Release is where you'd call FreeLibrary when the reference count reached zero; QueryInterface wouldn't do much at all, except claim that it supports IUnknown and the interface given to Supports.
Delphi used to come with a sample program that demonstrated implementing an interface without any classes at all. It was all done with records and function pointers (which is all an interface ultimately is, after all). Delphi also came with the corresponding code to do it with classes, in part to show how much easier Delphi can make things. I can't find the name of the demo program now, but I'm sure it's still around somewhere.
There are a number of Win32 options for this type of functionality. Project JEDI has an open source plugin system as part of the JVCL that loads either DLLs or packages, and can include forms and whatnot as additional functionality.
There are also a number of commercial products available, including the TMS Plugin Framework and RemObjects Hydra.
This is nothing new or special. The article's just talking about plugins. Native code's been able to do plugins for years. The only special thing about P/Invoke is that it allows native code and .NET to talk to each other in a plugin system, and the little trick where "the DLL can be seen as a singleton object that implements the interface [so that] you can use the Supports function from the Borland.Delphi.Win32 unit to check if the DLL and all the methods are available."
If you want to do what the article's talking about in Delphi for Win32, look at the LoadLibrary, GetProcAddress and FreeLibrary Windows API functions. If you absolutely must have an interface like the article describes, you have to write it yourself, either in the DLL (if you wrote the DLL yourself) by writing an exported function that returns an interface, or in the calling app, by writing a function that uses GetProcAddress to create an interface dynamically. (Caution: this requires mucking around with pointers, and is usually more trouble than it's worth.)
Your best bet is probably just to do what Tim Sullivan mentioned: use TJvPluginManager from the JEDI VCL if you only need native code, or Hydra if you have to talk to .NET assemblies.
I've used Hydra myself for a Delphi only solution (i.e., didn't interface to .NET) and it works great for that too. It's easier to use and adds some niceties, but I think that it's basically implemented the same way as the "roll-your-own" plugin framework that is well-described in this article:
http://www.saxon.co.uk/SinglePkg/
I would look for a plugin framework that's interface-based (like Hydra and the "roll-your-own" system in above paragraph), rather than one that simply sends messages between apps.
There is a Delphi plugin framework on sourceforge, don't know whether it's the same one as in JEDI project or not: http://sourceforge.net/projects/rd-dpf
There are also a couple of other commercial solutions, one of which is Dragonsoft's:
http://www.dragonsoft.us/products_dsps.php
What is wrong with doing this with simple com objects? Declare a simple interface that all of your plugins implement, and require that each com object include an exported function that returns its class guid. Then using the "plugins" is as simple as walking thru the plugins directory looking for DLL's which expose the special registration function, invoking it and then using the class guid to then invoke the com object.
I used something like this in a WIN32 commercial application with great success. The advantage was I could switch plugins in and out at will (provided of course the application wasn't running to remove existing ones), the magic was all in the interface that each one implemented.