Here's the C# translation, which goes in Program.cs in a standard WinForms project. My test form just has a browse folder button and OK.
Code:
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
using System.Threading;
namespace FMSelRS
{
static class Program
{
//Default main method was here but is not needed for this
private static sFMSelectorData FMSelData;
private static eFMSelReturn FMSelReturnValue = new eFMSelReturn();
[DllExport(CallingConvention=CallingConvention.Cdecl, ExportName="SelectFM")]
public static int SelectFM([MarshalAs(UnmanagedType.Struct)] ref sFMSelectorData data)
{
byte[] sName = new byte[256];
FMSelData = data;
Thread thd = new Thread(()=>
{
Form1 nForm = new Form1();
DialogResult dR = nForm.ShowDialog();
if (dR == DialogResult.OK)
{
string fol = nForm.getFMName;
sName = ASCIIEncoding.ASCII.GetBytes(fol);
FMSelReturnValue = eFMSelReturn.kSelFMRet_OK;
}
});
thd.SetApartmentState(ApartmentState.STA);
thd.Start();
thd.Join();
Marshal.Copy(sName, 0, FMSelData.sName, sName.Length);
return (int)FMSelReturnValue;
}
public enum eFMSelReturn
{
kSelFMRet_OK = 0, // run selected FM 'data->sName' (0-len string to run without an FM)
kSelFMRet_Cancel = -1, // cancel FM selection And start game As-Is (no FM Or If defined In cam_mod.ini use that)
kSelFMRet_ExitGame = 1 // abort And quit game
}
[StructLayout(LayoutKind.Sequential, Pack=4, CharSet = CharSet.Ansi)]
public struct sFMSelectorData
{
//sizeof(sFMSelectorData)
public int nStructSize;
//game version string as returned by AppName() (ie. in the form "Thief 2 Final 1.19")
public string sGameVersion;
//supplied initial FM root path (the FM Selector may change this)
public IntPtr sRootPath;
public int nMaxRootLen;
//buffer to copy the selected FM name
public IntPtr sName;
public int nMaxNameLen;
//set to non-zero when selector Is invoked after game exit (if requested during game start)
public int bExitedGame;
//FM selector should set this to non-zero if it wants to be invoked after game exits (only done for FMs)
public int bRunAfterGame;
//optional list of paths to exclude from mod_path/uber_mod_path in + separated format And Like the config
//vars, Or if "*" all Mod paths are excluded (leave buffer empty for no excludes)
//the specified exclude paths work as if they had a "*\" wildcard prefix
public IntPtr sModExcludePaths;
public int nMaxModExcludeLen;
public IntPtr sLanguage;
public int nLanguageLen;
public int bForceLanguage;
}
}
}