C# 6 and .NET Core 1.0:Modern Cross:Platform Development
上QQ阅读APP看书,第一时间看更新

Interoperating with unmanaged code

.NET applications are loaded, executed, and managed by the CLR. We use the term unmanaged to refer to any code that is outside the control of the CLR.

If a .NET developer needs to interact with unmanaged code, they can use two technologies: Component Object Model (COM) Interop and Platform Invoke (also known as P/Invoke).

Tip

Both of these technologies are specific to Windows and, therefore, are only supported by the .NET Framework, not by the .NET Core.

Automating Microsoft Excel using COM Interop

Most of the popular Microsoft Office products support being automated using COM. If you have Microsoft Excel (for Windows) installed, then you can complete this exercise.

Add a new console application project named Ch05_AutomatingExcel. In the Solution Explorer window, right-click on References and choose Add Reference….

In the Reference Manager window, on the left-hand side, click on COM, and then select the checkbox for Microsoft Excel 16.0 Object Library (or the latest version that you have installed). Click on OK:

At the top of the code, import the following types and namespaces:

using static System.Console;
using static System.Convert;
using Microsoft.Office.Interop.Excel;

In the Main method, enter the following statements:

const int xlPie = 5;
Write("Enter a number: ");
double number = ToDouble(ReadLine());
var excel = new Application();
excel.Visible = true;
excel.Workbooks.Add();
excel.Range["A1"].Value = number;
excel.Range["A2"].Formula = "=A1*2";
excel.Range["A1:A2"].Select();
excel.ActiveSheet.Shapes.AddChart2(251, xlPie).Select();
excel.ActiveChart.SetSourceData(Source: excel.Range["Sheet1!$A$1:$A$2"]);

When you run the console application, it starts Excel, makes it visible (because it runs hidden in the background by default), adds a blank new workbook, sets the cell A1 to contain the number the user entered, doubles it using a formula, then selects the cells and uses the numbers as a source for a pie chart:

Tip

To make it even easier to learn how to automate Excel, switch on the Developer tab in Excel and then use it to record a macro. The code recorded is Visual Basic for Applications, but that is easy to translate to C#.

Accessing the Win32 API with P/Invoke

All Windows applications make calls to the Win32 API to provide their functionality. That's what makes them Windows applications.

Technologies such as .NET are layers on top of the Win32 API. Most of the Win32 API functions have been exposed via .NET types, but not all. If a .NET developer needs to access a Win32 API that isn't already exposed, then they can use P/Invoke.

Add a new console application project named Ch05_HackNotepad. At the top of the file, import the following types and namespaces:

using static System.Console;
using static System.Diagnostics.Process;
using System.Runtime.InteropServices;
using System;

In the Program class, enter the following statements:

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool SetWindowText(IntPtr hwnd, string lpString);

In the Main method, enter the following statements:

Write("Enter a message: ");
string message = ReadLine();
WriteLine("Press any key to start Notepad.");
ReadKey();
Start("notepad.exe").WaitForInputIdle();
// use a Win32 API call to get reference to Notepad
IntPtr notepad = FindWindow("Notepad", null);
if (notepad != IntPtr.Zero)
{
    // if it is running, set it's window text with a message
    SetWindowText(notepad, "Notepad has been hacked! " + message);
}
else
{
    WriteLine("Notepad is not running!");
}

When you run the console application, it prompts the user to enter a message, starts an instance of Notepad, finds the Notepad window, and sets its title to a customized message.

Tip

A more practical example would be impersonating a user other than the current one while executing some statements. To do this, you would need to use P/Invoke to import the LogonUser function from advapi32.dll and the CloseHandle function from kernel32.dll. For more details, visit https://msdn.microsoft.com/en-us/library/w070t6ka(v=vs.110).aspx.