最近在测试将mono嵌入到C++应用程序中,苦于没有调试器,有时候还是不怎么方便。网上搜了一下,有VS插件MDebug、VSMonoDebugger,实际试用了一下,有点麻烦,而且似乎对Windows+Visual Studio 2022支持不大好。因此想到了,Unity引擎是基于mono的,Visual Studio 2022也内置了针对Unity的调试器,名为:Visual Studio Tools for Unity。我想如果这个插件也能调试我的应用程序就好了。
打开VS,使用菜单中的“附加到Unity”菜单打开附加对话框。最后发现并不能识别我的mono嵌入应用程序。因此直接调试Visual Studio 2022,查找和研究VS发现Unity进程的方法。经过一系列的调试,发现查找Unity相关进程的代码位于:SyntaxTree.VisualStudio.Unity.Messaging.dll 中,文件路径:
// c:\program files\microsoft visual studio\2022\professional\common7\ide\extensions\microsoft\visual studio tools for unity\SyntaxTree.VisualStudio.Unity.Messaging.dll // SyntaxTree.VisualStudio.Unity.Messaging, Version=17.8.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
具体路径可能你跟我不一样。下面这个函数位于:SyntaxTree.VisualStudio.Unity.Messaging.UnityProbe类中。
public static IEnumerable<UnityProcess> GetUnityProcesses(string informationFormat = null, bool localPlayerProcessDetection = false) { Process[] array = SafeProcess.GetProcesses().ToArray<Process>(); IEnumerable<UnityProcess> enumerable = from p in array where p.ProcessProperty((Process _) => _.ProcessName) == "Unity" select UnityProbe.UnityProcessFor(p, UnityProcessType.Editor, UnityProbe.GetDebuggerPort(p.Id), informationFormat); if (!localPlayerProcessDetection) { return enumerable; } IEnumerable<UnityProcess> enumerable2 = from p in array.Where(new Func<Process, bool>(UnityProbe.IsLocalPlayerProcess)) select UnityProbe.UnityProcessFor(p, UnityProcessType.Player, 0, informationFormat); return enumerable.Concat(enumerable2); }
我们可以看到,这里使用了两种方法来探查Unity相关进程。其一是直接查找名字叫Unity的进程,其二是探查可能是Unity Player(即Windows PC档)的进程。前者直接查看进程名称,后者通过下面这个函数来判断:
public static bool IsLocalPlayerProcess(Process process) { bool flag; try { if (process.MainWindowHandle == IntPtr.Zero) { flag = false; } else { ProcessModule mainModule = process.MainModule; if (mainModule == null) { flag = false; } else { string fileName = mainModule.FileName; string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); string directoryName = Path.GetDirectoryName(fileName); if (directoryName == null) { flag = false; } else { flag = Directory.Exists(Path.Combine(directoryName, fileNameWithoutExtension + "_Data")) && File.Exists(Path.Combine(directoryName, "UnityPlayer.dll")); } } } } catch (Exception) { flag = false; } return flag; }
可以看到,只要目标进程目录下有一个 “进程名(无扩展名)” + "_Data"的目录,且该目录下有一个UnityPlayer.dll,即可被视为Unity相关进程。
因此要将我们自己的进程被该插件识别到,也有两种方法,假如我们的项目叫MyApp。那么其一是让我们生成的进程也叫Unity.exe;其二是在MyApp.exe所在目录下,新增一个MyApp_Data,然后再随便新建一个空白文本文件,把名称(含扩展名)改成"UnityPlayer.dll"即可。
这样执行后,你就会发现,你的进程出现在了搜索对话框中了。
当然,如果此时你直接双击连接是无法连接成功的,因为前面的任务只是让你可以被找到,如果要被连接上,还有另外一些额外的要求。让我们看一下下面这个函数:
public static int GetDebuggerPort(int processId) { return 56000 + processId % 1000; }
可以看到,调试器假定了目标端口和进程id之间的关联关系,因此在我们初始化mono的时候,也需要考虑到这一点,因此,我们初始化mono调试器的时候,应该这样:
int DebuggerPort = 56000 + GetProcessId() % 1000; std::string argument = std::string("--debugger-agent=transport=dt_socket,embedding=1,server=y,suspend=n,address=127.0.0.1:") + ToStlString(DebuggerPort); const char* options[] = { argument.c_str() }; mono_jit_parse_options(sizeof(options)/sizeof(options[0]), (char**)options); mono_debug_init(MONO_DEBUG_FORMAT_MONO);
这样你就可以白嫖Visual Studio Tools for Unity,用于调试你自己的mono嵌入程序了。
标签:插件,Mono,flag,Visual,Unity,Studio,mono,进程 From: https://www.cnblogs.com/bodong/p/17962564