最近公司要做一个用户操作手机应用的监控程序,主要是客户体验手机在营业厅中给用户使用的过程中记录用户使用手机中各项应用的次数和时间.
为了解决这个问题,我在网上找了很久,几乎无例外都是C++编写的,而且大部分都是运行于PC的,在手机上的相关例子太少了.
无废话,上代码,方便以后自己查看:
第一个文件: UsbSocketHelper.cs,此文件主要实现手机直接通过usb连接到pc后在手机通过socket以tcp方式发送消息到pc端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace G3PcocessListener
{
public class UsbSocketHelper
{
/// <summary>
/// 发送消息到PC机的Tcp端口,默认端口为:8888
/// </summary>
/// <param name="info">要发送的消息</param>
public static bool SendInfo(string info)
{
string errMsg;
return SendInfo(info, 8888, out errMsg);
}
/// <summary>
/// 发送消息到PC机的Tcp端口,默认端口为:8888
/// </summary>
/// <param name="info">要发送的消息</param>
/// <param name="errMsg">运行时发生的错误的提示信息</param>
public static bool SendInfo(string info, out string errMsg)
{
return SendInfo(info, 8888, out errMsg);
}
/// <summary>
/// 发送消息到PC机的Tcp端口,默认端口为:8888
/// </summary>
/// <param name="info">要发送的消息</param>
/// <param name="port">远程服务器端的TCP端口</param>
/// <param name="errMsg">运行时发生的错误的提示信息</param>
public static bool SendInfo(string info, int port, out string errMsg)
{
errMsg = string.Empty;
try
{
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint localIpEndPoint = new IPEndPoint(host.AddressList[0], 0);
IPHostEntry rhost = Dns.GetHostEntry("ppp_peer");
IPAddress rhost_ipaddr = rhost.AddressList[0];
IPEndPoint RemoteIpEndPoint = new IPEndPoint(rhost_ipaddr, port);//远程服务器端
Byte[] sendBytes = Encoding.ASCII.GetBytes(info);
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
socket.Bind(localIpEndPoint);
socket.Connect(RemoteIpEndPoint);
socket.Send(sendBytes, SocketFlags.None);
socket.Close();
}
return true;
}
catch (Exception ex)
{
errMsg = ex.Message;
return false;
}
}
//end of class
}
}
第二个文件SystemInfoHelper.cs,此文件主要用于获取手机所使用的平台及版本:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System;
namespace G3PcocessListener
{
public class SystemInfoHelper
{
public PlatformID PlatformID { get; set; }
public Version Version { get; set; }
public SystemInfoHelper()
{
OperatingSystem myOS = System.Environment.OSVersion;
PlatformID = myOS.Platform;
Version = myOS.Version;
}
}
}
第三个文件ProcessEnumerator.cs,此文件用来枚举手机当前运行的进程:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace ToolHelpApi
{
/// <summary>
/// 进程实体类
/// </summary>
public class ProcEntry
{
public string ExeName;
public uint ID;
}
/// <summary>
/// 实现IEqualityComparer接口,用来实现IEnumerable<ProcEntry> tmpList = newestList.Distinct(new Comparer4ProcEntry());
/// </summary>
public class Comparer4ProcEntry : IEqualityComparer<ProcEntry>
{
#region IEqualityComparer<ProcEntry> 成员
public bool Equals(ProcEntry x, ProcEntry y)
{
if (x == null && y == null) return false;
return x.ExeName.Equals(y.ExeName, StringComparison.CurrentCultureIgnoreCase) && x.ID == y.ID;
}
public int GetHashCode(ProcEntry obj)
{
return obj.ToString().GetHashCode();
}
#endregion
}
/// <summary>
/// 进程枚举器
/// </summary>
public class ProcessEnumerator
{
#region Constants
private const uint TH32CS_SNAPPROCESS = 0x00000002;
private const uint TH32CS_SNAPNOHEAPS = 0x40000000; // optimization to not snapshot heaps
private const uint TH32CS_SNAPHEAPLIST = 0x00000001;
private const uint TH32CS_SNAPTHREAD = 0x00000004;
private const uint TH32CS_SNAPMODULE = 0x00000008;
private const uint TH32CS_SNAPALL = (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE);
private const uint TH32CS_GETALLMODS = 0x80000000;
private const int MAX_PATH = 260;
#endregion
#region Structs
/// <summary>
/// 进程结构体
/// </summary>
public struct PROCESSENTRY
{
public uint dwSize;
public uint cntUsage;
public uint th32ProcessID;
public uint th32DefaultHeapID;
public uint th32ModuleID;
public uint cntThreads;
public uint th32ParentProcessID;
public int pcPriClassBase;
public uint dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
public string szExeFile;
uint th32MemoryBase;
uint th32AccessKey;
}
#endregion
#region P/Invoke
[DllImport("toolhelp.dll")]
private static extern IntPtr CreateToolhelp32Snapshot(uint flags, uint processID);
[DllImport("toolhelp.dll")]
private static extern int CloseToolhelp32Snapshot(IntPtr snapshot);
[DllImport("toolhelp.dll")]
private static extern int Process32First(IntPtr snapshot, ref PROCESSENTRY processEntry);
[DllImport("toolhelp.dll")]
private static extern int Process32Next(IntPtr snapshot, ref PROCESSENTRY processEntry);
#endregion
#region public Methods
/// <summary>
/// 枚举当前活动进程
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
public static bool Enumerate(ref List<ProcEntry> list)
{
if (list == null)
{
return false;
}
list.Clear();
IntPtr snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot_ == IntPtr.Zero)
{
return false;
}
PROCESSENTRY entry_ = new PROCESSENTRY();
entry_.dwSize = (uint)Marshal.SizeOf(entry_);
if (Process32First(snapshot_, ref entry_) == 0)
{
CloseToolhelp32Snapshot(snapshot_);
return false;
}
do
{
ProcEntry procEntry = new ProcEntry();
procEntry.ExeName = entry_.szExeFile;
procEntry.ID = entry_.th32ProcessID;
list.Add(procEntry);
entry_.dwSize = (uint)Marshal.SizeOf(entry_);
}
while (Process32Next(snapshot_, ref entry_) != 0);
CloseToolhelp32Snapshot(snapshot_);
return true;
}
private static bool KillProcess(uint procID)
{
try
{
System.Diagnostics.Process proc_ = System.Diagnostics.Process.GetProcessById((int)procID);
proc_.Kill();
proc_.Dispose();
return true;
}
catch (ArgumentException)
{
return false; //process does not exist
}
catch (Exception)
{
return false; //cannot kill process (perhaps its system process)
}
}
#endregion
}
}
第四个文件WindowsEnumerator.cs,此文件主要是获取当前用户操作的窗口,并得到创建该窗口的进程标记:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace CoredllApi
{
public class WindowsEnumerator
{
[DllImport("coredll.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("coredll.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hwnd, ref uint lpdwProcessId);
public static bool Enumerate(ref uint procId)
{
if (procId == null)
{
procId = 0;
}
IntPtr hwnd = GetForegroundWindow();
if (hwnd == IntPtr.Zero)
{
return false;
}
GetWindowThreadProcessId(hwnd, ref procId);
return true;
}
//public static bool Enumerate(ref List<ProcEntry> list, ref ProcEntry proc)
//{
// if (list == null)
// {
// return false;
// }
// IntPtr hwnd = GetForegroundWindow();
// if (hwnd == IntPtr.Zero)
// {
// return false;
// }
// uint pid = 0;
// GetWindowThreadProcessId(hwnd, ref pid);
// ProcEntry proc_ = new ProcEntry();
// foreach (ProcEntry item in list)
// {
// if (item.ID == pid)
// {
// proc_ = item;
// break;
// }
// }
// proc = proc_;
// return true;
//}
//end of class
}
}
第五个ProcessListener.cs,此文件用来监听并发送消息:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ToolHelpApi;
using CoredllApi;
namespace G3PcocessListener
{
public class ProcessListener
{
//private static List<ProcEntry> procList = new List<ProcEntry>();
private static List<ProcEntry> newestList = new List<ProcEntry>();//最新进程列表
private static uint lastProcId = 0;//上次活动窗体对应的进程标记
#region 单例模式:饿汉式
private static ProcessListener _instance = new ProcessListener();
public static ProcessListener Instance
{
get { return _instance; }
}
private ProcessListener()
{
//procList.Clear();
//ProcessEnumerator.Enumerate(ref procList);
//procList = procList.Distinct(new Comparer4ProcEntry()).ToList();
}
#endregion
//private void FindNewestProcess()
//{
// if (ProcessEnumerator.Enumerate(ref newestList))
// {
// List<ProcEntry> tmpList = newestList.Distinct(new Comparer4ProcEntry()).ToList();
// List<ProcEntry> newList = tmpList.Except(procList, new Comparer4ProcEntry()).ToList();
// foreach (ProcEntry item in newList)
// {
// UsbSocketHelper.SendInfo(item.ExeName + System.Environment.NewLine);
// }
// procList.Clear();
// procList.AddRange(tmpList);
// newestList.Clear();
// }
//}
private void FindNewestWindow()
{
uint currentProcId = 0;
if (WindowsEnumerator.Enumerate(ref currentProcId))
{
if (currentProcId != lastProcId)
{
lastProcId = currentProcId;//记录当前活动窗体对应的进程标记
if (ProcessEnumerator.Enumerate(ref newestList))
{
ProcEntry proc_ = newestList.Find(item => item.ID == currentProcId);
if (!string.IsNullOrEmpty(proc_.ExeName))
{
UsbSocketHelper.SendInfo(proc_.ExeName + System.Environment.NewLine);
}
}
}
}
}
//private void FindNewestWindow()
//{
// ProcEntry proc=new ProcEntry();
// if (ProcessEnumerator.Enumerate(ref newestList))
// {
// if (WindowsEnumerator.Enumerate(ref newestList,ref proc))
// {
// UsbSocketHelper.SendInfo(proc.ExeName + System.Environment.NewLine);
// }
// }
//}
public void Listen(object stateInfo)
{
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
//FindNewestProcess();
FindNewestWindow();
Thread.Sleep(1000);
autoEvent.Set();
}
}
}
第六个文件就是Program.cs啦,无废话:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System.Threading;
namespace G3PcocessListener
{
class Program
{
static void Main(string[] args)
{
AutoResetEvent autoEvent = new AutoResetEvent(true);
do
{
ProcessListener.Instance.Listen(autoEvent);
Thread.Sleep(1000);
} while (autoEvent.WaitOne());
autoEvent.WaitOne();
}
}
}
后续再研究怎么把这个程序安装到WinCe中,使实现开机自动运行.