为什么我必须重建一个未更改的项目



我有以下MASM代码:

.386
.model flat, stdcall
option casemap :none
include masm32includemasm32rt.inc
.data
NewLine db  13, 10, 0
.code
LibMain proc instance:dword,reason:dword,unused:dword 
mov     eax, 1
ret
LibMain endp
PrintMess proc
print "Printed from assembly"
invoke StdOut, addr NewLine
ret
PrintMess endp
TestReturn proc number:dword
mov     eax, number
ret
TestReturn endp
End LibMain

使用一个简单的.def文件:

LIBRARY MyLib
EXPORTS PrintMess
EXPORTS TestReturn

我从C#调用PrintMessTestReturn,如下所示:

[DllImport("MyLib")]
static extern void PrintMess();
[DllImport("MyLib")]
static extern int TestReturn(int num);
static void Main(string[] args) {
Console.WriteLine("Printed from C#");
PrintMess();
int value = TestReturn(30);
Console.WriteLine("Returned: " + value);
Console.ReadKey(true);
}

我第一次运行它时,它在Console.ReadKey(true)处暂停,我得到了预期的输出:

Printed from C#
Printed from assembly
Returned: 30

如果我在C#项目中进行更改,比如TestReturn(30)更改为TestReturn(50),那么它的行为会很奇怪。程序在没有错误的情况下终止,并且没有在Console.ReadKey(true)上暂停(看起来它甚至没有到达那一行),这是我的输出:

Printed from C#
Printed from assembly

我必须重建装配项目。具体来说,我必须重新构建,如果我再进行一次常规构建,程序就会继续错误行为。当我重建时,输出和行为会恢复正常,并反映输出中的数字变化。我的猜测是,Build和Rebuild之间的某些不同之处在于部分破坏了DLL。

为什么我必须重建,我如何设置它,这样我就不必重建了?

@HansPassant很可能是正确的,但没有解释为什么必须重建@雅各布很接近。

VS正在使用所谓的"托管过程"来简化和隔离调试。当您从VS调试test.exe时,实际上您正在调试test.vshost.exe,它会加载您的exe。当您停止调试时,主机可执行文件不会被卸载,所以您真正的可执行文件。当您在不更改任何内容的情况下构建代码时,VS实际上只会检查文件是否是最新的。VS认为,若文件并没有被更改,那个么就并没有必要重新加载托管过程。如果您重新构建,即使您没有更改任何代码,您真正的可执行文件也会更新,这将迫使主机进程终止并重新加载,以及您真正的执行文件。

我认为,这个过程实际上是为了通过预加载汇编代码来加快调试的启动。您可以尝试关闭项目属性中的"启用Visual Studio宿主进程"。在那之后,你应该看到你的项目按预期进行。

在你进一步行动之前,要意识到@HansPassant是正确的,你有一个损坏的堆栈,随着时间的推移,你的项目将以意想不到的方式在意想不到的时间以最令人不快的方式失败。在大多数情况下,您的应用程序将抛出毫无意义的异常,在某些情况下,应用程序将消失。

最新更新