Invalid pointer operation

Invalid pointer operation
U3
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 2 lata
  • Postów:196
0

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

Kod DLL:

Kopiuj
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:

Kopiuj
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

Kopiuj
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
JU
  • Rejestracja:około 22 lata
  • Ostatnio:2 miesiące
  • Postów:5042
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.

abrakadaber
abrakadaber
co do stringów to nieprawda jeśli używa interfejsów a chyba tak jest.
JU
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 :)
U3
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 2 lata
  • Postów:196
0

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.

JU
  • Rejestracja:około 22 lata
  • Ostatnio:2 miesiące
  • Postów:5042
0

Chłopaku, masz tak:

Kopiuj
 LNotifyButton.OnClick := TNotifyEvent(LMethod);

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

Kopiuj
 LNotifyButton.OnClick := @AOnClickProc;
U3
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 2 lata
  • Postów:196
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
JU
  • Rejestracja:około 22 lata
  • Ostatnio:2 miesiące
  • Postów:5042
0

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

U3
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 2 lata
  • Postów:196
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

JU
  • Rejestracja:około 22 lata
  • Ostatnio:2 miesiące
  • Postów:5042
0

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

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 18 godzin
  • Lokalizacja:Tuchów
  • Postów:12171
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.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
U3
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 2 lata
  • Postów:196
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
JU
  • Rejestracja:około 22 lata
  • Ostatnio:2 miesiące
  • Postów:5042
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

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 18 godzin
  • Lokalizacja:Tuchów
  • Postów:12171
0

No jak to nie? A to?

Kopiuj

LNotifyButton.OnClick := TNotifyEvent(LMethod);

Kopiuj

A to proszę pana jest przekopiowanie danych z rekordu LMethod do pola FOnClick za pomocą właściwości OnClick, czyli przekopiowanie dwóch wskaźników, zawartych w polach Data i Code; Można by mówić o wskazywaniu na martwą przestrzeń, jeśli by do zmiennej poza metodą AddNotifyBadgeButton przypisać wskaźnik na zmienną lokalną, czyli w ten sposób:

Kopiuj
LGlobalVar := @LMethod;

Po wyjściu z metody AddNotifyBadgeButton, zmienna LGlobalVar zawierałaby wskazanie na nieistniejącą w pamięci zmienną lokalną LMethod, więc wskazywała by na jakieś śmieci; Zresztą problemem nie był LMethod (o czym pisałem wcześniej i co potwierdził pytacz) i nie jest nadal, a przekazywanie ciągów znaków;

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

Nie klasę, a instancję klasy (obiekt), bo metody statyczne nie mogą być do tego celu użyte.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 3x, ostatnio: flowCRANE
JU
  • Rejestracja:około 22 lata
  • Ostatnio:2 miesiące
  • Postów:5042
0
furious programming napisał(a):

No jak to nie? A to?

Kopiuj

LNotifyButton.OnClick := TNotifyEvent(LMethod);

Kopiuj

A to proszę pana jest przekopiowanie danych z rekordu LMethod do pola FOnClick za pomocą właściwości OnClick, czyli przekopiowanie dwóch wskaźników, zawartych w polach Data i Code;

A jak to się dzieje? Bo, patrząc na definicję TMethod, to jest po prostu record. Tutaj go rzutujemy na typ. Więc ja tu po prostu widzę rzutowanie rekordu na typ, czyli wg mnie OnClick powinien tak naprawdę mieć adres do LMethod. Więc w jaki sposób tu działa to kopiowanie?

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

Nie klasę, a instancję klasy (obiekt), bo metody statyczne nie mogą być do tego celu użyte.

No zgadza się, miałem na myśli np. jakiś singleton to przechwytywania zdarzeń.

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 18 godzin
  • Lokalizacja:Tuchów
  • Postów:12171
1

Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.