Invalid pointer operation

Invalid pointer operation
U3
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad rok
  • 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:około 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:ponad rok
  • 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:około 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:ponad rok
  • 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:około 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:ponad rok
  • 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:około 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:24 minuty
  • 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:ponad rok
  • 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:około 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:24 minuty
  • 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:około 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:24 minuty
  • 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.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)