Recent

Author Topic: [SOLVED] Where to place functions to make them accessible from any unit  (Read 1168 times)

Raul_ES

  • Full Member
  • ***
  • Posts: 169
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Hello friends,

I want to create a unit with the following code:


Code: Pascal  [Select][+][-]
  1. unit unit_ciphers;
  2.  
  3. {$mode objfpc}
  4.  
  5. interface
  6.  
  7.  
  8. uses
  9.   Classes, SysUtils, DCPblowfish, DCPrijndael, DCPserpent, DCPidea, DCPmars,
  10.   DCPtwofish, DCPcast128, DCPcast256, DCPdes, DCPice, DCPtea, DCPsha1,
  11.   DCPsha256, DCPmd5;
  12.  
  13.  
  14.  
  15.  
  16. implementation
  17.  
  18.  
  19. function Code(key:string; uncrypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif} //Encode(key, text, level)
  20.   var
  21.     motor: TDCP_blowfish;
  22.     i: integer;
  23.     t: string;
  24.   begin
  25.     if level=0
  26.       then level:=1
  27.       else if level>2
  28.         then level:=2;
  29.     motor:=TDCP_blowfish.Create(nil);
  30.     t:=uncrypted_string;
  31.     for i:=1 to level do begin
  32.       motor.InitStr(key,TDCP_sha256);
  33.       t:=motor.EncryptString(t);
  34.       motor.Burn;
  35.     end;
  36.     result:=t;
  37.     motor.Free;
  38.   end;
  39.  
  40. function Decode(key:string; crypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif} //Decode(key, text, level)
  41.   var
  42.     motor: TDCP_blowfish;
  43.     i: integer;
  44.     t: string;
  45.   begin
  46.     if level=0
  47.       then level:=1
  48.       else if level>2
  49.         then level:=2;
  50.     motor:=TDCP_blowfish.Create(nil);
  51.     t:=crypted_string;
  52.     for i:=1 to level do begin
  53.       motor.InitStr(key,TDCP_sha256);
  54.       t:=motor.DecryptString(t);
  55.       motor.Burn;
  56.     end;
  57.     result:=t;
  58.     motor.Free;
  59.   end;
  60.  
  61.  
  62. end.                
  63.  

In other unit (the main one) I specify uses "unit_ciphers" with the believe that it would make accessible all the contents of the
"used" units. But not. When compiling I find that:

(buffer is a string)

if CheckBox1.Checked = True then begin
        buffer := Code('aDc32bBlmBvCx283sdDwZz', EditSend.Text, 1);
              FNet.SendMessage(buffer);

      end;


gives an error Identifier not found "Code".

Whats wrong with unit_cipher? I still don't seem to manage this kind of situations.

regards


« Last Edit: January 22, 2020, 04:17:34 pm by Raul_ES »
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

Raul_ES

  • Full Member
  • ***
  • Posts: 169
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Where to place functions to make them accessible from any unit
« Reply #1 on: January 22, 2020, 04:03:13 am »
I found the following:

https://www.freepascal.org/docs-html/ref/refse106.html

Quote
The implementation part is primarily intended for the implementation of the functions and procedures declared in the interface part. However, it can also contain declarations of it’s own: the declarations inside the implementation part are not accessible outside the unit.

How can I make them public and accessible from elsewhere?
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

HeavyUser

  • Sr. Member
  • ****
  • Posts: 310
Re: Where to place functions to make them accessible from any unit
« Reply #2 on: January 22, 2020, 04:05:21 am »
the unit is devided in to two main sections. Implementation and interface. what ever is declared in interface is public and can be accessed from other units what ever is declared in implementation it is private and can not be accessed from other units.

Please note the use of the term declared instead of written or placed etc. The interface section can only have declarations, types, constants, function names etc, no code can exists in the interface section. In your case simply copy the function declaration from the implementation to the interface section and you should be able to use them from other units.
« Last Edit: January 22, 2020, 04:09:35 am by HeavyUser »

PaulRowntree

  • Full Member
  • ***
  • Posts: 132
    • Paul Rowntree
