Compact .NET (Mobile) + MapPoint .NET (Web Service)

 

http://www.brains-N-brawn.com/noMadMap 5/27/2002 casey chesnut

Background

If you have been browsing the MS mapPoint or compactFramework newsgroups, then you could have guessed that I was putting this article together. Have made my niche to take 2 bleeding edge technologies, think of some silly idea to use them together, and then document my endeavors. Sometimes will tackle 2 technologies with absolutely no experience in either, but this time I thought it would be cake, cause had kicked around both of these previously; and wanted to reinforce my knowledge ... or lack thereof, as we shall soon find out :( It's bleak until the very end :)

  • CompactFramework (Tech Preview NOT Beta 1) - Stayed up all night after the technical preview CD was handed out at DevDays sometime late 2001. This was after getting a couple hours of sleep the previous night having driven from Dallas to Denver in one shot. The result of that experiment was that the tech preview was not ready. I called out because it was 1) painfully slow 2) had no design time support 3) had no exception message info and 4) could not get it to call a simple helloWorld web service
  • MapPoint Evaluation - This was just a month or so ago, in which I wrote a wireless web app for the Pocket PC to consume the MapPoint .NET Web Service. It was so simple and easy to develop with, cut scope on my article's demo app because I was not learning anything ... which was the overall intent. The result of that is here: http://www.brains-N-brawn.com/clubMap

Idea

So I got the brand new CompactFramework Beta 1 release, and the 1st thing I did was crack it open and consume a HelloWorld Web Service. Worked Great! Then, checked out the 4 reasons the techPreview sucked (listed above), and they had fixed all of those. It ran decent, there was design time support, exceptions had more info, and web service consumption was taking place. Hell yeah! So then I say, lets do something for real. At the same time, was pissed off from every stinking book I was reading having an intro to Web Services chapter in them. So decided to tie it in with a legit Web Service. So my listing of full on legit Web Services turned up: MapPoint and Google. Had just integrated Google into my /pass application for intelligent agent action, so did not really want to do work with it again. Also, had recent memories of being totally lost and new in Pittsburgh, so MapPoint was a shoe in. Also, still needed to call the Routing service that MapPoint exposes. So the one thing I did not like about MapPoint was the chatty nature of the service (e.g. If you have a zip, you have to find the lat/long of that zip, then find surrounding entities of interest, and then get a map rendered with that info - 3 round trips). Bet that they end up extending the service to expose Batch type APIs. Until then, part of the beauty of the CompactFramework was that it would let me keep state, so my app could be less chatty. So that is the reasoning behind the idea. Actually, I had a much cooler idea for integrating this with .NET My Services, but a complete lack of vision has sent that effort underground.

Day One (5/1) - Hurry up to wait

Created a new Smart Device Application project - Pocket PC flavor. Added MapPoint .NET staging web reference. Then needed some place to store my credentials for accessing MapPoint. Saw that System.Configuration was there, but was missing appSettings, so could not read from appName.exe.config, and was missing my beloved dynamicProperties :). Had not used a resource file in .NET yet, so threw them in there and got that working (more on configuration later). As far as UI, decided on a TabControl with multiple pages:

  1. Addresses - page for adding/deleting and generating maps for a particular address
    • when saving, if a network is available it will get the lat/long by calling the Find service and then store that info to reduce round trips
    • maps that were generated would be saved for disconnected use
  2. Directions - provides two drop downs for selecting a to/from address and then getting directions between the 2 from the Route service
    • text directions would be stored for when network was not available to save trees
    • if the address did not have a lat/long yet, then it would get it and save it off now
    • would get the generated map showing the route overlayed and save it off
  3. Maps - this would be a simple repository for choosing a previously saved map to view
    • the mapView is a seperate form to reclaim maximum screen space
  4. Settings - had to throw this in so that when released, people could easily change their MapPoint credentials

