Recent

Author Topic: problem by export and import a function  (Read 770 times)

paule32

  • Hero Member
  • *****
  • Posts: 645
  • One in all. But, not all in one.
problem by export and import a function
« on: July 11, 2025, 03:56:56 pm »
Hello,
why is it not possible to EXPORT and IMPORT the TFileStream_Create Function ?  >:(

EDIT:
a more structured version of the File Stream.pas - but same problem

Code: Pascal  [Select][+][-]
  1. // ---------------------------------------------------------------------------------------
  2. // Copyright(c) 2025 @paule32 and @fibonacci
  3. // ---------------------------------------------------------------------------------------
  4. {$mode objfpc}{$H+}
  5. unit Stream;
  6.  
  7. interface
  8. uses
  9.   Windows, Dialogs;
  10.  
  11. // ---------------------------------------------------------------------------------------
  12. // fm - stream file modes ...
  13. // ---------------------------------------------------------------------------------------
  14. const fmOpenRead        = 0;        // open file for read  only
  15. const fmOpenWrite       = 1;        // open file for write only
  16. const fmOpenReadWrite   = 2;        // open file for read & write
  17. const fmCreate          = $FF00;    // create a new file
  18.  
  19. const fmShareCompat     = $00;      // DOS compatible (obsulete)
  20. const fmShareExclusive  = $10;      // no other process can access the file
  21. const fmShareDenyWrite  = $20;      // by other processes: deny read/write
  22. const fmShareDenyRead   = $30;      // other processes - only read access
  23. const fmShareDenyNone   = $40;      // read/write access for other processes
  24. // ---------------------------------------------------------------------------------------
  25. const soBeginning       = 0;
  26. const soCurrent         = 1;
  27. const soEnd             = 2;
  28.  
  29. const FILE_BEGIN        = 0;
  30. const FILE_CURRENT      = 1;
  31. const FILE_END          = 2;
  32.  
  33. // ---------------------------------------------------------------------------------------
  34. /// <class name="TStream">
  35. ///   <brief>
  36. ///     <lang name="deu">
  37. ///     </lang>
  38. ///     <lang name="enu">
  39. ///       This is the base class of streams for:
  40. ///       - Memory
  41. ///       - File
  42. ///       - Resource
  43. ///     </lang>
  44. ///   </brief>
  45. ///   <private></private>
  46. ///   <protected></protected>
  47. ///   <public>
  48. ///     <constructor name="Create">
  49. ///       <param></param>
  50. ///       <brief>
  51. ///         <lang name="enu">
  52. ///         </lang>
  53. ///         <lang name="deu">
  54. ///         </lang>
  55. ///       </brief>
  56. ///     </constructor
  57. ///   </public>
  58. /// </class>
  59. // ---------------------------------------------------------------------------------------
  60. type
  61.   TStream = class(TObject)
  62.   private
  63.     FBuffer     : PByteArray;
  64.     FSize       : Integer;
  65.     FCapacity   : Integer;
  66.     FPosition   : Integer;
  67.     FFileHandle : THandle;
  68.   protected
  69.     function  GetSize:            Integer ;
  70.     procedure SetSize    (AValue: Integer);
  71.     procedure SetCapacity(AValue: Integer);
  72.     procedure ReAlloc    (AValue: Integer);
  73.   public
  74.     constructor Create;
  75.     destructor Destroy; override;
  76.    
  77.     procedure ReadBuffer (var   Buffer; Count: Integer);
  78.     function  Read       (var   Buffer; Count: Integer): Integer;
  79.     function  WriteBuffer(const Buffer; Count: Integer): Integer;
  80.     function  Write      (const Buffer; Count: Integer): Integer;
  81.    
  82.     function Seek(Offset: Integer; Origin: Integer): Integer;
  83.    
  84.     procedure ReadFromFile(const FileName: string);
  85.     procedure LoadFromFile(const FileName: string);
  86.    
  87.     procedure LoadFromStream(Source: TStream);
  88.    
  89.     procedure SaveToFile(const FileName: string);
  90.     procedure SaveToStream(dest: TStream);
  91.    
  92.     function  CopyFrom(Source: TStream; Count: Integer): Integer;
  93.   published
  94.     property Size     : Integer read FSize;
  95.     property Capacity : Integer read FCapacity write SetCapacity;
  96.     property Position : Integer read FPosition write FPosition;
  97.   end;
  98.  
  99.   TMemoryStream = class(TStream)
  100.   public
  101.     constructor Create;
  102.     destructor Destroy; override;
  103.    
  104.     //function Seek(Offset: Integer; Origin: Integer): Integer;
  105.   end;
  106.  
  107.   TFileStream = class(TStream)
  108.   public
  109.     constructor Create(AFileName: String; mode: Integer);
  110.     destructor Destroy; override;
  111.    
  112.     function Seek(Offset: Integer; Origin: Integer): Integer;
  113.   end;
  114.  
  115.   TResourceStream = class(TStream)
  116.   public
  117.     constructor Create;
  118.     destructor Destroy; override;
  119.   end;
  120.  
  121. {$ifdef DLLEXPORT}
  122. // ---------------------------------------------------------------------------------------
  123. function  TStream_WriteBuffer(p: TStream; const Buffer; Count: Integer): Integer; stdcall; export;
  124. function  TStream_CopyFrom(p: TStream; Source: TStream; Count: Integer): Integer; stdcall; export;
  125.  
  126. procedure TFileStream_Create(p: TFileStream; AFileName: String; mode: Integer); stdcall; export;
  127. function  TFileStream_Seek  (p: TFileStream; Offset: Integer; Origin: Integer): Integer; export;
  128.  
  129. procedure TStream_ReadBuffer(p: TStream; var Buffer; Count: LongInt); stdcall; export;
  130. procedure TStream_ReAlloc   (p: TStream; AValue: Integer); stdcall; export;
  131. // ---------------------------------------------------------------------------------------
  132. {$endif DLLEXPORT}
  133. {$ifdef DLLIMPORT}
  134. // ---------------------------------------------------------------------------------------
  135. function  TStream_WriteBuffer(p: TStream; const Buffer; Count: Integer): Integer; stdcall; external RTLDLL;
  136. function  TStream_CopyFrom(p: TStream; Source: TStream; Count: Integer): Integer; stdcall; external RTLDLL;
  137.  
  138. procedure TFileStream_Create(p: TFileStream; AFileName: String; mode: Integer); stdcall; external RTLDLL;
  139. function  TFileStream_Seek  (p: TFileStream; Offset: Integer; Origin: Integer): Integer; external RTLDLL;
  140.  
  141. procedure TStream_ReadBuffer(p: TStream; var Buffer; Count: LongInt); stdcall; external RTLDLL;
  142. procedure TStream_ReAlloc   (p: TStream; AValue: Integer); stdcall; external RTLDLL;
  143. // ---------------------------------------------------------------------------------------
  144. {$endif DLLIMPORT}
  145.  
  146. implementation
  147. uses
  148.   Memory, Exceptions, ErrorData;
  149.  
  150. const
  151.   CopyBufferSize = 8192; // 8 KB
  152.  
  153. { TStream }
  154. constructor TStream.Create;
  155. begin
  156.   inherited Create;
  157.  
  158.   FSize     := 0;
  159.   FCapacity := 0;
  160.   FPosition := 0;
  161. end;
  162.  
  163. destructor TStream.Destroy;
  164. begin
  165.   if FBuffer <> nil then
  166.   FreeMem(FBuffer);
  167.  
  168.   inherited Destroy;
  169. end;
  170.  
  171. function TStream.GetSize: Integer;
  172. begin
  173.   result := FSize;
  174. end;
  175.  
  176. {$ifdef DLLEXPORT}
  177. function TStream_WriteBuffer(p: TStream; const Buffer; Count: Integer): Integer; stdcall; export;
  178. var
  179.   Pb: PByte;
  180.   BytesWritten, TotalWritten: Integer;
  181. begin
  182.   Pb := @Buffer;
  183.   TotalWritten := 0;
  184.  
  185.   while Count > 0 do
  186.   begin
  187.     BytesWritten := Write(Pb^, Count);
  188.    
  189.     if BytesWritten <= 0 then
  190.     Break;
  191.    
  192.     inc(Pb, BytesWritten);
  193.     inc(TotalWritten, BytesWritten);
  194.    
  195.     dec(Count, BytesWritten);
  196.   end;
  197.  
  198.   result := TotalWritten;
  199. end;
  200. {$endif DLLEXPORT}
  201. function TStream.WriteBuffer(const Buffer; Count: Integer): Integer;
  202. begin
  203.   TStream_WriteBuffer(self, Buffer, Count);
  204. end;
  205.  
  206. procedure TStream.LoadFromFile(const FileName: string);
  207. begin
  208.   ReadFromFile(FileName);
  209. end;
  210. procedure TStream.ReadFromFile(const FileName: string);
  211. var
  212.   FileStream: TFileStream;
  213. begin
  214.   FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  215.   try
  216.     // Position an das Ende setzen
  217.     FileStream.Seek(0, soEnd);
  218.     CopyFrom(FileStream, FileStream.Size);
  219.   finally
  220.     FileStream.Free;
  221.   end;
  222. end;
  223. procedure TStream.SaveToFile(const FileName: string);
  224. var
  225.   FileStream: TFileStream;
  226. begin
  227.   FileStream := TFileStream.Create(FileName, fmCreate);
  228.   try
  229.     SaveToStream(FileStream);
  230.   finally
  231.     FileStream.Free;
  232.   end;
  233. end;
  234.  
  235. {$ifdef DLLEXPORT}
  236. function TStream_CopyFrom(p: TStream; Source: TStream; Count: Integer): Integer; stdcall; export;
  237. var
  238.   Buffer: PByte;
  239.   ReadNow, ToRead: Integer;
  240.   TotalCopied: Integer;
  241. begin
  242.   Result := 0;
  243.   GetMem(Buffer, CopyBufferSize);
  244.   try
  245.     // Wenn Count = 0 → alles vom aktuellen Position bis EOF
  246.     if Count = 0 then
  247.       Count := Source.Size - Source.Position;
  248.  
  249.     TotalCopied := 0;
  250.     while Count > 0 do
  251.     begin
  252.       ToRead := CopyBufferSize;
  253.       if Count < ToRead then
  254.         ToRead := Count;
  255.  
  256.       ReadNow := Source.Read(Buffer^, ToRead);
  257.       if ReadNow = 0 then
  258.         Break; // EOF oder Fehler
  259.  
  260.       p.Write(Buffer^, ReadNow);
  261.  
  262.       Inc(TotalCopied, ReadNow);
  263.       Dec(Count, ReadNow);
  264.     end;
  265.     Result := TotalCopied;
  266.   finally
  267.     FreeMem(Buffer);
  268.   end;
  269. end;
  270. {$endif DLLEXPORT}
  271. function TStream.CopyFrom(Source: TStream; Count: Integer): Integer;
  272. begin
  273.   result := TStream_CopyFrom(self, Source, Count);
  274. end;
  275.  
  276. procedure TStream.SetSize(AValue: Integer);
  277. begin
  278.   if AValue <> GetSize then
  279.   begin
  280.     if AValue > FCapacity then
  281.     SetCapacity(AValue);
  282.    
  283.     FSize := AValue;
  284.    
  285.     if FPosition > FSize then
  286.     FPosition := FSize;
  287.   end;
  288. end;
  289.  
  290. procedure TStream.LoadFromStream(Source: TStream);
  291. begin
  292.   SetSize(0);             // Inhalt löschen
  293.   Seek(0, soBeginning);   // an Anfang gehen
  294.   CopyFrom(Source, Source.Size); // neuen Inhalt lesen
  295.   Seek(0, soBeginning);   // wieder zurück
  296. end;
  297. procedure TStream.SaveToStream(dest: TStream);
  298. begin
  299.   if FSize > 0 then
  300.   dest.WriteBuffer(FBuffer^, FSize);
  301. end;
  302.  
  303. procedure TStream.SetCapacity(AValue: Integer);
  304. begin
  305.   if AValue <> FCapacity then
  306.   ReAllocMemory(FBuffer, AValue);
  307. end;
  308.  
  309. {$ifdef DLLEXPORT}
  310. procedure TStream_ReAlloc(p: TStream; AValue: Integer);
  311. begin
  312.   if AValue < p.FSize then
  313.   AValue := p.FSize;
  314.  
  315.   if AValue = 0 then
  316.   begin
  317.     if p.FBuffer <> nil then
  318.     begin
  319.       FreeMem(p.FBuffer);
  320.       p.FBuffer := nil;
  321.     end;
  322.   end else
  323.   begin
  324.     if p.FBuffer = nil then
  325.     GetMem(p.FBuffer, AValue) else
  326.     ReAllocMemory(p.FBuffer, AValue);
  327.   end;
  328.  
  329.   FCapacity := AValue;
  330. end;
  331. {$endif DLLEXPORT}
  332. procedure TStream.ReAlloc(AValue: Integer);
  333. begin
  334.   TStream_ReAlloc(self, AValue);
  335. end;
  336.  
  337. {$ifdef DLLEXPORT}
  338. procedure TStream_ReadBuffer(p: TStream; var Buffer; Count: LongInt); stdcall; export;
  339. var
  340.   Pb: PByte;
  341.   BytesRead, Remaining: LongInt;
  342. begin
  343.   if Count <= 0 then
  344.   exit;
  345.  
  346.   Pb := @Buffer;
  347.   Remaining := Count;
  348.  
  349.   while Remaining > 0 do
  350.   begin
  351.     BytesRead := p.Read(Pb^, Remaining);
  352.     if BytesRead <= 0 then
  353.     raise EReadError.Create('Fehler beim Lesen aus dem Stream');
  354.  
  355.     Inc(Pb, BytesRead);
  356.     Dec(Remaining, BytesRead);
  357.   end;
  358. end;
  359. {$endif DLLEXPORT}
  360. procedure TStream.ReadBuffer(var Buffer; Count: LongInt);
  361. begin
  362.   TStream_ReadBuffer(self, Buffer, Count);
  363. end;
  364.  
  365. function TStream.Read(var Buffer; Count: Integer): Integer;
  366. begin
  367.   if FPosition >= FSize then
  368.   Exit(0);
  369.  
  370.   if FPosition + Count > FSize then
  371.   FPosition := Count + FSize;
  372.  
  373.   Move(PByteArray(FBuffer)^[FPosition], Buffer, Count);
  374.   inc(FPosition, Count);
  375.  
  376.   result := Count;
  377. end;
  378.  
  379. function TStream.Write(const Buffer; Count: Integer): Integer;
  380. var
  381.   NewPos: LongInt;
  382. begin
  383.   NewPos := FPosition + Count;
  384.  
  385.   if NewPos > FCapacity then
  386.   SetCapacity(NewPos * 2); // wächst dynamisch
  387.  
  388.   Move(Buffer, PByteArray(FBuffer)^[FPosition], Count);
  389.   FPosition := NewPos;
  390.  
  391.   if FPosition > FSize then
  392.   FSize  := FPosition;
  393.  
  394.   result := Count;
  395. end;
  396.  
  397. function TStream.Seek(Offset: Integer; Origin: Integer): Integer;
  398. begin
  399.   case Origin of
  400.     soBeginning: FPosition := Offset;
  401.     soCurrent:   FPosition := FPosition + Offset;
  402.     soEnd:       FPosition := FSize     + Offset;
  403.     else
  404.     raise Exception.Create('invalid Seek-Offset');
  405.   end;
  406.  
  407.   if FPosition < 0 then
  408.   FPosition := 0 else if FPosition > FSize then
  409.   FPosition := FSize;
  410.  
  411.   result    := FPosition;
  412. end;
  413.  
  414.  
  415. { TMemoryStream }
  416. constructor TMemoryStream.Create;
  417. begin
  418.   inherited Create;
  419.   FBuffer   := nil;
  420.   FSize     := 0;
  421.   FCapacity := 0;
  422.   FPosition := 0;
  423. end;
  424.  
  425. destructor TMemoryStream.Destroy;
  426. begin
  427.   if FBuffer <> nil then
  428.   FreeMem(FBuffer);
  429.   inherited Destroy;
  430. end;
  431.  
  432.  
  433. { TFileStream }
  434. {$ifdef DLLEXPORT}
  435. procedure TFileStream_Create(p: TFileStream; AFileName: String; mode: Integer); stdcall; export;
  436. var
  437.   BytesRead: PDWORD;
  438. begin
  439.   p.FFileHandle := CreateFileA(
  440.     PChar(AFileName),       // Dateiname
  441.     GENERIC_READ,           // Zugriffsmodus: lesen
  442.     FILE_SHARE_READ,        // anderen Prozessen lesen erlauben
  443.     nil,                    // Sicherheit
  444.     OPEN_EXISTING,          // nur öffnen, wenn existiert
  445.     FILE_ATTRIBUTE_NORMAL,  // Dateiattribute
  446.     0                       // Template
  447.   );
  448.  
  449.   if p.FFileHandle = INVALID_HANDLE_VALUE then
  450.   begin
  451.     ShowError('file could not be open.');
  452.     Exit;
  453.   end;
  454.  
  455.   // 2. Dateigröße ermitteln
  456.   p.FSize := GetFileSize(p.FFileHandle, nil);
  457.   if p.FSize = INVALID_FILE_SIZE then
  458.   begin
  459.     ShowError('could not get file size.');
  460.     CloseHandle(p.FFileHandle);
  461.     Exit;
  462.   end;
  463.  
  464.   // 3. Speicher allozieren
  465.   GetMem(p.FBuffer, p.FSize);
  466.  
  467.   // 4. Datei einlesen
  468.   if not ReadFile(p.FFileHandle, p.@FBuffer^[0], p.FSize, BytesRead, nil) then
  469.   begin
  470.     ShowError('could not read file: ' +
  471.     SysErrorMessage(GetLastError));
  472.    
  473.     FreeMem(p.FBuffer);
  474.     CloseHandle(p.FFileHandle);
  475.     Exit;
  476.   end;
  477. end;
  478. {$endif DLLEXPORT}
  479. constructor TFileStream.Create(AFileName: String; mode: Integer);
  480. begin
  481.   inherited Create;
  482.   TFileStream_Create(self, AFileName, mode);
  483. end;
  484. {$ifdef DLLEXPORT}
  485. function TFileStream_Seek(p: TFileStream; Offset: Integer; Origin: Integer): Integer; stdcall; export;
  486.   function SeekFile(hFile: THandle; Offset: Integer; MoveMethod: DWORD): Integer;
  487.   var
  488.     NewPos: DWORD;
  489.   begin
  490.     NewPos := SetFilePointer(hFile, Offset, nil, MoveMethod);
  491.     if NewPos = $FFFFFFFF then
  492.     if GetLastError <> 0 then
  493.     raise Exception.CreateFmt('Seek fehlgeschlagen: %s', [SysErrorMessage(GetLastError)]);
  494.     result := NewPos;
  495.   end;
  496. begin
  497.   result := SeekFile(p.FFileHandle, Offset, DWORD(Origin));
  498. end;
  499. {$endif DLLEXPORT}
  500.  
  501. function TFileStream.Seek(Offset: Integer; Origin: Integer): Integer;
  502. begin
  503.   result := TFileStream_Seek(self, Offset, Origin);
  504. end;
  505.  
  506. destructor TFileStream.Destroy;
  507. begin
  508.   // 5. Aufräumen
  509.   FreeMem(FBuffer);
  510.   CloseHandle(FFileHandle);
  511.  
  512.   inherited Destroy;
  513. end;
  514.  
  515.  
  516. { TResourceStream }
  517. constructor TResourceStream.Create;
  518. begin
  519.   inherited Create;
  520. end;
  521.  
  522. destructor TResourceStream.Destroy;
  523. begin
  524.   inherited Destroy;
  525. end;
  526.  
  527. {$ifdef DLLEXPORT}
  528. exports
  529.   TStream_ReadBuffer  name 'TStream_ReadBuffer',
  530.   TStream_WriteBuffer name 'TStream_WriteBuffer',
  531.   TStream_ReAlloc     name 'TStream_ReAlloc',
  532.   TStream_CopyFrom    name 'TStream_CopyFrom',
  533.  
  534.   TFileStream_Create  name 'TFileStream_Create',
  535.   TFileStream_Seek    name 'TFileStream_Seek'
  536.   ;
  537. {$endif DLLEXPORT}
  538.  
  539. end.
« Last Edit: July 11, 2025, 04:56:06 pm by paule32 »
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

Thaddy

  • Hero Member
  • *****
  • Posts: 19124
  • Glad to be alive.
Re: problem by export and import a function
« Reply #1 on: July 11, 2025, 04:00:41 pm »
Again.... that is possible with a shared memory manager or making sure you do not use managed types.
objects are fine constructs. You can even initialize them with constructors.

paule32

  • Hero Member
  • *****
  • Posts: 645
  • One in all. But, not all in one.
Re: problem by export and import a function
« Reply #2 on: July 11, 2025, 04:04:56 pm »
I know.
But it seems that some Symbols can be export/import and some not - I don't know why.
In Line: 422 ...
- when I remove the comment, it works (but not exported, compile code build into executable)
- when I don't remove the comment, I get no error from FPC compiler, but I get a OS System Message, that the TFileStream_Create Symbol can not be resolved in DLL test.exe
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

paule32

  • Hero Member
  • *****
  • Posts: 645
  • One in all. But, not all in one.
[SOLVED] problem by export and import a function
« Reply #3 on: July 12, 2025, 07:43:53 pm »
- I don't know why the Compiler does not provide Error(s)
- I don't know why I have to involve the Modules in used EXE Code
  when and when not the Symbols will be used.

But with include the Modules on the right Place, it works
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

 

TinyPortal © 2005-2018