【问题标题】:Why am I having to rebuild an unchanged project?为什么我必须重建未更改的项目?
【发布时间】:2012-12-18 19:26:29
【问题描述】:

我有以下 MASM 代码:

.386
.model flat, stdcall
option casemap :none

include \masm32\include\masm32rt.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。

为什么我必须重建以及如何设置它以使我不必重建?

【问题讨论】:

  • +1 表示包含汇编语言的问题。顺便说一句,不知道。
  • 会不会是抛出异常?您是否尝试过在调试时打开异常?
  • 我正在 Visual Studio 中进行调试,到了这一点,我抛出了异常(做错事从程序集中返回了一个已修复的值),但现在没有抛出异常。跨度>
  • 这段代码破坏了堆栈。您将需要了解调用约定。任何一本关于 x86 汇编的好书都有很好的介绍。
  • 你是对的。我错了。

标签: c# visual-studio-2010 interop masm


【解决方案1】:

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

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

我认为,这个过程实际上是为了通过预加载汇编代码来加速调试的启动。您可以尝试在项目属性中关闭“启用 Visual Studio 托管进程”。之后,您应该会看到您的项目按预期工作。

在您进一步前进之前,请意识到@HansPassant 是正确的,并且您的堆栈已损坏,随着时间的推移,您的项目将在意想不到的时间以最不愉快的方式以意想不到的方式失败。在大多数情况下,您的应用程序会抛出没有意义的异常,而在某些情况下,您的应用程序会消失。

【讨论】:

  • 这是我第一次编写从外部程序集调用的程序集。这个项目是一种学习体验,我发现资源很少。我如何破坏堆栈?我一直在阅读有关禁用序言和尾声并自己做的文章,但没有区别。处理堆栈的正确方法是什么?
  • 事实上,我对这个主题知之甚少,因为我不擅长组装。在写我的答案时,我还尝试通过制作一个导出函数并反汇编它的简单 dll 来回答这个问题。但是 MS 编译器创建了太多的汇编代码,所以这对我来说是不可用的。尝试为 x86 而不是 MSIL 编译,尝试使用 DllImport 参数。尝试从 c 控制台应用程序调用您的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-21
  • 2023-02-10
  • 2011-03-18
  • 2012-11-08
  • 2014-03-11
  • 1970-01-01
相关资源
最近更新 更多