Re: Where to place functions to make them accessible from any unit
« Reply #3 on: January 22, 2020, 06:34:40 am »
You can think of the interface portion as a contract between the unit and any code that uses it.  This is what the unit promises to provide (and how, exactly), and the compiler enforces this agreement.  What ever the contract promises must be fully worked out in the implementation.
Paul Rowntree
- coding for instrument control, data acquisition & analysis, CNC systems

Raul_ES

  • Full Member
  • ***
  • Posts: 169
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Where to place functions to make them accessible from any unit
« Reply #4 on: January 22, 2020, 02:24:51 pm »
Thanks, sorry I didn't said I tried also to place it there, but then it complains with another error:

Quote
unit_ciphers.pas(10,1) Fatal: Syntax error, "IMPLEMENTATION" expected but "USES" found
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

Raul_ES

  • Full Member
  • ***
  • Posts: 169
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Where to place functions to make them accessible from any unit
« Reply #5 on: January 22, 2020, 02:29:58 pm »
Quote
unit unit_ciphers;

{$mode objfpc}

interface

function Code(key:string; uncrypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif}
function Decode(key:string; crypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif}


uses
  Classes, SysUtils, DCPblowfish, DCPrijndael, DCPserpent, DCPidea, DCPmars,
  DCPtwofish, DCPcast128, DCPcast256, DCPdes, DCPice, DCPtea, DCPsha1,
  DCPsha256, DCPmd5;




implementation
//function Code(key:string; uncrypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif}
//function Decode(key:string; crypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif}


function Encode(key:string; uncrypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif} //Encode(key, text, level)
  var
    motor: TDCP_blowfish;
    i: integer;
    t: string;   

(...)

unit_ciphers.pas(10,1) Fatal: Syntax error, "IMPLEMENTATION" expected but "USES" found
« Last Edit: January 22, 2020, 02:33:50 pm by Raul_ES »
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

Raul_ES

  • Full Member
  • ***
  • Posts: 169
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Where to place functions to make them accessible from any unit
« Reply #6 on: January 22, 2020, 02:33:20 pm »
I am trying different combinations, I don't seem to get the right order

Quote
unit unit_ciphers;

{$mode objfpc}


uses
  Classes, SysUtils, DCPblowfish, DCPrijndael, DCPserpent, DCPidea, DCPmars,
  DCPtwofish, DCPcast128, DCPcast256, DCPdes, DCPice, DCPtea, DCPsha1,
  DCPsha256, DCPmd5;



interface

function Code(key:string; uncrypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif}
function Decode(key:string; crypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif}

(...)

 

unit_ciphers.pas(6,5) Fatal: Syntax error, "INTERFACE" expected but "USES" found
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

Bart

  • Hero Member
  • *****
  • Posts: 3817
    • Bart en Mariska's Webstek
Re: Where to place functions to make them accessible from any unit
« Reply #7 on: January 22, 2020, 02:47:36 pm »
Put the uses clause below interface.

Bart

hansotten

  • New Member
  • *
  • Posts: 43
Re: Where to place functions to make them accessible from any unit
« Reply #8 on: January 22, 2020, 02:49:26 pm »
unit

interface

uses

implementation

uses

and have a look at the freepascal unit syntax about what goes where and why


Raul_ES

  • Full Member
  • ***
  • Posts: 169
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Where to place functions to make them accessible from any unit
« Reply #9 on: January 22, 2020, 03:43:34 pm »
Put the uses clause below interface.

Bart

Already tried in Reply #5

This is a nightmare  %)
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

wp

  • Hero Member
  • *****
  • Posts: 7237
Re: Where to place functions to make them accessible from any unit
« Reply #10 on: January 22, 2020, 03:48:05 pm »
Here is a reworked version of your unit from the initial post which compiles fine:

