在Windows Mobile设备上检测存储

Progress means simplifying, not complicating. Bruno Munari
进步意味着简化而不是复杂化。 布鲁诺·穆纳里(Bruno Munari)

Preface

前言

How to detect the name of the internal storage or an SD-card on Windows Mobile device from the desktop application? 如何从桌面应用程序检测Windows Mobile设备上的内部存储器或SD卡的名称?

I got this question, when I was working on a PC application copying a huge amount of data on a storage card inserted into a Windows Mobile device (a phone in this case).  I found the answer, very simple answer, but on my way I tested a few interesting ideas and I'd like to show them in this article.

当我在PC应用程序上进行工作时,遇到一个问题,即在插入Windows Mobile设备(在这种情况下为手机)的存储卡上复制大量数据。 我找到了答案,非常简单的答案,但是在途中,我测试了一些有趣的想法,并希望在本文中进行介绍。

Remote API

远程API

So the task is to copy a big amount of data to a storage (SD-card or an internal storage) of the device connected to the desktop. Both, the computer and the device, are running Windows - Mobile and XP or Vista. So, let's use RAPI.

因此,任务是将大量数据复制到连接到台式机的设备的存储设备(SD卡或内部存储设备)中。 计算机和设备都运行Windows-Mobile和XP或Vista。 因此,让我们使用RAPI。

Remote API is a small set of functions that allows one to create or remove files, folders, registry keys on the windows mobile device connected to the PC via ActiveSync or Windows Device Mobile Center.

远程API是一小组功能,允许用户在通过ActiveSync或Windows设备移动中心连接到PC的Windows移动设备上创建或删除文件,文件夹,注册表项。

Storage cards inserted into a device are usually shown in File Explorer as a folder named as "Storage Card" or "SD". Internal storage may have name "Internal Storage" or "My Flash Disk" or "Resident Flash".

插入设备的存储卡通常在文件资源管理器中显示为名为“存储卡”或“ SD”的文件夹。 内部存储器的名称可能是“内部存储器”或“我的闪存盘”或“常驻闪存”。

My first idea was to check the existance of these names on the device and copy the data on the first detected storage. Have a look at the following console application demonstrating this approach:

我的第一个想法是检查设备上这些名称的存在并将数据复制到第一个检测到的存储中。 看一下以下演示此方法的控制台应用程序:

#define WIN32_LEAN_AND_MEAN

#include <rapi2.h>
#pragma comment(lib, "rapi.lib")
#pragma comment(lib, "rapiuuid.lib")

#include <cstdio>

static const DWORD s_nTime = 5000;

const static LPCWSTR s_szFolder = L"RAPITestFolder";
static const int s_nSD = 5;
const static LPCWSTR s_arrSD[s_nSD] =
{
	L"Internal Storage",
	L"ResidentFlash",
	L"My Flash Disk",
	L"Storage Card",
	L"SD"
};

int main()
{
	RAPIINIT riCopy = { 0 };
	riCopy.cbSize = sizeof(riCopy);
	HRESULT hr = CeRapiInitEx(&riCopy);
	if (FAILED(hr))
	{
		wprintf_s(L"Connection failed\n");
		return 0;
	}

	DWORD nRapiInit = WaitForSingleObject(riCopy.heRapiInit, 
		s_nTime);

	if (WAIT_OBJECT_0 != nRapiInit)
	{
		wprintf_s(L"Connection failed\n");
		return 0;
	}

	LPCWSTR lpszSD = NULL;
	int nCnt = 0;
	WCHAR szDir[MAX_PATH];
	BOOL bCreated = FALSE;
	DWORD nError = 0;
	while (nCnt < s_nSD)
	{
		lpszSD = s_arrSD[nCnt];
		ZeroMemory(szDir, sizeof(WCHAR) * MAX_PATH);
		_snwprintf_s(szDir, MAX_PATH, 
			L"\\%s\\%s", lpszSD, s_szFolder);
		bCreated = CeCreateDirectory(szDir, NULL);
		if (!bCreated)
		{
			nError = CeGetLastError();
			if (nError == ERROR_ALREADY_EXISTS)
				bCreated = TRUE;
		}
		if (bCreated)
		{
			wprintf_s(L"Found: %s\n", lpszSD);
			CeRemoveDirectory(szDir);
		}
		nCnt++;
	}

	CeRapiUninit();

	return 0;
}

