HotXLS rakentuu Free Pascalilla ja Lazarusilla Windowsilla, ja portti riippui neljästä päätöksestä, joilla ei ole mitään tekemistä Object Pascal -syntaksin kanssa: pidä ydin DELPHIUNICODE-tilassa, määrittele OLE-structured storage -rajapinnat CORBA-rajapinnoina käsin hoidetulla referenssilaskennalla, korvaa Win32:n AES-objektitiedostot Pascal-toteutuksella ja korjaa inflate-silmukka, joka saattoi hyväksyä katkaistun ZIPin täydellisenä
Jokainen, joka on portannut kypsän Delphi-kirjaston, tuntee tämän työn muodon. Kääntäjä hyväksyy melkein kaiken ensimmäisellä kierroksella. Seuraa pitkä häntä käyttäytymiseroja, jotka kääntyvät puhtaasti ja tuottavat vääriä tuloksia, ja taulukkolaskentamoottori on niille epätavallisen altis, koska se koskettaa tekstimuotoilua, COM-structured storagea, pakkausta ja kryptografiaa yhdessä koodipolussa
Miksi ydin vaatii DELPHIUNICODEa pelkän DELPHIn sijaan?
Koska kaavamoottori riippuu siitä, että String ja Char kantavat UTF-16-semantiikkaa, ja ANSI-vaihtoehto menettää merkkejä ennen kuin mikään saavuttaa tiedoston. On houkuttelevaa rakentaa ydin FPC:n DELPHI-tilassa, koska se on yhteensopivuuskytkin, johon useimmat portit tarttuvat, ja koodi kääntyy. Sitten työkirja, jossa on kiinalaisia taulukkonimiä tai kyrillisiä nimikkeitä, kulkee laskentapolun läpi, ja merkit ovat poissa siihen mennessä, kun kirjoittaja näkee ne, ilman virhettä missään
Tila ei ole yhtenäinen kirjaston läpi, ja se on tahallista eikä sekasotkua. PNG:n tavudekooderi ja LCL-overridet tarvitsevat aidosti ANSI-signatuureja, koska ne käsittelevät tavuja ja sitä, mitä widgetset niille ojentaa. Nämä yksiköt kytkevät erillisen LX_FPC_ANSI-kytkimen. Kaksi tilaa yhdessä kirjastossa kuulostaa koodihajulta, kunnes huomaat, että vaihtoehto on tavudekooderi, joka kohtelee syötettään tekstinä
On kumppaniksi yksityiskohta, joka nappaa ihmiset myöhemmin. DELPHIUNICODE ei tee TFormatSettings.DecimalSeparatorista WideCharia FPC:n ajonaikaisessa ympäristössä. Syöte, joka kantaa Unicoden desimaalierotinta, on normalisoitava ASCII-erottimeksi Unicode-merkkijonon sisällä ensin, ja jokainen syöte, jonka erottin ei täsmää odotettuun, on hylättävä, ei hiljaa katkaistava siihen merkkiin, jota jäsennin ei tunnistanut
program ExportReport;
{$MODE DELPHI}
uses
Interfaces, // täytyy tulla ensin: alustaa LCL-widgetsetin
SysUtils, lxHandle; // ja UTF-8-muunnoskerroksen
var
Book: TXLSWorkbook;
begin
Book := TXLSWorkbook.Create(nil);
try
Book.LoadFromFile('input.xls');
Book.Sheets[0].AsString[1, 1] := 'Quarterly summary';
Book.SaveToFile('output.xls');
finally
Book.Free;
end;
end.
Interfaces-yksikkö ei ole valinnainen, ja sen on tultava ensin. Se on se, mikä alustaa LCL-widgetsetin ja UTF-8-muunnoskerroksen, ja HotXLS nojaa molempiin heti, kun fontit, tiedostopolut tai teksti ylittävät RTL:n ja LCL:n rajan. Konsoliohjelma, joka ohittaa sen, kääntyy ja käyttäytyy väärin millä tahansa ei-ASCII-polulla. Tämä on myös syy, miksi onnistunut käännös todistaa niin vähän täällä: portti oli todistetusti toimiva vasta, kun oikeat dokumentit oikeilla fonttinimillä ja oikeilla poluilla tekivät täyden edestakaisen matkan
Luokan VMT ei ole COM-vtable
Free Pascal ei anna sinun ojentaa luokan VMT:tä Windowsille COM-rajapinnan vtablena, vaikka määrittely näyttäisi identtiseltä sille, jonka Delphi hyväksyy. Asettelut eroavat tavoilla, jotka tuottavat kutsun väärään slottiin, mikä ilmenee kaatumisena jossain kutsupaikasta riippumattomassa. Structured storage merkitsee täällä, koska klassinen binäärinen työkirjamuoto on OLE-yhdistelmätiedosto, ja sellaisen lukeminen tai kirjoittaminen tarkoittaa ILockBytesin toteuttamista, johon Windowsin storage API kutsuu takaisin
Toimiva järjestely on CORBA-rajapinta, jossa COM-slotit on määritelty eksplisiittisesti ja AddRef ja Release hoidetaan käsin. Tämä merkitsee automaattisen referenssilaskennan luopumista näille tyypeille ja vastuun ottamista elinkaaresta, mikä on reilua vaihtokauppaa kouralliselle rajapintoja, jotka asuvat yhden yksikön sisällä. Kyseisen työn sisällä oleva tarkka ansa on QueryInterface: sen on palautettava rajapintaosoitin, ei objektiosoitin. Molemmat kääntyvät. Toinen niistä ojentaa Windowsille osoitteen, jonka ensimmäinen konesana ei ole vtable
FPC-kohtaiset määrittelyt asuvat lxOleInterfaces.incissä, lxAESBackend.incin ja lxZlibBackend.incin vieressä FPC:n lähdehakemistossa, joten kääntäjäkohtaiset valinnat istuvat yhdessä paikassa hajallaan moottorin läpi olemisen sijaan. Muoto itse ja se, miten kirjasto kulkee sen läpi, on kuvattu artikkelissa OLE2-yhdistelmätiedostojen lukeminen Pascalilla
Yksi tyyppiyksityiskohta lisää kuuluu samaan perheeseen. LargeIntin on ratkaistava Int64iksi FPC-haarassa, ja Compin kääntäjäluokittelu eroaa riittävästi kahden työkaluketjun välillä, että ylikuormien ratkaisu voi poimia eri ehdokkaan. Testaa suurten siirtymien käytöstä tiedostovirralla HGLOBAL-virran sijaan: Windowsin globaalimuistivirta kiertyy ympäri hauissa yli 4 GiB:n itsestään, joten läpäisevä testi siellä ei todista mitään omasta aritmetiikastasi
Mitä itsensä kanssa yhdenmukainen AES-toteutus kätkee
Win32:n AES-objektitiedostot, jotka Delphi-käännös linkittää, ovat OMF-muodossa, eikä Free Pascalin linkkeri voi nielaista niitä, joten FPC-haara käyttää sen sijaan Pascal-AES-toteutusta. Delphi jatkaa niiden objektitiedostojen linkittämistä, joita se aina linkitti, mikä pitää julkaistun binäärin muuttumattomana nykyisille asiakkaille
Varmistusvaatimus on se osa, joka kannattaa viedä mukanaan mihin tahansa projektiin. Datan salaaminen ja sen purkaminen uudelleen samalla toteutuksella ei todista mitään: symmetrinen algoritmi, jolla on väärä key schedule, väärä lohkojärjestys tai väärä ketjutus, on täydellisen itsensä kanssa yhdenmukainen ja tekee omasta tuloksestaan edestakaisen matkan joka kerta. Vain known-answer-vektorit nappaavat sen, tarkistaen avainlaajennuksen, lohkojärjestyksen ja CBC-ketjutuksen julkaistuja arvoja vasten. Toimita itsensä kanssa yhdenmukainen väärä toteutus, ja oire ilmestyy ensimmäisellä kerralla, kun asiakas avaa tiedoston Excelissä
Pakkauksessa oli toisen luonteen vika. Pascal-inflate-tausta voi yhä pitää tulostetta kesken, kun se on nielaissut kaiken pakatun syötteensä, joten kutsujan on jatkettava kutsumista, kunnes virta raportoi loppunsa. Loppuneen syötteen kohteleminen virran loppuna katkaisee viimeisen lohkon. Pahempaa, se muuttaa vaurioituneen arkiston hiljaisesti hyväksytyksi, mikä on täsmälleen se vikamuoto, jota vastaan artikkelin ZIP:n end-of-central-directory-tietueen validoiminen kovennus on tehty. Sääntö on, ettei etenemistä eikä valmiutta ole, on katkaisuvirhe, ei koskaan EOF
Kaksi buildijärjestelmän ansaa, jotka maksavat oikeita tunteja
LCL-hakupolkujen on edeltettävä FPC-pakettien jokerimerkkipolkuja, muuten Free Visionin Menus-yksikkö varjostaa samannimisen LCL-yksikön, ja saat PPU-tarkistussumman ristiriidan, joka ei kerro mitään kummastakaan. Lazarus-asennus, joka siirrettiin asentamisen jälkeen, voi myös jättää vanhentuneita polkuja fpc.cfgään, joten käännösten sisääntulopisteet määrittelevät yksikkö- ja binääripolut eksplisiittisesti perien ympäristön tarjoaman sijaan
Toinen ansa ei liity mitenkään Pascaliin. LF-rivinvaihdoin kirjoitettu .cmd-eräajotiedosto toimii, kunnes tiedosto kasvaa tulkin lukupuskurin kokoa suuremmaksi, jolloin call :label epäonnistuu väittämällä, ettei eräotsikkoa ole olemassa, ja vika ilmestyy siihen ohjelmaan, joka sattuu istumaan rajan yli. Jokaisen eräskriptin uudelleenkirjoittavan työkalun on kirjoitettava CRLF takaisin. Ja lazbuild --build-all tyhjentää paketin yksikkötulostushakemiston ennen kääntämistä, joten siihen hakemistoon pysäköity asetustiedosto poistetaan ennen kuin sitä ehditään lukea: pidä se ulkopuolella ja muista, että @-polku ratkaistaan pakettihakemiston suhteen, koska lazbuild kutsuu kääntäjää sieltä
// Lazarus-ruudukon vienti: TGridToXLS toimituu Lazarus-paketissa, joten
// sama DB-grid-vientikoodi toimii LCL-sovelluksessa
var
Exporter: TGridToXLS;
begin
Exporter := TGridToXLS.Create(nil);
try
Exporter.DBGrid := GridOrders;
Exporter.WorksheetName := 'Orders';
Exporter.ExportHeader := True;
Exporter.SetColumnsWidth := True;
Exporter.ExportDBGrid;
Exporter.SaveAs('orders.xls');
finally
Exporter.Free;
end;
end;
Mitä kääntäjän varoitus on arvansa
Free Pascal raportoi alustamattomia paikallismuuttujia, joita Delphi ei raportoi, ja FPC-käännöksen ajaminen käänsi tuon eron kahdeksi oikeaksi viaksi laskentayksikössä. Toinen funktio luki laskurimuuttujan, jota ei koskaan sijoitettu ennen käyttöä, ja toinen käytti kahta koordinaattia yhdessä haarassa ennen kuin niitä laskenut koodi ajoi eri haarassa. Delphillä molemmat käyttäytyivät sen mukaan, mitä pino sattui pitämään, mikä on määritelmä bugille, joka toistuu yhdellä koneella eikä toisella
Käytännön johtopäätös on, että toinen kääntäjä kannattaa pitää silmukassa jopa tuotteelle, joka toimituu ensisijaisesti ensimmäisellä. FPC-varoitusluokkien selaaminen säännöllisesti on halpa staattisen analyysin kierros Delphi-koodikannan yli, ja se löytää defektiluokan, johon yksikään testisviitti ei luotettavasti yletä. Laajempi versiomatriisin kurinalaisuus, jonka sisällä tämä istuu, on kuvattu artikkelissa ristikkäiskääntäjäbuildimatriisi
Free Pascal- ja Lazarus-tuki Windowsille toimituu HotXLS Delphi -taulukkolaskentakomponentin mukana Lazarus-pakettina Delphi- ja C++Builder-pakettien rinnalla, rakennettuna samasta lähdekoodipuusta forkkaamisen sijaan. Tuo on harjoituksen pointti: yksi moottori, neljä työkaluketjua ja kääntäjäkohtaiset päätökset eristettyinä include-tiedostoihin, joista ne voi lukea yhdellä istumalla