Delphi Xe3 Com Port Component
Website dedicated to Delphi components written/donated by Project JEDI members. September 2015. Focusing on Delphi and C++ Builder XE3 support. Creating components in Delphi is a fairly simple task as long as you understand the workings of.
I've a program that access multiple serial ports using cport. To configure, till now I simply listed all available comports in a combobox to make a selection, but the increasing number of drivers with (virtual) serial interfaces makes configuring for end-users troublesome. The current detection works with createfile(), but that has the problem that you only get exists/nonexists and maybe 'busy' as information. However to improve, I need per COM port a identification string, like the hardware device/driver (device manager) it is connected too.
This would make it easier for the user to narrow the comports down (since we deliver a finite number of serial cards) Probably it is available from WMI, but that's quite a jungle, does sb have more concrete information, or better, code? (Delphi XE3, Win7+, no solution that requires additional installing or deployment please).
Building a COM Server - COM, COM+, Delphi Tutorials and References - Binh Ly on 9/27/2002 Building a COM Server Application A COM server application provides services to a COM client application. If you've previously studied the basics of, we're now ready to see it in action in Delphi.
The following basic steps are performed to build a COM server: • Determine what kind of COM server to create. This can be an. • Create the COM server framework/housing. • Create the COM components • Deploy the COM server DLL vs.
EXE A DLL server normally executes in the address space of its client. As such, it is very efficient in terms of execution speed.
Examples of DLL servers are windows shell extensions, plugins, ActiveX controls, and utility servers. An EXE server executes outside the address space of its client. Since an EXE server is isolated from the client application, it can be configured to run under a separate security context, implement its own threading mechanisms, and has less impact on the client in case of runtime failure.
Examples of EXE servers are standalone applications that also support automation such as the Microsoft Office applications, or a COM server implemented as a Windows Service application. Although DLLs are normally executed in the address space of a client, it is possible to host a DLL server into an EXE application and thus achieve the same behavior and advantages of an EXE server. An example of such host is the MTS/COM+ runtime environment. One of main reasons to do this is to have the host provide add-on infrastructure not normally/easily available for DLL servers such as security management, thread management, process isolation, etc. In general, it is safe to assume the we want to build DLL servers unless we are building COM into an existing standalone EXE application or a Windows Service application. Note that only DLLs have the ability to be hosted into the MTS/COM+ runtime.
If we build an EXE server, it cannot be hosted into the MTS/COM+ runtime down the road unless, of course, we convert it to a DLL server. Creating the COM Server Framework/Housing In Delphi, we create a DLL server using File New ActiveX ActiveX Library. This creates a skeleton project that provides the 4 standard exports of a valid DLL COM server: uses ComServ; exports DllGetClassObject, //called by COM to obtain a class factory object DllCanUnloadNow, //called by COM at runtime to determine if this DLL server is safe to unload DllRegisterServer, //called by COM to register this DLL server DllUnregisterServer; //called by COM to unregister this DLL server The implementations of these exports can be found in ComServ. The Delphi COM library automatically handles management of the class factories and server outstanding reference count used to implement the above exports. For the EXE server, we simply create a standard EXE application: File New Application. Delphi automatically adds a default form to our server that acts as the server's interactive user interface. If we don't want an EXE server to show this form, we simply add the following lines to our project's DPR file: begin Application.Initialize; Application.ShowMainForm:= False; Application.CreateForm(.); Application.Run; end.
Note that it is important to have the Application. Power Civil V8i Cracker there. Initialize call as the first statement in the DPR file. This enables the ComObj module to initialize the COM runtime by calling CoInitialize/Ex at startup. If you are migrating an EXE application to a COM server and forgot to call Application.Initialize, you'll get a 'CoInitialize has not been called' error at the first statement that makes a COM call that requires exporting/importing a COM interface. This is a common error when migrating standalone applications into COM servers or upgrading a COM server from an older version of Delphi to Delphi 5.
Creating COM Components In Delphi, we can create several types of COM components: • COM Object - a COM component that does not support IDispatch/Automation. This is used to build lightweight COM components such as Windows shell extensions and non-scriptable servers such as plugins, etc. • Automation Object - a COM component that supports IDispatch/Automation. This is used to build COM components that are scriptable and support late-binding, in addition to being able to implement a standard vtable interface. In general, this is the most common type of COM component that we are going to create. • MTS Object - an Automation Object that has access to the intrinsic MTS/COM+ runtime context object. This is used to build COM components that will be hosted in the MTS/COM+ runtime and will need the convenience of accessing the MTS/COM+ context object and other basic MTS/COM+ facilities.
• Active Server Object - an Automation Object that has access to the intrinsic ASP server objects such as Request, Response, etc. ASP is a scripting environment used to build web applications on the Microsoft IIS platform. This is used to build COM components that will be called from ASP and will need the convenience of accessing the ASP server objects. • ActiveX Control - a COM component that conforms to the COM ActiveX control standard. An ActiveX control is a UI control that is interoperable across and can be hosted into ActiveX container environments. When creating a COM component, the wizard always asks for the desired threading model. As we've, the threading model specifies how our COM components behave when used in a multithreaded environment.
The wizard also asks for an Instancing option. Defines how COM asks a to create our server components. The COM Object A COM Object is created using File New ActiveX COM Object.
In the COM Object Wizard dialog, we're presented with 2 extra options: • Include Type Library - if checked, specifies that our COM component will implement a new IUnknown-derived interface that should be defined in the type library. If this option is unchecked, no new interface is created and the resultant COM component does not implement any custom interfaces by default. • Mark Interface OleAutomation - if checked, specifies that if a new interface is implemented (Include Type Library option is checked), this interface should have the flag set. IMO, this option has no use because you'll most likely need to check it all the time.
Unchecking this option makes no sense because Delphi does not support creation of custom proxy-stub marshalers and so the resultant interface is not usable by client applications (since it is not marked as [oleautomation] and there is no other marshaling option). When creating a COM Object, the resultant class derives from either TComObject (Include Type Library option unchecked) or TTypedComObject (Include Type Library option checked). TComObject does not support any kind of type information exposure at all. TTypedComObject supports the most basic type information exposure through the IProvideClassInfo interface. When adding methods to this COM component using the TLE (Type Library Editor), Delphi does not use the safecall calling convention by default. Thus, we'll see every method implemented to return the standard COM HRESULT and use the stdcall calling convention.
To enable the safecall mapping, tweak the Tools Environment Options Type Library Safecall function mapping option in the IDE. If set to 'All vtable interfaces', this enables the safecall mapping for our interface. The Automation Object An Automation Object is created using File New ActiveX Automation Object. In the Automation Object wizard dialog, we're presented with 1 extra option: • Generate Event Support Code - if checked, this generates a dispinterface event interface definition in the type library and some simple code that allows management of the event. This event is based off of the architecture. We'll get into the details of this in a later lesson.
When creating an Automation Object, the resultant class derives from TAutoObject. TAutoObject supports type information exposure (IProvideClassInfo) as well as a standard type-information based implementation of IDispatch. A new interface is created in the type library that derives from IDispatch and is marked [dual, oleautomation]. Methods added to an Automation Object are automatically mapped as safecall by default. Again this behavior can be changed by tweaking the Tools Environment Options Type Library Safecall option in the IDE. The MTS Object An MTS Object is created using File New Multitier MTS Object.
In the MTS Object wizard dialog, we're presented with a Transaction Model option. This option specifies how the MTS/COM+ runtime manages transactions while hosting our component. The principles behind MTS transactions are non-trivial so I highly recommend that you read up on the theories behind MTS/COM+ before doing any serious MTS/COM+ development. Some excellent references on the subject are: Understanding COM+ by David Platt or Understanding Windows 2000 Distributed Services by David Chappell. When creating an MTS Object, the resultant class derives from TMtsAutoObject. TMtsAutoObject provides a default implementation of IObjectControl and encapsulates some of the facilities provided by the MTS context object. For example, the following illustrates usage of the IObjectContext SetComplete and SetAbort methods as wrapped by TMtsAutoObject: type TAccount = class(TMtsAutoObject, IAccount); function TAccount.Update(var ID: OleVariant; const LoginID, Name: WideString): WordBool; begin try.Execute Update logic here.
//MTS SetComplete SetComplete; except //MTS SetAbort SetAbort; raise; end; end; The Active Server Object An Active Server Object is created using File New ActiveX Active Server Object. In the Active Server Object wizard dialog, the Active Server Type option selections are: • Page-level methods - this adds the OnStartPage and OnEndPage methods to our COM component.
These methods provide support for a legacy protocol that enables IIS to hook into our component when setting up the link to the ASP server objects. I don't recommend this option unless you are running IIS 3.0 or you are building an EXE server to be called from ASP/IIS.
• Object Context - this enables access to the ASP server objects through the newer MTS/COM+ runtime context object. When building DLL servers to run under the latest version of IIS, this option is recommended.
When creating an Active Server Object, the resultant class derives from either TASPObject (Page-level methods option) or TASPMTSObject (Object Context option). Either way, access to the intrinsic ASP objects is the same. The following illustrates writing to the ASP response stream from within an Active Server Object: type TBar = class(TASPMTSObject, IBar); procedure TBar.HelloWorld; begin Response.ContentType:= 'text/html'; Response.Write ('); Response.Write ('Hello World'); Response.Write ('); end; //ASP code <% dim Bar set Bar = Server.CreateObject ('BarServer.Bar') Bar.HelloWorld set Bar = nothing%>If you come from a Java/J2EE background, an Active Server Object is similar in concept to a Servlet component. If you come from an ASP background, you'll probably wonder why you'd want to create an Active Server Object instead of performing business logic (page generation, etc.) directly in ASP.
The main reasons are: • An Active Server Object can hide a lot of complex business logic that executes at maximum performance. • ASP is script-based and makes late-bound calls. Therefore, it is less efficient that an Active Server Object that contains compiled code when accessing the intrinsic ASP objects. Deploying COM Servers We've how to register COM servers and how to properly check for a registered COM server. In general, we cannot use a COM server unless it is correctly installed and registered. When developing COM clients, it is not uncommon to get the error 'Invalid class string' or 'Class not registered' once in a while or in a new install in a production environment. What this error means is that the COM server that our client is trying to create is somehow not properly registered on the target machine.
It is also important to understand that different versions of a COM server can produce this error. For example, if our COM client is expecting to automate MS Word 2000 and the target machine has MS Word 97 (but not 2000), it is very possible to receive the above error.
The fix, obviously, is to ensure that the correct COM server version is installed and registered on the target machine. COM servers that are intended to be accessed from a remote machine through DCOM almost always need to be properly configured before usage. This is usually done using the DCOMCNFG utility. Since the mechanics of configuring DCOM security is a complex topic, I refer you to some resources that might be of help: • • Miscellany Inside the COM Server Housing Every COM server contains a global object, ComServer (ComServ module), that serves as the heartbeat of the server's housing.
Some of the most important aspects of TComServer are: TComServer = class(TComServerObject) public procedure UpdateRegistry(Register: Boolean); property ObjectCount: Integer; property StartMode: TStartMode; property UIInteractive: Boolean; //D5 and above only property OnLastRelease: TLastReleaseEvent; property ServerFileName: string; property ServerKey: string; property TypeLib: ITypeLib; end; TComServer.UpdateRegistry This method registers (and unregisters) our COM server. For DLLs, UpdateRegistry (True) is called by DLLRegisterServer and UpdateRegistry (False) is called by DLLUnregisterServer. For EXEs, UpdateRegistry (True) is called when the server is not run with the '/unregserver' command-line parameter; otherwise UpdateRegistry (False) is called. For EXEs, UpdateRegistry (True) is always called unless the '/unregserver' command-line parameter is specified. This means that our server will execute the registration process under circumstances that we may not expect.
For instance, whenever the server is activated as a result of a request from a COM client, it registers itself, unnecessarily. This may have implications on a deployment scenario where registration could fail if the server's activator account does not have sufficient rights to the registry (registration writes entries into the registry). In fact, this was a problem with D4 and prior versions, but was corrected in D5.
However, the fact still remains that EXE servers perform registration under circumstances that we may not expect. TComServer.ObjectCount ObjectCount returns the total number of outstanding COM objects in the server at any given time. This does not include the count of outstanding class factory instances - this count is kept in a private TComServer field, FFactoryCount. ObjectCount (and FFactoryCount) is used to implement DLLCanUnloadNow for DLLs or the shutdown process for EXEs. TComServer.StartMode StartMode specifies the activation mode for EXE servers. It can be any of the following values: StartMode Description smStandAlone Server is not activated through COM and is not being registered/unregistered smAutomation Server is activated through COM smRegServer Server is activated with the '/regserver' command-line parameter smUnregServer Server is activate with the '/unregserver' command-line parameter TComServer.UIInteractive UIInteractive specifies if an EXE server should pop up a confirmation dialog when an attempt is made to terminate it while there are still outstanding COM objects running.
It is convention for a COM server to refuse termination until the last outstanding COM object is released. If the server didn't do this, clients may get fatal errors as a result of unexpected termination of the server. The default value for UIInteractive is True, meaning that a confirmation should always be asked. If we want to turn this behavior off, we simply add the following lines to our server's DPR file: begin Application.Initialize; Application.UIInteractive:= False; Application.CreateForm(.); Application.Run; end. TComServer.OnLastRelease This is an event that gets called after the last outstanding server object is released in an EXE server. We can assign a custom handler to this event to determine the fate of our server's shutdown.