65.9K
CodeProject 正在变化。 阅读更多。
Home

HOWTO:将托管和非托管项目合并到单个 Visual Studio 解决方案中

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.28/5 (24投票s)

2004 年 4 月 9 日

CPOL

18分钟阅读

viewsIcon

149656

downloadIcon

360

本文介绍如何将托管项目和非托管项目合并到单个 Visual Studio .NET 解决方案中。

本文中的信息适用于

  • Microsoft Visual Studio .NET 2003
  • Microsoft eMbedded Visual C++ 4

摘要

本文介绍如何将托管项目和非托管项目合并到单个 Visual Studio .NET 解决方案中,以便您可以在单个环境中编辑、构建和部署整个解决方案。然后将其与安装项目结合,自动生成 MSI 来将解决方案安装到多个设备上。

更多信息

Microsoft Visual Studio .NET 2003 使我们能够使用 .NET Compact Framework 为智能设备(例如 Pocket PC)创建托管应用程序。

但是,此框架是完整 .NET 框架的子集——Microsoft 减小了其占用空间以适应移动设备。对于完整框架,有时需要调用非托管代码来访问 .NET 中未直接提供的服务;对于 Compact Framework,这一点更为突出,因为 .NET 程序员根本无法使用许多有用的功能。幸运的是,移动设备的非托管开发环境,即 eMbedded Visual C++,对移动设备有很好的支持。

