- 要想查看一个DLL内的函数名是否被mangle,可以启动一个VS command line,进入DLL文件所在目录,运行DEPENDS [dllname]。所有WinCE OS功能dll都没有对方法名称进行mangle。
- C#中使用DllImport来导入native dll中的函数
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnComputeSquare;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox txtInput;
private System.Windows.Forms.TextBox txtResult;
private System.Windows.Forms.MainMenu mainMenu1;
[DllImport("SquareAnInt.dll")]
private static extern void SquareAnInt(int input,
ref int output);
// The native declaration is SquareAnInt(int, int*)
// Rest of the class declarations deleted for brevity
// ...
// ...
// Usage of the SquareAnInt function occurs as part of
// btnComputeSquare_Click
private void btnComputeSquare_Click(object sender,
System.EventArgs e)
{
int output = 0;
int input = Convert.ToInt32(this.txtInput.Text);
SquareAnInt(input, ref output);
this.txtResult.Text = Convert.ToString(output);
}
// Rest of class cut for brevity...
{
private System.Windows.Forms.Button btnComputeSquare;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox txtInput;
private System.Windows.Forms.TextBox txtResult;
private System.Windows.Forms.MainMenu mainMenu1;
[DllImport("SquareAnInt.dll")]
private static extern void SquareAnInt(int input,
ref int output);
// The native declaration is SquareAnInt(int, int*)
// Rest of the class declarations deleted for brevity
// ...
// ...
// Usage of the SquareAnInt function occurs as part of
// btnComputeSquare_Click
private void btnComputeSquare_Click(object sender,
System.EventArgs e)
{
int output = 0;
int input = Convert.ToInt32(this.txtInput.Text);
SquareAnInt(input, ref output);
this.txtResult.Text = Convert.ToString(output);
}
// Rest of class cut for brevity...
- 在Managed Code和Native Code间传递参数和返回值的过程成为marshalling;在.Net Compact Framework中,只有长度短于32bit的数据对象可以按值传递(否则会得到一个NotSupportedException);
int、uint、short、ushort、char、byte、bool既可以按值传递,也可以按引用传递(native code中的DWORD相当于uint)
[DllImport("Foo.dll")]
private static extern void IntInFunc(int in_Int);
// Usage, where l_Int is an integer
IntInFunc(l_Int)
[DllImport("Foo.dll")]
private static extern void UIntInFunc(uint in_UInt);
// Usage, where l_UInt is an unsigned integer
UIntInFunc(l_UInt);
[DllImport("Foo.dll")]
private static extern void ShortInFunc(short in_Short);
// Usage...
short in_Short = Convert.ToInt16(this.txtShortIn.Text);
ShortInFunc(in_Short);
[DllImport("Foo.dll")]
private static extern void UShortInFunc(ushort in_UShort);
// Usage...
ushort in_UShort = Convert.ToUInt16(this.txtUShortIn.Text);
UShortInFunc(in_UShort);
[DllImport("Foo.dll")]
private static extern void CharInFunc(char in_Char);
// Usage...
char in_Char = Convert.ToChar("C");
CharInFunc(in_Char);
[DllImport("Foo.dll")]
private static extern void ByteInFunc(byte in_Byte);
// Usage...
byte in_Byte = Convert.ToByte(this.txtByteIn.Text);
ByteInFunc(in_Byte);
[DllImport("Foo.dll")]
private static extern void BoolInFunc(bool in_Bool);
// Usage...
bool in_Bool = false;
BoolInFunc(in_Bool, out_StringBuilder);
float、long、ulong只能按引用传递
[DllImport("Foo.dll")]
private static extern void FloatInFunc(ref float in_Float);
// Usage...
float in_Float = 4.00;
FloatInFunc(ref in_Float);
[DllImport("Foo.dll")]
private static extern void LongInFunc(ref long in_Long);
// Usage...
long in_Long = Convert.ToInt64(4);
LongToString(ref in_Long, out_StringBuilder);
[DllImport("FundamentalToString.dll")]
private static extern void ULongToString(ref ulong in_ULong);
// Usage...
ulong in_ULong = Convert.ToUInt64(4);
ULongToString(ref in_ULong, out_StringBuilder);
[DllImport("Foo.dll")]
private static extern void IntInFunc(int in_Int);
// Usage, where l_Int is an integer
IntInFunc(l_Int)
[DllImport("Foo.dll")]
private static extern void UIntInFunc(uint in_UInt);
// Usage, where l_UInt is an unsigned integer
UIntInFunc(l_UInt);
[DllImport("Foo.dll")]
private static extern void ShortInFunc(short in_Short);
// Usage...
short in_Short = Convert.ToInt16(this.txtShortIn.Text);
ShortInFunc(in_Short);
[DllImport("Foo.dll")]
private static extern void UShortInFunc(ushort in_UShort);
// Usage...
ushort in_UShort = Convert.ToUInt16(this.txtUShortIn.Text);
UShortInFunc(in_UShort);
[DllImport("Foo.dll")]
private static extern void CharInFunc(char in_Char);
// Usage...
char in_Char = Convert.ToChar("C");
CharInFunc(in_Char);
[DllImport("Foo.dll")]
private static extern void ByteInFunc(byte in_Byte);
// Usage...
byte in_Byte = Convert.ToByte(this.txtByteIn.Text);
ByteInFunc(in_Byte);
[DllImport("Foo.dll")]
private static extern void BoolInFunc(bool in_Bool);
// Usage...
bool in_Bool = false;
BoolInFunc(in_Bool, out_StringBuilder);
float、long、ulong只能按引用传递
[DllImport("Foo.dll")]
private static extern void FloatInFunc(ref float in_Float);
// Usage...
float in_Float = 4.00;
FloatInFunc(ref in_Float);
[DllImport("Foo.dll")]
private static extern void LongInFunc(ref long in_Long);
// Usage...
long in_Long = Convert.ToInt64(4);
LongToString(ref in_Long, out_StringBuilder);
[DllImport("FundamentalToString.dll")]
private static extern void ULongToString(ref ulong in_ULong);
// Usage...
ulong in_ULong = Convert.ToUInt64(4);
ULongToString(ref in_ULong, out_StringBuilder);
- 如果在native C代码中使用了handle类型的变量,可以向其按值传递IntPtr类型,如果需要传入NULL,可以写成IntPtr.Zero;要想得到IntPtr实际指向的数值,调用IntPtr.ToInt32和IntPtr.ToInt64方法;
- C#中的String可以传递给native C代码中的WCHAR*,这是传递的string对于native是只读的;如果需要可写的功能,请传递StringBuilder类;要得到StringBuilder中的string,可以使用StringBuilder.ToString方法;
// Declaration
[DllImport("FundamentalToString.dll")]
private static extern void IntToString(int in_Int, StringBuilder
out_IntAsString);
// Usage...
private void DoIntConversion()
{
StringBuilder out_StringBuilder = new StringBuilder(MAX_CAPACITY);
int in_Int = Convert.ToInt32(this.txtIntegerIn.Text);
IntToString(in_Int, out_StringBuilder);
this.txtIntegerOut.Text = out_StringBuilder.ToString();
}
[DllImport("FundamentalToString.dll")]
private static extern void IntToString(int in_Int, StringBuilder
out_IntAsString);
// Usage...
private void DoIntConversion()
{
StringBuilder out_StringBuilder = new StringBuilder(MAX_CAPACITY);
int in_Int = Convert.ToInt32(this.txtIntegerIn.Text);
IntToString(in_Int, out_StringBuilder);
this.txtIntegerOut.Text = out_StringBuilder.ToString();
}
- .NET Compact Framework中所有的简单结构都按照引用传递,并且只有内部不含string和嵌套结构的结构可以被自动marshalled;对于无法自动完成的marshall,必须手动添加代码(需要unsafe代码将复杂结构的memory layout调整到和native C代码一样);
///Native Side///
struct AllIntsInside
{
int m_one;
int m_two;
int m_three;
};
struct DeepStruct
{
char * m_message;
AllIntsInside * m_someInts;
};
// Caution! Very unsafe code here used for demonstration purposes only.
// inout_DeepStruct is assumed to exist as a valid pointer, and m_message is a string
// with at least 1 character
void __cdecl ManipulateDeepStruct(DeepStruct * inout_DeepStruct)
{
inout_DeepStruct->m_message[0] = 'H';
inout_DeepStruct->m_someInts->m_one++;
inout_DeepStruct->m_someInts->m_two++;
inout_DeepStruct->m_someInts->m_three++;
}
///C#//
// Puts a null terminator on a string, which makes it usable to
// native c-style code
private char[] NullTerminateString(string in_managedString)
{
in_managedString += "/0";
return (in_managedString.ToCharArray());
}
private unsafe string NativeStringToManaged(char* in_NativeNullTerminatedString)
{
System.Text.StringBuilder l_SB = new System.Text.StringBuilder(100);
int i = 0;
while (in_NativeNullTerminatedString[i] != '/0')
{
char[] l_toInsert = new char[1];
l_toInsert[0] = in_NativeNullTerminatedString[i];
l_SB.Insert(i, l_toInsert);
i++;
}
return l_SB.ToString();
}
[DllImport("ManipulateStruct.dll")]
private static extern void ManipulateDeepStruct(ref DeepStruct
inout_ShallowStruct);
public struct AllIntsInside
{
public int m_one;
public int m_two;
public int m_three;
}
public unsafe struct DeepStruct
{
public char * m_message;
public AllIntsInside * m_someInts;
}
DeepStruct l_DeepStruct;
l_DeepStruct = new DeepStruct();
char [] l_messageBuffer = NullTerminateString(" ello World!");
AllIntsInside l_Ints = new AllIntsInside();
l_Ints.m_one = 1;
l_Ints.m_two = 2;
l_Ints.m_three = 3;
unsafe
{
fixed (char * l_ptrMessageBuf = &l_messageBuffer[0])
{
l_DeepStruct.m_message = l_ptrMessageBuf;
l_DeepStruct.m_someInts = &l_Ints;
MessageBox.Show(NativeStringToManaged(l_DeepStruct.m_message), "BEFORE P/INVOKE");
String l_IntValuesString = "Int Values: "
+ Convert.ToString(l_DeepStruct.m_someInts->m_one)
+ "," + Convert.ToString(l_DeepStruct.m_someInts->m_two) + ","
+ Convert.ToString(l_DeepStruct.m_someInts->m_three);
MessageBox.Show(l_IntValuesString, "BEFORE P/INVOKE");
//call native func
ManipulateDeepStruct(ref l_DeepStruct);
MessageBox.Show(NativeStringToManaged(l_DeepStruct.m_message), "AFTER P/INVOKE");
l_IntValuesString = "Int Values: "
+ Convert.ToString(l_DeepStruct.m_someInts->m_one) + ","
+ Convert.ToString(l_DeepStruct.m_someInts->m_two) + ","
+ Convert.ToString(l_DeepStruct.m_someInts->m_three);
MessageBox.Show(l_IntValuesString, "AFTER P/INVOKE");
}
}
struct AllIntsInside
{
int m_one;
int m_two;
int m_three;
};
struct DeepStruct
{
char * m_message;
AllIntsInside * m_someInts;
};
// Caution! Very unsafe code here used for demonstration purposes only.
// inout_DeepStruct is assumed to exist as a valid pointer, and m_message is a string
// with at least 1 character
void __cdecl ManipulateDeepStruct(DeepStruct * inout_DeepStruct)
{
inout_DeepStruct->m_message[0] = 'H';
inout_DeepStruct->m_someInts->m_one++;
inout_DeepStruct->m_someInts->m_two++;
inout_DeepStruct->m_someInts->m_three++;
}
///C#//
// Puts a null terminator on a string, which makes it usable to
// native c-style code
private char[] NullTerminateString(string in_managedString)
{
in_managedString += "/0";
return (in_managedString.ToCharArray());
}
private unsafe string NativeStringToManaged(char* in_NativeNullTerminatedString)
{
System.Text.StringBuilder l_SB = new System.Text.StringBuilder(100);
int i = 0;
while (in_NativeNullTerminatedString[i] != '/0')
{
char[] l_toInsert = new char[1];
l_toInsert[0] = in_NativeNullTerminatedString[i];
l_SB.Insert(i, l_toInsert);
i++;
}
return l_SB.ToString();
}
[DllImport("ManipulateStruct.dll")]
private static extern void ManipulateDeepStruct(ref DeepStruct
inout_ShallowStruct);
public struct AllIntsInside
{
public int m_one;
public int m_two;
public int m_three;
}
public unsafe struct DeepStruct
{
public char * m_message;
public AllIntsInside * m_someInts;
}
DeepStruct l_DeepStruct;
l_DeepStruct = new DeepStruct();
char [] l_messageBuffer = NullTerminateString(" ello World!");
AllIntsInside l_Ints = new AllIntsInside();
l_Ints.m_one = 1;
l_Ints.m_two = 2;
l_Ints.m_three = 3;
unsafe
{
fixed (char * l_ptrMessageBuf = &l_messageBuffer[0])
{
l_DeepStruct.m_message = l_ptrMessageBuf;
l_DeepStruct.m_someInts = &l_Ints;
MessageBox.Show(NativeStringToManaged(l_DeepStruct.m_message), "BEFORE P/INVOKE");
String l_IntValuesString = "Int Values: "
+ Convert.ToString(l_DeepStruct.m_someInts->m_one)
+ "," + Convert.ToString(l_DeepStruct.m_someInts->m_two) + ","
+ Convert.ToString(l_DeepStruct.m_someInts->m_three);
MessageBox.Show(l_IntValuesString, "BEFORE P/INVOKE");
//call native func
ManipulateDeepStruct(ref l_DeepStruct);
MessageBox.Show(NativeStringToManaged(l_DeepStruct.m_message), "AFTER P/INVOKE");
l_IntValuesString = "Int Values: "
+ Convert.ToString(l_DeepStruct.m_someInts->m_one) + ","
+ Convert.ToString(l_DeepStruct.m_someInts->m_two) + ","
+ Convert.ToString(l_DeepStruct.m_someInts->m_three);
MessageBox.Show(l_IntValuesString, "AFTER P/INVOKE");
}
}
- .NET Compact Framework一般使用OS API来完成加密、解密、访问注册表、播放声音、进行高级的图像操作;
- .NET提供了System.Environment.TickCount来估算计算系统的时间,单位ms;
XmlDocument dom = new XmlDocument();
int startTime = System.Environment.TickCount;
dom.Load("test.xml");
int executionTime = System.Environment.TickCount - startTime;
int startTime = System.Environment.TickCount;
dom.Load("test.xml");
int executionTime = System.Environment.TickCount - startTime;
- QueryPerformanceCounter可以用于提供精确的计时,如果处理器提供了一个高精确度的性能计数器,QueryPerformanceFrequency方法可用于获取计数器每秒的计数次数;(这是Native API)
public sealed class StopWatch {
// Native Methods
[DllImport("coredll.dll")]
public static extern bool QueryPerformanceCounter(out long c);
[DllImport("coredll.dll")]
public static extern bool QueryPerformanceFrequency(out long c);
// Static data
static long frequency;
static bool perfCounterSupported;
// Instance Data
long startTime = 0;
// Initialize the counter frequency static
static StopWatch() {
perfCounterSupported = QueryPerformanceFrequency (out frequency);
}
// Start the StopWatch
public void Start() {
startTime = TickCount;
}
// Stop the StopWatch
public long Stop() {
if(perfCounterSupported)
return (long)((float)(TickCount-startTime)/frequency)*1000;
else
return (TickCount - startTime);
}
// Get the current tick count
public static long TickCount {
get {
long val;
bool perfCounterSupported = QueryPerformanceCounter(out val);
if (perfCounterSupported)
return val;
else
return (long)System.Environment.TickCount;
}
}
}
StopWatch timer = new StopWatch();
timer.Start();
Thread.Sleep(1000);
long elapseTime = timer.Stop();
// Native Methods
[DllImport("coredll.dll")]
public static extern bool QueryPerformanceCounter(out long c);
[DllImport("coredll.dll")]
public static extern bool QueryPerformanceFrequency(out long c);
// Static data
static long frequency;
static bool perfCounterSupported;
// Instance Data
long startTime = 0;
// Initialize the counter frequency static
static StopWatch() {
perfCounterSupported = QueryPerformanceFrequency (out frequency);
}
// Start the StopWatch
public void Start() {
startTime = TickCount;
}
// Stop the StopWatch
public long Stop() {
if(perfCounterSupported)
return (long)((float)(TickCount-startTime)/frequency)*1000;
else
return (TickCount - startTime);
}
// Get the current tick count
public static long TickCount {
get {
long val;
bool perfCounterSupported = QueryPerformanceCounter(out val);
if (perfCounterSupported)
return val;
else
return (long)System.Environment.TickCount;
}
}
}
StopWatch timer = new StopWatch();
timer.Start();
Thread.Sleep(1000);
long elapseTime = timer.Stop();
- .NET Compact Framework可以跟踪程序运行的一些性能统计信息,包括内存的使用和回收,P/Invoke的次数等;HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETCompactFramework/PerfMonitor注册表下Counters的值决定了是否打开性能统计(0或者没有这个键值意味着关闭);.NET execution engine第一次启动的时候会检查这个键值,对这个键值所作的修改要到下一次启动execution engine才会生效;打开性能统计功能后,会在设备的根目录下生成mscoree.stat性能文件;