Needed some place to store data. My options were serialized DataSet or SQL CE. Thought SQL CE was overkill since would not need to sink with a parent DB, nor need to store alot of data on the Pocket PC. Was really upset that Typed DataSets are not supported, but did the pseudo typing workaround by generating an XSD and then tying that in to a generic DataSet. NOTE somebody on the newsgroup was able to generate a typed DataSet for the CF (CompactFramework) by stripping out alot of the serialation stuff. Saw what he was doing, and decided not to go down that route because it would have been difficult to maintain, and I wasnt dead set on my XML Schema being correct yet. If the ICodeParser was available with CodeDom, then would have made an app to programmatically gen CF-compliant typed DataSets. Building off a previous effort to carry XSD enum facet info along with Typed DataSets: http://www.brains-N-brawn.com/strongerTDS  Had to use a FileStream and XmlTextReader to read the XSD and XML into the generic DataSets. Looks like the interface is there to read from a filePath, but it was not working for me. Also had to remove null values from my XML file because it kept throwing System.FormatExceptions. After getting that base stuff set up, was ready to call the Web Service. Modified my pre-existing helper class for calling the MapPoint Find service. Looked like the only code change was that the .PreAuthenticate() method was no longer available. Tested to make sure I could pull that out of my other codeBase and that it would still work as well, and sure enough it did. Started, calling the FindMethod and got System.InvalidOperationException/Could not load resource assembly. Suck! This is when the pain began ...

Probably had some other design decisions here, but this was along time ago ... as you shall see ... so I forget what they were.

3+ Weeks Pass - Bored

During this time ... off and on ... I peruse the newsgroups, send off some whining emails asking for help, beat my head against the wall, and try every brute force methodology I can to get it to work ... to no avail ... pretty much end up shelving it because of CF Tech Preview flashbacks.

  • Initial look shows that others are having problems calling a webService with domain names and that switching to IP address works. Tried that, no success.
  • Picked up something about adding a reference to SR.dll to get better error info. Do that and get: The enum value 0 is unknown ??? My guess is that SR.dll stands for String Resources?
  • Somebody mentions that it might be that I dont actually have a Pocket PC and it is because I'm calling it from the emulator. Head down to CompUsa and pick up a disposable Audiovox Maestro ... same problem. Actually love my Maestro, but am having REAL issues trying to stop using Post-It Notes.
  • Saw that someone else was not having problems with Find, but with the Render service. Add code to call that, and get the exact same error he is getting: MethodNotAllowed. Write him about this, but we get nowhere. He ends up calling out and writing his own web service to call the MapPoint web service. Creative, but not an effective workaround for my problem.
  • Coworker points out an article on MSDN about another guy hinting about his own MP (MapPoint) and CF article ... NO! Wont be a copycat
  • During this downtime, I'm toying with my PPC endlessly and fix up my PPC sites that worked fine with the classic PPC OS, but dont work as well with Pocket PC 2002.
  • Some guy writes and says a newer CF drop is working alot better with MapPoint ... thanks, if I could get my hands on that drop ...
  • Set my live video feed back up out of boredom: http://www.brains-N-brawn.com/live
  • Finally get a posting about needing to set some more properties before calling Find, and it starts working. No clue how this guy figured this out, but would really like to know (more on this later)! Specifically, need to add:
    • myFindOptions.ResultMask = FindResultMask.LatLongFlag; //on the desktop, it just defaults to 0 and works fine
  • Taught myself the eBook .lit format and used the MSReaderSDK to create an app to autogen eBooks for one of my PPC sites. Got some more ideas off of this ... and they involve the Google API <insert evil laugh here>
  • My MapPoint .NET evaluation expires, they go ahead and extend me since I'm still kicking it around
  • Am about to give up and start thinking about other things to integrate with the CF ...
  • Get the email addy of some MS guys and start harrassing them. Ends up they can call it just fine with some sample code I send their way ... WTF! We keep trying to figure out why I'm a loser, and then one of them throws out this gem below; he had a little explanation to go with it ... which sadly did not understand either ... but it makes my Render service work!
    • GlobalProxySelection.Select = GlobalProxySelection.GetEmptyWebProxy();

The very minimal code sent to the MS guys for calling MapPoint .NET from CF can be found here: dkMapSamp.zip It has the enum to allow the FindAddress call to work, but not the GetEmptyWebProxy() method, so when you hit the 'Map' button, you might get this: output.JPG The odd thing is that it works for them right out of the box!

Day Two (5/25) - More fun/pain

