Posted by: Zeeshan Amjad | November 10, 2009

Calling Assembly Language from WPF Program


We can’t directly call Assembly language from WPF program. But we can do this indirectly. We can easily call the assembly language from any VC++ unmanaged program and make a DLL of it and export it as a C functions. After that we can call the functions of that DLL just like we call the windows API.

Now lets take a look at the example. First we are going to make a simple DLL, which export C function and uses inline assembly. We have 5 function to perform some low level work for us. Here is a header file of our DLL.

  1: 
  2: #ifndef __SYSINFO_H
  3: #define __SYSINFO_H
  4: 
  5: extern "C" __declspec(dllexport) int __stdcall getCPUSpeed();
  6: extern "C" __declspec(dllexport) char* __stdcall getCPUType();
  7: extern "C" __declspec(dllexport) int __stdcall getCPUFamily();
  8: extern "C" __declspec(dllexport) int __stdcall getCPUModel();
  9: extern "C" __declspec(dllexport) int __stdcall getCPUStepping();
 10: 
 11: #endif
 12: 

Here is a implementation of these function. Here we have some low level assembly language work.

  1: #include "SysInfo.h"
  2: #include <windows.h>
  3: 
  4: BOOL __stdcall DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved) 
  5: {
  6: 	return  TRUE;
  7: }
  8: 
  9: extern "C" __declspec(dllexport) int __stdcall getCPUSpeed() 
 10: {
 11: 	LARGE_INTEGER ulFreq, ulTicks, ulValue, ulStartCounter, ulEAX_EDX, ulResult;
 12: 
 13: 	// it is number of ticks per seconds
 14: 	QueryPerformanceFrequency(&ulFreq);
 15: 
 16: 	// current valueofthe performance counter
 17: 	QueryPerformanceCounter(&ulTicks);
 18: 
 19: 	// calculate one second interval
 20: 	ulValue.QuadPart = ulTicks.QuadPart + ulFreq.QuadPart;
 21: 
 22: 	// read time stamp counter
 23: 	// this asm instruction load the highorder 32 bit of the register into EDX
 24: 	// and the lower order 32 bits into EAX
 25: 	_asm 
 26: 	{
 27: 		rdtsc
 28: 		mov ulEAX_EDX.LowPart, EAX
 29: 		mov ulEAX_EDX.HighPart, EDX
 30: 	}
 31: 
 32: 	// start no of ticks
 33: 	ulStartCounter.QuadPart = ulEAX_EDX.QuadPart;
 34: 
 35: 	// loop for 1 second
 36: 	do {
 37: 		QueryPerformanceCounter(&ulTicks);
 38: 	} while (ulTicks.QuadPart <= ulValue.QuadPart);
 39: 
 40: 	// get the actual no of ticks
 41: 	_asm {
 42: 		rdtsc
 43: 		mov ulEAX_EDX.LowPart, EAX
 44: 		mov ulEAX_EDX.HighPart, EDX
 45: 	}
 46: 
 47: 	// calculate result
 48: 	ulResult.QuadPart = ulEAX_EDX.QuadPart - ulStartCounter.QuadPart;
 49: 
 50: 	return (int)ulResult.QuadPart / 1000000;
 51: }
 52: 
 53: extern "C" __declspec(dllexport) char* __stdcall getCPUType() 
 54: {
 55: 	static char pszCPUType[13];
 56: 	memset(pszCPUType, 0, 13);
 57: 
 58: 	_asm 
 59: 	{
 60: 		mov eax, 0
 61: 		cpuid
 62: 
 63: 		// getting information from EBX
 64: 		mov pszCPUType[0], bl
 65: 		mov pszCPUType[1], bh
 66: 
 67: 		ror  ebx, 16
 68: 		mov pszCPUType[2], bl
 69: 		mov pszCPUType[3], bh
 70: 
 71: 		// getting information from EDX
 72: 		mov pszCPUType[4], dl
 73: 		mov pszCPUType[5], dh
 74: 
 75: 		ror  edx, 16
 76: 		mov pszCPUType[6], dl
 77: 		mov pszCPUType[7], dh
 78: 
 79: 		// getting information from ECX
 80: 		mov pszCPUType[8], cl
 81: 		mov pszCPUType[9], ch
 82: 
 83: 		ror  ecx, 16
 84: 		mov pszCPUType[10], cl
 85: 		mov pszCPUType[11], ch
 86: 	}
 87: 
 88: 	pszCPUType[12] = '';
 89: 
 90: 	return pszCPUType;
 91: }
 92: 
 93: extern "C" __declspec(dllexport) int __stdcall getCPUFamily() 
 94: {
 95: 	int retVal;
 96: 
 97: 	_asm {
 98: 		mov eax, 1
 99: 		cpuid
100: 		mov retVal, eax
101: 	}
102: 
103: 	return (retVal >> 8);
104: }
105: 
106: extern "C" __declspec(dllexport) int __stdcall getCPUModel() 
107: {
108: 	int retVal;
109: 
110: 	_asm {
111: 		mov eax, 1
112: 		cpuid
113: 		mov retVal, eax
114: 	}
115: 
116: 	return ((retVal >> 4 ) & 0x0000000f);
117: }
118: 
119: extern "C" __declspec(dllexport) int __stdcall getCPUStepping() 
120: {
121: 	int retVal;
122: 
123: 	_asm {
124: 		mov eax, 1
125: 		cpuid
126: 		mov retVal, eax
127: 	}
128: 
129: 	return (retVal & 0x0000000f);
130: }
131: 