The application screenshot is here:

该应用程序的屏幕截图位于:

Enumarating

I don't know if you can see the problem with this method. Our QA did a few tests on Windows Mobile phones with pre-installed German support. Now hopefully you will see the problem. The name of the storage card was "Speicherkarte". Consider how it will be in French, or other languages ?

我不知道您是否可以看到这种方法的问题。 我们的质量检查人员在预先安装了德语支持的Windows Mobile手机上进行了一些测试。 现在希望您会看到问题所在。 存储卡的名称为“ Speicherkarte”。 考虑一下法语或其他语言的情况吗?

To a certain extent this method is acceptable only for the English speaking users. :)

在某种程度上,该方法仅适用于说英语的用户。 :)

A Mobile Application

移动应用

Many years ago I make applications for Windows Mobile and CE devices and I don't have a problem to detect my database located on the storage card. I look for

许多年前,我为Windows Mobile和CE设备开发了应用程序,并且检测存储卡上的数据库没有问题。 我在找

a folder with the temporary attribute and check if there are my data files. I use the well-known API: FindFirstFile, FindNextFile and FindClose to enumerate all folders on the device.

具有临时属性的文件夹,并检查是否有我的数据文件。 我使用著名的API:FindFirstFile,FindNextFile和FindClose来枚举设备上的所有文件夹。

So I can make an executable, download it on the device and launch it via RAPI (CeCreateProcess). This executable (the daemon) will make a text report that I can upload to the PC and read.

因此,我可以制作一个可执行文件,将其下载到设备上,然后通过RAPI(CeCreateProcess)启动。 该可执行文件(守护程序)将生成一个文本报告,我可以将其上传到PC并阅读。

I think I've seen this approach implemented. It even worked. But it is so simple... It looks like a trick made because of the laziness, or a lack of time (or knowledge) - a programmer knows only few functions in Win32 API and applies them everywhere because he's lazy enough to open the book and read something new.

我想我已经看到了这种方法的实现。 它甚至有效。 但这很简单...似乎是由于懒惰或缺乏时间(或知识)而做出的一个技巧-程序员只知道Win32 API中的几个函数,并将它们应用到所有地方,因为他足够懒惰才能打开书并读一些新东西。

Of course there is a more modern way -  make a DLL that will export a special function that can be called by CeRapiInvoke function. The example of such DLL that can be called via RAPI can be found on Native Mobile blog.

当然,还有一种更现代的方法-制作一个DLL,该DLL将导出可以由CeRapiInvoke函数调用的特殊函数。 可以通过RAPI调用的此类DLL的示例可以在Native Mobile博客上找到。

More details you can find in:

您可以在以下位置找到更多详细信息:

1. MSDN: How To Use CeRapiInvoke()

1. MSDN:如何使用CeRapiInvoke()

2. Dr. Dobb's: The Windows CE 2.0 Remote API. The CeRapiInvoke API is a versatile tool

2. Dobb博士:Windows CE 2.0远程API。 CeRapiInvoke API是一种多功能工具

The Answer

答案

The previous, a complicated enough method, enumerates the folders on the device and this information should be retrieved by a desktop application via RAPI. If I will decide to implement this approach, I will need to add one more project to my solution - the daemon DLL. I will have to sign this DLL in order to avoid the annoying question from Microsoft asking the user if he allows to launch this DLL from an unknown provider. It already smells bad.

先前的方法很复杂,它枚举了设备上的文件夹,并且此信息应由桌面应用程序通过RAPI检索。 如果我决定实施这种方法,则需要在我的解决方案中添加另一个项目-守护程序DLL。 为了避免Microsoft询问用户是否允许从未知提供程序启动此DLL的烦人问题,我将必须对此DLL进行签名。 它已经闻起来很难闻。

Can I enumerate the folders on the device via RAPI? 我可以通过RAPI枚举设备上的文件夹吗?

There is no CeFindFirstFile function.

没有CeFindFirstFile函数。

But there is CeFindAllFiles!

但是这里有CeFindAllFiles!

You can find a detailed explanation of this function on CodeGuru:

