Lazarus

Free Pascal => Beginners => Topic started by: Raul_ES on January 22, 2020, 03:58:02 am

Title: [SOLVED] Where to place functions to make them accessible from any unit
Post by: Raul_ES on January 22, 2020, 03:58:02 am
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


Title: Re: Where to place functions to make them accessible from any unit
Post by: Raul_ES 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?
Title: Re: Where to place functions to make them accessible from any unit
Post by: HeavyUser 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.
Title: Re: Where to place functions to make them accessible from any unit
Post by: PaulRowntree 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.
Title: Re: Where to place functions to make them accessible from any unit
Post by: Raul_ES 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
Title: Re: Where to place functions to make them accessible from any unit
Post by: Raul_ES 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
Title: Re: Where to place functions to make them accessible from any unit
Post by: Raul_ES 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
Title: Re: Where to place functions to make them accessible from any unit
Post by: Bart on January 22, 2020, 02:47:36 pm
Put the uses clause below interface.

Bart
Title: Re: Where to place functions to make them accessible from any unit
Post by: hansotten 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

Title: Re: Where to place functions to make them accessible from any unit
Post by: Raul_ES on January 22, 2020, 03:43:34 pm
Put the uses clause below interface.

Bart

Already tried in Reply #5

This is a nightmare  %)
Title: Re: Where to place functions to make them accessible from any unit
Post by: wp 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:
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!).
Title: Re: Where to place functions to make them accessible from any unit
Post by: Raul_ES 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
Title: Re: Where to place functions to make them accessible from any unit
Post by: Raul_ES 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
Title: Re: Where to place functions to make them accessible from any unit
Post by: wp 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 ....").
Title: Re: Where to place functions to make them accessible from any unit
Post by: Raul_ES 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.
Title: Re: [SOLVED] Where to place functions to make them accessible from any unit
Post by: Raul_ES on January 22, 2020, 04:19:19 pm
Thanks also to HeavyUser, Bart, Hansotten and Paul.

regards
TinyPortal © 2005-2018