Code: Pascal  [Select][+][-]
  1. unit unit_ciphers;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses                   // In fact, your code does not use these units at all.
  8.   Classes, SysUtils;   // Therefore these lines could be skipped.
  9.  
  10. function Code(key:string; uncrypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif}
  11. function Decode(key:string; crypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif}
  12.  
  13.  
  14. implementation
  15.  
  16. uses
  17.   DCPblowfish, DCPtwofish, DCPsha256;
  18.  
  19. function Code(key:string; uncrypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif} //Encode(key, text, level)
  20. var
  21.   motor: TDCP_blowfish;
  22.   i: integer;
  23.   t: string;
  24. begin
  25.   if level=0
  26.     then level:=1
  27.     else if level>2
  28.       then level:=2;
  29.   motor:=TDCP_blowfish.Create(nil);
  30.   t:=uncrypted_string;
  31.   for i:=1 to level do begin
  32.     motor.InitStr(key,TDCP_sha256);
  33.     t:=motor.EncryptString(t);
  34.     motor.Burn;
  35.   end;
  36.   result:=t;
  37.   motor.Free;
  38. end;
  39.  
  40. function Decode(key:string; crypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif} //Decode(key, text, level)
  41. var
  42.   motor: TDCP_blowfish;
  43.   i: integer;
  44.   t: string;
  45. begin
  46.   if level=0
  47.     then level:=1
  48.     else if level>2
  49.       then level:=2;
  50.   motor:=TDCP_blowfish.Create(nil);
  51.   t:=crypted_string;
  52.   for i:=1 to level do begin
  53.     motor.InitStr(key,TDCP_sha256);
  54.     t:=motor.DecryptString(t);
  55.     motor.Burn;
  56.   end;
  57.   result:=t;
  58.   motor.Free;
  59. end;
  60.  
  61. end.

Some rules and comments:
  • The first (non-comment) line must be "unit <unitname>".
  • The second (non-comment) line must be "interface".
  • Then: "uses <comma-separated list of units needed by the declarations in the interface part>". In your code, in fact, the DCP units are not needed at all by the interface declarations which follow, therefore I moved them to the "uses" clause of the implementation part. This step is not absolutely necessary, but in large project you may run into circular unit references (unit A uses unit B, and unit B uses unit A) if you don't do this. Furthermore, what is left is Classes and SysUtils -- these units are not needed either (just try to compile without them) and you can skip the entire interface uses clause (I left it though to show you a valid unit structure).
  • Publicly visible declarations: type, const, procedure and function headers, NO code
  • Line "Implementation"
  • Then: "uses <comma-separated list of units needed by the declarations in the implementation part>". A comment here again: Your unit actually only uses DCPblowfish, DCPtwofish and DCPsha256; so, there is no need to add the other DCP units. This may add unnecessary code to your program (initialization).
  • Then optional additional declarations private to the unit, auxiliary code - not needed here.
  • code for the procedures/functions listed under "Interface".
  • Last line "end." (with a period!)
Regarding the {$MODE ObjFPC} directive I also added {$H+} which avoids using short strings in this unit (you probably want to encrypt strings longer than 255 characters!).
« Last Edit: January 22, 2020, 03:57:18 pm by wp »
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

Raul_ES

  • Full Member
  • ***
  • Posts: 169
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Where to place functions to make them accessible from any unit
« Reply #11 on: January 22, 2020, 03:50:02 pm »
unit

interface

uses

implementation

uses

and have a look at the freepascal unit syntax about what goes where and why



unit

1) interface --------> function declarations here

2) uses -------------> external units

implementation

3) uses
------------> also tried here, instead of above.


If 1 & 2 or 2 & 1 always the same error: unit_ciphers.pas(10,1) Fatal: Syntax error, "IMPLEMENTATION" expected but "USES" found


If 1 & 3 then new error: unit_ciphers.pas(7,10) Error: Forward declaration not solved "Code(ShortString;ShortString;LongInt):ShortString; CDecl;"

If I try the following:

Code: Pascal  [Select][+][-]
  1. interface
  2.  
  3. function Code(key:string; uncrypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif} forward;
  4. function Decode(key:string; crypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif} forward;
  5.  

I will get an error:
Quote
unit_ciphers.pas(7,124) Error: Procedure directive "FORWARD" not allowed in interface section
« Last Edit: January 22, 2020, 03:54:37 pm by Raul_ES »
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

Raul_ES

  • Full Member
  • ***
  • Posts: 169
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Where to place functions to make them accessible from any unit
« Reply #12 on: January 22, 2020, 03:51:47 pm »
Here is a reworked version of your unit from the initial post which compiles fine:


