One of the cool new features in the Windows Azure Mix 09 CTP is the ability to run your Web and/or Worker Roles in full trust (non-admin). This opens up all kinds of features that weren’t available in the previous CTPs.
An interesting feature, which is the subject of this post is the ability to make PInvoke calls.
One of the things I have noticed in playing with calling native code is that you have to be more aware of the actual environment in the cloud. For example, Windows Azure in the cloud:
- Runs your Cloud Services on an x64 Operating System. The processes in which your role instances run are 64-bit processes.
- Has the .Net Framework 3.5 SP1 redistributable installed, which includes a subset of the full Microsoft Visual C++ 2008 Redistributable (x64)
I also want to reiterate here that your Role Instances run in separate VMs and those VMs can come and go – it’s important not to count on any file system persistence in the VM.
1. Create a new Web Cloud Service project. File | New | Project. Select Visual C#/VB | Cloud Services | Web Cloud Services
2. Add a project to your solution for your native code. Right click on the Solution Explorer and select Add | New Project…
3. Select “Win32 Project” and call it “NativeCalc”
Setup the win32 project to be a DLL – we’ll just call a simple C function from it. Select “Export symbols”.
3. Open NativeCalc.h and change the dummy fnNativeCalc function to:
NATIVECALC_API int AddNumbers(int left, int right);
Note that the extern “C” specifies to use C linkage convention – what you see for the exported symbol if you used dumpbin – instead of the C++ decorations. This is what PInvoke will look for.
4. Now implement the method in NativeCalc.cpp
NATIVECALC_API int AddNumbers(int left, int right)
return left + right;
5. Next we have to ensure that this DLL is included as part of the Service Package. See this post for more details.
First I set the output directory of the DLL to be in the Web Role project directory.
I build all then right click on the nativeCloudService_WebRole project in Solution Explorer and select Add | Existing Item | NativeCalc.dll
I then set the CopyToOutputDirectory property to “CopyIfnewer”
6. Add a button and a label on default.aspx and in the button handler, set the label to the output of the native call:
static extern int AddNumbers(int left, int right);
protected void Button1_Click(object sender, EventArgs e)
Label1.Text = AddNumbers(2, 3).ToString();
7. Set the enableNativeExecution attribute on the WebRole in the ServiceDefinition.csdef
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="NativeCloudService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="WebRole" enableNativeCodeExecution="true">
8. Run the application and hit the button – everything will work as expected – you just called native code running on Windows Azure!
9. If you want to publish and deploy this to the Cloud – make sure that the native DLL is being built in release mode and is built for x64. See the troubleshooting section below for more details.
Small troubleshooting section:
- If you run and get a SecurityException, you forgot to set the enableNativeCodeExecution attribute to true.
Description: The application attempted to perform an operation not allowed by the security policy. To grant this application the required permission please contact your system administrator or change the application's trust level in the configuration file.
Exception Details: System.Security.SecurityException: System.Security.Permissions.SecurityPermission
When trying in the Cloud:
- If you get an exception: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
- You are trying to PInvoke to a 32-Bit DLL instead of a 64-bit DLL. Remember what I said above: Windows Azure runs your Cloud Service on a 64 Bit Operating System.
- You can solve this by building your DLL for x64. Otherwise, you’ll have to launch a 32-bit process that can make calls into your 32 Bit DLL.
- If you get an exception: Unable to load DLL <DLL>: The application failed to start because its side-by-side configuration is incorrect. Please see the application event log for more detail. (Exception from HRESULT: 0x80073681).
- This could be many things, the most likely one is that you are missing a Visual C++ runtime dll on Windows Azure.
- The most common situation is if you uploaded a debug version of your native code dll – it uses the debug version of the VC++ runtime which has a different name and isn’t available on Windows Azure. To solve this, either build release or deploy any necessary dlls with your Service Package.
Compiling for x64 in Visual Studio related:
- To configure VS to build your NativeCalc DLL as x64, use the Configuration Manager and change the platform to x64. (notable if you are using a 32 bit Operating System)
- In order to be able to compile for x64, you may have to install the x64 compiler. You can do this by going to Add/Remove programs, selecting Visual Studio and adding the “X64 Compiler and Tools” option