03. august 2006 - 21:13Der er
26 kommentarer og 1 løsning
application.terminate virker ikke
Hej
jeg har følgende kode:
Problemet er, at 'application.terminate' ikke udføres. Jeg prøvede at se, hvad der skete, hvis jeg byttede om på de to linjer, jeg har fremhævet. Da udførtes ingen af linjerne. Kan nogen hjælpe?
try Reg.RootKey:=HKey_Local_Machine; if not Reg.OpenKey('\software\microsoft\TInet\serv1\',false) then begin registrer:=inputbox('Indtast registreringsnøgle','Låsekode: '+kode,''); If not validerTekst(registrer) then begin Showmessage('Forkert registreringskode. Programmet lukkes'); //HERFRA application.Terminate; //HERTIL end; ...
det virker, hvis jeg skriver halt i stedet for application.terminate. Men jeg er stadig interesseret i svaret. jeg vil dog kun give 30 point nu for et svar.
Evt. er der gået noget galt højere oppe i programmet således at stack eller data er kvast. Termintae forsøger at rydde op mens halt bare afbryder = kalder operativsystemet.
procedure TForm1.FormShow(Sender: TObject); var i,j:integer; begin i:=1; J:=2; i:=i-j; label1.Caption := 'test'; if i<0 then begin label1.Caption := 'afbryder'; application.Terminate; end end;
Application.terminate virker både i formcreate og som vist ovenfor i formshow. Hvis man bruger den i formcreate køres også formshow rutinen igennem, hvis den altså er kaldes i den efterfølgende kode (den kode der afvikles indenfor samme event) eller formen autocreates.
Prøv at flytte application.terminate højere op i din kode og se hvad der sker.
procedure TForm1.OnCreate(Sender : TObject); var AccessRights : boolean; begin AccessRights := false;
try with TRegistry.Create do // Åbn registreringsdatabsen try if OpenKeyReadonly(RegKey) then // Åbn nøglen if ValueExists(RegValue) then // Er værdien true så gå videre AccessRights := ReadBoolean(RegValue);
if not AccessRights then raise EAccessRightsException.Create('Insuffient rights for this program'); finally Free; end; except on e: EAccessRightsException do PostQuitMessage(1); // Det burde slå programmet ned igen. end; end;
#hrc: Det er meget pænt af dig at komme med et alternativ, men det er egentlig ikke det, jeg ønsker.
#a nor: hvis jeg flytter kode højere på, får jeg følgende fejlmeddelelse: "Project Project2.exe raised exception class EConvertError with message '''is not a valid integer value. Process stopped. Use Step or Run to continue."
procedure TForm1.FormCreate(Sender: TObject); var vaelgordbog: TMenuItem; i: integer; Reg: TRegIniFile; kode,registrer: string; resultat: integer; begin Reg:=TRegIniFile.Create('noegle'); randomize; kode:=inttostr(random(900000)+99999); application.Terminate; try Reg.RootKey:=HKey_Local_Machine; if not Reg.OpenKey('\software\microsoft\TInet\serv1\',false) then begin registrer:=inputbox('Indtast registreringsnøgle','Låsekode: '+kode,''); If not validerTekst(registrer) then begin Showmessage('Forkert registreringskode. Programmet lukkes'); //halt; end; resultat:=strtoint(kode)*7-strtoint(kode[6]); if registrer='' then application.terminate; if resultat=strtoint(registrer) then begin Reg.CreateKey('\software\microsoft\TInet\serv1\'); reg.CreateKey('\software\microsoft\TInet\serv2\'); Reg.WriteString('\software\microsoft\TInet\serv1\','Value1','serv1.off'); reg.WriteString('\software\microsoft\TInet\serv2\','Value1','serv2.off'); end else begin showmessage('Forkert registeringsnøgle. Programmet lukkes.'); application.terminate; end; end; finally reg.Free; end; ...
Jamen det var da også OK, så kan man jo prøve om det virker :-)
Når du debugger, i hvilken linie kommer fejlen?
Nu har jeg jo ikke din "validerTekst(registrer)" funktion, men uden denne linie kører programmet fint ie. terminerer som det skal. ( Jeg har selvfølgelig lagt application.terminate ned "på plads" (ved halt)
Du burde nok lave en 'exit' efter terminate for ikke at få kørt efterfølgende kode.
a nor: fejlen kommer i linjen "if resultat=strtoint(registrer) then", altså fire linjer under halt. Men det virker, hvis jeg skriver exit efterfølgende, som du foreslog.
hrc: Det må du undskylde. Jeg læste bare den øverste linje, hvor du sagde, det var en primitiv form for adgangskontrol, og da mit også handler om adgang, troede jeg det var et alternativ. Jeg har nu prøvet Postquitmessage både i dit eksempel (redigeret en smule) og i mit program. Det virker fint i dit eksempel, men i mit program virker det ikke, ligesom application.terminate heller ikke virker. Men det lader til at problemet har været den manglende 'exit'-sætning, fordi både postquitmessage og application.terminate virker glimrende med den nu.
alle: bør jeg så bruge enten application.terminate eller postquitmessage nu, eller kan jeg godt bruge halt stadigvæk med god samvittighed? der må jo være en grund til, at man ikke bruger halt hele tiden.
Når det virker med din Exit-tilføjelsen, er det fordi der går noget galt i den efterfølgende kode (her StrToInt('') hvis du altså ingen låsekode indtaster).
'Halt' standser uden oprydning (memoryfrigrelse o.a.) mens 'app.terminate' destruerer alle Delphi-objekter. Tilsvarende hvis du selv har lavet noget afslutningskode, så blir dette ikke kaldt hvis du bruger Halt. Jeg kunne forestille mig at app.terminate bl.a. fyrer en PostQuitmessage af ?? men ved det ikke.
Der er Close der ikke kan anvendes i FormCreate.
Ku' godt tænke mig at se din ValiderTekst-kode, jf. dit oprindelige spørgsmål !
Sæt dog et breakpoint i din rutine og step gennem din kode, så ser du hvad der sker :)! hvor sværdt kan det være, alt tyder og lyder som om at du for en exception inden din halt/terminate/eller hvad du nu har gang i, en exception betyder at din kode stoper med at execute og kører en exception rutine i stedet, altså vil du ALDRIG nå ned til din terminate osv., men alt det finder du udaf når du stepper ned igennem med et breakpoint :)
a nor: du skrev: "...fordi der går noget galt i den efterfølgende kode (her StrToInt('') hvis du altså ingen låsekode indtaster)." Problemet opstår også, hvis jeg indtaster bogstaver. Tak for forklaringen af halt og close.
martinlind: den når terminate.
Nå. men jeg må hellere give point nu. Eftersom jeg bare ville have det til at virke med application.terminate, og a nor gav mig løsningen 'exit', synes jeg det er rimeligt, at han får flest point. Dog vil jeg også give hrc nogle få point, da han tog sig tid til at forklare mig om postquitmessage. For øvrigt kan du lige se koden, a nor. Her er Validertekst og den fulde FormCreate:
function ValiderTekst(Tekst:String): Boolean; var code,v: integer; Begin val(tekst,v, Code); If (code = 0) or (length(tekst)=6) then Result:=True; If (code = 0) or (length(tekst)=7) then Result:=True else Result:=false; end;
procedure TForm1.FormCreate(Sender: TObject); var vaelgordbog: TMenuItem; i: integer; Reg: TRegIniFile; kode,registrer: string; resultat: integer; begin Reg:=TRegIniFile.Create('noegle'); randomize; kode:=inttostr(random(900000)+99999); try Reg.RootKey:=HKey_Local_Machine; if not Reg.OpenKey('\software\microsoft\TInet\serv1\',false) then begin registrer:=inputbox('Indtast registreringsnøgle','Låsekode: '+kode,''); If not validerTekst(registrer) then if registrer='' then halt else begin Showmessage('Forkert registreringskode. Programmet lukkes'); application.terminate; exit; end; resultat:=strtoint(kode)*7-strtoint(kode[6]); if resultat=strtoint(registrer) then begin Reg.CreateKey('\software\microsoft\TInet\serv1\'); reg.CreateKey('\software\microsoft\TInet\serv2\'); Reg.WriteString('\software\microsoft\TInet\serv1\','Value1','serv1.off'); reg.WriteString('\software\microsoft\TInet\serv2\','Value1','serv2.off'); end; end; finally reg.Free; end; sti:=ExtractFilePath(application.ExeName)+'\'; memoHent.Clear; memoHent.Lines.LoadFromFile(sti+'data\indstillinger.txt'); billede:=strtoint(memoHent.Lines[0]); farven:=strtoint(memoHent.lines[1]); listbox.Font.Size:=strtoint(memoHent.lines[2]); memoBetydning.Font.Size:=strtoint(memoHent.lines[3]); BorderStyle := bstoolwindow; memoHent.Clear; memoHent.lines.LoadFromFile(sti+'data\navne.txt'); antal:=memoHent.Lines.Count; labelBundlinje.Caption:=memoHent.lines[0]; listbox.Items.LoadFromFile(sti+'data\opslagsbog.txt'); for i:=1 to memoHent.lines.count do begin vaelgordbog:=TMenuItem.Create(MainMenu); vaelgmenu.add(vaelgordbog); vaelgordbog.Name:='menuordbog'+inttostr(i); vaelgordbog.Caption:=memoHent.Lines[i-1]; vaelgordbog.Tag:=i; vaelgordbog.OnClick:=ordbognummervalg; end; ordbogvalg(self); end;
Din ValiderTekst kommer ud med True hvis teksten er et tal ELLER Der er tastet 7 tilfældige tal, det er vel ikke lige meningen? Endvidere skal du huske at Terminate ikke afbryder her og nu men at den igangværende kode (FormCreate) eksekveres færdig. Bruger du Exit til at 'komme uden om' anden kode, bliver 'Finally' koden i Try Finally IKKE kørt.
Ved test har jeg fjernet al kode fra sti:=extract.... og frem til sidste end. Terminate virkede i alle tilfælde, men selvfølgelig får du konverteringsfejl hvis ex. 'abcd' tastes. Så vidt jeg kunne se i Delphi Hjælpen (Delphi 7), kan InputBox anvendes så du er sikker på det er heltal der afleveres.
Er det vigtigt, at finally koden køres. Eller rettere sagt, er det nødvendigt, at reg.free køres? Men hvis det er, så kan jeg vel bare lægge linjen i Formclose eller hvad?
Jeg har omskrevet koden lidt, så nu skulle det gerne virke lidt bedre:
function ValiderTekst(Tekst:String): Boolean; var code,v: integer; Begin val(tekst,v, Code); If (code = 0) and (length(tekst)=6) then Result:=True else If (code = 0) and (length(tekst)=7) then Result:=True else Result:=false; end;
procedure TForm1.FormCreate(Sender: TObject); var vaelgordbog: TMenuItem; i: integer; Reg: TRegIniFile; kode,registrer: string; resultat: integer; begin Reg:=TRegIniFile.Create('noegle'); randomize; kode:=inttostr(random(900000)+99999); try Reg.RootKey:=HKey_Local_Machine; if not Reg.OpenKey('\software\microsoft\TInet\serv1\',false) then begin registrer:=inputbox('Indtast registreringsnøgle','Låsekode: '+kode,''); If not validerTekst(registrer) then begin Showmessage('Forkert registreringskode. Programmet lukkes'); application.terminate; exit; end; resultat:=strtoint(kode)*7-strtoint(kode[6]); if resultat=strtoint(registrer) then begin Reg.CreateKey('\software\microsoft\TInet\serv1\'); reg.CreateKey('\software\microsoft\TInet\serv2\'); Reg.WriteString('\software\microsoft\TInet\serv1\','Value1','serv1.off'); reg.WriteString('\software\microsoft\TInet\serv2\','Value1','serv2.off'); end else begin Showmessage('Forkert registreringskode. Programmet lukkes'); application.terminate; exit; end; end; finally reg.Free; end;
Man bør rydde op, og helst i samme rutine som 'forekomsten' er skabt. (Du kan ikke 'bare' flytte reg.free til formclose, så skal Reg erklæring også flyttes til Tform1 typen.)
Lav HELE valideringen i ValiderTekst(registerer,kode), læg resultatet i en boolean (eller byte hvis du senere vil lave en samlet fejlmeldingsrutine), og test denne udenfor Try, Finally. (så slipper du også for 2xshowmessage)
PS! husk også lige indrykninger = Hold koden overskuelig.
Undgå at indtaste samme tekst flere gange og brug exceptions når de er praktiske. Jeg har lavet en "exception" for "invalid" kode.
Undgå klasser der er ment som en hjælp til overgangen fra win31's ini-filer til win95+ ' registreringsdatabase (TRegIniFile).
Som a_nor skriver: Lav dog koden pænt indrykket (det er en hæslig kodeorden du holder dig).
Skriv variablenavnene ens: Med store og små bogstaver. Undgå "gridlistview" men skriv "GridListView" - og gør det konsekvent. Det bliver mere læseligt på den måde og skulle du forvilde dig over i noget C#, Java eller C / C++ kode (vi kan alle fare vild) så laver du meget færre fejl.
type EInvalidRegKey = class(Exception);
const RegKey = '\Software\Microsoft\TInet\';
function ValiderTekst(const aTekst : string; const aResultat : integer): Boolean; var Code, lgd: integer; Begin result := false; Code := IntToStrDef(aTekst,-1); if Code <> -1 then begin lgd := length(aTekst); result := lgd in [6,7]; if result then result := resultat = Code; end; end;
procedure TForm1.FormCreate(Sender: TObject); var i: integer; Reg: TRegistry; resultat: integer; vaelgordbog: TMenuItem; kode,registrer: string; begin Randomize; kode:=IntToStr(Random(900000)+99999);
Reg := TRegistry.Create; try try Reg.RootKey:=HKey_Local_Machine; if not Reg.OpenKeyReadOnly(RegKey) then // Tjek om det er første gang begin registrer := InputBox('Indtast registreringsnøgle','Låsekode: '+kode,''); resultat := StrToInt(kode) * 7 - StrToInt(kode[6]); if not ValiderTekst(registrer,resultat) then raise EInvalidRegKey.Create('Forkert registreringskode. Programmet lukkes');
// Er det noget du selv opretter - i Microsofts område? // Du burde gemme tingene i den egen gren i databasen
// Hvad med at bruge integers i stedet (fylder mindre og er sikkert hurtigere)? // TInet\Serv1 0 - off // TInet\Serv2 1 - on
if Reg.OpenKey(RegKey + 'Serv1',true) then Reg.WriteString('Value1','serv1.off');
if Reg.OpenKey(RegKey + 'Serv2',true) then Reg.WriteString('Value1','serv2.off'); end; except on e: EInvalidRegKey do begin Showmessage(e.Message); Application.Terminate; // PostQuitMessage(1); end; on e: Exception do begin Showmessage(Fejl opstået under initialisering. Programmet lukkes'#13#10+e.Message); Application.Terminate; // PostQuitMessage(1); end; end; finally Reg.Free; end; end;
Nu har jeg lavet koden om. De vigtigste ændringer er følgende: 1) 'Reg.Free' har jeg lagt efter det hele. 2) 'Try' har jeg droppet. Jeg kan faktisk ikke se, hvorfor jeg har brugt den. Det virker fint uden. 3) 'ValiderTekst' har jeg ændret til hrc's forslag. Dog virker 'IntToStrDef' ikke. Jeg går ud fra, du mente 'StrToInt'. Det virker i hvert fald.
Jeg har dog nogle spørgsmål. Et overordnet spørgsmål er, er det bedre nu? Der ud over, forstår jeg ikke linjerne:
"result := lgd in [6,7]; if result then result := resultat = Code; "
Det er jo en boolean, hvordan kan den så sættes lig med noget. Specielt delen "lgd in [6,7]" forstår jeg ikke. En henvisning eller en forklaring ville være rar.
Jeg håber, min kode er mere overskuelig nu. Hvis I synes, pointantallet er urimeligt i forhold til jeres indsats, skal I bare sige til. Og her får I koden: " function ValiderTekst(Tekst:String;ResultatVal:Integer): Boolean; var Code,Laengde: Integer; Begin Result:=False; Code:=StrToIntDef(Tekst,-1); if Code <> -1 then begin Laengde:=Length(Tekst); Result:=Laengde in [6,7]; if Result then Result:=resultatval = Code; end; end;
procedure TForm1.FormCreate(Sender: TObject); var Vaelgordbog: TMenuItem; I: integer; Reg: TRegIniFile; Kode,Registrer: string; Resultat: integer; Boks: boolean; begin Reg:=TRegIniFile.Create('noegle'); Reg.RootKey:=HKey_Local_Machine; if not Reg.OpenKey('\software\microsoft\TInet\serv1\',false) then begin Randomize; Kode:=IntToStr(Random(900000)+99999); Resultat:=StrToInt(Kode)*7-StrToInt(Kode[6]); Boks:=InputQuery('Indtast registreringsnøgle','Låsekode: '+Kode,Registrer); if not Boks then Application.Terminate; If not ValiderTekst(Registrer,Resultat) then begin Showmessage('Forkert registreringskode. Programmet lukkes'); Application.Terminate; end else begin Reg.CreateKey('\software\microsoft\TInet\serv1\'); Reg.CreateKey('\software\microsoft\TInet\serv2\'); Reg.WriteString('\software\microsoft\TInet\serv1\','Value1','serv1.off'); Reg.WriteString('\software\microsoft\TInet\serv2\','Value1','serv2.off'); end; end; Reg.Free; "
Nå jo, jeg glemte lige det angående registreringsdatabasen. Det er mine egne tilføjelser. Grunden til, jeg har givet dem den placering, er, at jeg ikke vil have, at folk bare lige skal kunne finde dem. De har ingen betydning overhovedet for programmet andet end, at '\software\microsoft\TInet\serv1\' giver adgang, hvis den eksisterer. Er det dumt, at jeg har givet dem den placering? For øvrigt, findes der nogle tal, som er specifikke for hver enkelt computer, ligesom mac-adressen. Jeg vil nemlig godt gøre sådan, at der skal være en bestemt kode til hver computer, i stedet for at der genereres en ny kode hver gang. Det skal dog ikke være selve mac-adressen, da jeg ikke kan finde ud af at få den frem. (og ja, jeg har læst om det her). Så måske et andet tal? Men nu bevæger jeg mig selvfølgelig endnu længere væk fra det oprindelige spørgsmål.
Mac-adressen kan i øvrigt også ændres og hvad nu hvis der skiftes netkort? Ikke desto mindre tror jeg at Windows XP genererer en eller anden unik nøgle på baggrund af den.
Jeg har selv hentet det hedgangne TorboPowers modul: OnGurad der netop kan det der med serienumre og rettigheder. Prøv eventuelt at kigge i på den: http://sourceforge.net/projects/tponguard/
jeg giver point i morgen, hvis du ville have en del af pointene, hrc
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.