Delphi interface inheritance. Features of working with interfaces in Delphi

I have a problem using Delphi class from C ++ code. delphi dll demo that exports a function that returns an object.
my Delphi Dll code looks like this:

Library DelphiTest; // uses part .... type IMyObject = interface procedure DoThis (n: Integer); function DoThat: PWideChar; end; TMyObject = class (TInterfacedObject, IMyObject) procedure DoThis (n: Integer); function DoThat: PChar; end; // TMyObject implementation go here ... procedure TMyObject.DoThis (n: Integer); begin showmessage ("you are calling the DoThis methode with" + intToStr (n) + "parameter"); end; function TMyObject.DoThat: PChar; begin showmessage ("you are calling the DoThat function"); Result: = Pchar ("Hello im Dothat"); end;

// export the DLL function:

Function CreateMyObject: IMyObject; stdcall; export; var txt: TextFile; begin AssignFile (txt, "C: \ log.log"); Reset (txt); Writeln (txt, "hello"); Result: = TMyObject.Create; end; exports CreateMyObject;

in my C ++ project I have declared the IMyObject interface like this:

Class IMyObject (public: IMyObject (); virtual ~ IMyObject (); virtual void DoThis (int n) = 0; virtual char * DoThat () = 0;);

and my main function is like this:

Typedef IMyObject * (__stdcall * CreateFn) (); int main () (HMODULE hLib; hLib = LoadLibrary (L "DelphiTest.dll"); assert (hLib! = NULL); // pass !! CreateFn pfnCreate; pfnCreate = (CreateFn) GetProcAddress ((HINSTANCE) hLib, "CreateMyObject "); if (pfnCreate == NULL) (DWORD errc = GetLastError (); printf ("% u \ n ", errc); // it gets error 127) else (printf (" success load \ n ");) IMyObject * objptr = pfnCreate (); objptr-> DoThis (5); FreeLibrary (hLib); int in; scanf_s ("% i", & in); return 0;)

in this example, I got a runtime error when I try to access the exported function. errors in the line:
IMyObject * objptr = pfnCreate ();

Can you tell me what is wrong with my example.
and if possible any working example for accessing a Delphi class (in DLL) from C ++ code.

Solution

The first problem is calling the convention of methods. The Delphi interface uses register which is a Delphi specific calling convention. using stdcall For example, for interface methods.

The next problem is in C ++. Your C ++ interface must derive from IUnknown. Also, it must not declare a constructor or destructor.

Apart from this, your Delphi code is exported by PWideChar which does not map to char *, It maps to wchar_t *.

Looking further, returning PChar works great here because your implementation is returning a literal. But more serious code will probably want to use a dynamically allocated string, at which point your design is flawed.

Please note that you must be an elevated administrator to create a file at the root of the system drive. So this is another potential point of failure.

I expect there are other errors, but this is all I have found so far.

The article was written based on the results of analysis of programs written by young developers of our group.

Correctly arrange the sequence of switching components

Many users, especially those who have previously worked in DOS, have the habit of switching between input fields not with the mouse, but using the keyboard with the Tab key. Plus, it's much faster than selecting each field with the mouse. Therefore, the order of switching components must be set correctly. This applies both to the components inside all container components (panels, GroupBoxes and the like), and to the container components themselves, if there are several of them on the form.

The order of switching components inside the container is set by the TabOrder property. The first becomes the active component, in which the TabOrder is 0, the second with 1, and so on, until all components are enumerated. In addition, the component has a TabStop property that indicates whether the component will receive focus when switched with the Tab key. If you need to prohibit switching to any component, set its TabStop = false. In this case, you can only switch to this component using the mouse.

There are times when users who are accustomed to switching a certain key in one program, out of habit, continue to use it in the rest. This often happens with 1C users, where the Enter key can be used to navigate through the input fields. Well, let's give them this opportunity in our programs, if they ask for it. Set the form's KeyPreview property to true and write an event handler for the OnKeyPress event:

Procedure TForm1.FormKeyPress (Sender: TObject; var Key: Char);
begin
if ord (key) = vk_Return then
Form1.SelectNext (PriemForm.ActiveControl, true, true);
end;

Such a handler provides navigation through the form elements when the Enter key is pressed. It should be noted that this method will not work with buttons, since pressing Enter on a button causes it to be pressed, while pressing Tab transfers the input focus to the next component in the toggle sequence.

Default buttons

All the same users quickly get used to the fact that in application dialog boxes, as a rule, you can confirm your choice with the Enter key, and cancel with the Esc key. Let's not disappoint them in our programs, especially since it's very easy to do this. For a button that responds to Enter, set the Default property to true. For a button that responds to Esc, set the Cancel property to true. And that's all.

Yes or no

All dialog boxes requesting user actions must have at least two buttons: confirm the action and cancel the action (Yes / No, Save / Cancel, etc.). An action can be canceled by closing the window with the [X] button in the window title. It is unacceptable if there is only one button to confirm the action, and to refuse it is supposed to close the window with the [X] button in the header, or there is no possibility of refusal at all. This confuses the user, raising a logical question: how to refuse?

Also, do not forget about what was said above in the "Default buttons" section.

All dialog boxes should open in the center of the screen

Centered, not where they were created in design mode. Firstly, it is clearer, and secondly, it automatically eliminates the problem of different screen resolutions for different users.

An exception is made if the dialog box is not modal, and as a result of the user's work, changes in the main window immediately occur in this window (for example, filtering the dataset, redrawing graphs, etc.).

Windows must not be larger than the screen

In no case. It is a disgrace when part of the window crawls out of the screen. This requirement does not depend on the user's screen resolution, i.e. excuses like "Let them get more permission" do not work.

Correct resizing of window elements

Window elements must resize or move correctly when the window is resized, when the window is maximized, and when the window is restored after maximizing.

Everything is always visible

Reducing the size of the window should not lead to the disappearance of window elements and, preferably, should not lead to the appearance of scroll bars (scrollers) of the window itself. You can limit the minimum size of the window so that all elements are visible and accessible. If it is not possible to place components in such a way that all are visible in the window, you can use tabs (such as PageControl) to divide components into groups. We also don’t miss excuses about the screen resolution.

Hints everywhere, hints always

For buttons, especially on toolbars (such as ToolBar), hints should be set so that it is always clear why this or that button is needed.

Color spectrum

Don't paint the components on the form all the colors of the rainbow. This tires the eyes and distracts the user's attention. It doesn't look cool. Highlighting is used when it is necessary to draw the user's attention to a certain element or a certain part of the window. For example, color records with light red color, which contain errors, or, conversely, light green color for records that were checked successfully.

Conclusion

There is a very good method that allows you to find the shortcomings of the program in general and the interface in particular. It is simple: imagine yourself in the user's place and for half an hour try to work the way it works. It's even better if your user is within reach (for example, works in the same organization). In this case, sit next to him, or rather instead of him, and try to make his work. Enter data, change it, display reports, etc. If you don't know how to do it right, ask your user. Do not one or two operations of the same type, as in debug mode, but 20-30, or even more, different operations, in a different order. Forget to enter something or enter it incorrectly and see how the program reacts to it. You will quickly see the weaknesses of your program.

The author of the article automated the work of the admissions office at the university, and in the first year of the introduction of the program, he spent 3-4 hours a day at the admissions office, registering applicants, filling out their personal data and giving them exam reports. And in the remaining working hours he corrected mistakes and shortcomings. Believe me, next year there are practically no problems left. It was the same with the introduction of the personnel module.

Thus, keep the user experience in mind. Make it easy and pleasant for them to work with your programs.

This article is based on the questions on the forums: "How can I return a string from a DLL?", "How to transfer and return an array of records?", "How to transfer a form to a DLL?"

So that you don't waste half your life trying to figure it out, in this article I will bring everything on a silver platter.

The topics of this article have already been touched upon in this blog to varying degrees, but in this article they are collected in a bunch, the rationale is given. In short, a link to this article can be thrown at those who develop DLLs.

Important note: the article needs to be read consistently... Code examples are provided only as examples, at each step (paragraph) of the article, the code of examples is added with new details. For example, at the very beginning of the article there is no error handling, the "classic" methods (such as using GetLastError, sdtcall conventions, etc.) are indicated, which are replaced with more adequate ones in the course of the article. This is done for the reason that the "new" ("unusual") constructions do not raise questions. Otherwise, for each example, you would have to insert a note of the form: "this is discussed in that paragraph below, but that is in this one." In any case, at the end of the article there is a link to the ready-made code, written taking into account everything said in the article. You can just take it and use it. And the article explains why and why. If you are not interested in "why and why" - scroll down to the conclusion and the link to download the example.

only for the result

strict adherence to deadlines

Transparency

project execution

technical support as a gift

Programming, revision of advice on 1C

How we are working

1. We discuss the problem over the phone. If you have remote access - show it on the screen of your computer.

2. We estimate the work in rubles, if the project is large, if not - the approximate number of hours.

3. We get the job done.

4. You accept work in your program, if there are any shortcomings, we correct them.

5. We issue an invoice, you pay.

Cost of work

1. All work is divided into 3 categories: consultation, updating a typical configuration, developing or programming a new report, processing, buttons, etc.

3. For work more than 10 hours, a technical assignment with a description and cost of work is preliminarily drawn up. Work begins after agreeing on the terms of reference with you.

Technical support

1. If you find any errors in previously accepted works, within 3 months, we correct them free of charge.

2. For regular customers, we correct any shortcomings in our work free of charge throughout the year.

Programs to manage your business.

Buy 1C: Enterprise

We are an official dealer of 1C, you can purchase various software products and licenses from us. In addition to buying a "box", we will help you set up the program, advise and make basic settings.

  • Accounting
  • Store automation
  • Wholesale
  • Installation and initial setup help is included in the package!
  • Fine tuning of configurations for the needs of the customer, development of new modules in the absence of the necessary functions in the standard configuration.
1c accounting 1C: Trade Management 1C: Retail 1C: Salary and Personnel Management
From 3300 rub. From 6700 rub. From 3300 rub. From 7400 rub.

Server provision.

Instant setup server + 1C.

Don't have a server? It doesn't matter, we'll pick up and quickly set up a server in the "cloud". For a small fee, you get a very reliable solution.

  • Availability 24/7
  • No need to keep your own sysadmin (the savings will cover your server costs).
  • Quick setup and installation of 1C on the server, in 3 days you will already have a fully working system.
  • At any time, you can move to a local server if the solution does not suit you.

SMS from your 1C

Do you want customers to know about promotions, discounts on time? Customers not returning? Set up sending SMS directly from 1C!

Our company will be able to quickly set up sending SMS to your customers directly from 1C. Examples of events that can be automated:

  • Thanks for the purchase and the accrual of bonuses immediately after the next purchase.
  • Accrual of bonuses to the card as a gift for a birthday \ for another significant or holiday.
  • Notification of goods arrival at the warehouse.
  • Expiration of gift bonuses.
  • Notification of the receipt of an advance payment and reservation of goods.
  • Address with details of how to get to the store / office, phone numbers.
  • Etc.

Settings in 1C can be done by our specialists or our employees. You can get acquainted with the tariffs on the SMS tariffs page.

  • SMS delivery guarantee, money is withdrawn only for delivered SMS.
  • Separate billing for each SMS.
  • Balance replenishment in different ways.
  • View the history of all sent SMS at any time.
  • The sender's name instead of the digital number on the message recipient's phone.

Object-oriented programming (OOP), in addition to the concept of a class, also provides for the fundamental concept of an interface.

What is an interface and what are the features of working with it in the Delphi programming language?

Interface is a semantic and syntactic construct in program code used to specify the services provided by a class or component (Wikipedia).

In fact, the interface defines a list of properties and methods that should be used when working with the class that implements this interface, as well as their signature (name, data type, accepted parameters (for procedures and functions), etc.). Thus, a class that implements a particular interface must necessarily implement all of its components. Moreover, in strict accordance with how they are described in it.

Interfaces are often compared with abstract classes, but despite the similarity, this comparison is not entirely correct. In abstract classes, at least control over the visibility of members is available. At the same time, no scopes are defined for interfaces.

Interfaces allow you to make the architecture more flexible, since they unify access to a particular functionality, and also allow you to avoid a number of problems associated with class inheritance (interfaces can also be inherited from one another).

To declare an interface in Delphi, use the interface keyword. This is the same keyword that defines the section of the unit that can be accessed from outside (between the keywords interface and implementation). However, when declaring an interface, a different syntax is used, similar to class declarations.

Delphi / Pascal

IMyNewInterface = interface procedure InterfaceProc; end;

IMyNewInterface = interface

procedure InterfaceProc;

end;

Thus, the syntax of the interface declaration itself does not fundamentally differ from other programming languages ​​(the features of the syntax based on Pascal do not count). At the same time, the implementation of the interfaces has a number of characteristic features.

The point is that Delphi interfaces were originally introduced to support COM technology. Therefore, the IInterface interface, which in Delphi is the ancestor of all other interfaces (a kind of analogue of TObject), already contains three basic methods for working with this technology: QueryInterface, _AddRef, _Release. As a result, if a class implements any interface, then it must implement these methods without fail. Even if this class is not designed to work with COM.

Due to this feature of the IInterface interface, in Delphi, the use of interfaces, in most cases, leads to the addition of deliberately unused capabilities to the class.

There is a library class TInterfaceObject, which already contains the implementation of these methods and, when inheriting from it, there is no need to implement them yourself. But since Delphi does not support multiple class inheritance, its use often only causes additional difficulties in the design and implementation of the already required functionality.

All this led to the fact that, despite all the possibilities provided by interfaces, their practical use in Delphi almost did not go beyond working with COM.

Optimized to work primarily with this technology, interfaces, or rather the functionality and architectural constraints they add on a mandatory basis, do not justify themselves when solving other problems.

Therefore, many Delphi programmers are still, in fact, deprived of a powerful and flexible tool for developing application architecture.

Share this