.Net Compact Framework开发(5)——P/Invoke和性能测量

  • 要想查看一个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...
  • 在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);
  • 如果在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();
}
  • .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");
   }
}
  • .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;

  • 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();
  • .NET Compact Framework可以跟踪程序运行的一些性能统计信息,包括内存的使用和回收,P/Invoke的次数等;HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETCompactFramework/PerfMonitor注册表下Counters的值决定了是否打开性能统计(0或者没有这个键值意味着关闭);.NET execution engine第一次启动的时候会检查这个键值,对这个键值所作的修改要到下一次启动execution engine才会生效;打开性能统计功能后,会在设备的根目录下生成mscoree.stat性能文件;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值