6.5. 如何获得系统还有多少可用内存?
您可以调用GetSystemMemoryDivision和GlobalMemorySystem函,数获得程序和存储器间有多少内存是隔离的和已经分配的。
参数的说明可以在API参考文档中找到。
//C#
using System.Runtime.InteropServices;
public class MEMORYSTATUS
{
public uint dwLength;
public uint dwMemoryLoad;
public uint dwTotalPhys;
public uint dwAvailPhys;
public uint dwTotalPageFile;
public uint dwAvailPageFile;
public uint dwTotalVirtual;
public uint dwAvailVirtual;
}
[DllImport("CoreDll.dll")]
public static extern void GlobalMemoryStatus
(
MEMORYSTATUS lpBuffer
);
[DllImport("CoreDll.dll")]
public static extern int GetSystemMemoryDivision
(
ref uint lpdwStorePages,
ref uint lpdwRamPages,
ref uint lpdwPageSize
);
public void Test()
{
uint storePages = 0;
uint ramPages = 0;
uint pageSize = 0;
int res = GetSystemMemoryDivision(ref storePages, ref ramPages, ref pageSize);
MEMORYSTATUS memStatus = new MEMORYSTATUS();
GlobalMemoryStatus(memStatus);
}
'VB
Imports System.Runtime.InteropServices
Public Structure MEMORYSTATUS
Public dwLength As UInt32
Public dwMemoryLoad As UInt32
Public dwTotalPhys As UInt32
Public dwAvailPhys As UInt32
Public dwTotalPageFile As UInt32
Public dwAvailPageFile As UInt32
Public dwTotalVirtual As UInt32
Public dwAvailVirtual As UInt32
End Structure 'MEMORYSTATUS
_
Private Shared Sub GlobalMemoryStatus(ByRef ms As MEMORYSTATUS)
End Sub
_
Public Shared Function GetSystemMemoryDivision( _
ByRef lpdwStorePages As UInt32, _
ByRef lpdwRamPages As UInt32, _
ByRef lpdwPageSize As UInt32) As Integer
End Function
Public Shared Sub Test()
Dim storePages As UInt32
Dim ramPages As UInt32
Dim pageSize As UInt32
Dim res As Integer = GetSystemMemoryDivision(storePages, ramPages, pageSize)
Dim memStatus As New MEMORYSTATUS
GlobalMemoryStatus(memStatus)
End Sub 'Test
6.6. 如何是窗口一直保持最小化?
继承窗体的OnGotFocus方法。
找到窗体的窗口句柄。
调用ShowWindow(hwnd, SW_MINIMIZE)强制窗体最小化。
//C#
using System.Runtime.InteropServices;
[DllImport("CoreDll")]
public static extern IntPtr FindWindow(string className,string WindowsName);
[DllImport("CoreDll")]
public static extern bool ShowWindow(IntPtr hwnd,int nCmdShow);
const int SW_MINIMIZE = 6;
protected override void OnGotFocus(EventArgs e)
{
IntPtr hwnd = FindWindow(null, this.Text);
ShowWindow(hwnd, SW_MINIMIZE);
base.OnGotFocus(e);
}
'VB
Imports System.Runtime.InteropServices
_
Public Shared Function FindWindow(ByVal className As String, ByVal WindowsName As String) As IntPtr
End Function
_
Public Shared Function ShowWindow(ByVal hwnd As IntPtr,ByVal nCmdShow As Integer) As Boolean
End Function
Private Const SW_MINIMIZE As Integer = 6
Protected Overrides Sub OnGotFocus(ByVal e As EventArgs)
Dim hwnd As IntPtr = FindWindow(Nothing, Me.Text)
ShowWindow(hwnd, SW_MINIMIZE)
MyBase.OnGotFocus(e)
End Sub 'OnGotFocus
6.7. 在微软.net精简框架上调用系统函数时,如何装配数据类型?
见本问答的 "6.1. 如何调用本地写的DLL中的函数? " 章节。
6.8. 如何得到一个窗体或控件的句柄 (HWND) ?
其实有一些使用调用本地代码的方法可以获得控件的句柄HWND。下面列出其中两种,一种使用GetCapture,另一个使用FindWindow。
//C#
[DllImport("coredll.dll"]
public static extern IntPtr GetCapture();
[DllImport("coredll.dll")]
public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
this.Text = "FindMe";
IntPtr hwnd1 = FindWindow(null, "FindMe");
this.Capture = true;
IntPtr hwnd2 = GetCapture();
this.Capture = false;
'VB
_
Public Shared Function GetCapture() As IntPtr
End Function
_
Public Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
End Function
Me.Text = "FindMe"
Dim deskWin As IntPtr = FindWindow(Nothing, "FindMe")
Me.Capture = True
Dim hwnd As IntPtr = GetCapture()
Me.Capture = False
6.9. 如何使用性能计数器功能?
使用QueryPerformanceFrequency函数和QueryPerformanceCounter函数可以建立精确的计时程序。这些功能是和设备提供商相关的,如果他们不能执行,那么只能和GetTickCount功能得到一样的结果。如果能执行这些函数,就能保证计时器最准确的运行,比GetTickCounter或Environment.TickCount准确得多。TickCount其实是调用 GetTickCounter的。
如果性能计数器是GetTickCount的一个实例,QueryPerformanceFrequency将把1000作为计时频率。如果这些函数不能执行,将得到返回值为0。以下代码演示了如何使用这些函数。
//C#
[DllImport("CoreDll.dll")]
public static extern int QueryPerformanceFrequency(ref Int64 lpFrequency);
[DllImport("CoreDll.dll")]
public static extern int QueryPerformanceCounter(ref Int64 lpPerformanceCount);
private void TestTimer()
{
System.Int64 freq = 0;
if (QueryPerformanceFrequency(ref freq) != 0)
{
System.Int64 count1 = 0;
System.Int64 count2 = 0;
if (QueryPerformanceCounter(ref count1) != 0)
{
System.Threading.Thread.Sleep(1200);
QueryPerformanceCounter(ref count2);
System.Int64 time_ms = (count2 - count1) * 1000 / freq;
}
}
}
'VB
_
Public Shared Function QueryPerformanceFrequency(ByRef lpFrequency As Int64) As Integer
End Function
_
Public Shared Function QueryPerformanceCounter(ByRef lpPerformanceCount As Int64) As Integer
End Function
Private Sub TestTimer()
Dim freq As System.Int64 = 0
If QueryPerformanceFrequency(freq) <> 0 Then
Dim count1 As System.Int64 = 0
Dim count2 As System.Int64 = 0
If QueryPerformanceCounter(count1) <> 0 Then
System.Threading.Thread.Sleep(1200)
QueryPerformanceCounter(count2)
Dim time_ms As System.Int64 = (count2 - count1) * 1000 / freq
End If
End If
End Sub 'TestTimer
6.10. 调用本地代码时,数据类型有什么限制?What are the limitations on marshalling types via P/Invoke?
返回值
只能是长度小于等于32位的类型
非浮点型not floating point
参数
Only support marshaling blittable types
blittable types -> same representation in memory in both managed and native
non-blittable -> memory transformation required
Since only blittable types, all objects are pinned and never copied
Exception: passing String ByVal in VB.NET
Implies that you can't marshal nested objects since this requires a memory transformation (non-blittable)
只能是长度小于等于32位的类型
值通过堆栈传递
例外:float32
参考(References)
Pass blittable reference types
把参考传递到值类型变量
这就是如何传递float32类型的值
可以传递值类型的数组
在本地代码中,您可以使用指针指向第一个对象,然后一个接一个地访问其他对象
String是特殊的,传递char数组 -> 不变的
StringBuilder是特殊的,传递char数组 -> 易变的 (需要单独传递长度)
注意:C# bool是8个比特位的,并且不等于Win32的BOOL
队列:编译器默认的队列 (4字节)
Marshal.GetLastWin32Error 支持 GetLastError() 语义
未支持的:
MarshalAs: no support for non-blittable types
StructLayout: 不能改变外观
Delegates(委托)
DateTime
Only support default calling convention
6.11. 调用GetLastError时,总是获得不定的代码?
尽量不要尝试调用Windows GetLastError() API,因为CLR调用本地代码时可能会改变last error的代码。取而代之的是,使用调用的返回值标记错误代码,再调用System.Runtime.InteropServices.Marshal.GetLastWin32Error()方法来获得错误代码。
using System.Runtime.InteropServices;
[DllImport("coredll.dll", SetLastError=true)]
int myFoo(...);
Foo(...)
{
int rc = myFoo(...);
if (rc == false)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "Foo failed");
}
}
6.12. 调用本地代码时,有没有参数数量的限制?
有限制。.net精简框架版本1.0的限制为12个。
6.13. 调用本地代码时,为什么得到"NotSupportedException"异常?
通常有三种可能性:
在托管代码中的申明不正确
.net精简框架不支持你想做的操作
dll的名称在暴露过程中损坏了
检查以下项目:
有没有违反.net精简框架 P/Invoke(调用)的限制?
有没有参数需要预先分配内存(如,是不是指针)? 如果是的,您应该传递已经存在的变量的参考。
暴露的函数名是否正确? 可以用DUMPBIN.EXE工具来验证
是不是想尝试太多的参数?
例如,针对上面的第二点,RegOpenKey API的最后一个参数HKEY的指针。您应该这样申明和调用:
//C#
[DllImport("coredll.dll", SetLastError=true)]
public static extern long RegOpenKey(
IntPtr hkey,
string lpSubKey,
ref IntPtr hkeyResult
);
public long OpenMySubKey()
{
IntPtr hkey = IntPtr.Zero;
return RegOpenKey(HKEY_CLASSES_ROOT, "MySubKey", ref hkey);
}
'VB
_
Public Shared Function RegOpenKey(ByVal hkey As IntPtr, ByVal lpSubKey As String, ByRef hkeyResult As IntPtr) As Long
End Function
Public Function OpenMySubKey() As Long
Dim hkey As IntPtr = IntPtr.Zero
Return RegOpenKey(HKEY_CLASSES_ROOT, "MySubKey", hkey)
End Function 'OpenMySubKey
6.14. 如何把 byte[] 转换成 IntPtr?
有不止一种的方法访问IntPtr。
第一种方法,使用非安全代码,直接用指针指向byte数组。
//C#
unsafe
{
byte[] test = new byte[5];
fixed (byte* p = &test[0])
{
*p = 0xff;
}
}
也可以使用GCHandle指向对象。
//C#
using System.Runtime.InteropServices;
byte[] test = new byte[5];
GCHandle hObject = GCHandle.Alloc(test, GCHandleType.Pinned);
IntPtr pObject = hObject.AddrOfPinnedObject();
if(hObject.IsAllocated)
hObject.Free();
'VB
Imports System.Runtime.InteropServices
Dim test(4) As Byte
Dim hObject As GCHandle = GCHandle.Alloc(test, GCHandleType.Pinned)
Dim pObject As IntPtr = hObject.AddrOfPinnedObject()
If hObject.IsAllocated Then
hObject.Free()
End If
最后,可以使用LocalAlloc和Marshalling函数复制内存块得到数据块。
//C#
[DllImport("coredll.dll",SetLastError=true)]
public static extern IntPtr LocalAlloc(uint uFlags, uint uBytes);
[DllImport("coredll.dll",SetLastError=true)]
public static extern IntPtr LocalFree(IntPtr hMem);
[DllImport("coredll.dll",SetLastError=true)]
public static extern IntPtr LocalReAlloc(IntPtr hMem, uint uBytes, uint fuFlags);
public const uint LMEM_FIXED = 0;
public const uint LMEM_MOVEABLE = 2;
public const uint LMEM_ZEROINIT = 0x0040;
byte[] test = new byte[5];
IntPtr p = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, (uint)test.Length);
if (p == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
else
{
Marshal.Copy(test, 0, p, test.Length);
}
'VB
_
Public Shared Function LocalAlloc(ByVal uFlags As UInt32, ByVal uBytes As UInt32) As IntPtr
End Function
_
Public Shared Function LocalFree(ByVal hMem As IntPtr) As IntPtr
End Function
_
Public Shared Function LocalReAlloc(ByVal hMem As IntPtr, ByVal uBytes As UInt32, ByVal fuFlags As UInt32) As IntPtr
End Function
Public Const LMEM_FIXED As Integer = 0
Public Const LMEM_MOVEABLE As Integer = 2
Public Const LMEM_ZEROINIT As Integer = &H40
Dim test(4) As Byte
Dim p As IntPtr = LocalAlloc(Convert.ToUInt32(LMEM_FIXED Or LMEM_ZEROINIT), Convert.ToUInt32(test.Length))
If p.Equals(IntPtr.Zero) Then
Throw New OutOfMemoryException
Else
Marshal.Copy(test, 0, p, test.Length)
End If
6.15. Why do I get a MissingMethodException when I call a function from a native DLL?
There are several issues to consider when determining the case of a MissingMethodException. When this exception occurs you should verify the following:
If targeting Pocket PC 2003 use Microsoft eMbedded Visual C++ 4.0.
If targeting Pocket PC 2000 or 2002 use Microsoft eMbedded Visual Tools 3.0
Verify that the parameters to the function match those of the original
A long in native code is typically 32-bits, whereas in the .NET Compact Framework it is 64-bits
Beware of bool
According to MSDN documentation, "Its size is unspecified.":
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vccelng4/html/ellrffundamentaltypes.asp
In a Microsoft specific section of the MSDN documentation, the bool size is described as varying depending on the version of Visual C++ used to build the binary.:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vccelng4/html/ellrfbool.asp
A BOOL is defined as an int (32-bit value)
.NET Compact Framework Blittable Types:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vccelng4/html/ellrffundamentaltypes.asp
Non Blittable Types and Marshaling Support:
http://msdn.microsoft.com/library/en-us/dv_evtuv/html/etconNonBlittableTypesMarshalingSupport.asp
Make sure that the function name is spelled correctly
Verify that the DLL is located correctly - Windows or executing folder of target device
Verify with DUMPBIN that the names of the functions were not mangled on exporting of the DLL (extern "C" fixes this). More information on this topic can be found in section "6.1. How do I call a function that is in a native DLL?" of this FAQ.
Verify that the DLL being imported is not dependant upon other DLLs. A missing dependant DLL will result in the MissingMethodException.
For the latest Microsoft eMbedded Visual Tools and SDK downloads, visit the MSDN Mobile and Embedded Developer Center "Products & Updates" download page at:
http://msdn.microsoft.com/mobility/downloads/updates/default.aspx
6.16. How do I set the system time?
You can set the system time by P/Invoking the SetSystemTime function.
//C#
using System.Runtime.InteropServices;
public struct SYSTEMTIME
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}
[DllImport("coredll.dll")]
public extern static void GetSystemTime(ref SYSTEMTIME lpSystemTime);
[DllImport("coredll.dll")]
public extern static uint SetSystemTime(ref SYSTEMTIME lpSystemTime);
// Set the clock ahead one hour
SYSTEMTIME st = new SYSTEMTIME();
GetSystemTime(ref st);
st.wHour = (ushort)(st.wHour + 1 % 24);
SetSystemTime(ref st);
'VB
Imports System.Runtime.InteropServices
Public Structure SYSTEMTIME
Public wYear As UInt16
Public wMonth As UInt16
Public wDayOfWeek As UInt16
Public wDay As UInt16
Public wHour As UInt16
Public wMinute As UInt16
Public wSecond As UInt16
Public wMilliseconds As UInt16
End Structure
_
Public Shared Sub GetSystemTime(ByRef lpSystemTime As SYSTEMTIME)
End Sub
_
Public Shared Function SetSystemTime(ByRef lpSystemTime As SYSTEMTIME) As UInt32
End Function
'Set the clock ahead one hour
Dim st As New SYSTEMTIME
GetSystemTime(st)
st.wHour = Convert.ToUInt16(((Convert.ToInt32(st.wHour) + 1)) Mod 24)
SetSystemTime(st)
6.17. How do I programmatically soft reset the device?
The device can be soft reset through P/Invoking of the KernelIoControl function, as demonstrated in the code below. For more information on how to use the function and extend the functionality of this sample, refer to Visual Studio .NET Help.
Note: On Smartphone devices, this will only work if you are signed with a privileged certificate.
//C#
using System.Runtime.InteropServices;
public const uint FILE_DEVICE_HAL = 0x00000101;
public const uint METHOD_BUFFERED = 0;
public const uint FILE_ANY_ACCESS = 0;
public uint CTL_CODE(uint DeviceType, uint Function, uint Method, uint Access)
{
return ((DeviceType << 16) | (Access << 14) | (Function << 2) | Method);
}
[DllImport("Coredll.dll")]
public extern static uint KernelIoControl
(
uint dwIoControlCode,
IntPtr lpInBuf,
uint nInBufSize,
IntPtr lpOutBuf,
uint nOutBufSize,
ref uint lpBytesReturned
);
uint ResetPocketPC()
{
uint bytesReturned = 0;
uint IOCTL_HAL_REBOOT = CTL_CODE(FILE_DEVICE_HAL, 15,
METHOD_BUFFERED, FILE_ANY_ACCESS);
return KernelIoControl(IOCTL_HAL_REBOOT, IntPtr.Zero, 0,
IntPtr.Zero, 0, ref bytesReturned);
}
private void Form1_Load(object sender, System.EventArgs e)
{
DialogResult r = MessageBox.Show
(
"Are you sure you want to reset?",
"Test",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2
);
if (r == DialogResult.Yes)
{
ResetPocketPC();
}
}
'VB
Public Const FILE_DEVICE_HAL As Integer = &H101
Public Const METHOD_BUFFERED As Integer = 0
Public Const FILE_ANY_ACCESS As Integer = 0
Public Function CTL_CODE( _
ByVal DeviceType As Integer, _
ByVal Func As Integer, _
ByVal Method As Integer, _
ByVal Access As Integer) As Integer
Return (DeviceType << 16) Or (Access << 14) Or (Func << 2) Or Method
End Function 'CTL_CODE
_
Public Shared Function KernelIoControl _
( _
ByVal dwIoControlCode As Integer, _
ByVal lpInBuf As IntPtr, _
ByVal nInBufSize As Integer, _
ByVal lpOutBuf As IntPtr, _
ByVal nOutBufSize As Integer, _
ByRef lpBytesReturned As Integer _
) As Integer
End Function
Function ResetPocketPC() As Integer
Dim bytesReturned As Integer = 0
Dim IOCTL_HAL_REBOOT As Integer = CTL_CODE(FILE_DEVICE_HAL, _
15, METHOD_BUFFERED, FILE_ANY_ACCESS)
Return KernelIoControl(IOCTL_HAL_REBOOT, IntPtr.Zero, 0, _
IntPtr.Zero, 0, bytesReturned)
End Function 'ResetPocketPC
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
Dim r As DialogResult = MessageBox.Show( _
"Are you sure you want to reset?", _
"Test", _
MessageBoxButtons.YesNo, _
MessageBoxIcon.Question, _
MessageBoxDefaultButton.Button2)
If r = DialogResult.Yes Then
ResetPocketPC()
End If
End Sub 'Form1_Load
6.18. How can I put an icon on the title bar regardless of the which form is active?
This is not supported with the current version of the .NET Compact Framework. You can, however, P/Invoke Pocket PC's notificaiton system to do this. Refer to the following for more information:
Sample Code:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnppc2k2/html/ppc_fications.asp
AYGShell APIs:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceui40/html/_cerefaygshellfunctions.asp
The native Notification APIs are: SHNotificationAdd, SHNotificationRemove, SHNotificationGetData, and SHNotificationUpdate.
6.19. How do I disable and capture hardware buttons?
Refer to the sample in the P/Invoke library.
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp#PInvokeLib_Topic03
6.20. How do I hide the start icon?
The Start icon can be hidden using the SHFullScreen API.
//C#
const uint SHFS_SHOWTASKBAR = 0x0001;
const uint SHFS_HIDETASKBAR = 0x0002;
const uint SHFS_SHOWSIPBUTTON = 0x0004;
const uint SHFS_HIDESIPBUTTON = 0x0008;
const uint SHFS_SHOWSTARTICON = 0x0010;
const uint SHFS_HIDESTARTICON = 0x0020;
[DllImport("aygshell.dll")]
static extern uint SHFullScreen(IntPtr hwndRequester, uint dwState);
[DllImport("coredll.dll")]
public static extern IntPtr GetCapture();
private void Form1_Load(object sender, System.EventArgs e)
{
Capture = true;
IntPtr hwnd = GetCapture();
Capture = false;
SHFullScreen(hwnd, SHFS_HIDESTARTICON);
}
'VB
Const SHFS_SHOWTASKBAR As Integer = &H1
Const SHFS_HIDETASKBAR As Integer = &H2
Const SHFS_SHOWSIPBUTTON As Integer = &H4
Const SHFS_HIDESIPBUTTON As Integer = &H8
Const SHFS_SHOWSTARTICON As Integer = &H10
Const SHFS_HIDESTARTICON As Integer = &H20
_
Shared Function SHFullScreen(ByVal hwndRequester As IntPtr, ByVal dwState As Integer) As Integer
End Function
_
Public Shared Function GetCapture() As IntPtr
End Function
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Capture = True
Dim hwnd As IntPtr = GetCapture()
Capture = False
SHFullScreen(hwnd, SHFS_HIDESTARTICON)
End Sub 'Form1_Load
6.21. How do I enumerate, create, and terminate processes?
Refer to the sample:
http://msdn.microsoft.com/mobility/understanding/articles/default.aspx?pull=/library/en-us/dnnetcomp/html/processmanager.asp
6.22. Where can I find a centralized library of P/Invoke samples?
This sample demonstrates how to P/Invoke numerous useful native functions that are not directly available through the .NET Compact Framework. A test Form is provided that enumerates all available test procedures and allows the user to select and run them:
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp
6.23. How do I play and record .WAV audio files with the Waveform Audio Inteface?
Learn how to use the Waveform Audio Interface to record and play ".wav" files:
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/WaveInOut.asp
--------------------------------------------------------------------------------
7. 通用
7.1. 如何确定应用程序的主目录?
使用Reflection,应用程序可以确定自己是从哪个目录启动的,也可以使用IO.Path命名空间来修改它。
//C#
using System.Reflection;
using System.IO;
// This is the full directory and exe name
String fullAppName = Assembly.GetExecutingAssembly().GetName().CodeBase;
// This strips off the exe name
String fullAppPath = Path.GetDirectoryName(fullAppName);
// This adds a file name to the path
String splashImageName = Path.Combine(fullAppPath, "myfile.txt");
'VB
Imports System.IO
Imports System.Reflection
' This is the full directory and exe name
Dim fullAppName As String = [Assembly].GetExecutingAssembly().GetName().CodeBase
' This strips off the exe name
Dim fullAppPath As String = Path.GetDirectoryName(fullAppName)
' This adds a file name to the path
Dim splashImageName As String = Path.Combine(fullAppPath, "myfile.txt")
学习如何获得程序执行的当前目录。在Embedded Visual Basic中,程序执行的当前目录可以通过App.Path属性获得。执行程序的目录可以通过程序集的AssemblyName对象的获得,AssemblyName对象包含了程序集的所有描述:
http://msdn.microsoft.com/library/en-us/dncfhowto/html/HOWTOExecutingAppPath.asp
这篇快速入门教程告诉您如何获得您的程序集和数据文件所在的目录。Windows CE .NET本身不支持应用程序的当前目录的设置:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/getappdir.aspx
7.2. 如何计算精确的时间间隔?
一个应用程序有四种方法得到时间间隔:
System.Environment.TickCount
获得一个带符号的整型值,表示从机器启动到调用时经过的豪秒数。在.NET精简框架下,这个值的误差在0.5秒内,大多情况下会比0.5秒小。
GetTickCount()
属性Environment.TickCount就是调用GetTickCount函数的,所以没有必要再调用本地代码中的这个方法。
Performance Monitor
可以作为压力测试用途,但不是为最终使用的应用程序而设计的。如需更多信息,请查看本问答的 "7.5. 如何使用性能监视器? " 章节
Timers
使用System.Threading.Timer类,可以在线程内设定计时器,用委托(delegate)指向应用程序 。
Performance Counter
如果OEM厂商支持的话,QueryPerformanceCounter函数能提供最高精度的计时功能。
请查看本问答的"6.9. 如何使用性能计数器功能? "章节。
7.3. 如何把嵌入式资源当作一个流(Stream)?
为了能够访问嵌入资源,应用程序只须简单地引用相关的程序集(assembly)并调用GetManifestResourceStream方法。下面这个例子岩石了如何从嵌入资源中建立一个位图:
//C#
using System.Reflection;
Assembly asm = Assembly.GetExecutingAssembly();
Bitmap bmpSprite = new Bitmap(asm.GetManifestResourceStream("AssemblyName.FileName"));
'VB
Imports System.Reflection
Dim asm As [Assembly] = [Assembly].GetExecutingAssembly()
Dim bmpSprite As New Bitmap(asm.GetManifestResourceStream("AssemblyName.FileName"))
上面代码中, 字符串AssemblyName部分可以在运行时通过调用asm.GetName().Name得到。
注意:如果AssemblyName中有空格,它将被下划线代替,而且必须这样访问。
7.4. 为什么得到一个"An unhandled exception of type 'System.Net.Sockets.SocketException' occurred in System.dll"的错误?
这是.net精简框架的BUG。这是由于Windows CE底层的Secure Sockets Layer (SSL)的限制造成的。但是,也偶避免的方法,如果设置 req.AllowWriteStreamBuffering为true,不要设置req.ContentLength属性,那就不会在发生这个错误了。
7.5. 如何使用性能监视器?
性能计数器通过编辑设备注册表建立:
建立注册表键:"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETCompactFramework\PerfMonitor"
新建双字节项,值就是计数器的名字。
把Counters的值设置为1表示允许计数器,设置为0表示禁止使用。
设置了性能计数器后,当程序关闭时,会建立一个文本文件"mscoree.stat"。这个文件会存放在设备的根目录。这是一个文件每行的长度是固定的,所以导入Excel是非常方便的。
注意: 计数器只能被一个运行着的托管的程序使用。
注意: 使用性能计数器时,会导致30%的性能下降。
7.6. 如何取消一个程序的关闭?
程序可以重载OnClosing方法,设置CancelEventArgs.Cancel为true就可以取消关闭。
//C#
protected override void OnClosing(CancelEventArgs e)
{
e.Cancel = true;
}
'VB
Protected Overrides Sub OnClosing(ByVal e As CancelEventArgs)
e.Cancel = True
End Sub 'OnClosing
7.7. 如何在我的程序中调用另一个应用程序?
您可以调用本地代码的CreateProcess函数开始运行第二个程序。然后调用本地代码的WaitForSingleObject函数暂停调用的程序,直到第二个程序运行结束。以下快速入门演示了通过PocketPC模拟器来实现这一操作:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/waitforsingleobject.aspx
7.8. .net精简框架的应用程序会建立什么线程?
一个.net精简框架程序最多会产生4个线程:
一个主应用程序线程。
一个线程控制各种时间间隔,时间间隔是供系统和其他应用程序使用的。
一个线程跟踪活动的TCP/IP接口的变化(模拟Windows XP上的媒体动作,Windows CE上是没有这些操作的)。
一个执行终止对象的线程。当第一个被垃圾回收的对象回收时,就被建立了。
本文作者:佚名 来源:www.weste.net
CIO之家 www.ciozj.com 微信公众号:imciow