Wątek przeniesiony 2016-03-24 22:31 z Newbie przez furious programming.

Bład przy zamykaniu po zamianie TMemo na TRichEdit - Form w DLL

0

Mam formularz w bibliotece DLL. Cały formularz ma za zadanie jedynie wyświetlanie tekstu przez
jedną procedurę.
Kiedy wyświetlał do komponentu TMemo wszystko ładnie działało, jednak kiedy zamieniłem TMemo
na TRichEdit, przy zamykaniu wyrzuca błąd o nieprawidłowym dojściu okna, oraz o błędzie w RichEd.DLL
(Jak dobrze zapamiętałem)
Sprawdziłem cały kod kilka razy i nie ma żadnych kodów (pisanych przeze mnie), które by sprawiły,
że może być tylko komponent TMemo.
Dodam, że błąd wywala tylko jeśli zostanie wcześniej wywołane

 LogForm.show;

Kod formularza:

 unit ServerLogForm;
{Zamiast TMemo zamieniam na TRichEdit (oczywiście na formularzu robię przez "klikanie",
 a potem resztę procedur w kodzie manualnie)}
interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Menus, ComCtrls;

type
  TLogForm = class(TForm)
    SaveDialog1: TSaveDialog;
    PopupMenu1: TPopupMenu;
    Zapisz1: TMenuItem;
    Wyczy1: TMenuItem;
    Kopiuj1: TMenuItem;
    Memo1: TMemo;
    procedure Zapisz1Click(Sender: TObject);
    procedure Wyczy1Click(Sender: TObject);
    procedure Kopiuj1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

procedure AddLog(s : string; color : integer = clBlue);

var
  LogForm: TLogForm;

implementation

{$R *.dfm}

procedure AddLog(s : string; color : integer = clBlue);
begin
 //LogForm.memo1.SelAttributes.Color := color;  //tu w przypadku TRichEdit nie było komentarza
 LogForm.memo1.Lines.Add(s);
end;

procedure TLogForm.Zapisz1Click(Sender: TObject);
begin
 If savedialog1.Execute then
  memo1.Lines.SaveToFile(Savedialog1.FileName);
end;

procedure TLogForm.Wyczy1Click(Sender: TObject);
begin
 memo1.Lines.Clear;
end;

procedure TLogForm.Kopiuj1Click(Sender: TObject);
begin
 memo1.CopyToClipboard;
end;

end.

Obsługa:

 //Tworzenie: (w sekcji begin biblioteki)
 LogForm := TLogForm.Create(Application); 

//pokazywanie: (w buttonie drugiego formularza)
 LogForm.Show;

//niszczenie: (w DLLProc)
  if Reason = DLL_PROCESS_DETACH then
  begin
   LogForm.Free;
  end;

Proszę też o uwagi na temat kodu.

0

Pokaż jak formularz otwierasz/obsługujesz/cokolwiek z poziomu aplikacji.
Na pewno nie przekazujesz nigdzie na pałę stringa między apką a biblioteką?

0

Przekazuję string, ale używam w bibliotece i w apce ShareMem.
Dołącze kod biblioteki:

library ServerDLL;

uses
  ShareMem,
  Windows,
  Forms,
  SysUtils,
  Classes,
  ActiveX,
  ServerUnit in 'ServerUnit.pas' {ServerForm},
  ServerLogForm in 'ServerLogForm.pas' {LogForm};

{$R *.res}

 procedure ShowForm(H : Phandle); stdcall;
 begin
  GetProcedures(H);
  ServerForm.Show;
 end;

 procedure TotalStart; stdcall;
 var
  H : THandle;
 begin
  H := LoadLibrary(PChar(extractFilePath(ParamStr(0)) + 'CentralLibrary.dll'));
  GetProcedures(@H);
  OpenFile(ParamStr(1));
  TerminateOnClose := True;
  ServerForm.Show;
 end;

 procedure Exit(Reason : integer);
 begin
  if Reason = DLL_PROCESS_DETACH then
  begin
   ServerForm.Free;
   LogForm.Free;
  end;
 end;

exports
 ShowForm Name 'ShowForm',
 TotalStart Name 'TotalStart';

begin
 CoInitialize(nil);
 adresy := TStringList.Create;
 adresy.Add('/');
 adresy.Add('/back');
 adresy.Add('/starttest');
 adresy.Add('/test');
 adresy.Add('/wyniki');
 adresy.Add('/wynik');
 adresy.Add('/wyniki2');
 adresy.Add('/');
 ServerForm := TServerForm.Create(Application);
 LogForm := TLogForm.Create(Application);
 DLLProc := Exit;

end. 

Poza tym z TMemo działa, a z TRichEdit nie działa.

0

@pawel24pl - dlaczego nazwałeś procedurę Exit? Przecież tak nazywa się wbudowana pseudoprocedura - Exit; Cuda jaja...

0

Zmieniełem z "Exit" na "Koniec", ale nadal to samo.

0

Nic z tego kodu nie rozumiem, bo masz większość rzeczy opakowane i zadeklarowane gdzie indziej; Poza tym po co używasz typu PHandle, skoro uchwyt to zwykła liczba? Wystarczy THandle i dane tego typu przekazywać;

Czas posprzątać ten kod, albo posłać go do kosza i napisać jeszcze raz;

PS: Obstawiam, że przypisanie procedurki do DLLProc masz złe; Zauważ, że DLLProc to wskaźnik, więc powinieneś użyć operatora @ lub funkcji Addr:

