Author Topic: C# AGILE  (Read 87639 times)

0 Members and 1 Guest are viewing this topic.

Offline Collector

Re: C# AGI Interpreter
« Reply #195 on: November 15, 2022, 12:54:33 PM »
I came across a reference that .NET Core uses a newer folder browser dialog, so I tried to change it to .NET Core, but that option it is not available to the project. So I tried to recreate it from scratch. You cannot copy and paste controls between the two. I imported all of the AGI classes and recreated the main form. The browse dialog seems to always show the selected, but even though it compiles without error, it fails to load a game and does not throw any errors to help trace where the failure is. It will take some time to track it down.

Even if I fix it, do we really want to use .NET Core when many will not have that runtime installed? The NSIS installer could check what .NET runtimes are on a users machine, but I don't know if .NET Core can be installed on older Windows.

As I said, my gong-shell based custom folder dialog seems to work 100%, but it seems unacceptably too slow to me. I don't know what alternative controls there are to gong-shell or if they would be any faster.

Edit: I made a stand alone app with the custom browser using .NET 6.0 and the speed seems OK.
« Last Edit: November 15, 2022, 12:56:40 PM by Collector »
KQII Remake Pic

Offline lance.ewing

Re: C# AGI Interpreter
« Reply #196 on: November 15, 2022, 04:28:50 PM »
I came across a reference that .NET Core uses a newer folder browser dialog, so I tried to change it to .NET Core, but that option it is not available to the project. So I tried to recreate it from scratch. You cannot copy and paste controls between the two. I imported all of the AGI classes and recreated the main form. The browse dialog seems to always show the selected, but even though it compiles without error, it fails to load a game and does not throw any errors to help trace where the failure is. It will take some time to track it down.

Yeah, I came across the same reference a while back and decided that I'd rather stay on the .NET Framework than move to .NET Core.

Even if I fix it, do we really want to use .NET Core when many will not have that runtime installed? The NSIS installer could check what .NET runtimes are on a users machine, but I don't know if .NET Core can be installed on older Windows.

Yeah, good question. As I say, I think I'd prefer to stay on .NET Framework 4.8.

I did spend some time trying to use a normal "full" open file dialog instead of the FolderBrowserDialog, but I just didn't like the result. I found it harder to use, and it looked too complex for what it needed to be. I think the current FolderBrowserDialog serves the purpose well, in general. It is only this small issue, where it sometimes doesn't scroll down, that we need a reliable fix for.

Did you try the latest code that I pushed to github? Just wondering if that worked for you.

Offline Collector

Re: C# AGI Interpreter
« Reply #197 on: November 15, 2022, 04:59:37 PM »
Yes, I did and it seems to miss as often as the other ones. Give the test app I posted a try and see how it works for you. I might try to see if I can speed it up with 4.8. I like how it not only scrolls to the selected folder, but displays it in the middle of the treeview instead of the bottom edge.
KQII Remake Pic

Offline lance.ewing

Re: C# AGI Interpreter
« Reply #198 on: November 15, 2022, 05:42:12 PM »
Yeah, that seems to work quite well, and still has the same look and feel. For me, it doesn't always display the selected folder in the middle, in fact the first couple of times I tried it, the selection was at the bottom edge. It seemed to depend on what folder I had previously selected. Given where my games are on my C: drive, I seem to always get it at the bottom edge if I select an AGI game folder. I don't think that matters though. I'm happy that the folder is visible, i.e. that it has scrolled down.

Yeah, see if you can get it working like that on 4.8

Offline Collector

Re: C# AGI Interpreter
« Reply #199 on: November 15, 2022, 08:18:32 PM »
Here is an experimental branch with my custom browser dialog in 4.8. Take a look and if you like it I'll update my branch with the new dialog and send a pull request.

https://github.com/ABranscom/AGILE-with-custom-folder-browser-
KQII Remake Pic

Offline lance.ewing

Re: C# AGI Interpreter
« Reply #200 on: November 16, 2022, 05:44:13 AM »
Unfortunately the solution doesn't compile as is. It isn't able to find the AGILibrary or NAudio. The AGILibrary seemed to be completely missing, and for some reason the paths to the NAudio packages are broken.