通常,在使用 .NET Compact Framework 进行开发时,您会混合使用托管项目(例如 C#)和非托管项目(eMbedded Visual C++),其中托管代码使用 Platform Invoke 调用非托管代码。

在 Microsoft Visual Studio .NET 2003 中创建新的 Smart Device Application 时,会为您创建两个项目配置:DebugRelease。由于 .NET 的设计是平台中立的,只要 Common Language Runtime (CLR) 已移植到目标设备,这两者都不是针对任何移动硬件的。这对开发人员来说是个好消息,因为我们只需要创建一个可用于多个紧凑型设备的单个二进制文件(程序集)。CLR 会隐藏 .NET 程序与硬件之间的差异,我们的 .NET 程序与虚拟机(CLR)通信,而不是与本机设备通信。

.NET 还允许我们使用 Platform Invoke 调用非托管代码,以便访问 Compact Framework 中未直接公开的功能。任何非托管代码二进制文件通常都会添加到 .NET 项目中,以便在调试期间与 .NET 程序集同时部署到设备上。

此部署展示了一个重要问题:当您将设备特定的非托管二进制文件(EXE 或 DLL)添加到 .NET 项目时,整个项目就变成了平台特定的,因为您只能在目标非托管二进制文件的平台上进行部署和调试。然而,Visual Studio 中没有对这种设备依赖性的自动识别——您仍然只有标准的 DebugRelease 设备无关项目配置。

当我第一次遇到此限制时,我很快想出了一个我在其他地方也看到过的解决方案——在非托管项目中创建自定义构建步骤,将非托管二进制文件复制到托管解决方案的相应位置。对于非托管项目中的所有配置,自定义构建步骤都相同,即无论不同的配置针对不同的设备,它们都将输出定向到托管解决方案中的同一位置。例如

Managed Project
    Unmanaged.dll

Unmanaged Project
    emulatorDbg
        Unmanaged.dll -> copy to -> Managed Project\Unmanaged.dll
    emulatorRel
        Unmanaged.dll -> copy to -> Managed Project\Unmanaged.dll
    ARMV4Dbg
        Unmanaged.dll -> copy to -> Managed Project\Unmanaged.dll
    ARMV4Rel
        Unmanaged.dll -> copy to -> Managed Project\Unmanaged.dll

整个解决方案的目标设备取决于托管项目中恰好是哪个版本的非托管二进制文件。要定位不同的设备,需要打开 eMbedded Visual C++ 4 中的非托管项目,选择目标设备的相应项目配置,然后构建该配置。自定义构建步骤可确保生成的二进制文件被复制到托管项目中。

此方法有两个很大的缺点

  • 它需要一个完全脱离 Visual Studio .NET 开发环境的手动构建步骤,并且很容易忘记托管项目中当前是非托管二进制文件的哪个版本。
  • 它使用了一种模型,其中生产者项目(非托管项目)负责将其输出推送到使用者项目(托管项目)。如果您创建了一个需要非托管组件的新 .NET 项目,那么您必须更改非托管项目,使其将输出复制到新的 .NET 项目。这与我们逻辑上预期的相反——.NET 项目应该能够获取其所需的所有组件,而无需依赖它一无所知的外部构建事件。

我现在已经放弃了这种方法,转而采用了一种更好的技术,该技术使我能够在 .NET 项目中拥有特定于设备的配置,并一步构建托管和非托管项目。我将这种托管和非托管项目的组合称为 混合项目解决方案;本文其余部分将分步介绍如何创建此类混合项目解决方案。

分步示例

对于我们的混合项目解决方案,我们将创建一个名为 MakeDemo 的应用程序,该应用程序由一个带有 Press Me 按钮的单个窗体组成;单击按钮会显示一个带有 That tickles 字样的消息框。

窗体是用 C# 实现的,但消息框(为演示目的)是从用 eMbedded Visual C++ 编写的非托管 DLL 显示的。Press Me 按钮使用 Platform Invoke 从托管代码调用非托管代码。

  1. 在 Microsoft Visual Studio .NET 2003 中创建一个新的 Smart Device Application:从 File 菜单中选择 New,然后选择 Project。在 New Project 对话框中,从 Project Types 中选择 Visual C# Projects,从 Templates 中选择 Smart Device Application。将项目名称输入为 Managed,将 Location 设置为 directory\MakeDemo

    点击**确定**。

  2. Smart Device Application Wizard 中,为目标平台选择 Pocket PC,为项目类型选择 Windows Application

    单击 OK 生成项目。

  3. Solution Explorer 中,将 Form1.cs 文件重命名为 MakeDemoForm.cs
  4. MakeDemoForm.cs 的初始代码如下
    using System;
    using System.Drawing;
    using System.Collections;
    using System.Windows.Forms;
    using System.Data;
    
    namespace Managed
    {
        public class MakeDemoForm : System.Windows.Forms.Form
        {
            private System.Windows.Forms.Button PressMe;
    
            public MakeDemoForm()
            {
                this.PressMe = new System.Windows.Forms.Button();
                this.PressMe.Location = new System.Drawing.Point(80, 112);
                this.PressMe.Text = "Press Me";
                this.PressMe.Click += new System.EventHandler(this.OnPressMe);
                this.Controls.Add(this.PressMe);
                this.Text = "Make Demo";
            }
    
            protected override void Dispose( bool disposing )
            {
                base.Dispose( disposing );
            }
    
            static void Main() 
            {
                Application.Run(new MakeDemoForm());
            }
    
            private void OnPressMe(object sender, System.EventArgs e)
            {      
            }
        }
    }
  5. 现在在 eMbedded Visual C++ 4 中创建非托管项目:从 File 菜单中选择 New,然后在 Projects 选项卡中,选择 WCE Dynamic-Link Library。将 Project name 输入为 Unmanaged,将 Location 设置为 directory\MakeDemo\Unmanaged。最后选择您要定位的 CPUs——在本例中为 Win32 (WCE ARMV4)Win32 (WCE emulator)

    单击 OK。此时您应该有一个 MakeDemo 文件夹,其中包含 ManagedUnmanaged 子文件夹。

  6. WCE Dynamic Link Library 对话框中,选择创建 A DLL that exports some symbols,然后单击 Finish,再单击 New Project Information 对话框的 OK

    这将创建一个 Unmanaged.cpp Unmanaged.h 文件,其中包含一个名为 fnUnmanaged 的导出函数等。

  7. Unmanaged.cpp 文件中的 fnUnmanaged 函数更改为以下内容
    UNMANAGED_API int fnUnmanaged(LPCTSTR lpszMessage)
    {
        return MessageBox(NULL, lpszMessage, _T("Unmanaged"), MB_OK);
    }

    当从 .NET 项目调用此函数时,我们将传递一个字符串,该函数将显示在消息框中。

    还要更改 Unmanaged.h 文件中函数的声明

    #ifdef __cplusplus
    extern "C"
    {
    #endif
    
    UNMANAGED_API int fnUnmanaged(LPCTSTR lpszMessage);
    
    #ifdef __cplusplus
    } // extern "C"
    #endif

    我们使用 extern "C" 声明来确保我们的导出函数不会发生 C++ 名称修饰。

  8. Build 菜单中选择 Batch Build...,确保选中所有项目配置,然后单击 Rebuild All

    此步骤不是必需的,但有助于演示构建过程会自动为每个项目配置创建一个子目录,即

    Win32 (WCE 模拟器) Release

    emulatorRel

    Win32 (WCE 模拟器) Debug

    emulatorDbg

    Win32 (WCE ARMV4) Release

    ARMV4Rel

    Win32 (WCE ARMV4) Debug

    ARMV4Dbg

  9. 返回 Microsoft Visual Studio .NET 2003 中的托管项目,并在 MakeDemoForm.cs 中进行以下代码更改。

    在此文件顶部添加以下行,以使我们能够访问 Platform Invoke 命名空间

    using System.Runtime.InteropServices;

    OnPressMe 方法更改为如下

    private void OnPressMe(object sender, System.EventArgs e)
    {
        fnUnmanaged("That tickles");
    }

    并将以下行添加到 Managed 类的末尾。此声明使我们能够调用 Unmanaged.dll 中的 fnUnmanaged 函数。

    [DllImport("Unmanaged.dll")]
    private static extern int fnUnmanaged(string message);
  10. 我们现在需要将 Unmanaged.dll 添加到项目中,以便它与托管程序集一起部署到目标设备。在 Solution Explorer 中,右键单击 Managed 项目,然后选择 Add,再选择 Add Existing Item...。导航到 Unmanaged\emulatorDbg 文件夹,将 Files of type 更改为 All Files (*.*),选择 Unmanaged.dll,然后单击 Open

    这将物理上将 Unmanaged.dllUnmanaged\emulatorDbg 文件夹复制到 Managed 文件夹,因此您现在有了该 DLL 的两个副本。

  11. Standard 工具栏中,为项目配置选择 Debug,在 Device 工具栏中,确保选择了 Pocket PC 2003 Emulator。按 F5 通过 Visual Studio 调试器将程序集部署并运行到模拟器上。

    当您单击 Press Me 按钮时,应该会调用 Unmanaged.dll 来显示消息框。

  12. 到目前为止,我们已经遵循了标准实践来设置我们的托管和非托管项目。如果我们想更改非托管项目(例如显示消息框中的图标),那么我们需要切换到 eMbedded Visual C++ 环境,更改源代码,重新构建项目,然后将生成的 DLL 复制到我们的托管项目中。此外,如果我们想定位不同的设备,我们必须手动将相应的非托管 DLL 复制到托管项目中。

    以下步骤描述了如何将分离的托管和非托管项目合并到单个 混合项目解决方案 中。

  13. 在 Microsoft Visual Studio .NET 2003 Solution Explorer 中,右键单击 Solution 'Managed',然后从弹出菜单中选择 Add,再选择 New Project...。在 Add New Project 对话框中,展开 Project Types 中的 Visual C++ Projects;高亮显示 General,然后在 Templates 中高亮显示 Makefile Project。将 Location 更改为 MakeDemo,将 Name 更改为 Unmanaged(以匹配我们非托管项目的名称)。

    单击 OK,然后单击 Finish。这将在 Solution Explorer 中创建一个新的 Unmanaged 项目,并在我们现有的 Unmanaged 文件夹中有一个相应的 Microsoft Visual Studio .NET 2003 项目文件 Unmanaged.vcproj

  14. Solution Explorer 中的 Unmanaged 项目有三个自动生成的文件夹:Source FilesHeader FilesResource Files。将非托管项目中的现有文件添加到相应的文件夹(例如,将 StdAfx.cppUnmanaged.cpp 添加到 Source Files 文件夹)。要将文件添加到文件夹,请在 Solution Explorer 中右键单击该文件夹,然后从弹出菜单中选择 Add,再选择 Add Existing Item...。您可以在 Add Existing Item 对话框中使用 Ctrl 键和鼠标单击来多选文件。

    非托管项目没有资源文件,但如果有,我们也会将它们添加到 Resource Files 文件夹中。

    您的 Solution Explorer 窗口现在应该看起来像这样

    我们现在可以使用 Microsoft Visual Studio .NET 2003 环境来编辑非托管项目中的所有文件,包括资源文件。

    下一步,也是最重要的一步,是从 Microsoft Visual Studio .NET 2003 中构建非托管项目。

  15. 我们现在将在 Visual Studio .NET 中为非托管项目创建配置,以匹配 eMbedded Visual C++ 项目中的现有配置。从 Build 菜单中选择 Configuration Manager...。在 Unmanaged 项目的 Configuration 列中,从组合框中选择 <Edit...>,然后 Rename 将现有的 DebugRelease 解决方案配置重命名为 emulatorDbgemulatorRel。这些名称必须与 eMbedded Visual C++ 项目中模拟器构建的输出文件夹名称匹配。

    关闭 Edit Project Configurations 对话框。

  16. 现在为我们正在定位的其他设备添加配置,即 ARMV4,方法是选择 Unmanaged 项目配置组合框中的 <New...>。对于 Project Configuration Name,输入 ARMV4Dbg,以匹配 eMbedded Visual C++ 项目中 ARMV4 调试构建的输出文件夹名称。将 Copy Settings from 更改为 emulatorDbg。确保 Also create new solution configuration(s) 未选中。

    ARMV4Rel 重复此过程,从 emulatorRel 复制设置。

    现在我们应该有四个 Unmanaged 项目的配置,而 Managed 项目只有两个配置。

    Configuration Manager 中,当您选择一个 Active Solution Configuration 时,各个项目配置应该会随之更改。因此,如果 Active Solution ConfigurationDebug,那么 Managed 项目配置也应该是 Debug,而 Unmanaged 项目配置应该是 emulatorDbgARMV4Dbg。要定位不同的设备,只需打开 Configuration Manager,并将 Unmanaged 项目配置更改为相应的设备。

    关闭 Configuration Manager

  17. Solution Explorer 中,右键单击 Unmanaged 项目,然后从弹出菜单中选择 Properties...。在 Unmanaged Property Pages 对话框中,将 Configuration 设置为 All Configurations,并从 Configuration Properties 中选择 NMake。将 NMake 选项设置为如下

    $(ConfigurationName) 宏将根据我们正在构建的配置来设置,即它将是 emulatorDbgemulatorRelARMV4DbgARMV4Rel 之一。

    下一步描述 Make 命令。

    单击 OK 按钮。

  18. Make 命令实现为一个传统的批处理文件。在 Solution Explorer 中,右键单击 Unmanaged 项目,然后从弹出菜单中选择 Add,再选择 Add New Item...。在 Add New Item 对话框中,选择 Text File (*.txt) 模板,并将 Name 设置为 Make.batLocation 应为 MakeDemo\Unmanaged

    单击 OpenMake.bat 文件可能被添加到 Source Files 文件夹。我更喜欢将其拖到主 Unmanaged 文件夹。

  19. Make.bat 文件可以包含构建非托管项目所需的任何命令。通常,您需要执行一个命令来构建非托管项目,然后将生成的输出复制到托管项目中。下面的示例 Make.bat 使用 eMbedded Visual C++ 环境 EVC.EXE 来构建项目,然后复制输出。

    我在 Make.bat 文件中用 *斜体* 标出了您需要为自己的环境和项目更改的部分。还重要的是要注意,Config 变量将设置为 $(ConfigurationName) 宏的当前值,该宏在命令行上传递给批处理文件。Config 变量决定了将构建哪个配置,以及输出将从何处复制。对于复制,假定输出文件夹的名称与 Config 变量完全相同,即当前配置名称。这就是为什么解决方案中的配置名称与非托管项目中的输出文件夹名称匹配很重要。如果您不想像这样重用输出文件夹名称,那么您需要更改 Make.bat 文件,使其将解决方案配置名称映射到输出文件夹,就像它已经将配置名称映射到非托管项目中的相应配置一样。

    if "%1"=="" goto errNoArg
    
    set Config=%1
    set Arg=%2
    
    REM Change to the location of EVC.EXE on your machine.
    set EVCPath="D:\Program Files\Microsoft eMbedded C++ 4.0\Common\EVC\Bin\EVC.EXE"
    
    REM The configuration names are CASE sensitive,
    REM e.g., "emulatorDbg" must be the same case
    REM as the configuration name in Configuration Manager.
    if "%1"=="emulatorDbg" set ConfigEx=Win32 (WCE emulator) Debug
    if "%1"=="emulatorRel" set ConfigEx=Win32 (WCE emulator) Release
    if "%1"=="ARMV4Dbg" set ConfigEx=Win32 (WCE ARMV4) Debug
    if "%1"=="ARMV4Rel" set ConfigEx=Win32 (WCE ARMV4) Release
     
    REM Change to the location and name of your unmanaged project.
    echo %EVCPath% "E:\PROJECTS\PocketPC\MakeDemo\Unmanaged\Unmanaged.vcp" 
                               /make "Unmanaged - %ConfigEx%" %Arg%
    %EVCPath% "E:\PROJECTS\PocketPC\MakeDemo\Unmanaged\Unmanaged.vcp" 
                               /make "Unmanaged - %ConfigEx%" %Arg%
     
    if "%Arg%"=="/clean" goto end
     
    REM Change to the name of your unmanaged DLL and managed project.
    echo copy %Config%\Unmanaged.dll ..\Managed
    copy %Config%\Unmanaged.dll ..\Managed
     
    goto end
     
    :errNoArg
    echo "Invalid project configuration"
     
    :end
  20. 现在我们需要确保非托管项目在托管项目之前构建。在 Solution Explorer 中,右键单击解决方案,然后从弹出菜单中选择 Project Dependencies...。在 Projects 组合框中选择 Managed 项目,并选中 Depends on Unmanaged 项目。

  21. 混合项目解决方案现已设置完毕。要进行测试,请在 Unmanaged 项目中打开 Unmanaged.cpp 文件。将 fnUnmanaged 函数更改为
    UNMANAGED_API int fnUnmanaged(LPCTSTR lpszMessage)
    {
        return MessageBox(NULL, lpszMessage, _T("Unmanaged"), 
                                     MB_OK | MB_ICONEXCLAMATION);
    }

    确保 Managed 项目的部署设备为 Pocket PC 2003 Emulator,并且当前解决方案配置为 Debug。按 F5 构建并部署解决方案。单击 Press Me 按钮现在将显示一个略有不同的消息框——解决方案已自动合并了我们对非托管 DLL 所做的更改。

  22. 要在硬件设备上进行调试,请将 Managed 项目的部署设备更改为 Pocket PC Device。在 Configuration Manager 中,将 Unmanaged 项目配置更改为例如 ARMV4Dbg。关闭 Configuration Manager 并按 F5 在设备上启动应用程序。

您会发现,现在您可以使用 Visual Studio .NET 来编辑托管和非托管项目中的源代码和资源,并按预期进行构建和部署。唯一的真正限制是,如果您进行了影响非托管项目文件本身的更改(例如,向项目中添加新文件),那么您需要在 eMbedded Visual C++ 和 Visual Studio .NET 中都进行这些更改。此外,任何编译器和链接器选项只能在 eMbedded Visual C++ 中应用。请记住在尝试从 Visual Studio .NET 使用项目之前,在 eMbedded Visual C++ 中保存项目。

最后,无法从托管项目调试到非托管代码。要调试非托管代码,您需要使用 eMbedded Visual C++ 作为调试环境;在非托管项目的 Debug 设置中,将本地和远程可执行文件设置为托管应用程序的名称。或者,您可以将本地可执行文件设置为 Visual Studio .NET 本身——当您使用 eMbedded Visual C++ 开始调试时,Visual Studio .NET 将会启动,这使您也可以调试托管代码。

混合项目解决方案和安装应用程序

Code Project 上有一篇 MSDN 团队的优秀文章,讨论了 开发和部署 Pocket PC 安装应用程序。该文章介绍了如何在构建步骤中为多个设备自动生成 cab 文件。这些技术与混合项目解决方案配合良好,但该文章并未说明如何将此类安装添加到现有解决方案中。

以下简要介绍了如何将安装添加到我们的 MakeDemo 解决方案。

  1. 开发和部署 Pocket PC 安装应用程序 文章中安装 Deployment 示例。
  2. 将示例中的 CustomInstallerSetup 项目复制到 MakeDemo 文件夹,并将这两个项目添加到 MakeDemo 解决方案。
  3. 将示例 PocketApp 文件夹中的 BuildCabs 文件夹复制到 MakeDemo\Managed 文件夹。将 MakeDemo\Managed \BuildCabs\PocketApp_PPC.inf 重命名为 Managed.inf。在 Solution Explorer 中,在 Managed 项目中创建一个新的 BuildCabs 文件夹,并将 MakeDemo\Managed\BuildCabs\BuildCab.batMakeDemo\Managed\BuildCabs\Managed.inf 添加到其中。
  4. PocketApp 文件夹中的 app.icoSetup.ini 文件复制到 MakeDemo\Managed 文件夹,并将这些文件添加到 Solution Explorer 中的 Managed 项目。将 app.icoBuild Action 属性设置为 None。将 Managed 项目的 Application Icon 设置为 app.ico。在 MakeDemoForm.csMakeDemoForm 构造函数中添加以下行,以使窗体中的图标与 Application Iconapp.ico)相同
    System.Resources.ResourceManager resources = 
       new System.Resources.ResourceManager(typeof(MakeDemoForm));
    this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
  5. Project Dependencies 设置为如下
    CustomInstaller depends on Managed
    Managed depends on Unmanaged
    Setup depends on CustomInstaller

    构建顺序应为:UnmanagedManagedCustomInstallerSetup

  6. CustomInstaller 项目属性中,将 Build Events 设置为 ..\..\..\Managed\BuildCabs\BuildCab.bat
  7. Configuration Manager 中,删除 CustomInstallerSetup 项目的 Debug 配置。对于 Debug Active Solution Configuration,请不要构建 CustomInstallerSetup 项目。确保两者都为 Release Active Solution Configuration 构建。
  8. Setup 项目属性中,为 Release 配置将 Output file name 设置为 Release\Managed Setup.msi
  9. 编辑 MakeDemo\Managed\BuildCabs\BuildCab.bat 来更改文件位置和 inf 文件名。您还可以指定要定位的处理器类型。为简单起见,我只定位 EmulatorARMV4

    您需要为每个目标处理器构建非托管 DLL。

  10. 编辑 MakeDemo\Managed\BuildCabs\BuildCab.inf
    • 更改 SourceDiskNames 部分,使其条目指向托管项目的发布输出文件夹。
    • 为每个目标处理器添加一个 SourceDiskNames 部分。这应指向相应处理器的非托管项目的发布输出文件夹。
    • 为每个目标处理器添加一个 Files 部分。这应引用非托管组件。
    • DestinationDirs 部分添加每个 Files 部分的条目。
  11. 编辑 MakeDemo\Managed\Setup.ini 来更改 cab 文件名,例如 Managed.ARMV4.CAB,Managed.Emulator.CAB
  12. 将解决方案配置设置为 Release,重新构建 CustomInstaller 项目。这将生成 cab 文件,然后您可以将它们添加到 Setup 项目。在 Solution Explorer 中,删除 Setup 项目中的任何现有 cab 文件,并删除 Setup.ini 文件和 CustomInstaller.dll 文件(因为它们引用 PocketApp 项目)。将 MakeDemo\Managed 文件夹中的 Setup.ini 文件和 MakeDemo\Managed\BuildCabs\Cabs 文件夹中的 cab 文件添加到其中。
  13. Solution Explorer 中双击 Setup 项目中的 Setup.ini 文件。这应该会打开一个 File System on Target Machine 树视图。将 Application Folder 中的 Setup.ini 文件和 cab 文件拖到 Application Folder\Setup 文件夹。
  14. Solution Explorer 中右键单击 Setup 项目,然后选择 ViewCustom Actions。右键单击 Install 自定义操作,从弹出菜单中选择 Add Custom Action...,然后在 Look in 组合框中选择 Setup。单击 Add File... 并选择 MakeDemo\CustomInstaller\bin\Release\CustomInstaller.dll 文件,然后单击 Open,再单击 OK。对 Uninstall 自定义操作重复此过程,但您应该能够从 Select Item In Project 对话框中选择 CustomInstaller.dll,而无需转到 Add File...
  15. Solution Explorer 中选择 Setup 项目,并查看其属性。更改以下属性:AddRemoveProgramsIconAuthorManufacturerProductName(例如 Managed)和 Title(再次为 Managed)。还通过单击 ... 并生成新代码来更改 ProductCodeUpgradeCode;这确保您的安装项目不会与您复制的原始 Setup 项目混淆。
  16. 重新构建整个解决方案。MakeDemo\Setup\Release 文件夹现在应该包含一个 Managed Setup.msi,可用于将应用程序安装到目标设备上。

其他环境

我只在 Visual Studio .NET 2003 和 eMbedded Visual C++ 4 中尝试过本文中的技术,但原则上,它们应该适用于早期版本的这两种产品。我很想听听大家关于这方面的经验。

历史

2004 年 4 月 9 日 - 新文章。

© . All rights reserved.