Start putting together the calls to MapPoint .NET

  • Find-FindAddress() - From the addresses that are being saved to the serialized DataSet, write the logic to check for a network connection and then use that address to retrieve that lat/long from MapPoint and save that info to the TypedDataSet so do not have to query for the address of my apartment every time I want to figure out how to get someplace else new. Especially with the limited bandwidtch capabilities of current cell phones. My assumption from the minimal GIS work I have done is that the lat/long is key, and I can forget about the address once I've got that. 
  • Render-GetMap() - Now that I have a location in lat/long, can ask for a map for that location. Since downtown pittsurgh is pretty small, just hardcode the scale to a nice round number that makes the map look decent. Create a new WinForm with a pictureBox that takes up the whole view and then write out the bits returned form the service to a gif file. Then associate that gif file to that pictureBox to render ... Success!. Have not added the logic to save these off to a repository for the MapPage on the TabControl yet.
  • Route-CalculateSimpleMap() [Text flavor] - Checking out the MapPoint sample pages, when you ask for a route between 2 addresses, you can map it as well as display text instructions (e.g. Head south on Liberty, turn left on 6th). Thinking text would be easier, wrong, tackle that 1st. Grab the code from the desktop sample and make my little helper class. Get it to build and run it to get another ... The enum value 0 is unknown. Doh, and I have no clue how the other guy figured that out! Make a lucky guess and this fixes it: myRouteResultMask = RouteResultMask.Direction; There was one other enum value that it could have taken, but it did not look like it would help with Text Directions. Run it for getting the route 'to work from apartment', but only get back one line of text. My apartment is REAL close, but the line of text is wrong and doesnt even mention the main street. Set if for 'to dallas from pittsburgh' and only get back one line of text? H3ll, how did I set the 'Directions.AsTheCrowFiles' enum. Start stepping through the desktop sample code to see what is different. Couple things being they are not setting that enum to .Directions like I have to, and they are passing in more then just lat/long. Put the addresses from the tests above in that desktop sample, and it works great ... limiting variables. Add the .Directions to their sample, and they still get back good results, so that is not it. So unless I overlooked something, it has to be that lat/long is not enough info to pass it. But before adding that info to my page, I'll change their sample to see if it breaks. Nope, it works, lat/long is good enough to get directions from. So I'm out of ideas of why it is not working without going so far as to sniff the packets. Save that for another day. Go ahead and butcher my code trying to get it to work ... no luck, so give up and try to see if I can get the route to display graphically on a map at least. Also, noteworthy is that in the Directions object returned, does not even have total distance or driving time returned. 
  • Render-GetMapRoute() [Picture flavor] - While testing above, noted that I broke the sample's capability for rendering the route when setting the .Directions flag. So knew I would need to have the .Directions flag [int value 1] and the .CalculatedRouteRepresentation [int value 2]. Attempt to '|' them, and the 'Enum value of 0 is unknown' exception returns. NOTE 0 is what is successfully sent in the desktop sample when the enum is not set, same for the LatLong enum I had to set for the Find service. Try to '&' them, and get the 'Enum value of 3 is unknown' of course. Got no other options, so decide to call it twice with each flag, and then combine the results into a single object to pass on. Test to see if this hack works in the desktop sample and it does. Put it in my code, and get this error: 'Value cannot be found view[0]' ... which is the MapView property which would be in the results from the failed Route service call with the Directions flag. Did some more code butchering to see if I could some up with something ... no luck. Stuck here as well, save packet sniffing.
  • Config - Hate ending on unsuccessful notes, so revisited my config issues from Day One. Added an app.config to my source directory, and when I built it got copied correctly to the Debug and Release directories :), although I had no way to read it  :(. Remebered seeing a post, during the 3+ weeks, about somebody implementing the System.Configuration.AppSettings; went and grabbed that assembly here: http://www.nettech.co.nz/ConfigurationSDE.zip  Wish he would have done his namespace the way he named is assembly, but thankfully kept the interface the same. Wrote the author about a little bug, and he had it fixed within minutes, serious!, thanks Dino. The appName.exe.config came up as not found obviously, so set it as included in my project and 'content' to be deployed to the PPC to fix that. Works just as expected from there on. Cool, at least one thing works, too bad its not my code :( Wrote to him again, and his logic for making the namespace the same was for code reuse ... good point!
  • Started writing this ... to here. END

Day Three (5/26) - Sniff sniff

Yesterday afternoon stunk, so its time to start sniffing. One of the MS guys had recommended a couple diff packet sniffers. MS NetMon was my favorite for Win2K Server, but I'm on WinXP Pro now, and dont think you can install it on it. At least, could not find it. Tried out the ones he recommended and thought Ethereal was the best ... 'Sniffing the glue that holds the Internet together'. So busted it out, and started making requests. Saved 3 interactions each from both the CompactFramework and full .NET Framework to compare the results. You should be able to open these files in Ethereal if you want

NOTE would have much rather created a SoapExtension class to just write the request and responses off to file, instead of sniffing, but that class does not exist in the CF. Really dont think this is going to fly as people fumble around with their own security mechanisms and such while the Web Services standards solidify. Not that you can do heavy encryption on a 200mhz PPC, but their are light encryption algorithms out there

NOTE Each request was made with .PreAuthenticate not being set to true for PocketPC and the Desktop. GetEmptyWebProxy was ON for PocketPC calls unless specified and GetEmptyWebProxy was OFF for Desktop calls unless specified 

The txt saves are basically unreadable, even in Ethereal. But Ethereal has this option, where if you click on an HTTP line, then you can right click and say Follow TCP Stream. This gives you a much prettier dump of the associated HTTP Header, SOAP Request, HTTP Header, and hopefully SOAP Response. Did not do this for every request/response ... traced the larger file to note all the request and associated responses, and then broke out the pertinent ones that would allow me to do some pattern matching to see if I could figure out what was going on

NOTE the SOAP request is not even sent from the CF if one of the enums (LatLong or Direction/CalculatedRouteRepresentation) is not set. Initial guess is that the SOAP serializer fails beforehand with the enum value 0 is unknown. It is sent fine on the full .NET Framework, need to check out the differences between those requests.

NOTE So much for minimizing round trips! Have no clue why I kept getting so many 401 Unauthorized messages. Possibly because I took off the .PreAuthenticate()? Not like I sniff packets everyday (no comments please), but if that is what the internet is running on ... suck. Gathered the PocketPC data by using the PPC Emulator. The Desktop data is from Internet Explorer. Both were run off of my development machine, which is behind a Linksys switch connected through DSL. My actual PCC either connects through ActiveSync over USB to my dev machine, or directly to the switch with a Linksys CompactFlash 802.11b card

Right click-Save for the #'d txt files. You can click on the txt files in the tables to open them in the browser

  1. _Ppc-Find.FindAddress-Render.GetMap.txt
  2. _Ppc-Find.FindAddress-Render.GetMap (without GetEmptyWebProxy).txt
  3. _Ppc-Find.FindAddress-Route.CalculateSimpleRoute(2)-Render.GetRouteMap.txt
    • This is from pressing the Route button on my Directions tabPage. It had to find the lat/long for both addresses with the LatLong enum. Then it calls to get that Route twice, once with the Directions enum and then with CalculatedRouteRepresentation. Finally it calls GetRouteMap. Does not work because it exceptions about not having MapView within the Route results.
    • POST FindService401 Unauthorized  
      POST FindService200 OK 
      POST FindService200 OK  
      POST RouteService401 Unauthorized PPC-Route.CalculateSimpleRoute-401.txt
      POST RouteService200 OKPPC-Route.CalculateSimpleRoute-200.Direction.txt
      POST RouteService200 OKPPC-Route.CalculateSimpleRoute-200.Calculated.txt
      POST RenderService401 Unauthorized 
      POST RenderService401 Unauthorized  
      POST RenderService401 Unauthorized  
      POST RenderService401 Unauthorized  
      POST RenderService500 InternalServerError PPC-Render.GetRouteMap-500.txt
    • Internal Server Error is serialized to a full on SoapException
  4. _Desk-Render.GetMap.txt
  5. _Desk-FindAddress(2)-Route.CalculateSimpleRoute(2)-Render.GetRouteMap.txt
  6. _Desk-FindAddress(2)-Route.CalculateSimpleRoute-Render.GetRouteMap (with GetEmptyWebProxy).txt

Ok, my brain is near fried putting this together and I have not even analyzed it yet.

Headed to the gym at my apartment complex to relax the brains- and work on the -brawn. Being that I solve my hardest problems at the gym, realized that I still had some more variables; such as it might be my network connection OR a bad installation of the SDE. So I'm going to throw this over to my notebook, and walk over to Kinkos to see what's up. Going to walk there to continue my interrupted workout ... and just so I dont get lost :)