I'm trying to get those fixed at the moment so that I can launch the project to try it out.

Edit: It is strange. The NAudio folders are there, but they're all missing the DLL files. I have copied them over from my repo, so now its loading that bit fine.

Getting a different error now:  "'AgileForm' does not contain a definition for 'GetSelectedPath' and no accessible extension method 'GetSelectedPath' accepting a first argument of type 'AgileForm' could be found". Let me see if I can deduce what to add to fix that...

Edit 2: No, its not obvious, and its getting too late for me now. I'll let you fix it and I'll check again in the morning.
« Last Edit: November 16, 2022, 06:04:20 AM by lance.ewing »

Offline AGKorson

Re: C# AGI Interpreter
« Reply #201 on: November 16, 2022, 11:02:57 AM »
I have been following this thread with some interest, as I use the same dialog box in WinAGI in a number of places. I'm busy with another project right now, but I did find some time yesterday to take a look at my implementation to see if the behavior is similar. And it is- I find that on my Surface tablet, running latest version of Windows 11, it never seems to fail scrolling to the current item. (I got tired of opening/closing the dialog after several dozen attempts...) But on a Windows 10 Enterprise system, it has only scrolled properly once out of closer to a hundred tries. dunno why it's so different between OS versions.

In VB6, I can't access the folder browser directly, so I use an API call. This works really well, and it also allows me to set a callback function for the dialog, which I use to initialize the dialog box, and also to extract the selected folder when the user makes a change. So I thought it might be easy to fix by using the callback function to send the 'ensurevisible' message as part of initialization.

But that didn't work; it appears the dialog box is not completely set up when the callback function is sent the 'initialized' message, so results didn't change at all.  When examining the messages sent to the callback function, it looks like some additional setup occurs after 'initialization', which affects when the treelist updates, so it sometimes 'resets' even after it was originally forced to show the selection.

But since the 'selection-changed' message for the default/initial selection seems to hit AFTER initialization, I modified the callback to force visibility whenever the selection CHANGES - that works perfectly! (Well, it hasn't failed yet on any system I've tested yet). And since the selection will always be visible after startup, it doesn't affect the dialog while the user is browsing/selecting after startup.

Here is the code I use, in case you're interested - it's in VB of course, but it's not that complicated, and I assume you could easily convert to C# if you wanted to. (I will do it myself at some point in order to use in my C# WinAGI project, but I have my other work to finish first.)

Code: [Select]
  'folder dialog api declarations
  Public Declare Function SHBrowseForFolder Lib "shell32" (lpbi As BrowseInfo) As Long
  Public Declare Function SHGetPathFromIDList Lib "shell32" (ByVal pidList As Long, ByVal lpBuffer As String) As Long
  Public Declare Function GetWindowText Lib "user32" (ByVal hWnd As Long, ByVal lpString As String, ByVal nMaxCount As Long) As Long
  Public Declare Function GetClassName Lib "user32.dll" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
  'directory browser constants
  Public Const MAX_PATH = 260
  Public Const BFFM_INITIALIZED = 1
  Public Const BFFM_SELCHANGED = 2
  Public Const BFFM_VALIDATEFAILEDA = 3
  Public Const BFFM_VALIDATEFAILEDW = 4
  Public Const BFFM_IUNKNOWN = 5
  Public Const BFFM_SETSTATUSTEXT = (WM_USER + 100)
  Public Const BFFM_ENABLEOK = (WM_USER + 101)
  Public Const BFFM_SETSELECTION = (WM_USER + 102)
  Public Const BIF_RETURNONLYFSDIRS = 1
  Public Const BIF_DONTGOBELOWDOMAIN = 2
  Public Const BIF_STATUSTEXT = 4
  Public Const BIF_USENEWUI = 64
  Public Const TV_FIRST As Long = 4352
  Public Const TVM_SELECTITEM = (TV_FIRST + 11)
  Public Const TVM_GETNEXTITEM As Long = (TV_FIRST + 10)
  Public Const TVM_GETITEM = (TV_FIRST + 12)
  Public Const TVM_ENSUREVISIBLE As Long = (TV_FIRST + 20)
  Public Const TVGN_ROOT = 0
  Public Const TVGN_NEXT = 1
  Public Const TVGN_CHILD = 4
  Public Const TVGN_FIRSTVISIBLE = 5
  Public Const TVGN_NEXTVISIBLE = 6
  Public Const TVGN_CARET = 9
 
  'according to most recent MSDN, use CoTaskMemFree in place of ITMalloc.Free
  Private Declare Sub CoTaskMemFree Lib "ole32" (pv As Long)

  Public Declare Function GetWindow Lib "user32" (ByVal hWnd As Long, ByVal uCmd As Long) As Long
  Public Const GW_HWNDFIRST = 0
  Public Const GW_HWNDLAST = 1
  Public Const GW_HWNDNEXT = 2
  Public Const GW_HWNDPREV = 3
  Public Const GW_OWNER = 4
  Public Const GW_CHILD = 5
  Public Const GW_ENABLEDPOPUP = 6
 
