RS := TResourceStream.Create(HInstance,'data', RT_RCDATA);
RS.Read(RS_przes^,rs.Size);
Ten kawałek ładuje dane bezposrednio do zarezerowanej wczesniej pamięci. Jak wczytac te same dane z przesunięciem np o 100 bajtów do tej samej pamięci
RS := TResourceStream.Create(HInstance,'data', RT_RCDATA);
RS.Read(RS_przes^,rs.Size);
Ten kawałek ładuje dane bezposrednio do zarezerowanej wczesniej pamięci. Jak wczytac te same dane z przesunięciem np o 100 bajtów do tej samej pamięci
RS.Read(Pointer(RS_przes + 100)^, RS.Size);
lub inaczej:
Inc(RS_przes, 100);
RS.Read(RS_przes^, RS.Size);
O to chodzi? Jeśli nie to wytłumacz dokładniej.
var Identyfikator1 :THandle;
AdresE1 :pointer;
Function EdytorActivPointer:Pointer;
Begin
EdytorActivPointer:=adresE1;
End;
Procedure x;
Var
RS : TResourceStream;
Begin
Identyfikator1:=GlobalAlloc(gmem_Fixed+gmem_ZeroInit,$02000000);
AdresE1:=GlobalLock(Identyfikator1);
RS := TResourceStream.Create(HInstance,'PLIK', RT_RCDATA);
//Chodzi mi o to żeby do zarezerwowanej pamięci z pod wskażnika AdresE1 wgrać dane z plik do pamięci z przesunieciem 100 bajtów
RS.Read(EdytorActivPointer^,rs.Size);
End;
Byle jak opisujesz problem, to i trudno zrozumieć co masz na myśli.
Jak dobrze rozumiem, masz wskaźnik AdresE1
i do niego chcesz wczytać porcję danych. Dane te mają zostać wczytane ze strumienia RS
. I teraz Ty potrzebujesz wczytać dane z tego strumienia, ale nie od jego początku, a najpierw przesunąć kursor o 100 i dopiero wtedy wczytać. Racja?
Jeśli tak to skorzystaj z właściwości RS.Position
i wpisz do niej wartość 100
- kursor (inaczej mówiąc wskaźnik) w strumieniu zostanie przesunięty na bajt o indeksie 100
(licząc od 0
), dzięki czemu metoda RS.Read
rozpocznie odczytywanie porcji danych właśnie od tego bajtu. Skoro dane nie będą czytane od początku strumienia to w drugim parametrze trzeba to uwzględnić i odjąć liczbę pomijanych bajtów.
const
STREAM_OFFSET = 100;
{..}
RS := TResourceStream.Create(hInstance, 'PLIK', RT_RCDATA);
RS.Position := STREAM_OFFSET;
RS.Read(EdytorActivPointer()^, RS.Size - STREAM_OFFSET);
Przy okazji - nazwij te zmienne sensownie. RS
to zły identyfikator, a EdytorActivPointer
ma błąd, bo słówko Active
pisze się z e
na końcu.
Mi chodzi nie o przesunięcie strumienia a gdzie dane będą już zapisane czyli w pamięci nie od pierwszego bajtu tylko z przesunięciem.
Podałem to w pierwszym swoim poście.
Nie działa tak podczas komilaci mam błedy.
tak na początku miałem i chodziło ale bufor był ładowany od pierwszego bajtu
RS.Read(RS_przes^, RS.Size);
i chodziło dobrze, ale ładuje plik od początku pamięci
Po zamianie na :
Inc(RS_przes, 100); // błąd: ordinal type required
RS.Read(RS_przes, RS.Size); // bład operand not applicable to this operand type
Inc(RS_przes, 100); // błąd: ordinal type required
Jakiego typu jest to RS_przes
?
RS.Read(RS_przes, RS.Size); // bład operand not applicable to this operand type
Brakuje operatora ^
.
RS_przes:Pointer;
Inc(RS_przes^, 100); jak do tego dorzuce ^ to mam błąd //incompatybile types
RS.Read(RS_przes^, RS.Size); bo tu jest dobrze
Inc(RS_przes^, 100); // jak do tego dorzuce ^ to mam błąd incompatybile types
Dziwisz się? Nie wstawiaj na pałę operatorów - myśl co robisz. W pierwszym parametrze Inc masz podać wskaźnik, a nie zawartość na którą wskazuje (której i tak w tym przypadku typ nie jest znany).
No dobra, mały przykład, co prawda testowany w Lazarusie, ale także z dyrektywą {$mode delphi}
:
const
SOME_STRING = 'furious'#0'programming'#0;
var
L1stWord: Pointer;
L2ndWord: Pointer;
begin
L1stWord := @SOME_STRING[1];
L2ndWord := @SOME_STRING[9];
WriteLn('"', PChar(L1stWord), '"');
WriteLn('"', PChar(L2ndWord), '"');
WriteLn('"', PChar(L1stWord + 8), '"'); // z przesunięciem dodatnim o 8 bajtów
WriteLn('"', PChar(L2ndWord - 8), '"'); // z przesunięciem ujemnym o 8 bajtów
end.
Zadanie programu jest proste - wyświetlić to na co wskazują dwa wskaźniki:
L1stWord
- wskazuje na słówko furious
,L2ndWord
- wskazuje na słówko programming
.Na ekranie konsoli zobaczymy to:
"furious"
"programming"
"programming"
"furious"
I teraz najważniejsze - co się dzieje w wywołaniach Writeln, są cztery:
L1stWord
- wskaźnik zawiera adres pierwszego znaku pierwszego słowa, więc wyświetlane jest pierwsze słowo (słowo, bo do wystąpienia znaku NULL
),L2ndWord
- wskaźnik zawiera adres pierwszego znaku drugiego słowa, więc wyświetlane jest drugie słówki,L1stWord
i dodaniego przesunięcia o 8 bajtów - osiem bajtów dalej leży pierwszy znak drugiego słowa, więc ono zostaje wyświetlone,L2ndWord
i ujemnego przesunięcia o 8 bajtów - osiem bajtów wcześniej leży pierwszy znak pierwszego słowa, więc ono zostaje wyświetlone.Jak widzisz, w dwóch ostatnich wywołaniach obsługiwane są przesunięcia. Użyłem tutaj zwykłej arytmetyki, aby adresy zawarte w obu wskaźnikowych zmiennych nie uległy zmianie. Jeżeli zależy Ci na tym, aby zwiększyć adres w zmiennej to skorzystaj z Inc, która już od bardzo dawna wspiera wskaźniki.
no tak ale jak zrobie
Inc(RS_przes, 100); // błąd: ordinal type required
to też mam bład
Jakiego używasz kompilatora? Wszystkie podane w tym wątku kody sprawdziłem w Lazarusie, z dyrektywą {$mode objfpc}
i {$mode delphi}
, kompilują się i działają bez problemu. Nawet z {$mode tp}
.
Dalej nie wiem jak to zrobić technicznie rozumiem ze jak rs_przes to mam adres gdzie jest to w pamięci a jak mam rs_przes^ to jest wskaznik gdzie jest zapisany adres.
Komilator delphi2009.
Dalej nie wiem jak to zrobić technicznie rozumiem ze jak rs_przes to mam adres gdzie jest to w pamięci a jak mam rs_przes^ to jest wskaznik gdzie jest zapisany adres.
No nie bardzo rozumiesz. Samo rs_przes
to zawartość wskaźnika, czyli adres na który wskazuje. rs_przes^
(z operatorem ^
) to dane, na które wskazuje ten wskaźnik. Dwa różne zapisy, więc i dwa różne rezultaty - adres danych lub wartość danych.
Co do samego problemu - nie mam Delphi 2009 (ani żadnego innego) aby to sprawdzić, jednak podane konstrukcje są prawidłowe. Nie wiem dlaczego taki zapis akurat w tym środowisku nie jest prawidłowy. Zawsze można użyć pomocniczej zmiennej do przechowania adresu z offsetem - spróbuj skompilować poniższy kod, jako prostą konsolówkę:
var
LData, LDataOffset: Pointer;
begin
LData := nil;
LDataOffset := LData + 100;
end.
Jeśli się skompiluje to tymczasowo użyć pomocniczej zmiennej, a jeśli nie to trzeba szukać dalej.
Taki trochę "łopaciany" sposób, ale może zadziała (u mnie jest OK):
program Test;
type
//wskaźnik musi być rzutowany na odpowiedni typ
//zależnie od architektury
{$Ifdef CPU64}
MyInt = QWord;
{$Else}
MyInt = LongWord;
{$endIf}
var
P: Pointer;
L : QWord;
Offset : byte;
begin
P := @L; //przypisujemy zmienną do wskaźnika
readln(L); //wczytujemy wartość do zmiennej (tu 8 bajtów)
readln(Offset); //wczytujemy przesunięcie dla bajtu, który chcemy zobaczyć
OffSet := OffSet and 7; // to tylko dla bezpieczeństwa w tym przykładzie (OffSet mod 8)
Writeln(Byte(Pointer(MyInt(P)+Offset)^)); //wyświetlamy zmienną typu Byte,
//z adresu wskaźnika P przesuniętym o Offset
readln; //by nie zamknęło od razu
end.
Ogólnie to polega na:
Przykład pawel24pl działa. I teraz pytanko. Czy jeśli nie wstawię
{$Ifdef CPU64}
MyInt = QWord;
{$Else}
MyInt = LongWord;
{$endIf}
To program nie będzie działał na procesorach 64 bitowych czy tylko to jest potrzebne do kompilacji?
Dziekuje
Macie tam chyba takie typy danych jak PtrUInt
czy PtrInt
? Jak macie to nie bawcie się we własne definicje.
To program nie będzie działał na procesorach 64 bitowych czy tylko to jest potrzebne do kompilacji?
Program będzie działał na obu typach procesorów. Te dyrektywy są porzebne jedynie do kompilacji (kompilator na podstawie istniejących definicji pomija ten niepasujący kod), tak jak zresztą każde inne ifdef
y.
Edit: Moment, bo skomentowałem fragment cytatu, bez początku... Jeśli nie wstawisz tego kodu, do nie będziesz mógł używać typu MyInt
- to logiczne.
Jeśli wstawisz ten kod i skompilujesz go kompilatorem 32-bitowym dla 32-bitowej platformy, to program będzie działał zarówno na Windows 32-bit, jak i 64-bit. Jeżeli skompilujesz go dla 64-bitowej platformy to program da się uruchomić jedynie na Windows 64-bit.
No, teraz wszystko powinno być jasne.
Dziękuje temat uważam za zakończony. Podziękowania dla furious programming i pawel24pl.