Invalid pointer operation

Odpowiedz Nowy wątek
2017-01-24 22:18

Rejestracja: 7 lat temu

Ostatnio: 1 miesiąc temu

0

Tworzę w DLL wątek, który odwołuje się do interfejsu głównej aplikacji:

Kod DLL:

var
  OrderCount: string;
begin
OrderCount := '1';

    TThread.CreateAnonymousThread(procedure
    begin
      while not TThread.CheckTerminated do
      begin
          // AAP - interfejs głównej aplikacji
          if OrderCount = '' then
          begin
            AAP.UpdateNotifyBadgeButton('btnMobile', 'Lista zleceń mobilnych', '');
          end
          else
            AAP.UpdateNotifyBadgeButton('btnMobile', 'Liczba nowych zleceń mobilnych: ' + OrderCount, OrderCount);
       end;
    end).Start;

Kod aplikacji głównej:

function TfrmMain.UpdateNotifyBadgeButton(AButtonName, AHint,
  ABadgeValue: string): HRESULT;
var
  LNotifyButton: TAdvBadgeSpeedButton;
begin
  result := S_OK;

  LNotifyButton := pnlNotifications.FindComponent(AButtonName) as TAdvBadgeSpeedButton;
  if Assigned(LNotifyButton) then
  begin
    TThread.Synchronize(nil, procedure // próbowałem też bez tego - bez różnicy
      begin
        LNotifyButton.Hint := AHint; // tutaj za drugim razem Invalid Pointer (LNotifyButton jest przypisany)
        LNotifyButton.Badge := ABadgeValue;
      end);
  end;
end;

A tutaj tworzenie 1 raz przycisku LNotifyButton, przy inicjowaniu DLL

function TfrmMain.AddNotifyBadgeButton(AButtonName, AHint, ABadgeValue: string; ABitmapHandle: THandle; AOnClickProc: TNotifyProc): HRESULT;
var
  LMethod: TMethod;
  i: Integer;
begin
  result := S_OK;

  LMethod.Data := nil;
  LMethod.Code := @AOnClickProc;
  LNotifyButton := TAdvBadgeSpeedButton.Create(pnlNotifications);
  LNotifyButton.Parent := pnlNotifications;
  LNotifyButton.Name := AButtonName;
  LNotifyButton.ShowHint := AHint <> '';
  LNotifyButton.Hint := AHint;
  LNotifyButton.Align := alLeft;
  LNotifyButton.Flat := True;
  LNotifyButton.Width := 45;
  LNotifyButton.Badge := ABadgeValue;

  LNotifyButton.AlignWithMargins := True;
  LNotifyButton.Margins.Top := 10;
  LNotifyButton.Glyph.Handle := ABitmapHandle;
  LNotifyButton.OnClick := TNotifyEvent(LMethod);
end;

Za pierwszym razem działa, a za drugim dostaje Invalid Pointer Operation. Jak kliknę Break w oknie wyjątku to wyrzuca mnie miejsca jak w załączniku.

Dodam, że dzieje się tak, jeżeli przekazuję dodatkowy sklejony string ze zmiennej, natomiast jeżeli idzie stała wartość określona w apostrofach, to działa. Coś się dzieje z pamięcią.
Podejrzewam, ze to przez to, że przekazuję STRING z DLL, a powinienem PAnsiChar. Czy ktoś jest w stanie pokazać na moim przykładzie jak miałoby to wyglądać - muszę alokować pamięć dla PAnsiChar i ją zwalniać, czy tutaj manager pamięci zrobi to za mnie?
Proszę o pomoc.

edytowany 4x, ostatnio: user322, 2017-01-25 07:08

Pozostało 580 znaków

2017-01-25 10:23

Rejestracja: 16 lat temu

Ostatnio: 1 dzień temu

1

Tak, nie powinieneś posługiwać się stringami w połączeniu między DLL, a aplikacją. Chyba, że masz dołączony do DLL specjalny moduł. Jest opisany zawsze przy tworzeniu dll, nie pamiętam jak się nazywa. Oczywiście tak się nie powinno robić.

Po drugie Twoim problemem jest LMethod. Coś tu strasznie nakombinowałeś, a potem robisz z LMethod - ze zmiennej lokalnej - procedurę zdarzeniową. LMethod po zakończeniu metody AddNotifyBadgeButton przestaje istnieć. W Twój guzik potem chce ją wywoływać. Ale nie ma co wywołać, bo ma w tym miejscu w pamięci śmieci.

co do stringów to nieprawda jeśli używa interfejsów a chyba tak jest. - abrakadaber 2017-01-25 14:28
Jeśli masz dołączony moduł ShareMem, możesz się normalnie posługiwać stringami. Ale nie tylko. Również chyba innymi elementami typowo Delphiowymi. Ale dzięki temu ograniczasz możliwość budowania DLLek tylko do Delphi. Dlatego lepiej nie korzystać z ShareMem i robić wszystko po Bożemu :) - Juhas 2017-01-25 14:37

Pozostało 580 znaków