'
' GetNewDir function - uses an API call to show the system folder selection dialog
'
'    hWnd is the handle of the window that will be the parent of the dialog box
'    DialogMsg is the text shown at top of the dialog as a description of its purpose
'
Public Function GetNewDir(ByVal hWnd As Long, DialogMsg As String)

  On Error GoTo ErrHandler
 
  Dim lpIDList As Long
  Dim biNewDir As BrowseInfo
 
  'build browser info structure
  With biNewDir
    'handle of parent window
    .hWndOwner = hWnd
    'message that appears above treelist
    .lpszTitle = DialogMsg
    'set flags
    .ulFlags = BIF_RETURNONLYFSDIRS + BIF_DONTGOBELOWDOMAIN + BIF_USENEWUI + BIF_STATUSTEXT
    'set pointer to callback address
    .lpfnCallback = ByValAddressOf(AddressOf BrowseCallbackProc)
    .pszDisplayName = String$(MAX_PATH, 32)
  End With

  'show browser, get pidl
  lpIDList = SHBrowseForFolder(biNewDir)

  'if not canceled (valid pidl returned)
  If lpIDList Then
    'last msg sent to callback function
    'has gotten us the name of the chosen folder
    GetNewDir = SelectedFolder
    'according to most recent MSDN info, use CoTaskMemFree
    'to free up the lpIDList handle and the root handle
    CoTaskMemFree lpIDList
  End If
  ' Whether successful or not, free the PIDL which was used to
  ' identify the My Computer virtual folder.
  CoTaskMemFree biNewDir.pIDLRoot
Exit Function

ErrHandler:
  '*'Debug.Print "bad thing happened: "; Err.Number, Err.Description
  Resume Next
End Function