Code: Pascal  [Select][+][-]
  1. unit unit_ciphers;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses                   // In fact, your code does not use these units at all.
  8.   Classes, SysUtils;   // Therefore these lines could be skipped.
  9.  
  10. function Code(key:string; uncrypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif}
  11. function Decode(key:string; crypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif}
  12.  
  13.  
  14. implementation
  15.  
  16. uses
  17.   DCPblowfish, DCPtwofish, DCPsha256;
  18.  
  19. function Code(key:string; uncrypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif} //Encode(key, text, level)
  20. var
  21.   motor: TDCP_blowfish;
  22.   i: integer;
  23.   t: string;
  24. begin
  25.   if level=0
  26.     then level:=1
  27.     else if level>2
  28.       then level:=2;
  29.   motor:=TDCP_blowfish.Create(nil);
  30.   t:=uncrypted_string;
  31.   for i:=1 to level do begin
  32.     motor.InitStr(key,TDCP_sha256);
  33.     t:=motor.EncryptString(t);
  34.     motor.Burn;
  35.   end;
  36.   result:=t;
  37.   motor.Free;
  38. end;
  39.  
  40. function Decode(key:string; crypted_string:string; level:integer):string; {$ifndef linux} stdcall; {$else} cdecl; {$endif} //Decode(key, text, level)
  41. var
  42.   motor: TDCP_blowfish;
  43.   i: integer;
  44.   t: string;
  45. begin
  46.   if level=0
  47.     then level:=1
  48.     else if level>2
  49.       then level:=2;
  50.   motor:=TDCP_blowfish.Create(nil);
  51.   t:=crypted_string;
  52.   for i:=1 to level do begin
  53.     motor.InitStr(key,TDCP_sha256);
  54.     t:=motor.DecryptString(t);
  55.     motor.Burn;
  56.   end;
  57.   result:=t;
  58.   motor.Free;
  59. end;
  60.  
  61. end.

Some rules:
  • The first (non-comment) line must be "unit <unitname>".
  • The second (non-comment) line must be "interface".
  • Then: "uses <comma-separated list of units needed by the declarations in the interface part>". In your code, in fact, the units Classes and SysUtils are not needed at all. So, you can skip this line here altogether. But normally this does not happen all the time, and therefore I left them just to show you a valid unit structure.
  • Publicly visible declarations: type, const, procedure and function headers, NO code
  • Line "Implementation"
  • Then: "uses <comma-separated list of units needed by the declarations in the implementation part>". A comment here again: Your unit actually only uses DCPblowfish, DCPtwofish and DCPsha256; so, there is no need to add the other DCP units. This may add unnecessary code to your program (initialization).
  • Then additional declarations private to the unit, auxiliary code
  • code for the units listed under "Interface".
  • Last line "end." (with a period!)
The interface declarations of your code do need need the DCP* units, therefore, I moved them to the "uses" clause of the implementation part. This step is not absolutely necessary, but in large project you may run into circular unit references (unit A uses unit B, and unit B uses unit A) if you don't do this.

Regarding the {$MODE ObjFPC} directive I also added {$H+} which avoids using short string in this unit (you probably want to encrypt strings longer than 255 characters!).

Thanks a lot wp, I am studying your solution right now
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

wp

  • Hero Member
  • *****
  • Posts: 7237
Re: Where to place functions to make them accessible from any unit
« Reply #13 on: January 22, 2020, 04:04:24 pm »
BTW, if you use the IDE to create the unit ("File" > "New unit") you already get the correct skeleton. Save it under its intended name and the filename is added to the first line ("unit ....").
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

Raul_ES

  • Full Member
  • ***
  • Posts: 169
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Where to place functions to make them accessible from any unit
« Reply #14 on: January 22, 2020, 04:16:49 pm »
Thanks wp, it's fully working now  :D

The idea is to create a unit with all the encode/decode functions/procedures for all the DCP algorithms I want to use in my program. Actually is a collection of programs, hence the interest for creating a common external unit to implement all this.
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

 

TinyPortal © 2005-2018