首页 > 代码库 > 客户端数据上报的简单实现

客户端数据上报的简单实现

发布到外网的安装包和客户端程序,经常需要向后台上报一些数据。实现数据上报的方法有很多,其中最简单的方法是,用IE静默打开一个带有查询字符串的URL。这样,只要在apache上部署一个简单的脚本,就能统计数据上报了。

先看下安装包中数据上报的实现,nsis代码如下:

ExecShell "open" "iexplore.exe" "http://127.0.0.1" SW_HIDE

这个脚本对应到win32的API,是ShellExecute。奇怪的是,nsis脚本在安装包上运行的很好,IE能够静默打开,而到了客户端上,用ShellExecute并设置了SW_HIDE,总是不能隐藏。

接着我在网上找到了用CreateProcess打开IE的方法.如下代码展示了从注册表中读取IE的路径,然后用CreateProcess隐藏打开的方法。注意CreateProcess的第二个参数,url的前面要带上open。

STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
GetStartupInfo(&si);         
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;

PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
         
if (!CreateProcess(szIEPath, TEXT("open http://127.0.0.1"), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
{
     return -1;
}

IE的路径可由如下的GetIEPath获得:

BOOL GetIEPath(LPTSTR lpszPath, int nLen)
{
     BOOL bSuccess = FALSE;
     do
     {
          HKEY hKey = NULL;
          DWORD dwSizeOfPath = 0;
          if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
               TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\IEXPLORE.EXE"),
               0,
               KEY_READ,
               &hKey))
          {
               break;
          }
         
          if (ERROR_SUCCESS != RegQueryValueEx(hKey, TEXT(""), NULL, NULL, NULL, &dwSizeOfPath))
          {
               break;
          }


          if (dwSizeOfPath >= nLen)
          {
               break;
          }
          if (ERROR_SUCCESS != RegQueryValueEx(hKey, TEXT(""), NULL, NULL, (LPBYTE)lpszPath, &dwSizeOfPath))
          {
               break;
          }
          lpszPath[dwSizeOfPath + 1] = TEXT(‘\0‘);
          bSuccess = TRUE;
     } while(FALSE);
     return bSuccess;
}
写了这么多代码,现在问题解决了么?我在自己的机器上测试一切正常!
可是...
到了安装IE11的电脑上,nsis脚本的ExecShell和客户端的CreateProcess,打开的IE都展示在用户的面前,我们总不能让用户知道我们在收集数据吧:)

最终,找到了一种更简单的方法,只要调用两个win32接口即可。这样也不需要创建额外的IE进程了。 

HINTERNET hInternet1 = InternetOpen(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, NULL);
if (hInternet1)
{
     HINTERNET hInternet2 = InternetOpenUrl(hInternet1,szOpenUrlAddr, NULL, NULL,INTERNET_FLAG_NO_CACHE_WRITE,NULL);
     InternetCloseHandle(hInternet1);
     if (hInternet2)
     {
          InternetCloseHandle(hInternet2);
     }    
}

这样实现,我们上报数据,从任务管理器里也不留痕迹,而且代码更短!

把这段代码移植到NSIS插件中,nsis脚本也能够优雅的上报数据了:) 

客户端数据上报的简单实现