'
' BrowseCallbackProc function
'
Public Function BrowseCallbackProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

  Dim rtn As Long
  Dim lpDir As Long
  Dim shCurDir As String
  Dim lngLen As Long
  Dim tmpStr As String
  Dim treeitem As Long

  On Error GoTo ErrHandler

  Select Case uMsg
  Case BFFM_INITIALIZED
    'set directory by passing string pointer by Value
    '(pass 1(true) for wParam)
    rtn = SendMessageByString(hWnd, BFFM_SETSELECTION, 1, BrowserStartDir)
 
    ' it seems logical that we could force the selected item to be visible
    ' by sending a msg to the treelist right after initialization
    ' BUT it seems that there are additional things that happen to the
    ' control AFTER this initialization call which still cause the control
    ' to occasionally fail to scroll the treelist
    ' fix is to force it when a selection is changed; that seems to work
    ' every time!
   
  Case BFFM_SELCHANGED
    shCurDir = String$(MAX_PATH, 0)
    If (SHGetPathFromIDList(wParam, shCurDir)) Then
      shCurDir = Left$(shCurDir, InStr(shCurDir, vbNullChar) - 1)
      lpDir = lstrcat(shCurDir, vbNullString)
      rtn = SendMessage(hWnd, BFFM_SETSTATUSTEXT, 1, ByVal lpDir)
    End If
    SelectedFolder = shCurDir
   
    ' force the current selection to be visible by finding the treelist
    ' control and sending a ENSUREVISIBLE message
   
    ' begin with main dialog handle; find the child control under it
    ' that is the container for the tree (it has a class name of
    ' 'SHBrowseForFolder ShellNameSpace Control'
   
    Debug.Print "main dialog window: "; Hex(hWnd)
    rtn = GetWindow(hWnd, GW_CHILD)
    Do Until rtn = 0
      Debug.Print "dialog child: "; Hex(rtn); " - '";
      tmpStr = Space(256)
      lngLen = GetClassName(rtn, tmpStr, 255)
      tmpStr = Left(tmpStr, lngLen)
      Debug.Print tmpStr & "'"
      'is this the container?
      If tmpStr = "SHBrowseForFolder ShellNameSpace Control" Then
        'get first child of the container
        rtn = GetWindow(rtn, GW_CHILD)
        Exit Do
      End If
      'if not, get next window
      rtn = GetWindow(rtn, GW_HWNDNEXT)
    Loop
   
    ' if found, now search for the actual treelist control inside
    ' the container control
    Do Until rtn = 0
      Debug.Print "container child: "; Hex(rtn); " - '";
      tmpStr = Space(256)
      lngLen = GetClassName(rtn, tmpStr, 255)
      tmpStr = Left(tmpStr, lngLen)
      Debug.Print tmpStr & "'"
      'is this the treelist?
      If tmpStr = "SysTreeView32" Then
        'success
        Exit Do
      End If
      'if not, get next window
      rtn = GetWindow(rtn, GW_HWNDNEXT)
    Loop
   
    'if found, send the message to force it to be visible
    If rtn > 0 Then
      'get the selected item
      treeitem = SendMessage(rtn, TVM_GETNEXTITEM, TVGN_CARET, 0)
      Debug.Print "item: "; treeitem
      If treeitem <> 0 Then
        'now force it to show the selected item?
        SendMessage rtn, WM_SETFOCUS, 0, 0
       
        rtn = SendMessage(rtn, TVM_ENSUREVISIBLE, 0&, treeitem)
        Debug.Print "selected - "; rtn
      End If
    Else
      Debug.Print "Treelist not found"
    End If
  End Select
Exit Function

ErrHandler:
  Debug.Print "error: "; Err.Number; " - "; Err.Description
  Resume Next
End Function




Offline Collector

Re: C# AGI Interpreter
« Reply #202 on: November 16, 2022, 06:37:54 PM »
@Lance, just comment out/delete the agileForm.GetSelectedPath(); line in the FolderBrowser.cs. It was a leftover from an attempt to solve a problem that I fixed in a different way. For some reason GitHub Desktop readded it.
KQII Remake Pic

Offline lance.ewing

Re: C# AGI Interpreter
« Reply #203 on: November 16, 2022, 09:44:52 PM »
@Collector, I had tried that, just to see what would happen, but it immediately throws a NullReferenceException on startup, from the following line:

folderBrowser.ShowDialog();

The folderBrowser instance has a value, but it seems that the ShowDialog call is throwing the NullReferenceException. This is why I thought maybe the compile error that I'd commented out was for something that was required and so hadn't tried to go further. So I've tried that again, and it is still throwing the NullReferenceException. It seems to be coming out of the native part of what ShowDialog ends up calling.

If I do this in Debug mode, and choose to Continue a couple of times, then the dialog becomes usable, but when I click on a game folder, e.g. "kq2", then it throws the NullReferenceException again. If I click "Continue", it throws it again, and if I click "Continue" again, then finally it loads the selected game.



Offline lance.ewing

Re: C# AGI Interpreter
« Reply #204 on: November 16, 2022, 09:49:59 PM »
Here is the code I use, in case you're interested - it's in VB of course, but it's not that complicated, and I assume you could easily convert to C# if you wanted to. (I will do it myself at some point in order to use in my C# WinAGI project, but I have my other work to finish first.)