DLLProc := @TuWstawNazweProcedury;

Poza tym tworzenie formularzy także mógłbyś wykonać w tej procedurze - będzie czytelniej; Tylko nie rób drabinki **If**ów, a skorzystaj z instrukcji wyboru dla tych dwóch konkretnych stałych:

case Reason of
  DLL_PROCESS_ATTACH: { tworzenie formularzy  } ;
  DLL_PROCESS_DETACH: { zwalnianie formularzy } ;
end;
0

To trochę dziwana aplikacja pod względem budowy i wykorzystuje kilka bibliotek.
Jedna bibliotek przesyła do drugiej uchwyt trzeciej, aby druga mogła zaimportować z już załadowanej trzeciej
biblioteki z danymi procedury do wczytywania tych danych bez konieczności tworzenie kopii pomięci.

Przy TotalStart "druga" biblioteka sama ładuje "trzecią" bibliotekę i importuje procedury.
Procedury importowane:

  OpenFile : procedure(FN : string); stdcall;
 SaveFile : procedure; stdcall;
 GetExercise : procedure(const Index : integer; var Exercise : PZadanie); stdcall;
 SaveExercise : procedure(const Index : integer; var Exercise : PZadanie); stdcall;
 CreateNewExercise : procedure; stdcall;
 SetFileName : procedure(FN : string); stdcall;
 CloseFile : procedure; stdcall;
 NewFile : procedure(FN : string); stdcall;
 GetTMPPath : function : string; stdcall;
 GetExCount : function : integer; stdcall;
 RefreshCounts : procedure; stdcall;

//procedure importowania:
procedure GetProcedures(H : PHandle);
begin
 @OpenFile := GetProcAddress(H^, 'OpenFile');
 @SaveFile := GetProcAddress(H^, 'SaveFile');
 @GetExercise := GetProcAddress(H^, 'GetExercise');
 @SaveExercise := GetProcAddress(H^, 'SaveExercise');
 @CreateNewExercise := GetProcAddress(H^, 'CreateNewExercise');
 @SetFileName := GetProcAddress(H^, 'SetFileName');
 @CloseFile := GetProcAddress(H^, 'CloseFile');
 @NewFile := GetProcAddress(H^, 'NewFile');
 @GetTMPPath := GetProcAddress(H^, 'GetTMPPath');
 @GetExCount := GetProcAddress(H^, 'GetExCount');
 @RefreshCounts := GetProcAddress(H^, 'RefreshCounts');
end;

A zmienna "adresy" to zwykły TStrings.

0

Po zmianie procedury nie działa uruchamianie, więc zostawiłem tak jak było (przynajmniej na razie)
Sprawdziłem, czy działa przy zamykaniu (moja wersja) dodając "windows.beep(100, 100);" i procedura jest wykonywana.
Jeszcze raz przypominam: na TMemo działa, na TRichEdit wywala błąd.

0

Odpal ten program i wklej tutaj treść błędu, albo zrzut ekranu; I napisz której wersji Delphi używasz.

0

5 błedów (powtarzają się niektóre), używam Delphi 7 PE na Windows XP Pro.
Jeżeli nie pokażę formy (ale zostanie stworzona przez Create) błędy nie wyskakują.

0

Zamień: LogForm.Free; na LogForm.Hide;

0

@_13th_Dragon zmieniłem i trochę pomogło.
Trochę, bo zamiast pięciu, wywala trzy błędy.
Próbowałem też innych kombinacji, ale nic nie dało.

0

Zrobiłem to w ten sposób:
RichEdit1 zrobiłem zmienną globalną i tworzyłem przez:

LogForm.Show;
If RichEdit1 = nil then
begin
 RichEdit1 := TRichEdit.Create(LogForm);//self
 RichEdit1.PopupMenu := LogForm.PopupMenu1;
 LogForm.InsertControl(RichEdit1);
 RichEdit1.Align := alClient;
 RichEdit1.ReadOnly := true;
 ExistsMemo := true;
end;

Przez to ograniczyłem wyskakiwanie błędów do jednego.
Ostatni błąd ograniczyłem przez dodanie komponentu TApplicationEvents i w Event OnException dałem:

 E := nil;

Może troche nie fachowe, ale działa.

0

OnClose daj: Action:=caFree;
Nie twórz nowych kontrolek na zewnątrz formatki.

Grzebanie w TApplicationEvents tylko nie wyświetla błędu - błąd nadal istnieje tylko że go nie widzisz, ba nie widzisz też innych przyszłych błędów i kiedyś to podejście walnie cię tak że nie prędko się pozbierasz.

0

Nadal wywala błąd.

0

To wklej pełny kod, ewentualnie skróć go maksymalnie aby błąd pozostał.

0

jak używasz form z dll to przekazujesz i podmieniasz w dll zmienną Screen i Aplication?

0

Napisałem apkę z DLL-ką i formą, dałem RichEdit i mam ten sam błąd.
W załączniku kod źródłowy. Usuńcie RichEdit i błędu nie będzie.

0

u mnie działa - win 8.1

1

Poprawiłem, nie ma prawa wyskakiwać żaden błąd.

3

znaczy cały ten dll jest o kant d**y rozbić napisany bo nijak nie uwzględnia kilku odpalonych formatek

0

Dzięki, już wiem jak zrobić.

1 użytkowników online, w tym zalogowanych: 0, gości: 1