Now we are going to call these function just like Windows API using the PInvoke functionality. Here is a XAML file for the client of this DLL.

  1: <Window x:Class="AsmWpf.Window1"
  2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4:     Title="Assembly Language from WPF" Height="300" Width="400" Background="AliceBlue" Loaded="Window_Loaded">
  5:     <Grid>
  6:         <Grid.RowDefinitions>
  7:             <RowDefinition/>
  8:             <RowDefinition/>
  9:             <RowDefinition/>
 10:             <RowDefinition/>
 11:             <RowDefinition/>
 12:             <RowDefinition/>
 13:         </Grid.RowDefinitions>
 14:         
 15:         <Grid.ColumnDefinitions>
 16:             <ColumnDefinition/>
 17:             <ColumnDefinition/>
 18:         </Grid.ColumnDefinitions>
 19:         
 20:         <TextBlock Grid.Column="0" Grid.Row="0" Margin="5" VerticalAlignment="Center">
 21:             Computer Speed
 22:         </TextBlock>
 23:         <TextBlock Grid.Column="1" Grid.Row="0" Margin="5" VerticalAlignment="Center" Name="txtSpeed"/>
 24:         <TextBlock Grid.Column="0" Grid.Row="1" Margin="5" VerticalAlignment="Center">
 25:             Vendor Name
 26:         </TextBlock>
 27:         <TextBlock Grid.Column="1" Grid.Row="1" Margin="5" VerticalAlignment="Center" Name="txtVendor"/>
 28:         <TextBlock Grid.Column="0" Grid.Row="2" Margin="5" VerticalAlignment="Center">
 29:             Family
 30:         </TextBlock>
 31:         <TextBlock Grid.Column="1" Grid.Row="2" Margin="5" VerticalAlignment="Center" Name="txtFamily"/>
 32:         <TextBlock Grid.Column="0" Grid.Row="3" Margin="5" VerticalAlignment="Center">
 33:             Model
 34:         </TextBlock>
 35:         <TextBlock Grid.Column="1" Grid.Row="3" Margin="5" VerticalAlignment="Center" Name="txtModel"/>
 36:         <TextBlock Grid.Column="0" Grid.Row="4" Margin="5" VerticalAlignment="Center">
 37:             Stepping
 38:         </TextBlock>
 39:         <TextBlock Grid.Column="1" Grid.Row="4" Margin="5" VerticalAlignment="Center" Name="txtStepping"/>
 40:         <Button Grid.Column="0" Grid.Row="5" Grid.ColumnSpan="2" Width="75" Margin="5" Name="btnExit" Click="btnExit_Click">
 41:             Exit
 42:         </Button>
 43:     </Grid>
 44: </Window>
 45: 

The C# code of this project is very easy. We just define the signature of our exported function and call them one by one.

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: using System.Windows;
  6: using System.Windows.Controls;
  7: using System.Windows.Data;
  8: using System.Windows.Documents;
  9: using System.Windows.Input;
 10: using System.Windows.Media;
 11: using System.Windows.Media.Imaging;
 12: using System.Windows.Navigation;
 13: using System.Windows.Shapes;
 14: using System.Runtime.InteropServices;
 15: 
 16: namespace AsmWpf
 17: {
 18:     /// <summary>
 19:     /// Interaction logic for Window1.xaml
 20:     /// </summary>
 21:     public partial class Window1 : Window
 22:     {
 23:         [DllImport("SysInfo.dll")]
 24:         static extern int getCPUSpeed();
 25: 
 26:         [DllImport("SysInfo.dll")]
 27:         static extern string getCPUType();
 28: 
 29:         [DllImport("SysInfo.dll")]
 30:         static extern int getCPUFamily();
 31: 
 32:         [DllImport("SysInfo.dll")]
 33:         static extern int getCPUModel();
 34: 
 35:         [DllImport("SysInfo.dll")]
 36:         static extern int getCPUStepping();
 37: 
 38:         public Window1()
 39:         {
 40:             InitializeComponent();
 41:         }
 42: 
 43:         private void Window_Loaded(object sender, RoutedEventArgs e)
 44:         {
 45:             try
 46:             {
 47:                 txtSpeed.Text = getCPUSpeed().ToString();
 48:                 txtVendor.Text = getCPUType();
 49:                 txtFamily.Text = getCPUFamily().ToString();
 50:                 txtModel.Text = getCPUModel().ToString();
 51:                 txtStepping.Text = getCPUStepping().ToString();
 52:             }
 53:             catch (DllNotFoundException ex)
 54:             {
 55:                 MessageBox.Show(ex.Message);
 56:             }
 57:             catch (EntryPointNotFoundException ex)
 58:             {
 59:                 MessageBox.Show(ex.Message);
 60:             }
 61:         }
 62: 
 63:         private void btnExit_Click(object sender, RoutedEventArgs e)
 64:         {
 65:             Close();
 66:         }
 67:     }
 68: }
 69: 

Here is the output of this program.

AsmWpf

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: