Making a .NET Windows app without using Visual Studio

Posted on: 2015-12-22

Introduction

If you have any experience working with Windows development, the first thing you may be asking yourself is, why would you want to create Windows applications without using Microsoft Visual Studio? Truthfully, if you aim to become a professional developer, or even wish to get the full experience of the Windows development environment, then you probably don't want to proceed this way. Visual Studio Community is free, integrates with a myriad of things, and tons of people use it. However, there are reasons why you might want to do this. First, maybe you're curious about what really goes on behind the scenes when you press the Build button and wish to see the creation of an app from scratch without anything hidden by the GUI. Maybe you just can't install Visual Studio because of the platform or environment you work on. Or perhaps you just personally hate having to use a 5GB Integrated Development Environment (IDE) to create a 5KB app. Regardless of the reason, if you've always wanted to make a Windows binary but don't want to spend the time to download and learn VS, then read on.


Dependencies

For this tutorial, we're going to use C# with the .NET Framework. So if we aren't going to download Visual Studio, what do we need to create a .NET application? The great news is that as long as you have the Microsoft .NET Framework installed on your system, you don't need anything else! And chances are, you already have it installed, since so many things require it. To find out, go to C:\Windows\Microsoft.NET\Framework and see for yourself. Chances are you have more than one version, too. If you go in one of the sub folders, and for this tutorial we'll use the 3.5 framework, although you can use any version you want, then you will find several binaries.

The .NET Framework actually comes with a C# compiler by default. That means you have a fully functional compiler already on your system, without even knowing it. For our purposes, there are two binaries that we're going to see: csc.exe which is the C# compiler, and msbuild.exe which is the utility that reads Project files (.csproj) and compiles them. That means even if someone sends you a Visual Studio project, you can run msbuild on it and compile the source without ever installing Visual Studio (in most cases).


The structure of a project

Our test app is going to be very simple, so we won't make a project file, but it's good to know the typical structure that starting a new Visual Studio project creates, to help you understand some concepts. When you make a new app, the IDE creates a number of files, based on the type of app you want to make. Typically, these includes Program.cs which is your main C# source code, ProjectName.csproj which contains information about the resources your source depends on, assemblyinfo.cs which contains the binary name, version, copyright and so on, and finally App.config which contains custom configuration.

As I've mentioned, we won't use a project file so we can see exactly how the compiler gets called. The config file is required only if you use a library that depends on it. As one example among many, if you create an app that integrates with the Amazon AWS .NET SDK, it expects some information about your AWS account to be present in that file. The assembly file is fairly small, and we will integrate it in our main source file in a little bit. So now that we have an idea of what a project looks like, let's make our own!


Our console app

Create a new file and call it helloworld.cs. You can save it anywhere you want, and use any text editor. Since you're interested in editing code without using an IDE, I'm going to assume you already have a favorite text editor. In that file, put the following:

using System;

namespace HelloWorld
{
    public class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello world!");
        }
    }
}

As you can see, this is pretty simple code. You could easily write it in a single line. We're not going to cover C# as there are plenty of tutorials online, but basically we're importing a resource, which is the System library that comes by default with Windows, then doing an API call in our main function to the Console.WriteLine method to write text on the screen as soon as the app starts.

Of course, it doesn't do much yet, it's simply a typical sample project that writes Hello world! on the screen, but it's a good starting place. Now, compiling this is just as simple. Locate the compiler binary in the .NET Framework folder from earlier, and specify the output you want with the /out: parameter, followed by the name of your source file in a command prompt. It should parse and create your binary, which you can then run from the command line:

E:\code> C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe /out:helloworld.exe helloworld.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.5420
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.

E:\code> helloworld
Hello world!

E:\code>

Not bad for the creation of a fully functional Windows binary, isn't it? No need for massive tools, wrappers, SDKs, libraries, and so on. Just a text editor and a few lines of code. The resulting binary should be around 4KB which isn't bad either.


Adding assembly information

Open a file browser, locate your new .exe file, and right click on it. Go to Properties, and Details. There, you should see things like File Description, Version and Copyright information. Right now, they are empty. Usually, you fill those in by going in the Visual Studio menus and going through the proper wizard. But we're doing things the fun way, so let's add that in. All of these properties are defined with assembly values.

Edit your helloworld.cs to look like this:

using System;
using System.Reflection;
[assembly: AssemblyTitle("Hello World Application")]
[assembly: AssemblyCopyright("(C) 2015 John Doe")]
[assembly: AssemblyFileVersion("1.0")]

namespace HelloWorld
{
    public class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello world!");
        }
    }
}

As you can see, we added a reference to System.Reflection then a few definitions. Obviously you can use your name here, or type in any values you desire. Save the file and compile it again. Now, when you go right click on your binary, you will see the details filled in.


Our graphical app

You may now be thinking that sure, making console apps is easy, but surely there's no way to create graphical applications without an IDE, right?

Let's upgrade our hello world app to show our message in a graphical fashion. Windows actually has several different libraries to display graphics. Right now, Microsoft is pushing a technology called XAML to create universal apps, which use XML files to define the design of the app. But for now, we'll use Windows Forms, which is the most popular and widely used way to create desktop apps.

Edit your helloworld.cs to look like this:

using System;
using System.Reflection;
using System.Windows.Forms;
[assembly: AssemblyTitle("Hello World Application")]
[assembly: AssemblyCopyright("(C) 2015 John Doe")]
[assembly: AssemblyFileVersion("1.0")]

namespace HelloWorld
{
    public class Program
    {
        static void Main(string[] args)
        {
            MessageBox.Show("Hello world!", "Hi!");
        }
    }
}

As you can see, it's pretty similar to the previous version. All we're doing is importing the System.Windows.Forms library, and making a different API call, this time to the MessageBox.Show method. We've also added a title to the message box, so when you compile and run the app, the window will have a title. Windows handles everything else, from the creation of the graphical window, the close button, centering it in the middle of the screen, etc.

Here's what the result looks like:

You could actually create fully functional UIs with menus, buttons and labels this way, and can find more information about the various API calls on the MSDN Library.

Oh and if you're making an app that only uses the GUI, then you don't need a console. For your compile line, add the parameter /target:winexe just before the name of your source file. That way, when you double click on the app, you won't have an empty console window appearing. This is basically the difference between creating a console app and a Windows Forms app inside of VS, this one little compile option.


Importing third party libraries

You now have a good idea of how the .NET building process occurs, and see that you can create, compile and run .NET apps written in C# on any Windows PC with the Microsoft .NET Framework installed, leveraging the full range of the .NET APIs, without the need for any specific development tool. How useful that knowledge is can be up for debate, but I for one think it's pretty cool.

Now let's see one last option which may be useful should you ever want to use third party libraries. Our compiling has been pretty simple because the libraries we've used so far include solely default Windows API calls. You can do a whole lot with them, but sometimes you may want to use external resources. This also applies if you want to add custom parts, like data files. The way to include such references is with the /r: option. Here's a simple app which sends a SNS notification using the Amazon AWS SDK, just as an example:

using System;
using Amazon;
using Amazon.SimpleNotificationService;
using Amazon.SimpleNotificationService.Model;

namespace AwsSnsSample
{
    class Program
    {
        public static void Main(string[] args)
        {
            var sns = new AmazonSimpleNotificationServiceClient();
            sns.Publish(new PublishRequest
            {
                Subject = "Hi!",
                Message = "Hello world!",
                TopicArn = "arn:aws:sns:us-west-2:0000000000:snstest1"
            });
        }
    }
}

This is only a sample and could benefit from error handling and so on, but it will serve for now. To compile this code, you first need to install the AWS SDK and setup the proper IAM credentials for the message to go through. Then, to compile it, you simply need to reference the right library as part of your command line:

E:\code> C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe /out:helloworld.exe /r:"C:\Program Files (x86)\AWS SDK for .NET\bin\Net35\AWSSDK.dll" helloworld.cs

Visual Studio Code

Recently, Microsoft actually introduced a new version of Visual Studio called Code, which is a lightweight editor that comes without any of the overhead IDE parts. It's around 100MB as opposed to 6GB of the full Community version. This is a perfect text editor to use alongside the knowledge shown here. You can integrate it with Git and use a custom build script with the commands we've seen to compile your code at the touch of a key.


Conclusion

I'm not really expecting professional developers to start doing things manually like this. There are many benefits of using an IDE like Visual Studio, including a graphical form builder, source code control, wizards, and so on. But there are many people out there who aren't full time developers, and who aren't willing or can't setup a full development environment. Yet should you wish to learn a bit of C# and play with the .NET API calls, you can see how trivial it is to create full fledged Windows binaries with just a single command line.

Hopefully you've learned something and found this tutorial entertaining.