An hour later, and initial results look like it is not my network connection NOR installation. Got 401 Unauthorized errors from the desktop and emulator, as well as the Route service did not successfully work being called from the CF. Same thing, only minimal text was returned, nor was the total distance or driving time available.

Right click-Save for the these txt files

For little success, wrote simple file logic to support archiving of maps for the mapPage. Would be done if I could just get text directions and get a map with route overlay to generate.

 

Have knocked out a bunch of variables, but I need to do a recap because this is getting confusing:

  • PreAuthenticate
    • put it on desktop example to see if it gets rid of 401 errors
    • check out how requests are different
  • GetEmptyWebProxy - not a break error, whats diff about requests then
  • not setting enums - possibly a break error
    • LatLong enum - doesnt seem to be a break error because still works on Desktop when set to just LatLong
    • RouteResultMask
      • Direction - most likely break error, I believe this is what is breaking it all, even my hacks
      • CalculatedRouteRepresentation - this seems to return correct values, but I cant use it without Direction info, or can I?

Now, I'll start walking that list, plus more, to see if I can figure out what in the world is going on. Will be looking at the txt files above of SOAP request/responses to divine this info

  • PreAuthenticate
    • 401 - A little better asking for a route (same as 5 above) - Find 401, 200, 200, Route 401, 200, 200, Render 401, 200
      • Go ahead and hit some other sites that require basic authentication; Not getting any 401 errors from those trips
    • Requests - Dont see the difference. It makes the 1st request with no authorization. The response returns a WWW-Authenticated header, and then the next requests have an Authorization header. Does this for each Service proxy
  • GetEmptyWebProxy
    • PPC Requests - get an extra HTTP header Proxy-Authorization with digested credentials
    • Desktop Requests - no difference with or without
  • Serializing Enums
    • ResultMask.LatLong
      • PPC
        • SOAP Request body gets this param: <ResultMask>LatLongFlag</ResultMask>
        • Response only has <Score>0.9</Score><FoundLocation><LatLong Latitude="40.442375540442377" Longitude="79.999966624467532" /><GeoDataSource><Name>MapPoint.NA</Name><Version>NA.US.0C.0110</Version></GeoDataSource></FoundLocation>
      • Desktop
      • Result being you would have to call Find 4 times from the CF (hack), with each possible value of the ResultMask enum, to get the same result ... does this sound like a commercial for Total cereal ... I believe this is a bug in the SOAP serializer
    • RouteResultMask.Direction
      • PPC
        • SOAP Request body gets this param: <resultMask>Direction</resultMask>
        • Result is RRM.Direction.PPC.Result.xml Man, it has all my text driving info and everything. Even the View which I think is what the Render.GetRouteMap method is complaining about not having. Also, the total distance and driving time which aren't there when quickwatching that object in memory
        • I believe this is a bug in the SOAP deserializer, keeping this info from making it into object form
      • Desktop
      • Result being you have to call it twice from the CF, (hack) unless you intercept the request after serialization and set that element text to null (same for LatLong above). Not sure if you can do this without the SoapExtension hook, noted earlier.
    • RouteResultMask.CalculatedRouteRepresentation
      • The PPC request would be the same as above with CalculatedRouteRepresentation as the value. The result comes back as a bunch of bits, as in the Desktop result above ... so this seems to work fine