您可以在CodeGuru上找到有关此功能的详细说明:

Nancy Nicolaisen. "Using RAPI to Find Remote Files"

南希·尼古拉森。 “使用RAPI查找远程文件”

I made a console application to check this function:

我制作了一个控制台应用程序来检查此功能:

#define WIN32_LEAN_AND_MEAN

#include <rapi2.h>
#pragma comment(lib, "rapi.lib")
#pragma comment(lib, "rapiuuid.lib")

#include <cstdio>

static const DWORD s_nTime = 5000;

int main()
{
	RAPIINIT riCopy = { 0 };
	riCopy.cbSize = sizeof(riCopy);
	HRESULT hr = CeRapiInitEx(&riCopy);
	if (FAILED(hr))
	{
		wprintf_s(L"Connection failed\n");
		return 0;
	}

	DWORD nRapiInit = WaitForSingleObject(riCopy.heRapiInit, 
		s_nTime);

	if (WAIT_OBJECT_0 != nRapiInit)
	{
		wprintf_s(L"Connection failed\n");
		return 0;
	}

	LPCE_FIND_DATA pData = NULL;
	LPCWSTR lpszPath = L"\\*.*";
	DWORD nFlags = FAF_FOLDERS_ONLY | FAF_NAME | FAF_ATTRIBUTES;
	DWORD nCount = 0;
	BOOL bRetrieved = CeFindAllFiles(lpszPath, nFlags, &nCount, &pData);
	if (bRetrieved)
	{
		DWORD nCnt = 0;
		do
		{
			if ((pData[nCnt].dwFileAttributes & 
				FILE_ATTRIBUTE_TEMPORARY) == FILE_ATTRIBUTE_TEMPORARY)
				wprintf_s(L"Found: \\%s\n", 
					pData[nCnt].cFileName);

			nCnt++;
		} while (nCnt < nCount);
	}
	if (pData != NULL)
		CeRapiFreeBuffer(pData);

	CeRapiUninit();
	return 0;
}

With my HTC Touch Pro 2 phone this application gave me this result:

使用我的HTC Touch Pro 2手机,此应用程序给了我以下结果:

CeFindAllFiles.

Here is the screenshot from the phone itself:

这是手机本身的屏幕截图:

File Explorer

Compiling with RAPI

使用RAPI进行编译

You can compile the source code from this article only if you have Microsft Windows Mobile SDK installed. In the SDK folder in ActiveSync\inc folder you can find rapi2.h file and rapi.lib and rapiuuid.lib file in in ActiveSync\Lib folder.

只有安装了Microsft Windows Mobile SDK,才能编译本文的源代码。 在ActiveSync \ inc文件夹中的SDK文件夹中,可以在ActiveSync \ Lib文件夹中找到rapi2.h文件以及rapi.lib和rapiuuid.lib文件。

In your project you can add "$(ProgramFiles)\Windows Mobile 6 SDK\Activesync\inc" to Additional Include Directories and "$(ProgramFiles)\Windows Mobile 6 SDK\Activesync\lib" to Additional Library Directories of the project settings.

在您的项目中,您可以将“ $(ProgramFiles)\ Windows Mobile 6 SDK \ Activesync \ inc”添加到项目设置的“其他包含目录”中,将“ $(ProgramFiles)\ Windows Mobile 6 SDK \ Activesync \ lib”添加到项目设置的“其他库目录”中。

Disclaimer

免责声明

I've implemented the solution and have tested it on few Windows Mobile and CE devices.  I was writing this article and launched Google to find more information about PInvoke (it was a mistake, I needed CeRapiInvoke). It always happens this way - I found an example in VB that uses exactly the same method of the temporary folder detection on CodeProject:

我已经实现了该解决方案,并已在少数Windows Mobile和CE设备上对其进行了测试。 我正在写这篇文章,并启动了Google以查找有关PInvoke的更多信息(这是一个错误,我需要CeRapiInvoke)。 它总是以这种方式发生-我在VB中找到一个示例,该示例使用与CodeProject上的临时文件夹检测完全相同的方法:

Display device memory information using P/Invoke

使用P / Invoke显示设备内存信息

翻译自: https://www.experts-exchange.com/articles/1996/Detect-Storage-on-Windows-Mobile-Device.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值