2017-01-25 10:31

Rejestracja: 7 lat temu

Ostatnio: 1 miesiąc temu

Przy stringach dodawalem ShareMem do uses w DLL na 1 miejscu, ale to nie pomagało. Jak wrócę do domu to zmienię STRING na PAnsiChar.

z DLL przekazuję procedurę, którą chcę wywoływać w oknie głównym, w jaki inny sposób to wykonać? Tam gdzie się wywala, nie ma związku z LMethod, bo updateuje tylko string na przycisku, chyba że taka aktualizacja wiąże się ze sprawdzeniem wszystkich eventów i tam wywala Invalid Pointer.

Pozostało 580 znaków

2017-01-25 11:11

Rejestracja: 16 lat temu

Ostatnio: 1 dzień temu

0

Chłopaku, masz tak:

 LNotifyButton.OnClick := TNotifyEvent(LMethod);

Przy czym LMethod jest zmienną lokalną.
Powinieneś to zmienić na:

 LNotifyButton.OnClick := @AOnClickProc;

Pozostało 580 znaków

2017-01-25 11:48

Rejestracja: 7 lat temu

Ostatnio: 1 miesiąc temu

0

Gdybyś sprawidził to wiedziałbyś, że nie można przypisać pointera do OnClick, bo musi on być pochodną TNotifyEvent, o czym pisałem kilka postów wyżej.

edytowany 1x, ostatnio: user322, 2017-01-25 11:48

Pozostało 580 znaków

2017-01-25 12:33

Rejestracja: 16 lat temu

Ostatnio: 1 dzień temu

0

Nie mam Delphi pod ręką, więc sam sprawdź, jak to zrobić dobrze. Ja Ci pokazałem, gdzie masz błąd.

Pozostało 580 znaków

2017-01-25 12:41

Rejestracja: 7 lat temu

Ostatnio: 1 miesiąc temu

0

Domyślałem się, że to może być przyczyną, natomiast nie znam rozwiązania na przekazanie procedury z DLL do EXE nie korzystając z LMethod

Pozostało 580 znaków

2017-01-25 13:41

Rejestracja: 16 lat temu

Ostatnio: 1 dzień temu

0

To nie przekazuj TNotifyProc, tylko TNotifyEvent i zrób z tego metodę w DLL.

Pozostało 580 znaków

2017-01-25 16:52
Moderator Delphi/Pascal

Rejestracja: 8 lat temu

Ostatnio: 19 godzin temu

Lokalizacja: Tuchów

0
Juhas:

Przy czym LMethod jest zmienną lokalną.

Problemem na pewno nie jest LMethod; Do właściwości obiektu nie jest wpisywany wskaźnik na zmienną lokalną, więc nie ma mowy o tym, aby właściwość wskazywała na martwą pamięć (jakieś śmieci);

To nie przekazuj TNotifyProc, tylko TNotifyEvent i zrób z tego metodę w DLL.

Aby bezpośrednie przypisanie było możliwe, musi zostać przekazane wskazanie na metodę klasy, o czym już dyskutowaliśmy w poprzednim wątku i rozwiązania nie znaleźliśmy;

user322:

Domyślałem się, że to może być przyczyną, natomiast nie znam rozwiązania na przekazanie procedury z DLL do EXE nie korzystając z LMethod

Do pobrania wskaźnika na procedurę z biblioteki użyj funkcji GetProcAddress i wtedy spróbuj z TMethod.


edytowany 1x, ostatnio: furious programming, 2017-01-25 16:52

Pozostało 580 znaków

2017-01-25 20:31

Rejestracja: 7 lat temu

Ostatnio: 1 miesiąc temu

0

Poradziłem sobie już. Problemem było przekazywanie stringa zamiast PAnsiString z procedury. Po zmianie działa. LMethod nie był w ogóle problemem.

edytowany 1x, ostatnio: user322, 2017-01-25 20:31

Pozostało 580 znaków

2017-01-25 22:12

Rejestracja: 16 lat temu

Ostatnio: 1 dzień temu

0
furious programming napisał(a):
Juhas:

Przy czym LMethod jest zmienną lokalną.

Problemem na pewno nie jest LMethod; Do właściwości obiektu nie jest wpisywany wskaźnik na zmienną lokalną, więc nie ma mowy o tym, aby właściwość wskazywała na martwą pamięć (jakieś śmieci);

No jak to nie? A to?
LNotifyButton.OnClick := TNotifyEvent(LMethod);

To nie przekazuj TNotifyProc, tylko TNotifyEvent i zrób z tego metodę w DLL.

Aby bezpośrednie przypisanie było możliwe, musi zostać przekazane wskazanie na metodę klasy, o czym już dyskutowaliśmy w poprzednim wątku i rozwiązania nie znaleźliśmy;

No jak to. Przecież wystarczy stworzyć klasę, która będzie miała zdarzenie typu TNotifyEvent. Nie trzeba nawet tworzyć własnego typu procedure.... of object

Pozostało 580 znaków

Odpowiedz

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