Hacks within hacks (Dune perversion)

This is how stubborn; err, umm ... persistent I am. From the above, the only real issue I dont have a workaround for is not getting the full results from the Route.ResultMask.Directions SOAP response deserialized properly into my runtime object. Specifically, the text to be saved off and displayed, total distance/driving time, and the View to pass off to Render.GetRouteMap. Yeah, yeah, yeah ... it's beta; but I dont want to wait, and might learn some more stuff by pushing the issue.

  1. Try new'ing the View object before calling Render.GetRouteMap ... think I tried this, and just forgot to document, but not sure ... stupid stupid
    • new was not enough, but it complained about a CenterPoint after that. So calculated that with the idea from step 3 below and it rendered this map!
    • Sweet success! The picture sucks, but when I set the CenterPoint, noticed a bounding rectangle property, so will set that next.
    • My work here is done ... sweet! Actually, it still has the following bug that I cannot fix:
    • See how the path goes off the screen to the left. Since my hack is creating the bounding rectangle off of the to/from locations, then I cannot handle that. NOTE how the image is rotated, more on this later
  2. Direct access to the SOAP Response before deserialization (same for the SOAP request before serialization because then could set the enums to null to make chunky calls). This would allow me to get the text directions from the response, and also create the appropriate request for Render.GetRouteMap ... preferred hack
    • So all I have left to do is get the txt directions.
    • Checking the generated proxy, it comes down to this:
      • object[] results = this.Invoke("CalculateSimpleRoute", new object[] { geoWaypoints, resultMask});
      • return ((Route)(results[0]));
    • By doing a quickwatch on the results array, see that I have already lost the info that is in the SOAP result, and not in the cast ... so without a SOAP extension, do not think it can be hooked with the CF
  3. Figure out the centerPoint between the from/to address. Gen a CenterPoint map from that, and then overlay the CalculatedRouteRepresentation, if those bits properly render to an image ...  a hack to be proud of
    • saved off the bits from the  CalculatedRouteRepresentation ... not sure what it is, but it is not a gif, so this would not have worked; but the centerPoint idea spawned the idea that ultimately got 1 above to work 
    • Here is a link to those bits: nmm_route.gif GCRR? NOTE i really mean that it is not a gif, so you cant view it as one
  4. The Render.GetMap returns the image, as well as a View element. That might be useful for a perversion of 3 above
    • unnecessary at this point

