#include
namespace MSXML
{
#include
}
#include
objsafe.h和ocidl.h都是必须的,因为它们包含GUID描述,而GUID是与COM一起工作的指针必须的。为了使COM调用进入MSXML分析程序,你必须建立MSXML名字空间并包含msxml.h。此外,为了项目编译正确,你应该把ole32.lib和oleaut32.lib库添加到连接程序设置中。
一旦代码使用XMLDOM,你能简单地使用DOMDocument 的load方法从远程服务器检索数据。该方法只需要一个能找到并检索数据的URL。它在文档中重复构建窗体上的一个微调控件(spinner control)(图3)。完成后它显示一个包含整个XML文档的消息框。
MSXML::IXMLDOMDocument *iXMLDoc = NULL;
MSXML::IXMLDOMParseError *pParsingErr = NULL;
MSXML::IXMLDOMElement *iXMLElm = NULL;
MSXML::IXMLDOMNodeList *iXMLChild = NULL;
MSXML::IXMLDOMNode *iXMLItem = NULL;
short tEmpty;
BSTR bStr;
VARIANT vXMLSrc;
HRESULT hr;
HWND hListBox;
long lLength;
hr = CoInitializeEx(NULL,COINIT_MULTITHREADED);
if(!SUCCEEDED(hr)) return 0;
hr = CoCreateInstance (MSXML::CLSID_DOMDocument,
NULL,CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
MSXML::IID_IXMLDOMDocument, (LPVOID *)&iXMLDoc);
if(iXMLDoc)
{
iXMLDoc->put_async(VARIANT_FALSE);
//Smartphone 2002 工作区:
//删除文档安全选项
IObjectSafety *pSafety;
DWORD dwSupported, dwEnabled;
if ( SUCCEEDED(iXMLDoc->QueryInterface(
IID_IObjectSafety, (void**)&pSafety)))
{
pSafety->GetInterfaceSafetyOptions(
MSXML::IID_IXMLDOMDocument, &dwSupported, &dwEnabled );
pSafety->SetInterfaceSafetyOptions(
MSXML::IID_IXMLDOMDocument, dwSupported, 0 );
}
VariantInit( &vXMLSrc );
vXMLSrc.vt = VT_BSTR;
iXMLDoc->put_async(VARIANT_FALSE);
vXMLSrc.bstrVal = SysAllocString(L"http:/localhost/
smartphonearticledata.xml");
hr = iXMLDoc->load(vXMLSrc, &tEmpty);
SysFreeString(vXMLSrc.bstrVal);
iXMLDoc->get_documentElement(&iXMLElm);
iXMLElm->selectNodes(L"//DATA/STATUS/S",&iXMLChild);
//iXMLElm->get_childNodes(&iXMLChild);
iXMLChild->get_length(&lLength);
hListBox = GetDlgItem( hWnd, IDC_LISTISSUES);
for (int x=0;xget_item(x,&iXMLItem);
iXMLItem->get_text(&bStr);
SendMessage (hListBox, LB_ADDSTRING, 0, (LPARAM) bStr);
}
//iXMLChild->get_item(1,&iXMLItem);
iXMLDoc->get_xml(&bStr);
MessageBox(NULL,bStr,TEXT("Article Demo"),MB_OK);
图3.XML Load方法示例
本地存储数据
在检索数据到Smartphone后,下一步是研究在设备上本地存储数据的方法。一种选择是根本不保存。你可以检索数据,执行一些操作,接着从内存中释放数据。不幸的是在大多数情况下没有这么简单,因此你不得不决定适合应用程序的格式。你也许会保存数据到文件存储(例如闪存卡),或者保存在本地的数据存储(例如CEDB)中。
对于多数商业应用程序,你需要把数据保存在文件系统中。尽管能够将数据写入RAM文件系统,但是并不推荐这样使用,因为当设备关闭或掉电时所有数据都会丢失。对于持续的存储器,Smartphone设备提供作为IPSM内存控件的闪存文件系统。在多数Smartphone上空间受到限制,但是许多设备包含一个存储卡槽,允许使用可移走的存储卡。
编程决定Smartphone上在哪儿存储数据很简单,这得感谢你在Windows CE 平台上进行开发所熟悉的一些API。这些调用可以在Windows Shell API文档中找到。现在我将聚焦于SHGetSpecialFolderPath函数。该函数允许你访问主要的Smartphone文件系统并在运行时检索完整的路径。在检索路径后,你能使用该路径存储与应用程序相关的数据。该函数需要一个CSIDL_常数作为输入参数。这些常数反映了Smartphone操作系统中的共有文件夹(应用程序数据、收藏夹、程序、开始等等)。因为这些公共区域也许在不同设备上,CSIDL常量提供了一个唯一的系统标识来识别这些目录。推荐客户应用程序在CSIDL_APPDATA常量返回目录的子目录中保存数据。例如:
#ifdef CSIDL_APPDATA
if(!SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_APPDATA, TRUE))
{
ASSERT(FALSE);
hr = HRESULT_FROM_WIN32(GetLastError());
}
#else
// Pocket PC没有这种定义来在根中读取目录。
//也许未来会作些改变,但代码仍然可以工作
_tcscpy(szFolderPath, TEXT("\\"));
#endif
我先前讲到,有些设备需要附加存储卡。与你的桌面计算机的硬盘驱动器不同,Smartphone没有为存储卡分配驱动器符号。作为代替,操作系统在根目录中建立目录来表现每块存储卡上的不同部分。为了访问一个设备中的不同卡,使用FindFirstFlashCard和FindNextFlashCard函数。如果找到了存储卡,FindFirstFlashCard返回一个指向第一块存储卡的句柄和指针。如果句柄是正确的,你可以把它传递给FindNextFlashCard,该函数将返回下一块存储卡的指针和一个BOOL值来表明搜索是否成功。
一旦你找到了希望使用的存储卡,下一步就是查找一个位置来存储数据。在访问设备上的文档时通常使用SHGetDocumentsFolder函数。它可用于新的或者原来的存储卡。下面是使用SHGetDocumentsFolder的一个例子:
TCHAR szDocPath[250];
if (!SHGetDocumentsFolder(L"\\",szDocPath))
MessageBox(NULL,L"Retrieveing Path Failure",L"Call Failure",MB_OK); else
MessageBox(NULL,szDocPath,L"Documents Folder Path",MB_OK);
模拟器笔记:Smartphone模拟器不支持存储卡。它也不支持附加在运行模拟器的PC上的真正的存储卡。
数据库操作
对于几乎所有商业应用程序来说,把数据保存到本地数据库是必要的,对于许多Smartphone应用程序也是这样。与Windows CE和Pocket PC相比, Smartphone上数据库的选择只有少许的不同。对于第一个Smartphone版本Smartphone 2002,只支持本地Windows CE数据库,目前它不支持SQL Server CE或者Pocket Access。此外访问Windows CE数据库的唯一选择是使用包含在Windows CE 3.0中的数据库API。不过访问Windows CE数据库的代码与为Windows CE设备所写的代码几乎相同。
同步数据
在使用完连接并处理数据后,下一步就是与远程数据存储同步。因为我已经介绍过使用XMLDOM通过互联网检索数据,我将继续使用该模型并将改变通过XMLHTTP对象发送回远程服务器。
在介绍使用XMLHTTP的细节前,我们看看Smartphone怎样使用Web服务。目前,在Smartphone平台上没有内建库或组件提供SOAP客户端功能。但是Smartphone 的SOAP客户端并不在可能的范围之外,因为Smartphone 2002 SDK支持所有可能需要的组件。如果Smartphone上需要SOAP客户端,我建议查看第三方库,它也许能移植到Smartphone而没有太多问题。此外你应该记得一旦Smartphone上的.NET简洁框架组件可以使用,就能使用Smartphone客户端的功能了。
从Smartphone向远程数据存储同步数据的第一步是从主存储器中检索所有改变了的数据并转换为XML格式。完成后,实例化XMLHTTP对象并把数据传递到处理同步的特定URL。
先前讲到,因为XMLHTTP对象拥有使用XML格式发送信息到远程服务器的能力,在这儿它将被使用到。XMLHTTP对象是前面的项目中包含的MSXML库中可用的另一个对象。图4是该对象的使用。它很容易使用,从IXMLHttpRequest接口中建立了一个对象。此外,建立一个VARIANT来保持IXMLDOMDocument对象。为了传递这个复杂的类型,VARIANT必须通过VT_DISPATCH类型设置。剩下的步骤是调用XMLHTTP 对象的open和send方法。
MSXML::IXMLDOMDocument *iXMLDoc = NULL;
MSXML::IXMLHttpRequest *iXMLHttp = NULL;
HRESULT hr;
BSTR bStr = NULL;
VARIANT vUserID;
VARIANT vPassword;
VARIANT vPassValue;
VARIANT vAsync;
short tEmpty;
hr = CoInitializeEx(NULL,COINIT_MULTITHREADED);
if(!SUCCEEDED(hr)) return 0;
hr = CoCreateInstance (MSXML::CLSID_DOMDocument, NULL,
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
MSXML::IID_IXMLDOMDocument, (LPVOID *)&iXMLDoc);
if(iXMLDoc)
{
iXMLDoc->put_async(VARIANT_FALSE);
// Smartphone 2002工作区:
//删除文档安全选项
IObjectSafety *pSafety;
DWORD dwSupported, dwEnabled;
if ( SUCCEEDED(iXMLDoc->QueryInterface(IID_IObjectSafety,
(void**)&pSafety)))
{
pSafety->GetInterfaceSafetyOptions(
MSXML::IID_IXMLDOMDocument, &dwSupported, &dwEnabled );
pSafety->SetInterfaceSafetyOptions(
MSXML::IID_IXMLDOMDocument, dwSupported, 0 );
}
iXMLDoc->put_async(VARIANT_FALSE);
iXMLDoc->loadXML(L"Joe
Smith", &tEmpty);
}
VariantInit(&vAsync);
vAsync.vt = VT_BOOL;
vAsync.boolVal = false;
VariantInit(&vUserID);
vUserID.vt = VT_BSTR;
vUserID.bstrVal = L"";
VariantInit(&vPassword);
vPassword.vt = VT_BSTR;
vPassword.bstrVal = L"";
VariantInit(&vPassValue);
vPassValue.vt = VT_DISPATCH;
vPassValue.pdispVal = iXMLDoc;
hr = CoInitializeEx(NULL,COINIT_MULTITHREADED);
if(!SUCCEEDED(hr)) return 0;
hr = CoCreateInstance (MSXML::CLSID_XMLHTTPRequest, NULL,
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
MSXML::IID_IXMLHttpRequest, (LPVOID *)&iXMLHttp);
iXMLHttp->open(L"GET", L"http://localhost/smartphonesavetest.asp",
vAsync,vUserID,vPassword);
hr=iXMLHttp->send(vPassValue);
iXMLHttp->get_responseText(&bStr);
图4 XMLHTTP例子
访问电话特性
通过Windows CE API,开发人员能简单地给应用程序添加电话功能。类似自动拨号、与调用日志交互、访问SIM卡的能力、发送和接收SMS消息等等特性可以简单地添加到应用程序。为了工作正常,大多数技术API需要真实的设备或者GSM无线设备连接到模拟器,因此如果你计划开发这些类型的特性,准备好测试真实的设备。
电话特性的一个最简单的例子是在应用程序中建立语音通话。因为我们有随着Smartphone一起发布的辅助TAPI,只需要一行代码。所有需要作的是在代码中包含astdtapi.h文件,在连接程序设置中添加cellcore.lib,并调用tapiRequestMakeCall函数:
TCHAR szDefaultNum[] = TEXT("+1 (555) 555-5555");
LONG lResult;
lResult = tapiRequestMakeCall((LPTSTR) szDefaultNum, NULL, NULL, NULL);
return TRUE;
发送SMS消息也很简单。有了辅助TAPI,你只需要在代码中添加一个文件引用(sms.h),在连接程序设置中添加一个库(sms.lib)。发送或者接收消息的第一步是调用SmsOpen函数,下一步初始化源和目的地址,完成后调用SmsSendMessage函数。最后一步是调用SmsClose函数清除建立的SMS_HANDLE。代码见图5。
SMS_HANDLE smshHandle;
SMS_ADDRESS smsaSource;
SMS_ADDRESS smsaDestination;
TEXT_PROVIDER_SPECIFIC_DATA tpsd;
SMS_MESSAGE_ID smsmidMessageID;
//尝试打开一个SMS句柄
if(FAILED(SmsOpen(SMS_MSGTYPE_TEXT, SMS_MODE_SEND, &smshHandle, NULL)))
{
MessageBox(NULL,L"Call to SmsOpen failed.",L"Error",MB_OK |
MB_ICONERROR);
return;
}
//建立源地址
if(!bUseDefaultSMSC)
{
smsaSource.smsatAddressType = SMSAT_INTERNATIONAL;
_tcsncpy(smsaSource.ptsAddress, lpszSMSC, SMS_MAX_ADDRESS_LENGTH);
}
//建立目标地址
smsaDestination.smsatAddressType = SMSAT_INTERNATIONAL;
_tcsncpy(smsaDestination.ptsAddress, lpszRecipient, SMS_MAX_ADDRESS_LENGTH);
//建立提供者特定数据
tpsd.dwMessageOptions = bSendConfirmation ? PS_MESSAGE_OPTION_STATUSREPORT
: PS_MESSAGE_OPTION_NONE;
tpsd.psMessageClass = PS_MESSAGE_CLASS1;
tpsd.psReplaceOption = PSRO_NONE;
//发送消息,显示源或者失败
if(SUCCEEDED(SmsSendMessage(smshHandle, ((bUseDefaultSMSC) ? NULL :
&smsaSource),
&smsaDestination, NULL, (PBYTE) lpszMessage,
_tcslen(lpszMessage) * sizeof(TCHAR), (PBYTE) &tpsd,
sizeof(TEXT_PROVIDER_SPECIFIC_DATA), SMSDE_OPTIMAL,
SMS_OPTION_DELIVERY_NONE, &smsmidMessageID)))
{
MessageBox(NULL, L"Message sent", L"Success",MB_OK);
}
else
{
MessageBox(NULL, L"SmsSendMessage Failed", L"Error",MB_OK |
MB_ICONERROR);
}
//清除
VERIFY(SUCCEEDED(SmsClose(smshHandle)));
图5.SMS代码例子
它还提供了更多的API,我只介绍了几个基本的。有了这些能力,移动应用程序在原来的基础上有了很大的扩充。例如,当应用程序中特定事件发生时能够触发自动呼叫或消息。
结论
本文我讨论了建立真实Smartphone应用程序的一些基础。你可以看到该类型的Smartphone应用程序在企业计算领域是非常引人注目的。
作者:陶刚 来源:赛迪网
http://www.biplip.com/Default.aspx?tabid=34&mid=348&ctl=View&ItemID=281
本文地址:http://com.8s8s.com/it/it32528.htm