BOOL WriteFile(
HANDLE hFile, // handle to file to write to
LPCVOID lpBuffer, // pointer to data to write to file
DWORD nNumberOfBytesToWrite, // number of bytes to write
LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written
LPOVERLAPPED lpOverlapped // pointer to structure for overlapped I/O
);
ELI miten tämä pitäisi määritellä Delphissä? kokoajan kääntäjä ilmoittaa virhettä, olen aloittelija näiden windowsin kahvojen kanssa, jos joku voisi auttaa suomenkielellä tämän olisin hyvin kiitollinen.
Tarkoituksena olisi saada kirjoittaan sarjaporttiin, kuin lukukin ReadFile:llä.
Käytössä vanha delphi 7.
Auttakaa tämän windowsin kahvan kanssa
6
114
Vastaukset
- 20+6
Eikö se ole jo määritelty valmiiksi? Ainakin 5-versiossa on.
- Delphiguru
"Tarkoituksena olisi saada kirjoittaan sarjaporttiin"
Jos siis haluat omasta Delphillä tehtävästä ohjelmastasi käsin käyttää sarjaporttia (koskee yhtälailla oikeita COM1 -tyyppisiä laitesarjaportteja kuin myös virtuaalisia esim. COM11 -sarjaportteja, eli USB -laite, joka ohjelmiston näkökulmasta toimii kuten perinteinen sarjaportti), niin suosittelen, ettet tuhlaa aikaasi API -kutsujen kanssa, vaan imuroit ja asennat koneellesi Synapse -kokoelmaan kuuluvan SynaSer -paketin.
SynaSer on ite kokeilemastani luotettavasti toimiva Delphi -unit sarjaporttien käsittelyyn.
SynaSer:in löydät täältä:
http://www.ararat.cz/synapse
kohdasta "News":
2007-12-21 New SynaSer release 16! News are:
Support for non-LIBC Freepascal Unix based targets.
Kun ensin luot komponentin ja määrittelet sen parametrit:
var
FCommPort : TBlockSerial;
// Luo ja konfiguroi sarjaportti:
FCommPort := TBlockSerial.Create;
FCommPort.Connect(FCommPortName);
if NOT FCommPort.InstanceActive
then Exit;
FCommPort.config(115200,8,'N',0,false,true); // HW Handshake
// Portin SULKEMINEN:
FCommPort.CloseSocket;
Datan lähetys sarjaporttiin:
var
S : AnsiString;
// HUOM: Delphi 2009 ja uudemmat: Tämän on OLTAVA AnsiString, EI String.
// Vanhemmissa Delphi -versioissa kuin Delphi 2009, String = AnsiString.
begin
S := 'ATDT080002202;' #13; // komento, joka soittaa äänipuhelun siirrettyjen numeroiden tiedotuspalveluun, #13 = CR = Carriage return
if S '' then FCommPort.SendBuffer( @S[1], Length(S) );
end;
Sarjaportin lukemiseen suosittelen TBlockSerial -luokan metodeja:
RecvBuffer
RecvBufferEx
riippuen siitä, haluatko jäädä odottamaan, kunnes haluttu määrä dataa on luettavissa vai haluatko määritellä maksimiodotusajan, jonka jälkeen funktio palaa kutsujalleen siinäkin tapauksessa, että luettujen tavujen määrä on pyydettyä pienempi.- kysyjää
Miten tuo datan luku SynaSer:llä sujuu. Millaiseen muuttujaan data tallennetaan- Voisi saada vastaavan esimerkin
- Delphiguru
kysyjää kirjoitti:
Miten tuo datan luku SynaSer:llä sujuu. Millaiseen muuttujaan data tallennetaan- Voisi saada vastaavan esimerkin
ohjeita SYNASER käytöstä täällä:
http://synapse.ararat.cz/doc/help/synaser.html
ja lisää:
http://synapse.ararat.cz/doc/help/synaser.TBlockSerial.html
function RecvBuffer(buffer: pointer; length: integer): integer; virtual;
function RecvBufferEx(buffer: pointer; length: integer; timeout: integer): integer; virtual;
siis....
ESIMERKIKSI näin:
const
MaxLength = 1024;
MaxDelay_ms = 500; // 500 ms = ½ sekuntia.
var
S : AnsiString;
L : Integer;
begin
//
SetLength(S, MaxLength);
//
L := RecvBuffer(PAnsiChar(S), MaxLength);
if L < 0 then L := 0;
SetLength(S, L);
// Muuttujassa S on nyt 1024 tavua = 1024 merkkiä sarjaportista luettua dataa.
JOS luetun datan pituus EI ole etukäteen tiedossa, fiksumpi voi silloin olla muuten samoin, mutta RecvBuffer korvataan RecvBufferEx, siis näin:
L := RecvBufferEx(PAnsiChar(S), MaxLength, MaxDelay_ms);
(*
Toimii muuten samoin, mutta jos ½ sekunnin sisällä on dataa luettu vähemmän kuin 1024 tavua, funktio palaa silloinkin kutsujalleen, ja muuttuja L sisältää luettujen tavujen määrän.
*)
end;
HUOM:
Käytännössä on yleensä parempi käyttää RecvBufferEx -funktiota, sillä pelkkä RecvBuffer on käyttökelpoinen vain, jos tiedetään etukäteen luettavien tavujen tarkka määrä. RecvBuffer siis odottaa loputtomiin, kunnes annettu tavumäärä on kokonaan luettu, kun taas RecvBufferEx palaa joka tapauksessa kutsujalleen, kun viiveaika (millisekunteina) on kulunut, vaikka dataa olisikin luettu vähemmän kuin annettu maksimimäärä.
JOS teet sovelluksestasi 1-säikeisen, niin suosittelen TTimer -komponentin käyttöä, ja RecvBufferEx -funktion kutsumista OnTimer -tapahtumakäsittelijästä.
TOINEN vaihtohto on käyttää säikeitä ( New / Thread ) ja tehdä sarjaportin lukeminen omassa erillisessä säikeessään, jotta käyttöliittymä ei jumitu sillä aikaa kun odotellaan dataa saapuvaksi sarjaporttiin.
Pääsäikeestä kutsuttuna tuo L := RecvBufferEx(PAnsiChar(S), MaxLength, MaxDelay_ms); missä MaxDelay_ms = 500, odottaa aina ½ sekuntia kutsukertaa kohden, paitsi jos kutsuttaessa funktiota voidaan suoraan sisäisestä puskurimuistista lukea koko haluttu datamäärä täyteen, jolloin ei odotella.
JOS siis teet 1 -säikeisen ohjelman, voit hyvin pudottaa tuon MaxDelay_ms = 50 jolloin odotusaika on enää 1/20 s , mikä ei niin häiritsevästi jumita käyttöliittymää.
Toki vielä...
if NOT FCommPort.InstanceActive
then Exit;
tuo kannattaa laittaa niihin proseduureihin/funktioihin, joissa kutsut muita sarjaportin funktioita kuten RecvBufferEx ja/tai SendBuffer ENNEN ko. funktiokutsuja.
Tämä siksi, että RecvBufferEx ja/tai SendBuffer -funktion kutsuminen tilanteessa, jossa sarjaporttia ei ole avattu (tai avaaminen jostain syystä epäonnistui) voi nostaa poikkeuksen.
FIKSUA ohjelmointia, jos käytät TTimer -komponenttia, on vielä esim. tämä:
(OnTimer -käsittelijässä):
var
ErrorCount : Integer; // globaali muuttuja tai formin kenttä, EI paikallinen muuttuja !!!
try
// Koodia, joka lukee ja/tai kirjoittaa sarjaporttia
except
//
ON E:Exception do begin
//
inc(ErrorCount);
lblError.Visible := True;
lblError.Caption := IntToStr(ErrorCount) '. poikkeus: ' E.Message;
end;
end;
Tuon ansiosta tilanne EI riistäydy hallinnasta, JOS OnTimer -käsittelijässä tai siitä kutsutussa aliohjelmassa aiheutuu poikkeus. Muussa tapauksessa tulee Delphin omia poikkeusilmoitus -dialogeja nopeammin kuin niitä ehtii sulkea,
JOS näin käy, Delphin Ctrl-F2 on ystäväsi (tai Windows tehtävänhallinnan lopeta ohjelma, JOS Delphi ei ole käynnissä, vaan käynnistit oman ohjelmasi suoraan Delphin ulkopuolelta). - monisäikeinen,
Delphiguru kirjoitti:
ohjeita SYNASER käytöstä täällä:
http://synapse.ararat.cz/doc/help/synaser.html
ja lisää:
http://synapse.ararat.cz/doc/help/synaser.TBlockSerial.html
function RecvBuffer(buffer: pointer; length: integer): integer; virtual;
function RecvBufferEx(buffer: pointer; length: integer; timeout: integer): integer; virtual;
siis....
ESIMERKIKSI näin:
const
MaxLength = 1024;
MaxDelay_ms = 500; // 500 ms = ½ sekuntia.
var
S : AnsiString;
L : Integer;
begin
//
SetLength(S, MaxLength);
//
L := RecvBuffer(PAnsiChar(S), MaxLength);
if L < 0 then L := 0;
SetLength(S, L);
// Muuttujassa S on nyt 1024 tavua = 1024 merkkiä sarjaportista luettua dataa.
JOS luetun datan pituus EI ole etukäteen tiedossa, fiksumpi voi silloin olla muuten samoin, mutta RecvBuffer korvataan RecvBufferEx, siis näin:
L := RecvBufferEx(PAnsiChar(S), MaxLength, MaxDelay_ms);
(*
Toimii muuten samoin, mutta jos ½ sekunnin sisällä on dataa luettu vähemmän kuin 1024 tavua, funktio palaa silloinkin kutsujalleen, ja muuttuja L sisältää luettujen tavujen määrän.
*)
end;
HUOM:
Käytännössä on yleensä parempi käyttää RecvBufferEx -funktiota, sillä pelkkä RecvBuffer on käyttökelpoinen vain, jos tiedetään etukäteen luettavien tavujen tarkka määrä. RecvBuffer siis odottaa loputtomiin, kunnes annettu tavumäärä on kokonaan luettu, kun taas RecvBufferEx palaa joka tapauksessa kutsujalleen, kun viiveaika (millisekunteina) on kulunut, vaikka dataa olisikin luettu vähemmän kuin annettu maksimimäärä.
JOS teet sovelluksestasi 1-säikeisen, niin suosittelen TTimer -komponentin käyttöä, ja RecvBufferEx -funktion kutsumista OnTimer -tapahtumakäsittelijästä.
TOINEN vaihtohto on käyttää säikeitä ( New / Thread ) ja tehdä sarjaportin lukeminen omassa erillisessä säikeessään, jotta käyttöliittymä ei jumitu sillä aikaa kun odotellaan dataa saapuvaksi sarjaporttiin.
Pääsäikeestä kutsuttuna tuo L := RecvBufferEx(PAnsiChar(S), MaxLength, MaxDelay_ms); missä MaxDelay_ms = 500, odottaa aina ½ sekuntia kutsukertaa kohden, paitsi jos kutsuttaessa funktiota voidaan suoraan sisäisestä puskurimuistista lukea koko haluttu datamäärä täyteen, jolloin ei odotella.
JOS siis teet 1 -säikeisen ohjelman, voit hyvin pudottaa tuon MaxDelay_ms = 50 jolloin odotusaika on enää 1/20 s , mikä ei niin häiritsevästi jumita käyttöliittymää.
Toki vielä...
if NOT FCommPort.InstanceActive
then Exit;
tuo kannattaa laittaa niihin proseduureihin/funktioihin, joissa kutsut muita sarjaportin funktioita kuten RecvBufferEx ja/tai SendBuffer ENNEN ko. funktiokutsuja.
Tämä siksi, että RecvBufferEx ja/tai SendBuffer -funktion kutsuminen tilanteessa, jossa sarjaporttia ei ole avattu (tai avaaminen jostain syystä epäonnistui) voi nostaa poikkeuksen.
FIKSUA ohjelmointia, jos käytät TTimer -komponenttia, on vielä esim. tämä:
(OnTimer -käsittelijässä):
var
ErrorCount : Integer; // globaali muuttuja tai formin kenttä, EI paikallinen muuttuja !!!
try
// Koodia, joka lukee ja/tai kirjoittaa sarjaporttia
except
//
ON E:Exception do begin
//
inc(ErrorCount);
lblError.Visible := True;
lblError.Caption := IntToStr(ErrorCount) '. poikkeus: ' E.Message;
end;
end;
Tuon ansiosta tilanne EI riistäydy hallinnasta, JOS OnTimer -käsittelijässä tai siitä kutsutussa aliohjelmassa aiheutuu poikkeus. Muussa tapauksessa tulee Delphin omia poikkeusilmoitus -dialogeja nopeammin kuin niitä ehtii sulkea,
JOS näin käy, Delphin Ctrl-F2 on ystäväsi (tai Windows tehtävänhallinnan lopeta ohjelma, JOS Delphi ei ole käynnissä, vaan käynnistit oman ohjelmasi suoraan Delphin ulkopuolelta).Tein tälläisen version (perustuu ylläolevaan )
function TForm1.vastaanota:string;
var
S : AnsiString;
L : Integer;
begin
SetLength(S, MaxLength);
L := FCommPort.RecvBufferEx(PAnsiChar(S), MaxLength, MaxDelay_ms);
if L < 0 then L := 0;
SetLength(S, L);
result := s;
end;
Millainen koodi tulisi jos tuo vastaanotto olisi omassa säikeessä. Ei ole aikaisempaa kokemusta monisäikeisestä ohjelmpoinnista.
- 5dpo
5dpo komponentti (TSdpoSerial) on yksi kerros ylenpänä jolla voi toteuttaa sarjaliikenteen.
Tosin se taitaa toimia vain Lazaruksessa mutta se hyödyntää
samaa SynaSer kirjastoa mitä on tuossa aikaisemmin mainittu.
http://wiki.freepascal.org/5dpo
http://sourceforge.net/projects/sdpo-cl/files/
Ketjusta on poistettu 0 sääntöjenvastaista viestiä.
Luetuimmat keskustelut
Marin pyöräili jalkakäytävällä. Aikuinen ihminen! Vai onko?
https://www.seiska.fi/vain-seiskassa/hups-sanna-marin-ja-joni-rakas-kaahasivat-fillareilla-jalkakaytavalla-paljonkertova2202894TULI PALO HAAPAVEELLÄ
Omakotitalo tuhoutui tulipalossa Haapavedellä varhain torstaiaamuna, pelastuslaitos kertoo. Palokunnan saapuessa kohtee161774Miten sua nyt
Pitäisi lähestyä tai ylipäätään suhtautua mihinkään. Kyselenkö kuulumisia vai juttelenko päivän säästä. Vai hymyilenkö p771015Niina Lahtinen avautuu erikoisesta "krapula-metodista" ennen suoraa lähetystä: "Kuin mulla olisi..."
Kiitos, Niina! Upeasti vedit TTK-parketilla. Tsemppiä tuleviin tansseihin vaikkapa tuolla "krapulametodilla"! Lue Lahti291012Toivon vain
Ettet enää välittäisi. Kun näet niin ohitatko. Ettei silmissäsi loistaisi enää mikään minut nähdessäni. Ei sitä pilkettä4999Harmailla autoilla liikkuvat vorot
Keitäs sankareita nämä ovat? https://www.kainuunsanomat.fi/artikkeli/harmailla-autoilla-liikkuvat-vorot-ovat-tehneet-us16891Jenni Haukio ja Sauli Niinistö
Ero. Näinhän se menee kun ikäeroa on riittävästi. https://www.iltalehti.fi/viihdeuutiset/a/1c94ff48-185d-4d95-aff5-3e9322854Kuka on tämä henkilö
jonka pullukkaprinsessa kertoilee haisevan? Ennen nykyistä se oli erään seksuaalirikoksesta tuomitun tyypin kanssa, muit93822Minä näen sinut
Näen kuka olet. Osaan laskea. Olen todella, siis todella hämmentynyt, ihastunut, vaivautunut ja ehkä eniten todella epäu26795- 164782