library lazGUI_extn; {$mode delphi}{$H+} {$R *.res} uses Classes { you can add units after this } , Mainform, uHCDefines , uHCGCI, uHCGlobals, uHCTypeDefs, uHCEventHelpers, uHCDateTime , uHCAnnexDefs, uHCAnnexHelpers, uLazGUIGlobals, uHCUtils , Windows, Forms, ShellAPI, SysUtils ,Types ,Dialogs, Interfaces, Controls, FileInfo; const DLLVERN = 10; // DLLVERINTN = 32; // 2022.027 SIDES = 3; SLIVER360 = 134217728; var frmMain: TfrmMain; intGameTime: Long; intGameTimeLeft: Long; dt_scen_start: PHCDateTimeRec; FileVersionInfo: TFileVersionInfo; strFileVers: String; PCurrentStartGroup: PHCGroup; {*** Return DLL internal version, i.e. revision 5 of my DLL ***} function DLLVer():word;export;cdecl; begin result := DLLVERN; end; {*** Return DLL interface version, i.e. revision 1 of my HCE interface spec ***} function DLLVerInt():word;export;cdecl; begin result := DLLVERINTN; end; {*** Return DLL description, 255 characters max ***} function DLLDesc():PAnsiChar;export;cdecl; begin result := 'lazarus GUI test DLL by Tony Eischens extensions by Don Thomas'; end; {*** Free DLL ***} procedure DLLFree();export;cdecl; begin // Do any cleanup here, this is the end // frmMain.GTmemDLLcalls.Lines.Add('DLLFree'); frmMain.Free; end; {*** Init DLL ***} procedure DLLInit(hwndHC: HWND; pathHC: PAnsiChar; verHC: PAnsiChar; verSaveGame: LongWord; funcRefs: PHCDLL_FUNC_REF; PGEClosing: Pointer; PDLLBusy: Pointer; verInterface: LongWord; srandSeed: longword; harpoon_uuid_session: PAnsiChar; hclicense_dt_expire: Int64; hclicense_licensee: PAnsiChar; usblicense_desc: PAnsiChar; RESRSRStructureVersion: ulong; AnnexVersion: ushort );export;cdecl; var funcTmp: PHCDLL_FUNC_REF; begin // here we initialize globals and such for the life of the DLL // Application.Scaled:= False; // ddt 2022/09/25 trying to fix scaling issue Application.Initialize; // ALE 20120410 Freezes HC Application.Run; uLazGUIGlobals.PGEClosing:=PGEClosing; uLazGUIGlobals.PDLLBusy:=PDLLBusy; // uLazGUIGlobals.hwndHC:=hwndHC; // 20230405 version update uLazGUIGlobals.intVerInterface:=verInterface; uLazGUIGlobals.intVerSaveGame:=verSaveGame; FileVersionInfo:= TFileVersionInfo.Create(nil); FileVersionInfo.ReadFileInfo; frmMain := TfrmMain.Create(nil); // frmMain.ParentWindow := hwndHC; //20221231 place as indipendant window 0107 put back in harp window strFileVers:= FileVersionInfo.VersionStrings.Values['FileVersion']; FileVersionInfo.Free; if Length(strFileVers) = 0 then strFileVers := '1.4.3'; frmMain.Caption := 'HC Export DLL extension v ' + strFileVers //IntToStr(DLLVERN) + ', ExportDLL Interface v ' + IntToStr(DLLVERINTN) + 'for GE v 2023.003+'; frmMain.memDLLInit.Lines.Add('lazarus GUI Export DLL v' + IntToStr(DLLVERN)); frmMain.memDLLInit.Lines.Add('ExportDLL Interface v' + IntToStr(DLLVERINTN)); frmMain.memDLLInit.Lines.Add('hwndHC = 0x' + IntToHex(hwndHC, 8)); frmMain.memDLLInit.Lines.Add('pathHC = ' + pathHC); frmMain.memDLLInit.Lines.Add('verHC = ' + verHC); frmMain.memDLLInit.Lines.Add('verSaveGame = 0x' + IntToHex(verSaveGame, 8)); frmMain.memDLLInit.Lines.Add(Format('funcRefs = 0x%p', [funcRefs])); frmMain.memDLLInit.Lines.Add(Format('GE ExportDLL Interface Version = %d', [verInterface])); frmMain.memDLLInit.Lines.add('harpoon_uuid_session = ' + harpoon_uuid_session); // 20230405 vers upgrade // ALE 20130908 List the function pointers sent over by the GE // then capture one of them for example usage funcTmp := funcRefs; while (funcTmp <> nil) do begin frmMain.memDLLInit.Lines.Add(#9 + Format('funcRef: 0x%p %s', [funcTmp^.funcPtr, funcTmp^.funcName])); if (funcTmp^.funcName = 'NewPtr') then frmMain.NewPtr := funcTmp^.funcPtr else if (funcTmp^.funcName = 'QueueHarpoonEvent') then frmMain.HCQueueHarpoonEvent := THCQueueHarpoonEvent(funcTmp^.funcPtr) else if (funcTmp^.funcName = 'dllCheckLatLonDepth') then frmMain.HCdllCheckLatLonDepth := THCdllCheckLatLonDepth(funcTmp^.funcPtr) else if (funcTmp^.funcName = 'annex_id_to_disk_id') then frmMain.HCannex_id_to_disk_id := THCannex_id_to_disk_id(funcTmp^.funcPtr) else if (funcTmp^.funcName = 'disk_id_to_annex_id') then frmMain.HCdisk_id_to_annex_id := THCdisk_id_to_annex_id(funcTmp^.funcPtr) ; funcTmp := funcTmp^.next; end; frmMain.Show; end; procedure UnitShowing(UnitID: Byte; GroupID: PAnsiChar; Showing: Byte);export;cdecl; begin if (frmMain.USckbEnabled.Checked = True) then begin frmMain.USmemMsgLog.Lines.Insert(0, Format('%8.8d: GroupID=%s, UnitID=%2.2d, Showing=%d', [intGameTime, GroupID, UnitID, Showing])); if (frmMain.USmemMsgLog.Lines.Count > frmMain.USedtLines.Value) then begin frmMain.USmemMsgLog.Lines.Delete(frmMain.USedtLines.Value); end; end; end; procedure ScenLoad(strHarpPath: PAnsiChar; intScenNum: SmallInt; strScenFPath: PAnsiChar; intBSNum: ShortInt; strBSFName: PAnsiChar; intSide: byte; intGameTimeIn: Long; intGameTimeLeftIn: Long; // 20230405 dt_scen_start_in: PHCDateTimeRec; AnnexDataIn: PHCAnnexes_disk; DatabaseVersionDBIn: PHCDATABASE_VERSION; ScenDataIn: PHCSCENARIO_DATA; ScenSaveDataIn: PHCSCENARIO_SAVE_DATA; GlobalsIn: PHCGlobals);export;cdecl; var intIdx: NativeUInt; pLoadout: PHCAnnexY1_disk; pShip: PHCAnnexA1_disk; pSub: PHCAnnexA2_disk; pAir: PHCAnnexB1_disk; pBase: PHCAnnexP1_disk; pGun: PHCAnnexC1_disk; pMissile: PHCAnnexD1_disk; pBomb: PHCAnnexG1_disk; pECM: PHCAnnexG2_disk; pNuke: PHCAnnexI1_disk; pRadar: PHCAnnexJ1_disk; pSonar: PHCAnnexM1_disk; pMount: PHCAnnexZ1_disk; pMulti: PHCAnnexZ2_disk; begin intGameTime := intGameTimeIn; // ALE 20150712 Now that we receive the game time here, store it intGameTimeLeft := intGameTimeLeftIn; // ALE 20150712 Now that we receive the game time left here, store it // dt_scen_start := ScenData^.dt_scen_start;// 20230405 vers update /dt_scen_start_in; // ALE 20150712 Scenario Starting date and time AnnexData := AnnexDataIn; // ALE 20150813 Database/Platform information HCAnnexHelper := THCAnnexHelper.Create(AnnexDataIn, frmMain.HCannex_id_to_disk_id, uLazGUIGlobals.intVerInterface, uLazGUIGlobals.intVerSaveGame); // frmMain.GTmemDLLcalls.Lines.Add('scenarioload'); if (frmMain.SLckbEnabled.Checked = True) then begin frmMain.SLmemMsgLog.Lines.Insert(0, Format('ScenLoad HC Path=%s, Scen#=%d, ScenFNP=%s, BattleSet=%d, BattleSet=%s, PlayerSide=%d', [strHarpPath, intScenNum, strScenFPath, intBSNum, strBSFName, intSide])); if (frmMain.SLmemMsgLog.Lines.Count > frmMain.SLedtLines.Value) then begin frmMain.SLmemMsgLog.Lines.Delete(frmMain.SLedtLines.Value); end; end; // in lazgui tony dumps annex data to mainform page end; procedure TimeFactor(TimeFactor: longint);export;cdecl; begin // frmMain.GTmemDLLcalls.Lines.Add('timefactor'); if (frmMain.TFckbEnabled.Checked = True) then begin frmMain.TFmemMsgLog.Lines.Insert(0, Format('%8.8d: TimeFactor=%d', [intGameTime, TimeFactor])); if (frmMain.TFmemMsgLog.Lines.Count > frmMain.TFedtLines.Value) then begin frmMain.TFmemMsgLog.Lines.Delete(frmMain.TFedtLines.Value); end; end; end; procedure MsgLog(MsgLine: PAnsiChar);export;cdecl; begin if (frmMain.MLckbEnabled.Checked = True) then begin frmMain.MLmemMsgLog.Lines.Insert(0, Format('%8.8d: %s', [intGameTime, MsgLine])); if (frmMain.MLmemMsgLog.Lines.Count > frmMain.MLedtLines.Value) then begin frmMain.MLmemMsgLog.Lines.Delete(frmMain.MLedtLines.Value); end; end; end; procedure GameTime(GameTime: Long; GameTimeLeft: Long);export;cdecl; var PEvent: PHCHarpoonEvent; EventType: uchar; strGroupID: String; dtNow: THCDateTimeRec; begin intGameTime := GameTime; intGameTimeLeft := GameTimeLeft; // ALE 20150712 store remaining time frmMain.gGTNow:= intGameTime; frmMain.GTlblHMS.Caption:= 'GT in ' + frmMain.SecsToHRMinSec(intGameTime - 100000); frmMain.GTlblGameTime.Caption := 'GameTime: ' + Format('%8.8d', [intGameTime]); frmMain.GTlblGameTimeLeft.Caption :='GameTimeLeft: ' + Format('%8.8d', [intGameTimeLeft]); if (frmMain.GTckbPause.Checked) then begin Byte(PDLLBusy^) := CTRUE; // ALE 20130816 don't process other events in GE frmMain.GTbtnResume.Enabled:=True; frmMain.GTckbPause.Enabled:=False; frmMain.PageControl1.ActivePageIndex:=21; // GameTime/InvestigateStructures // ALE 20130816 this would be a good place to start your thread that does the long processing PEvent := frmMain.PHarpEventHead; frmMain.GTHEEventList.Clear; frmMain.GEHEmemDetail.Clear; while (PEvent <> nil) do begin EventType := PEvent^.flag AND CommandMask; // 202304045 vers update /flag AND CommandMask; strGroupID := ' '; if (PEvent^.ourGroup <> nil) then strGroupID := PHCGroup(PEvent^.ourGroup)^.id; // lUnitID := IntToStr(PEvent^.UnitID); //if (lUnitID = '') then //begin // lUnit_Uuid := ' '; // ALE 20230328 stupid formatting hack //end; //frmMain.GTHEEventList.Items.Add(Format('%s %8.5d 0x%p %s %s %3.3d %1.1d %s', // [PEvent^.uuid, PEvent^.Time, PEvent, strGroupID, lUnit_Uuid, EventType, // PEvent^.in_scroll_flag, HCEventType2String(EventType)])); frmMain.GTHEEventList.Items.Add(Format('%8.5d %s %3.3d %s UID:%p', [PEvent^.Time, strGroupID, PEvent^.UnitID, HCEventType2String(EventType), PEvent])); // 20230405 vers update PEvent := PEvent^.next; end; end; end; procedure StartGroup(StartGroup: PHCGroup);export;cdecl; var PHCGThis: PHCGroup; begin PCurrentStartGroup:= StartGroup; // frmMain.GTmemDLLcalls.Lines.Add('startgroup'); if (frmMain.SGckbEnabled.Checked = True) then begin //if (StartGroup <> nil) then // 250830 //begin // if (StartGroup^.Units <> nil) then // begin // frmMain.SGmemMsgLog.Lines.Insert(0, Format('%8.8d: %s %s', // [intGameTime, StartGroup^.id, StartGroup^.Units^.name])); // end // else // begin // frmMain.SGmemMsgLog.Lines.Insert(0, Format('%8.8d: %s', [intGameTime, StartGroup^.id])); // end //end //else //begin // frmMain.SGmemMsgLog.Lines.Insert(0, Format('%8.8d: StartGroup is NULL', [intGameTime])); //end; // //if (frmMain.SGmemMsgLog.Lines.Count > frmMain.SGedtLines.Value) then //begin // frmMain.SGmemMsgLog.Lines.Delete(frmMain.SGedtLines.Value); //end; // ALE 20130317 Fill up the SGlbxGroups frmMain.PStartGroup:=StartGroup; frmMain.SGlbxGroups.Items.Clear; frmMain.SGlbxGroups.Sorted := True; PHCGThis := StartGroup; while (PHCGThis <> nil) do begin frmMain.SGlbxGroups.Items.Add(PHCGThis^.id); PHCGThis := PHCGThis^.toSouth; end; end; frmMain.PStartGroup:=StartGroup; end; procedure HarpoonEventHead(HarpEventHead: PHCHarpoonEvent);export;cdecl; var strEventType: string; EventType, strUid: uchar; pTEventUnit: PHCUnit; begin // frmMain.GTmemDLLcalls.Lines.Add('HarpEventHead'); // ddt clocking procedure/function calls frmMain.PHarpEventHead:= HarpEventHead; if (HarpEventHead <> nil) then begin //if (frmMain.HHckbEnabled.Checked = True) then //begin // frmMain.HHmemMsgLog.Lines.Insert(0, Format('%8.8d: 0x%p', [intGameTime, HarpEventHead])); //end; //if (frmMain.HHmemMsgLog.Lines.Count > frmMain.HHedtLines.Value) then //begin // frmMain.HHmemMsgLog.Lines.Delete(frmMain.HHedtLines.Value); //end; // 20230405 tidyup // insert code for auto pause to investigate events if (frmMain.GTckbAutoP.Checked = true) and (frmMain.PEvent <> HarpEventHead) then begin EventType:=(HarpEventHead^.flag AND CommandMask); // vers update / flag and CommandMask); strEventType:= HCEventType2String(EventType); if ((frmMain.GTcklbAutoP.Checked[0]) and (EventType = ENEMY_AI_EVENT)) or ((frmMain.GTcklbAutoP.Checked[1]) and (EventType = INTERCEPT_EVENT)) or ((frmMain.GTcklbAutoP.Checked[2]) and (EventType = AIR_REFUEL_EVENT)) or ((frmMain.GTcklbAutoP.Checked[3]) and (EventType = LAUNCH_EVENT)) or ((frmMain.GTcklbAutoP.Checked[4]) and (EventType = ALT_SPEED_EVENT)) or ((frmMain.GTcklbAutoP.Checked[5]) and (EventType = ALT_COURSE_EVENT)) or ((frmMain.GTcklbAutoP.Checked[6]) and (EventType = ATTACK_EVENT)) or ((frmMain.GTcklbAutoP.Checked[7]) and (EventType = AIR_ATTACK_EVENT)) or ((frmMain.GTcklbAutoP.Checked[8]) and (EventType = AIR_PATROL_EVENT)) or ((frmMain.GTcklbAutoP.Checked[9]) and (EventType = LAUNCHLAND_EVENT)) then begin Byte(PDLLBusy^) := CTRUE; // ALE 20130816 don't process other events in GE frmMain.WindowState:= wsNormal; // want to wake up anf focus on page 7 frmMain.BringToFront; frmMain.PageControl1.ActivePageIndex:=7; frmMain.GTbtnResume.Enabled:=True; frmMain.GTckbPause.Enabled:=False; frmMain.PageControl1.ActivePageIndex:=21; // GameTime/InvestigateStructures frmMain.GTHEEventList.Clear; frmMain.GEHEmemDetail.Clear; // test that there is a Unit UUID and have default nuls if HarpEventHead^.UnitID >= 0 then begin // PTEventUnit:= HCuuid2UnitPtr(HarpEventHead^.unit_uuid, PCurrentStartGroup, HarpEventHead^.ourGroup); strUid := HarpEventHead^.UnitID; frmMain.GTHEEventList.Items.Add(Format('time: %8.5d Group: Unit %2.2s : %3.3d - %s', [HarpEventHead^.Time, PHCGroup(HarpEventHead^.ourGroup)^.id, strUid, strEventType])); end else begin PTEventUnit:= nil; frmMain.GTHEEventList.Items.Add(Format('time: %8.5d Group %2.2s %s', [HarpEventHead^.Time, PHCGroup(HarpEventHead^.ourGroup)^.id, strEventType])); end; frmMain.PEvent:= HarpEventHead; frmMain.PEventUnit:= PTEventUnit; frmMain.EventmemDetailWrite; end; end; end; end; procedure VictoryConditionsList(VictoryConditionsList: PHCVictoryConditions);export;cdecl; var PThisVicCondn: PHCVictoryConditions; begin if (frmMain.VCckbEnabled.Checked = True) then begin if (VictoryConditionsList <> nil) then begin frmMain.VCmemMsgLog.Lines.Insert(0, Format('%8.8d: 0x%p', [intGameTime, VictoryConditionsList])); PThisVicCondn:= VictoryConditionsList; frmMain.VClstbxItems.Clear; while PThisVicCondn <> nil do begin frmMain.VClstbxItems.Items.Add(Format('side: %d; UnitType: %d; VicType: %d; ItemType: %d; DetailType: %d; id: %d',[PThisVicCondn^.WhichSide, PThisVicCondn^.unitType, PThisVicCondn^.VicType, PThisVicCondn^.itemType, PThisVicCondn^.DetailType, PThisVicCondn^.numKilled])); // PThisVicCondn:= PThisVicCondn^.next; end; end else begin frmMain.VCmemMsgLog.Lines.Insert(0, Format('%8.8d: VictoryConditionsList is NULL', [intGameTime])); end; if (frmMain.VCmemMsgLog.Lines.Count > frmMain.VCedtLines.Value) then begin frmMain.VCmemMsgLog.Lines.Delete(frmMain.VCedtLines.Value); end; end; frmMain.PVictoryConditionsList := VictoryConditionsList; end; exports DLLVer, DLLVerInt, DLLDesc, DLLFree, DLLInit, UnitShowing, ScenLoad, TimeFactor, MsgLog, GameTime ,StartGroup // ALE 20130205 Sends updated GroupPtr whenever that changes ,HarpoonEventHead // ALE 20130805 Sends updated soonest HarpoonEvent pointer whenever it changes ,VictoryConditionsList // ALE 20130812 Sends a pointer to the list of victory conditions when a scenario is loaded ; end.