diff --git a/kernel/ps4_libkernel.pas b/kernel/ps4_libkernel.pas index 0e63179..39868d1 100644 --- a/kernel/ps4_libkernel.pas +++ b/kernel/ps4_libkernel.pas @@ -179,7 +179,7 @@ begin Writeln(' __free:',HexStr(heap_api^._free)); //__free end; -//registred destroy proc? +//cb used in pthread_exit function ps4_sceKernelSetThreadDtors(Proc:TProcedure):Integer; SysV_ABI_CDecl; begin Writeln('sceKernelSetThreadDtors:',HexStr(proc)); @@ -192,13 +192,14 @@ begin Result:=0; end; -//registred thread atexit proc? -function ps4_sceKernelSetThreadAtexitCount(proc:TKernelAtexitFunc):Integer; SysV_ABI_CDecl; +//cb used in sceKernelStopUnloadModule +function ps4_sceKernelSetThreadAtexitCount(proc:TKernelAtexitFuncCount):Integer; SysV_ABI_CDecl; begin Writeln('sceKernelSetThreadAtexitCount:',HexStr(proc)); Result:=0; end; +//cb used in sceKernelStopUnloadModule function ps4_sceKernelSetThreadAtexitReport(proc:TKernelAtexitReportFunc):Integer; SysV_ABI_CDecl; begin Writeln('sceKernelSetThreadAtexitReport:',HexStr(proc)); @@ -251,6 +252,10 @@ begin end; end; +//dynlib_get_obj_member(handle,8,&ptr); module param +//dynlib_get_obj_member(handle,1,&ptr); init +//dynlib_get_obj_member(handle,2,&ptr); fini + //dynamic load???? function ps4_sceKernelLoadStartModule(moduleFileName:Pchar; argc:size_t; diff --git a/ps4_elf.pas b/ps4_elf.pas index d624e6a..049d01c 100644 --- a/ps4_elf.pas +++ b/ps4_elf.pas @@ -12,7 +12,8 @@ uses ps4libdoc, ps4_program, ps4_elf_tls, - Classes, SysUtils; + Classes, + SysUtils; type PsceLibcMallocReplace=^TsceLibcMallocReplace; @@ -252,7 +253,7 @@ type type TinitProc =function(argc:Integer;argv,environ:PPchar):Integer; SysV_ABI_CDecl; //preinit_array/init_array TEntryPoint =procedure(pEnv:Pointer;pfnExitHandler:Pointer); SysV_ABI_CDecl; //EntryPoint - TmoduleStart=function(argc:size_t;argp:Pointer):Integer; SysV_ABI_CDecl; //module_start/module_stop + TmoduleStart=function(argc:size_t;argp,proc:Pointer):Integer; SysV_ABI_CDecl; //module_start/module_stop function LoadPs4ElfFromFile(Const name:RawByteString):TElf_node; @@ -1344,6 +1345,7 @@ begin STT_FILE :Result:='STT_FILE '; STT_COMMON :Result:='STT_COMMON '; STT_TLS :Result:='STT_TLS '; + STT_SCE :Result:='STT_SCE '; else Result:='STT_'+HexStr(sType,2)+' '; end; end; @@ -1404,6 +1406,7 @@ begin STT_SECTION:; STT_FILE :; STT_COMMON :; + STT_SCE :; STT_TLS :Writeln(__sType(Info.sType)); else Writeln(__sType(Info.sType)); @@ -1441,6 +1444,7 @@ begin STT_SECTION:; STT_FILE :; STT_COMMON :; + STT_SCE :; STT_TLS :Writeln(__sType(Info.sType)); else Writeln(__sType(Info.sType)); @@ -1488,6 +1492,7 @@ begin //STT_FILE :; STT_COMMON :; STT_TLS :; + STT_SCE :; else Writeln(__sType(Info.sType)); end; @@ -1537,30 +1542,12 @@ Procedure OnLoadRelaExport(elf:Telf_file;Info:PRelaInfo;data:Pointer); Import:Boolean; begin - Import:=(Info^.shndx=SHN_UNDEF); // - case _on_module_start_stop(Info^.pName) of - 0:begin //module_start - //nSymVal:=elf.mMap.pAddr+elf.dtInit; - _do_set(nSymVal); - - //IInfo.nid:=ps4_nid_hash(Info^.pName); - //IInfo.lib:=elf._get_lib(0); - //IInfo.lib^.set_proc(IInfo.nid,nSymVal); - - Exit; - end; - 1:begin //module_stop - //nSymVal:=elf.mMap.pAddr+elf.dtFini; - _do_set(nSymVal); - - //IInfo.nid:=ps4_nid_hash(Info^.pName); - //IInfo.lib:=elf._get_lib(0); - //IInfo.lib^.set_proc(IInfo.nid,nSymVal); - - Exit; - end; - else; + case Info^.sType of + STT_NOTYPE :Import:=False; + STT_SCE :Import:=False; + else + Import:=(Info^.shndx=SHN_UNDEF); end; if Import then Exit; @@ -1569,10 +1556,32 @@ Procedure OnLoadRelaExport(elf:Telf_file;Info:PRelaInfo;data:Pointer); nModuleId:=0; nLibraryId:=0; - if not DecodeEncName(Info^.pName,nModuleId,nLibraryId,IInfo.nid) then - begin - IInfo.nid:=ps4_nid_hash(Info^.pName); + + case Info^.sType of + STT_NOTYPE: + begin + IInfo.nid:=ps4_nid_hash(Info^.pName); + nModuleId:=elf._find_mod_export; + nLibraryId:=elf._find_lib_export; + end; + STT_SCE: + begin + if not DecodeValue64(Info^.pName,StrLen(Info^.pName),IInfo.nid) then + begin + Writeln(StdErr,'Error decode:',Info^.pName); + end; + nModuleId:=elf._find_mod_export; + nLibraryId:=elf._find_lib_export; + end; + else + begin + if not DecodeEncName(Info^.pName,nModuleId,nLibraryId,IInfo.nid) then + begin + Writeln(StdErr,'Error decode:',Info^.pName); + end; + end; end; + IInfo._md:=elf._get_mod(nModuleId); IInfo.lib:=elf._get_lib(nLibraryId); @@ -1581,6 +1590,7 @@ Procedure OnLoadRelaExport(elf:Telf_file;Info:PRelaInfo;data:Pointer); Writeln(StdErr,'Unknow module from ',Info^.pName); end; + if (IInfo._md<>nil) then if (IInfo._md^.Import<>Import) then begin Writeln(StdErr,'Wrong module ref:',IInfo._md^.strName,':',IInfo._md^.Import,'<>',Import); @@ -1683,20 +1693,13 @@ Procedure OnLoadRelaImport(elf:Telf_file;Info:PRelaInfo;data:Pointer); Import:Boolean; begin - Import:=(Info^.shndx=SHN_UNDEF); // - if (_on_module_start_stop(Info^.pName)<>-1) then Exit; - - //case _on_module_start_stop(Info^.pName) of - // 0:begin //module_start - // Writeln('module_start:',HexStr(PPointer(elf.mMap.pAddr+Info^.Offset)^)); - // Exit; - // end; - // 1:begin //module_stop - // Exit; - // end; - // else; - //end; + case Info^.sType of + STT_NOTYPE :Import:=False; + STT_SCE :Import:=False; + else + Import:=(Info^.shndx=SHN_UNDEF); + end; if not Import then Exit; @@ -1704,10 +1707,12 @@ Procedure OnLoadRelaImport(elf:Telf_file;Info:PRelaInfo;data:Pointer); nModuleId:=0; nLibraryId:=0; + if not DecodeEncName(Info^.pName,nModuleId,nLibraryId,IInfo.nid) then begin - IInfo.nid:=ps4_nid_hash(Info^.pName); + Writeln(StdErr,'Error decode:',Info^.pName); end; + IInfo._md:=elf._get_mod(nModuleId); IInfo.lib:=elf._get_lib(nLibraryId); @@ -1716,6 +1721,7 @@ Procedure OnLoadRelaImport(elf:Telf_file;Info:PRelaInfo;data:Pointer); Writeln(StdErr,'Unknow module from ',Info^.pName); end; + if (IInfo._md<>nil) then if (IInfo._md^.Import<>Import) then begin Writeln(StdErr,'Wrong module ref:',IInfo._md^.strName,':',IInfo._md^.Import,'<>',Import); @@ -1812,23 +1818,45 @@ const nModuleId,nLibraryId:Word; Import:Boolean; - mss:Integer; - space_lib:TLIBRARY; begin - Import:=(Info^.shndx=SHN_UNDEF); - - mss:=_on_module_start_stop(Info^.pName); - if (mss<>-1) then Import:=False; + case Info^.sType of + STT_NOTYPE :Import:=False; + STT_SCE :Import:=False; + else + Import:=(Info^.shndx=SHN_UNDEF); + end; IInfo:=Default(TResolveImportInfo); nModuleId:=0; nLibraryId:=0; - if not DecodeEncName(Info^.pName,nModuleId,nLibraryId,IInfo.nid) then - begin - IInfo.nid:=ps4_nid_hash(Info^.pName); + + case Info^.sType of + STT_NOTYPE: + begin + IInfo.nid:=ps4_nid_hash(Info^.pName); + nModuleId:=elf._find_mod_export; + nLibraryId:=elf._find_lib_export; + end; + STT_SCE: + begin + if not DecodeValue64(Info^.pName,StrLen(Info^.pName),IInfo.nid) then + begin + Writeln(StdErr,'Error decode:',Info^.pName); + end; + nModuleId:=elf._find_mod_export; + nLibraryId:=elf._find_lib_export; + end; + else + begin + if not DecodeEncName(Info^.pName,nModuleId,nLibraryId,IInfo.nid) then + begin + Writeln(StdErr,'Error decode:',Info^.pName); + end; + end; end; + IInfo._md:=elf._get_mod(nModuleId); IInfo.lib:=elf._get_lib(nLibraryId); @@ -1837,6 +1865,7 @@ const FWriteln('Unknow module from '+Info^.pName); end; + if (IInfo._md<>nil) then if (IInfo._md^.Import<>Import) then begin FWriteln('Wrong module ref:'+IInfo._md^.strName+':'+BoolToStr(IInfo._md^.Import)+'<>'+BoolToStr(Import)); @@ -1845,20 +1874,24 @@ const if (IInfo.lib=nil) then begin FWriteln('Unknow library from '+Info^.pName); - space_lib:=Default(TLIBRARY); - space_lib.Import:=Import; - IInfo.lib:=@space_lib; - //Exit; end; - if (IInfo.lib^.Import<>Import) and (mss=-1) then + if (IInfo.lib<>nil) then + if (IInfo.lib^.Import<>Import) then begin - FWriteln('Wrong library ref:'+IInfo.lib^.strName+':'+BoolToStr(IInfo._md^.Import)+'<>'+BoolToStr(Import)); - //Exit; + FWriteln('Wrong library ref:'+IInfo.lib^.strName+':'+BoolToStr(IInfo.lib^.Import)+'<>'+BoolToStr(Import)); end; functName:=ps4libdoc.GetFunctName(IInfo.nid); - FWriteln(__nBind(Info^.sBind)+':'+__sType(Info^.sType)+':'+IInfo._md^.strName +':'+IInfo.lib^.strName+':'+functName); + + FWrite(__nBind(Info^.sBind)+':'+__sType(Info^.sType)+':'+IInfo._md^.strName +':'); + + if (IInfo.lib<>nil) then + begin + FWrite(IInfo.lib^.strName); + end; + + FWriteln(':'+functName); if Import then begin @@ -2582,27 +2615,23 @@ end; function Telf_file.module_start(argc:size_t;argp:PPointer):Integer; var + mp:PsceModuleParam; + M:Pointer; P:TmoduleStart; begin Result:=0; - Pointer(P):=Pointer(mMap.pAddr+dtInit); - Writeln('module_start'); - Result:=P(argc,argp); + Pointer(mp):=Pointer(mMap.pAddr+pModuleParam); + + //M:=get_proc_by_name('module_start'); + M:=nil; + + Pointer(P):=Pointer(mMap.pAddr+dtInit); + + Writeln('module_start'); + + Result:=P(argc,argp,M); - //Pointer(P):=Pointer(pModule.pStart); - //Case Int64(P) of - // -1,0,1:;//skip - // else - // begin - // Pointer(P):=Pointer(mMap.pAddr+QWORD(P)); - // - // Writeln('module_start'); - // - // Result:=P(argc,argp); - // - // end; - //end; end; function Telf_file.GetCodeFrame:TMemChunk; diff --git a/ps4_program.pas b/ps4_program.pas index 0e693d7..135299f 100644 --- a/ps4_program.pas +++ b/ps4_program.pas @@ -65,6 +65,8 @@ type procedure _set_lib(id:Word;lib:TLIBRARY); inline; procedure _set_lib_attr(u:TLibraryValue); inline; function _get_lib(id:Word):PLIBRARY; inline; + function _find_mod_export:Word; + function _find_lib_export:Word; public pFileName:RawByteString; property IsStatic:Boolean read FStatic write FStatic; @@ -718,6 +720,19 @@ begin end; end; +function TElf_node._find_mod_export:Word; +var + i:Word; +begin + Result:=0; + if Length(aMods)>0 then + For i:=0 to High(aMods) do + if not aMods[i].Import then + begin + Exit(i); + end; +end; + procedure TElf_node._set_lib(id:Word;lib:TLIBRARY); inline; var i:SizeInt; @@ -775,6 +790,20 @@ begin aLibs[i]:=Result; end; +function TElf_node._find_lib_export:Word; +var + i:Word; +begin + Result:=0; + if Length(aLibs)>0 then + For i:=0 to High(aLibs) do + if (aLibs[i]<>nil) then + if not aLibs[i]^.Import then + begin + Exit(i); + end; +end; + function TElf_node.ModuleNameFromId(id:WORD):RawByteString; var _md:PMODULE; diff --git a/sys/sys_kernel.pas b/sys/sys_kernel.pas index aa6e5f4..994219d 100644 --- a/sys/sys_kernel.pas +++ b/sys/sys_kernel.pas @@ -19,8 +19,8 @@ type end; atexit_func=function(param:Pointer):Integer;SysV_ABI_CDecl; - TKernelAtexitFunc=function(param:Integer):Integer;SysV_ABI_CDecl; - TKernelAtexitReportFunc=procedure(param:Integer); + TKernelAtexitFuncCount=function(handle:Integer):Integer;SysV_ABI_CDecl; + TKernelAtexitReportFunc=procedure(handle:Integer); function px2sce(e:Integer):Integer; function sce2px(e:Integer):Integer; diff --git a/sys/sys_types.pas b/sys/sys_types.pas index df54e27..e5e0844 100644 --- a/sys/sys_types.pas +++ b/sys/sys_types.pas @@ -354,6 +354,8 @@ type Size:QWORD; Magic:QWORD; SDK_version:QWORD; + param1:Integer; + param2:Integer; end; PTLS_index=^TLS_index; @@ -392,6 +394,8 @@ Const STT_SPARC_REGISTER=13; STT_HIPROC =15; + STT_SCE =11; //module_start/module_stop + STV_DEFAULT =0; STV_INTERNAL =1; STV_HIDDEN =2; diff --git a/tools/nid_gui_test/main.lfm b/tools/nid_gui_test/main.lfm new file mode 100644 index 0000000..b27c650 --- /dev/null +++ b/tools/nid_gui_test/main.lfm @@ -0,0 +1,58 @@ +object frmMain: TfrmMain + Left = 441 + Height = 240 + Top = 138 + Width = 556 + Caption = 'nid_gui_test' + ClientHeight = 240 + ClientWidth = 556 + LCLVersion = '2.3.0.0' + object NidBase64: TLabeledEdit + Left = 8 + Height = 33 + Top = 24 + Width = 536 + Anchors = [akTop, akLeft, akRight] + EditLabel.Height = 15 + EditLabel.Width = 536 + EditLabel.Caption = 'Nid Base64' + Font.Height = -19 + ParentFont = False + TabOrder = 0 + OnClick = NidBase64Click + OnExit = NidBase64Click + OnKeyDown = TextKeyDown + end + object NidHex: TLabeledEdit + Left = 8 + Height = 33 + Top = 80 + Width = 536 + Anchors = [akTop, akLeft, akRight] + EditLabel.Height = 15 + EditLabel.Width = 536 + EditLabel.Caption = 'Nid Hex' + Font.Height = -19 + ParentFont = False + TabOrder = 1 + OnClick = NidHexClick + OnExit = NidHexClick + OnKeyDown = TextKeyDown + end + object NidName: TLabeledEdit + Left = 8 + Height = 33 + Top = 136 + Width = 536 + Anchors = [akTop, akLeft, akRight] + EditLabel.Height = 15 + EditLabel.Width = 536 + EditLabel.Caption = 'Nid Name' + Font.Height = -19 + ParentFont = False + TabOrder = 2 + OnClick = NidNameClick + OnExit = NidNameClick + OnKeyDown = TextKeyDown + end +end diff --git a/tools/nid_gui_test/main.pas b/tools/nid_gui_test/main.pas new file mode 100644 index 0000000..515a02f --- /dev/null +++ b/tools/nid_gui_test/main.pas @@ -0,0 +1,181 @@ +unit main; + +{$mode objfpc}{$H+} + +interface + +uses + sha1, + Classes, + SysUtils, + Forms, + Controls, + Graphics, + Dialogs, + ExtCtrls; + +type + + { TfrmMain } + + TfrmMain = class(TForm) + NidBase64: TLabeledEdit; + NidHex: TLabeledEdit; + NidName: TLabeledEdit; + procedure TextKeyDown(Sender:TObject;var Key:Word;Shift:TShiftState); + procedure NidBase64Click(Sender: TObject); + procedure NidHexClick(Sender: TObject); + procedure NidNameClick(Sender: TObject); + private + + public + + end; + +var + frmMain: TfrmMain; + +implementation + +uses + ps4libdoc; + +{$R *.lfm} + +function ps4_nid_hash(NidName:PChar):QWORD; +const + salt:array[0..15] of Byte=($51,$8D,$64,$A6,$35,$DE,$D8,$C1,$E6,$B0,$39,$B1,$C3,$E5,$52,$30); +var + Context:TSHA1Context; + Digest:TSHA1Digest; +begin + SHA1Init(Context); + SHA1Update(Context,NidName^,StrLen(NidName)); + SHA1Update(Context,salt,Length(salt)); + SHA1Final(Context,Digest); + Result:=PQWORD(@Digest)^; +end; + +function EncodeValue64(nVal:QWORD):RawByteString; +const + nEncLenMax=11; +var + i,nIndex:Integer; +begin + SetLength(Result,nEncLenMax); + For i:=nEncLenMax downto 1 do + begin + if (i<>nEncLenMax) then + begin + nIndex:=nVal and 63; + nVal:=nVal shr 6; + end else + begin + nIndex:=(nVal and 15) shl 2; + nVal:=nVal shr 4; + end; + case nIndex of + 0..25:Result[i]:=Char(nIndex+Byte('A')-0); + 26..51:Result[i]:=Char(nIndex+Byte('a')-26); + 52..61:Result[i]:=Char(nIndex+Byte('0')-52); + 62:Result[i]:='+'; + 63:Result[i]:='-'; + end; + end; +end; + +function DecodeValue64(strEnc:PAnsiChar;len:SizeUint;var nVal:QWORD):Boolean; +const + nEncLenMax=11; +var + i,nIndex:Integer; +begin + Result:=False; + nVal:=0; + if (len>nEncLenMax) or (len=0) then Exit; + For i:=0 to len-1 do + begin + case strEnc[i] of + 'A'..'Z':nIndex:=Byte(strEnc[i])-Byte('A')+0; + 'a'..'z':nIndex:=Byte(strEnc[i])-Byte('a')+26; + '0'..'9':nIndex:=Byte(strEnc[i])-Byte('0')+52; + '+':nIndex:=62; + '-':nIndex:=63; + else Exit; + end; + if (i<(nEncLenMax-1)) then + begin + nVal:=nVal shl 6; + nVal:=nVal or nIndex; + end else + begin + nVal:=nVal shl 4; + nVal:=nVal or (nIndex shr 2); + end; + end; + Result:=True; +end; + +{ TfrmMain } + +procedure TfrmMain.TextKeyDown(Sender:TObject;var Key:Word;Shift:TShiftState); +begin + if Sender.InheritsFrom(TLabeledEdit) then + if (TLabeledEdit(Sender).OnClick<>nil) then + if (Key=13) then + begin + TLabeledEdit(Sender).OnClick(Sender); + end; +end; + +procedure TfrmMain.NidBase64Click(Sender: TObject); +var + S:RawByteString; + nid:QWORD; +begin + S:=NidBase64.Text; + nid:=0; + if DecodeValue64(PAnsiChar(S),Length(S),nid) then + begin + NidHex.Text:=HexStr(nid,16); + NidName.Text:=ps4libdoc.GetFunctName(nid); + end else + begin + NidHex.Text:=''; + NidName.Text:=''; + end; +end; + +procedure TfrmMain.NidHexClick(Sender: TObject); +var + S:RawByteString; + nid:QWORD; +begin + S:='$'+NidHex.Text; + nid:=0; + if TryStrToQWord(S,nid) then + begin + NidBase64.Text:=EncodeValue64(nid); + NidName.Text:=ps4libdoc.GetFunctName(nid); + end else + begin + NidBase64.Text:=''; + NidName.Text:=''; + end; +end; + +procedure TfrmMain.NidNameClick(Sender: TObject); +var + S:RawByteString; + nid:QWORD; +begin + S:=NidName.Text; + nid:=ps4_nid_hash(PChar(S)); + NidBase64.Text:=EncodeValue64(nid); + NidHex.Text:=HexStr(nid,16); +end; + +{ TfrmMain } + +end. + diff --git a/tools/nid_gui_test/nid_gui_test.ico b/tools/nid_gui_test/nid_gui_test.ico new file mode 100644 index 0000000..10c5fc1 Binary files /dev/null and b/tools/nid_gui_test/nid_gui_test.ico differ diff --git a/tools/nid_gui_test/nid_gui_test.lpi b/tools/nid_gui_test/nid_gui_test.lpi new file mode 100644 index 0000000..63d07eb --- /dev/null +++ b/tools/nid_gui_test/nid_gui_test.lpi @@ -0,0 +1,80 @@ + + + + + + + + + <Scaled Value="True"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <XPManifest> + <DpiAware Value="True"/> + </XPManifest> + <Icon Value="0"/> + </General> + <BuildModes> + <Item Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <RequiredPackages> + <Item> + <PackageName Value="LCL"/> + </Item> + </RequiredPackages> + <Units> + <Unit> + <Filename Value="nid_gui_test.lpr"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="main.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmMain"/> + <ResourceBaseClass Value="Form"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="nid_gui_test"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="..\.."/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf2"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions> + <Item> + <Name Value="EAbort"/> + </Item> + <Item> + <Name Value="ECodetoolError"/> + </Item> + <Item> + <Name Value="EFOpenError"/> + </Item> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/tools/nid_gui_test/nid_gui_test.lpr b/tools/nid_gui_test/nid_gui_test.lpr new file mode 100644 index 0000000..064cac3 --- /dev/null +++ b/tools/nid_gui_test/nid_gui_test.lpr @@ -0,0 +1,25 @@ +program nid_gui_test; + +{$mode objfpc}{$H+} + +uses + {$IFDEF UNIX} + cthreads, + {$ENDIF} + {$IFDEF HASAMIGA} + athreads, + {$ENDIF} + Interfaces, // this includes the LCL widgetset + Forms, main + { you can add units after this }; + +{$R *.res} + +begin + RequireDerivedFormResource:=True; + Application.Scaled:=True; + Application.Initialize; + Application.CreateForm(TfrmMain, frmMain); + Application.Run; +end. + diff --git a/tools/nid_gui_test/nid_gui_test.res b/tools/nid_gui_test/nid_gui_test.res new file mode 100644 index 0000000..bb86af9 Binary files /dev/null and b/tools/nid_gui_test/nid_gui_test.res differ