如何摆脱 VW 3.1d 和 ENVY 中的非托管代码
我有一个旧的 VW3/ENVY 映像,其中一个包裹作为非托管代码加载(正是这种情况 掌握 ENVY/DEVELOPER 警告)。不幸的是,这个问题很久以前就发生了,现在“返回”到没有加载包裹的图像已经太晚了。
显然,有一种方法可以解决这个问题(我们有一个开发映像已经解决了这个问题,并且有正常的配置映射,其中包含与非托管包完全相同的代码,但无法加载),但是确切的方式早已被遗忘(并且将特定的开发映像作为新的运行时映像的基础存在一些问题,因此我需要找出如何再次执行此操作)。
理论上,应该可以删除包裹并从配置映射中重新加载代码。实际上,所有正常方法(使用 ParcelBrowser 或直接调用 UnmanagedCode>>remove)都会失败。我什至尝试手动从方法字典中删除有问题的选择器,但超过某个点(涉及对 #primBecome 的调用:)整个图像完全挂起(我什至无法放入调试器)。我开始破解类和方法的实例,希望我能欺骗 ENVY 认为这些特定的方法是正常的版本代码,但还没有成功。
是否有任何闲聊/嫉妒专家仍然记得足够多的 VW 3 来为我提供任何指示?
状态更新 经过一周的尝试解决问题,我终于成功了,至少部分成功了,所以以防万一有人感兴趣......
首先,我必须修复未管理代码的文件指针(否则,所有尝试触及这些方法的所有内容都会抛出异常)。看起来 ENVY 扩展了 Parcel,因此理论上,所有整数文件指针在加载时都会更改为 ENVY 的 void
文件指针,但就我而言,我必须手动执行此操作(Parcel 为所有文件提供枚举)它定义的选择器)。另一种方法是调整 filePointer
代码,但这并不容易在每个需要的图像上自动完成。
然后,可以丢弃包裹,这会丢弃包裹信息,但保留代码。官方的“丢弃”机制需要有一个有效的更改文件(envy 不使用该文件,因此必须手动设置,然后重置)和包裹源(幸运的是我们有)。
为了能够对方法进行任何更改(手动或通过从 ENVY 加载应用程序或类),他们需要摆脱其非托管状态。这可以通过手动调整 TheClass>>applicationAssocs
来完成(我还删除了对 UnmanagedCode 中的类的所有引用(如时间戳),并删除了对丢弃的包的引用)。实际上,我从老板那里得到了一些关于如何做到这一点的信息,但直到我几乎自己弄清楚之前,我一直无法理解这些说明。
这最终允许我加载和重新加载包含这些类的所有应用程序。理论上来说。实际上,每当我尝试加载应用程序的新版本(包含以前在包中的代码)时,图像仍然完全挂起。
事实证明,崩溃与代码不受管理完全无关,而是因为有问题的包裹修改了 InputState>>process:
,其中它由于缺少和/或未初始化的类变量而导致异常(直到新的 process:
方法就位后才调用 InputState>>initialize
方法) 。我必须修改 Notifier
类,将所有异常转储到文件中,以了解发生了什么情况。将类变量添加到类的源中(而不是通过反射添加),通过 toBeLoadedCode 挂起输入处理线程,并在 loaded 方法中再次启动它并创建该应用程序的新版本甚至解决了这个问题。
现在理论上一切正常。实际上它仍然无法使用,因为重新加载 WindowSystem 或 VisualworksBase 应用程序会导致它们的初始化块运行,并且大量设置会重置为默认值 - 字体和字体大小、窗口颜色、UI 设置...并且没有似乎有任何方法可以将设置保存到文件并稍后加载它们,或者只是查看所有设置是什么(官方设置菜单没有显示所有内容,或者我们有一个经过大量调整的图像......从头开始重建它就这么多了)。但这是一个完全不同的问题。
I have an old VW3/ENVY image with a parcel loaded as unmanaged code (exactly the situation Mastering ENVY/DEVELOPER warns against). Unfortunately, this problem happened a long time ago and it's too late to just "go back" to an image without the parcel loaded.
Apparently, there is a way to solve this problem (we have one development image where this has been solved, and there are normal configuration maps that contain the exact same code as the unmanaged parcel but they can't be loaded), but the exact way has long since been forgotten (and there are some problems with taking that particular dev image as the base for a new runtime image, so I need to find out how how to do it again).
In theory, it should be possible to remove the parcel and reload the code from a configuration map. In practice, all normal ways (using the ParcelBrowser or directly calling UnmanagedCode>>remove) fail. I even tried manually removing the offending selectors from the method dictionary, but past a certain point (involving a call to #primBecome:) the whole image hangs completely (I can't even drop into the debugger). I started hacking the instances of the classes and methods, hoping I'd trick ENVY into thinking that these particular methods are normal versioned code, but without any success yet.
Are there any smalltalk/envy gurus around that still remember enough of VW 3 to provide me with any pointers?
Status update
After a week of trying to solve the problem I finally made it, at least partially, so in case anyone's interested...
First, I had to fix file pointers for the umnanaged code (otherwise, all everything that tried to touch the methods would throw an exception). It looks like ENVY extends Parcel so that, in theory, all integer file pointers are changed to ENVY's void
filepointer when loaded, but in my case, I had to do it manually (a Parcel provides enumeration for all selectors it defines). Another way would be to tweak the filePointer
code, but that can't easily be done automatically on every image where it's needed.
Then, the parcel can be discarded, which drops the parcel information, but keeps the code. The official "Discard" mechanism needs to have a valid changes file (which envy doesn't use so it has to be set manually, and reset afterwards) and the parcel source (which we fortunately had).
To be able to make any changes to the methods (either manually, or via loading an application or class from ENVY), they need to get rid of their unmanaged status. This can be done by manually tweaking TheClass>>applicationAssocs
(I also got rid of all references to the classes in UnmanagedCode sich as timestamps, and removed the reference to the discarded parcel). I actually had some info on how to get to this point from my boss, but I haven't been able to understand the instructions until I almost figured it out by myself.
This finally allowed me to load and reload all the Applications that contained the classes. In theory. In practice, the image still hung completely whenever I tried to load a newer version of the Application (that contained the code formerly in the parcel).
It turned out that the crashes had absolutely nothing to do with the code being unmanaged, but with the fact that the parcel in question modified InputState>>process:
, where it caused an exception due to a missing and/or uninitialized class variable (the InputState>>initialize
method wasn't called until after the new process:
method was in place). I had to modify the Notifier
class to dump all exceptions to a file to find out what was going on. Adding the class variable to the source of the class (instead of adding it via reflection), suspending the input processing thread via toBeLoadedCode
and starting it again in the loaded
method and creating a new version of the application solved even this problem.
Now everything works, in theory. In practice it's still unusable, because reloading the WindowSystem or VisualworksBase applications causes their initialization blocks to run, and a whole lot of settings are reset to their defaults - fonts and font sizes, window colors, UI settings... And there doesn't seem to be any way to just save the settings to a file and load them later on, or just to see what all the settings are (either the official Settings menu doesn't show everything, or we have a heavily tweaked image... so much for reconstructing it from scratch). But that's a completely different question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好吧,通常建议您应该能够通过从存储库加载代码来从头开始重建您的开发映像。但如果你有这个,那么答案很简单,只需丢弃该图像并重新加载即可。我认为时间已经足够长了,我已经失去了所有关于如何弄乱内部结构以恢复它的知识,而且听起来你已经尝试了很多事情。因此,尽管这可能很痛苦,但通过从存储库加载内容来找出重建开发映像的秘诀听起来可能是您最好的选择。它可能并不是那么可怕,只是可能存在一些对图像状态的依赖,或者需要执行的特殊操作。
您可能还需要根据您正在使用的图像中的内容来验证存储库中的内容。如果加载了非托管代码,然后有人修改了它并保存了它,我不清楚它是否会被保存到 ENVY 中。因此,您可能想要审核所有非托管代码,如果已更改,请将其保存到存储库版本。
抱歉我没有更好的答案。
Well, normally the recommendation would be that you should be able to rebuild your development image from scratch by loading your code from the repository. But if you had that, then the answer would be simple, just discard that image and reload. I think it's been long enough that I've lost whatever knowledge I've had about how to mess with the internal structures to get it back, and it sounds like you've tried a lot of things. So, although it might be painful, figuring out the recipe to rebuild your development image by loading stuff from the repository sounds like it may be your best bet. It probably isn't all that horrible, there just might be a few dependencies on the image state, or special doits that need to be executed.
You also probably need to validate what's in the repository against what's in the image you're working from. If there was unmanaged code loaded and then someone modified it and saved it, it's not clear to me that it would have been saved to ENVY. So you probably want to audit everything that was unmanaged code and if it's been changed, save that to a repository edition.
Sorry I don't have any better answers.