Outstanding Issues

Hoping somebody from MS will help me address these

  • What is up with all these 401 Unauthorized responses
  • Why did my initial sample code work fine for the MS guys, but not for me and others

Image Rotation

The display on PPC is 320x240. With actual viewing area for apps being 300x240. Since space is so critical, wanted to squeeze as much out of it as I could. To do this, decided to ask for a differently sized image from the MapPoint service and then rotate it on the client. i.e. for paths that travel mostly east to west (based on bounding rectangle), will want to ask for a 240x300 image from the web service and then rotate it to 300x240 to display on the device. The user can just rotate the device in their hand to read it. The result being:

Since the CF Bitmap implementation did not have its own .Rotate() method, I wrote my own by doing pixel flipping. This ended up being SLOW! 2 minutes on the emulator per image and 45 seconds on my actual PPC device. My 1st idea was to have the server to the rotation, but MapPoint .NET does not currently offer that. 2nd idea was to just add a progress bar ... which I did

3rd idea, which I will revisit, is instead of doing the bit flipping between 2 bitmap objects; should attempt to use the lower level System.Drawing.Graphics object. Until the, this delay only happens for paths that are longer horizontally then vertically

Image Overlay

The image rotation added this extra requirement, because I could easily see getting confused which wasy was North. So this just takes a little graphic and overlays it on the map to display which way is North. Although, you can do this on the server using the service, this is not processor intensive and I wanted to do it client-side for kicks. The result being (my Kinko's trip):

And for a map that has been rotated, it is pointing left.

Until you flip your PocketPC. NOTE this map is the rotated version of a map above, the one that I got to render after the bounding rectangle hack. This gives you an idea of how much space was reclaimed

Future

This is stuff I still want to do

  • On the emulator, it can save state ... even files, anybody know where that gets saved, and if I can get to those files on my full desktop machine?
  • Do the image rotation using the Graphics object to see if it performs better, if not; then add a Cancel button during the progressBar

Source

My full source is here, minus my password! You will have to enter your own MapPoint credentials to actually run it

Full C# Source Code: noMadMapSrc.zip - updated 5/31

Full Ethereal Packet Sniffs: noMadMapEth.zip

Updates

5/28/2002 - fixed some bugs, will zip up that code later. converted article to MS Reader eBook .lit format so you can read on your PPC  noMadMap.lit

5/31/2002 - finished off most of everything i wanted to do with this: including image rotation and image overlays. the new version of the source is posted. got my speech .NET beta in the mail, so i probably will not touch this anymore.

7/4/2002 - Just saw that the CF team have released a MapPoint .NET sample on GotDotNet.com: http://www.gotdotnet.com/team/netcf/mappoint/default.aspx It includes an update to the CF beta that fixes the WebService bugs that I had to hack around above ... "The MapPoint .NET sample contains both a Visual Studio .NET project targeting the .NET Compact Framework, and an update to the Web Service components of the .NET Compact Framework."

7/18/2002 - installed the update mentioned above, and it works great. here is the code to retrieve the textual output that I could not retrieve previously, as well as a screenshot of the resulting output.

dirBox.AppendText("dist: " + r.Direction.Directions[0].Distance.ToString("##.##"));
dirBox.AppendText("/r/n");
dirBox.AppendText("time: " + r.Direction.DrivingTime.ToString("##.##"));
dirBox.AppendText("/r/n");
foreach(SegmentDirection sd in r.Direction.Directions)
{
	foreach(DirectionPrimitive dp in sd.Direction)
	{
		dirBox.AppendText(dp.Instruction + " " + dp.Distance.ToString("##.##"));
		dirBox.AppendText("/r/n");
	}
}

This image is one pulled directly from the file system of my PPC. Before I could do image rotations and overlays. No clue why Houston and Toronto have boxes around them?

 

http://www.mperfect.net/nmmWeb/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值