Thanks, I'll give that a go when I next get a chance. Glad that you've got something that works on both a setup like mine (I also have Windows 11 on a surface tablet), and a Windows 10 system. That sounds promising, if I can convert that to C#.

Offline Collector

Re: C# AGI Interpreter
« Reply #205 on: November 17, 2022, 05:44:23 AM »
Not sure what is going on with that. I thought that there might be something else missing from the GitHub repo, so I downloaded it, added the DLLs and commented that line out and it ran without error. The only difference there should be from the main branch is the addition of the FolderBrowser form, the GongShell.dll reference and a couple of changes in the AgileForm.
KQII Remake Pic

Offline lance.ewing

Re: C# AGI Interpreter
« Reply #206 on: November 17, 2022, 06:29:58 AM »
I tried doing everything again, from cloning a fresh copy of the repo, copying in the DLLs, commenting out the line of code, but it's still happening. Not sure why.

I've attached an image of what it looks like.

Offline lance.ewing

Re: C# AGI Interpreter
« Reply #207 on: November 17, 2022, 06:42:33 AM »
Here is the code I use, in case you're interested - it's in VB of course, but it's not that complicated, and I assume you could easily convert to C# if you wanted to. (I will do it myself at some point in order to use in my C# WinAGI project, but I have my other work to finish first.)

Thanks, I'll give that a go when I next get a chance. Glad that you've got something that works on both a setup like mine (I also have Windows 11 on a surface tablet), and a Windows 10 system. That sounds promising, if I can convert that to C#.

I have hacked together something in C# that does the same as what you're doing. I didn't actually convert your code, but found some C#, I think from a stackoverflow page I'd already linked to in an earlier message, that already had the callback method. I then added the extra bit for the TVM_ENSUREVISIBLE into the BFFM_SELCHANGED case and it seems to do the trick.

Sometimes it is already scrolled down, but in the cases when it isn't already scrolled down, there is an obvious delay before it scrolls down, which will be the ensure visible code kicking in on the selection change.

Offline lance.ewing

Re: C# AGI Interpreter
« Reply #208 on: November 17, 2022, 11:16:16 PM »
But since the 'selection-changed' message for the default/initial selection seems to hit AFTER initialization, I modified the callback to force visibility whenever the selection CHANGES - that works perfectly! (Well, it hasn't failed yet on any system I've tested yet). And since the selection will always be visible after startup, it doesn't affect the dialog while the user is browsing/selecting after startup.

I have just pushed to my repo my hacked together version of this, as mentioned in my previous post. It could probably do with some code tidying up by someone that understands more what is happening in the code. There might be some redundant bits in there.

@AGKorson, are you able to test this on both of your systems?

@Collector, can you test this on your system?

Offline Collector

Re: C# AGI Interpreter
« Reply #209 on: November 18, 2022, 09:35:42 AM »
I was messing around with my GongShell solution and I think Windows 10 has broken it or at least has made it unstable. I have manage to get it to work flawlessly, but later randomly throws errors. Then again, the project has been abandoned for some time, now. It seems stable with .NET Core, but that is not viable solution.

I was thinking that a real fix would involve a PInvoke. I'm getting an odd error with this update:
Quote
The designer must create an instance of type System.Windows.Forms.CommonDialog', but it cannot because the type is declared as abstract

Which is odd since there is no designer for this class. However it does compile and seems to address the issue. I am not sure why VS is not treating it as simply a non WinForm class. Since this works well for me I I'll be abandoning my GongShell branch.

I am curious as to what this is from. There are references to unrelated things such as selecting a printer or computer dialog as well as references to an 'EditBox', none of which is needed by AGILE. I can probably trim the unused parts out for AGILE, but I am in the middle of an 8day work week and won't have much time for a few days.
KQII Remake Pic


SMF 2.0.19 | SMF © 2021, Simple Machines
Simple Audio Video Embedder

Page created in 0.044 seconds with 24 queries.