Results 1 to 7 of 7

Thread: Access Violations in GUI

  1. #1
    Join Date
    Mar 2013
    Posts
    16
    Mentioned
    0 Post(s)
    Quoted
    8 Post(s)

    Default Access Violations in GUI

    The following code throws an access violation at 106. I have tried doing some debug which can be seen starting at line 97. However I do not understand the error.
    Here is the code in question.
    Thanks for your time
    MM
    Code:
    program new;
      {$DEFINE SMART}
      {$i AeroLib/AeroLib.Simba}
      {$i Reflection/Reflection.simba}
    type
      Key = (Cooking, Fletching, Fishing, Firemaking, Woodcutting);
      Choosen = set of Key;
      Skill = Procedure;
    
      TPair = record
        K: Key;
        V: Skill;
      end;
    
      TMap = array of TPair;
    const
      FULL_PATH = scriptPath + 'TestConfig.ini';
    var
      myForm: TForm;
      myCheckList: TCheckListBox;
      myTabControl: TPageControl;
      myTabs: array [0..5] of TTabSheet;
      myUserBox, MyPassBox, MyPinBox: TMemo;
      myStartButton: TButton;
      myTaskLabel, myUserLabel, myPassLabel, myPinLabel : TLabel;
      myMainMenu: TMainMenu;
      myMenuFile, mySubMenuSave, mySubMenuLoad: TMenuItem;
    
      MyPlayer: TReflectLocalPlayer;
      MyLogger: TReflectLogger;
    
    
    function TMap.Add(K: Key; V: Skill): boolean;
    var
      I: Integer;
    begin
      for I := 0 to High(Self) do
        if (Self[I].K = K) then
          Exit(False);
    
      SetLength(Self, Length(Self) + 1);
      Self[High(Self)].K := K;
      Self[High(Self)].V := @V;
      exit(True);
    end;
    
    function TMap.Remove(K: Key): boolean;
    var
      I: Integer;
    begin
      if (Self.get(K) = nil) then
        Exit(False);
    
      for I := 0 to High(Self) - 1 do
        if (Self[I].K = K) then
          Swap(Self[I], Self[I + 1]);
      SetLength(Self, Length(Self) - 1);
      Exit(True);
    end;
    
    function TMap.Get(K: Key): Skill;
    var
      I: Integer;
    begin
      for I := 0 to High(Self) do
        if (Self[I].K = K) then
          Exit(@Self[I].V);
      Exit(nil);
    end;
    
    procedure OnClickCheckList(sender: TObject; index: Integer);
    {$IFNDEF CODEINSIGHT} native; {$ENDIF}
    begin
      if myCheckList.getChecked(index) then
      begin
        myTabs[index] := myTabControl.addTabSheet();
        myTabs[index].setCaption(myCheckList.getItems().getStrings(index));
      end
      else
      begin
        myTabs[index].Free;
      end;
    end;
    
    procedure onClick(sender: TObject);
    {$IFNDEF CODEINSIGHT} native; {$ENDIF}
    var
      I : Integer;
    begin
        case sender of
          myStartButton:
            begin
              myForm.Free;
            end;
          mySubMenuSave:
            begin
              //Client.Writeln(myCheckList.getItems().getStrings(1));
              //Client.Writeln( BoolToStr(myCheckList.getChecked(1)) );
              //Client.WriteLn(FULL_PATH);
    for I:= 0 to myCheckList.getItems.getCount - 1 do
    begin
      Client.Writeln('In iteration ' + IntToStr(I));
      Client.Writeln('  ' + myCheckList.getItems().getStrings(I));
      Client.Writeln('  ' + BoolToStr(myCheckList.getChecked(I)));
      Client.Writeln('Does ' + FULL_PATH + ' exist? ' + BoolToStr(FileExists(FULL_PATH)));
      WriteINI('Tasks', myCheckList.getItems().getStrings(I), BoolToStr(myCheckList.getChecked(I)), FULL_PATH);
    end;
            end;
          mySubMenuLoad:
            begin
            end;
        end;
    end;
    
    procedure InitGUI;
    {$IFNDEF CODEINSIGHT} native; {$ENDIF}
    var
    I : Integer;
    K : Key;
    begin
      with myForm do
      begin
        Init(nil);
        SetCaption('Edgeville Extravaganza');
        setBounds(0, 0, 400, 170);
        setPosition(poScreenCenter);
      end;
    
      myMainMenu.Init(myForm);
      myMenuFile := myMainMenu.AddMenu('File');
      mySubMenuSave := myMenuFile.addMenu('Save');
      mySubMenuLoad := myMenuFile.addMenu('Load');
      mySubMenuSave.setOnClick(onClick);
      mySubMenuLoad.setOnClick(onClick);
    
      with myTabControl do
      begin
        Init(myForm);
        setParent(myForm);
        setBoundsRect(myForm.getBaseBounds);
        myTabs[0] := addTabSheet();
        myTabs[0].setCaption('Main');
      end;
    
      with myTaskLabel do
      begin
        Init(myForm);
        setParent(myTabs[0]);
        setCaption('Select Tasks:');
        setLeft(5);
        setTop(5);
      end;
    
      with myCheckList do
      begin
        Init(myForm);
        setParent(myTabs[0]);
        setLeft(myTaskLabel.getLeft);
        setTop(myTaskLabel.getTop + myTaskLabel.getHeight + 5);
        setHeight(95);
        for K := Low(Key) to High(Key) do
          getItems().add(ToStr(k));
        setOnItemClick(OnClickCheckList);
      end;
    
      with myUserLabel do
      begin
        Init(myForm);
        setParent(myTabs[0]);
        setCaption('Enter User Info:');
        setLeft(myCheckList.getLeft + myCheckList.getWidth + 10);
        setTop(myTaskLabel.getTop);
      end;
    
      with myUserBox do
        begin
          Init(myForm);
          setParent(myTabs[0]);
          setText('Username or EMail');
          setLeft(myUserLabel.getLeft);
          setTop(myUserLabel.getTop + myUserLabel.getHeight + 5);
          setWidth(270);
          setHeight(25);
        end;
    
      with myPassLabel do
        begin
          Init(myForm);
          setParent(myTabs[0]);
          setCaption('Password:');
          setLeft(myUserBox.getLeft);
          setTop(myUserBox.getTop + myUserBox.getHeight);
        end;
    
      with MyPassBox do
        begin
          Init(myForm);
          setParent(myTabs[0]);
          setText('Password');
          setLeft(myPassLabel.getLeft);
          setTop(myPassLabel.getTop + myPassLabel.getHeight);
          setWidth(150);
          setHeight(25);
          setPasswordChar('*');
          setMaxLength(20);
        end;
    
      with myPinLabel do
      begin
        Init(myForm);
        setParent(myTabs[0]);
        setCaption('Pin:');
        setLeft(myUserBox.getLeft + myUserBox.getWidth - getWidth - 15);
        setTop(myUserBox.getTop + myUserBox.getHeight);
      end;
    
      with MyPinBox do
        begin
          Init(myForm);
          setParent(myTabs[0]);
          setWidth(80);
          setHeight(25);
          setLeft(myPinLabel.getLeft);
          setTop(MyPassBox.getTop);
          setMaxLength(4);
          setPasswordChar('*');
        end;
    
      with MyStartButton do
        begin
          Init(myForm);
          setParent(myTabs[0]);
          setCaption('Start');
          setLeft(MyPinBox.getLeft);
          setTop(MyPinBox.getTop + MyPinBox.getHeight + 5);
        end;
    
      myForm.ShowModal;
    end;
    
    procedure FreeGUI;
    {$IFNDEF CODEINSIGHT} native; {$ENDIF}
    begin
      if (myForm = nil) then
       exit;
      MyLogger.Status('Freeing GUI...');
      myForm.free;
    end;
    
    procedure StartGUI;
    begin
      try
        sync(InitGUI);
      except
        MyLogger.Error('Failed to initialize GUI!');
      finally
        sync(FreeGUI);
      end;
    end;
    
    procedure Cook;
    begin
      Writeln('Cook!');
    end;
    
    procedure Fletch;
    begin
      Writeln('Fletch!');
    end;
    
    procedure Fish;
    begin
      Writeln('Fish!');
    end;
    
    procedure Burn;
    begin
      Writeln('Burn!');
    end;
    
    procedure Chop;
    begin
      Writeln('Chop!');
    end;
    
    function GearInInv() : Boolean;
    begin
      Result:= true;
    end;
    
    function GearInEquip() : Boolean;
    begin
      Result:= true;
    end;
    
    function HasGear() : Boolean;
    begin
      Result:= GearInEquip OR GearInInv;
    end;
    
    var
      Perform: TMap;
    begin
      StartGUI();
      {Perform.add(Cooking, @cook);
      if (Perform.get(Cooking) <> nil) then //check if it exists..
        Perform.get(Cooking)(); //call the function.
      Perform.get(Firemaking)();
      //writeln();
    
      Perform.remove(Cooking);
      writeln(Perform.get(Cooking)); }
    end.

  2. #2
    Join Date
    Mar 2013
    Posts
    16
    Mentioned
    0 Post(s)
    Quoted
    8 Post(s)

    Default

    Just for others who look in the future. According to @Olly , WriteINI is not thread safe meaning that it can not be used while the GUI is open. In order to save content from your GUI you must save them in strings then save them when the GUI is closed. This is just how LAPE is and will require a rewrite of LAPE for nicer solutions.

  3. #3
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by MrMonotone View Post
    Just for others who look in the future. According to @Olly , WriteINI is not thread safe meaning that it can not be used while the GUI is open. In order to save content from your GUI you must save them in strings then save them when the GUI is closed. This is just how LAPE is and will require a rewrite of LAPE for nicer solutions.
    That's actually quite sad.. A bad excuse IMO.

    If your GUI is the ONLY thread writing to that file, how exactly is it unsafe? It doesn't allocate any thread local storage variables.. Are you writing to the file from the GUI thread and main thread at the same time? If not, then you don't need to lock the file and there's nothing inherently unsafe about it. The only way it could be unsafe is if someone made it unsafe. Even with a mutex locking the file and an atomic variable guarding, it still crashes. This is due to bad code.

    It doesn't make any sense for it to be "inherently unsafe" :S


    Use:

    Simba Code:
    Client.getMFiles().WriteINI('Tasks', myCheckList.getItems().getStrings(I), BoolToStr(myCheckList.getChecked(I)), FULL_PATH);

    //or:

    getTClient().getMFiles().WriteINI('Tasks', myCheckList.getItems().getStrings(I), BoolToStr(myCheckList.getChecked(I)), FULL_PATH);

    //both will work.

    as a work around to avoid all the thread non-sense and bad design/code. It doesn't require a rewrite for a "nice" solution in this case. I'm sorry you have to "work around" something like file writing. I really am.

    Anyway, let me know if this solution works for you.

    P.S. You have a nice GUI (I like the tabs on checkmark).
    Last edited by Brandon; 02-23-2015 at 12:11 PM.
    I am Ggzz..
    Hackintosher

  4. #4
    Join Date
    Nov 2011
    Location
    England
    Posts
    3,072
    Mentioned
    296 Post(s)
    Quoted
    1094 Post(s)

    Default

    Maybe "not thread safe" is a bad way to explain it, but like any wrapper (DTM, Bitmap, Files, Finder, etc) in Simba it's accessed through current thread variable.
    Simba Code:
    CurrThread.Client.MFiles.ReadINI
    if CurrThread is Simba's mainthread none of that exists.. so crash crash crash. (Not that Brandon doesn't know this)

    There are multiple ways to do this a better way, personally I would like to add all the wrappers via AddDelayedCode though I have a feeling that would impact compiling time alot.

    Also I didn't know INI writing/reading was part of TMFiles, which is why I never suggested it.
    Last edited by Olly; 02-23-2015 at 04:04 PM.

  5. #5
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Olly View Post
    Maybe "not thread safe" is a bad way to explain it, but like any wrapper (DTM, Bitmap, Files, Finder, etc) in Simba it's accessed through current thread variable.
    Simba Code:
    CurrThread.Client.MFiles.ReadINI
    if CurrThread is Simba's mainthread none of that exists.. so crash crash crash. (Not that Brandon doesn't know this)

    There are multiple ways to do this a better way, personally I would like to add all the wrappers via AddDelayedCode though I have a feeling that would impact compiling time alot.

    Also I didn't know INI writing/reading was part of TMFiles, which is why I never suggested it.

    And no one blames you (or anyone else) for that. It's just a bad design decision that has been around too long and it's finally catching up to "us" (everyone).

    The decision to make file reading and a lot of things "dependent" on the current thread was a bad idea. It "used to be" a great idea back then and it was good enough back then, but Simba's usage + modern technology is slowly killing it.


    File reading and writing is one of the core concepts of any programming language. The fact that we have to work around it is what makes this a sad situation.

    No worries though. I had no idea it was part of TMFiles either. I had to go through the source to find it. Anyway, teach me how to export things to Simba and show me where writeln is exported (how does it accept infinite comma separated arguments without being variadic)?
    Last edited by Brandon; 02-24-2015 at 12:17 AM.
    I am Ggzz..
    Hackintosher

  6. #6
    Join Date
    Nov 2011
    Location
    England
    Posts
    3,072
    Mentioned
    296 Post(s)
    Quoted
    1094 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    No worries though. I had no idea it was part of TMFiles either. I had to go through the source to find it. Anyway, teach me how to export things to Simba and show me where writeln is exported (how does it accept infinite comma separated arguments without being variadic)?
    Lape man, I don't think anyone actually knows other than niels lol. There is no 'AddGlobalFuncWithAnyParam' it's all 'Internal' methods, and I think they are actually created at compile time.

    Here are where the internals are added, and the actual 'creating' but I don't know much more.

    https://github.com/SRL/Lape/blob/mas...iler.pas#L2895
    https://github.com/SRL/Lape/blob/cd8...tree.pas#L2306

    Tho.... New auto complete. !

    Last edited by Olly; 02-24-2015 at 12:29 AM.

  7. #7
    Join Date
    Mar 2013
    Posts
    16
    Mentioned
    0 Post(s)
    Quoted
    8 Post(s)

    Default

    Thanks @Olly @Brandon
    Last edited by MrMonotone; 02-25-2015 at 06:52 AM.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •