Vous êtes sur la page 1sur 63

M11: Network Communication

in Windows Phone 8
Target Agenda | Day 1
Module and Topic | 10-minute breaks after each session / 60-minute meal break
Planned
Duration
1a - Introducing Windows Phone 8 Application Development | Part 1 50:00
1b - Introducing Windows Phone 8 Application Development | Part 2 50:00
2 - Designing Windows Phone Apps 50:00
3 - Building Windows Phone Apps 50:00
4 - Files and Storage on Windows Phone 8 50:00
Meal Break | 60-minutes 60:00
5 - Windows Phone 8 Application Lifecycle 50:00
6 - Background Agents 25:00
7 - Tiles and Lock Screen Notifications 25:00
8 - Push Notifications 30:00
9 - Using Phone Resources on Windows Phone 8 50:00
Target Agenda | Day 2
Module and Topic | 10-minute breaks after each session / 60-minute meal break
Planned
Duration
10 - App to App Communication 35:00
11 - Network Communication on Windows Phone 8 50:00
12 - Proximity Sensors and Bluetooth 35:00
13 - Speech Input on Windows Phone 8 35:00
14 - Maps and Location on Windows Phone 8 35:00
15 - Wallet Support 25:00
16 - In App Purchasing 25:00
Meal Break | 60-minutes 60:00
17 - The Windows Phone Store 50:00
18 - Enterprise Applications in Windows Phone 8: Architecture and Publishing 50:00
19 - Windows 8 and Windows Phone 8 Cross Platform Development 50:00
20 Mobile Web 50:00
Networking for Windows Phone
WebClient
HttpWebRequest
Sockets
Web Services and OData
Simulation Dashboard
Data Compression
Module Agenda
Networking for
Windows Phone
Support for networking features
Windows Communication Foundation (WCF)
HttpWebRequest
WebClient
Sockets
Full HTTP header access on requests
NTLM authentication
Networking for Windows Phone
6
Two different Networking APIs
System.Net Windows Phone 7.1 API, upgraded with new features
Windows.Networking.Sockets WinRT API adapted for Windows Phone
Support for IPV6
Support for the 128-bit addressing system added to System.Net.Sockets and also is
supported in Windows.Networking.Sockets
NTLM and Kerberos authentication support
Incoming Sockets
Listener sockets supported in both System.Net and in Windows.Networking
Winsock support
Winsock supported for native development
New Features in Windows Phone 8
Networking APIs Platform Availability
API WP7.1 WP8 W8
System.Net.WebClient


System.Net.HttpWebRequest

System.Net.Http.HttpClient

Windows.Web.Syndication.SyndicationClient

Windows.Web.AtomPub.AtomPubClient

ASMX Web Services

WCF Services

OData Services

C# 5.0 includes the async and await keywords to ease writing of asynchronous code
In desktop .NET 4.5, and in Windows 8 .NET for Windows Store Apps, new Task-based
methods allow networking calls as an asynchronous operation using a Task object
HttpClient API
WebClient.DownloadStringTaskAsync(), DownloadFileTaskAsync(),
UploadStringTaskAsync() etc
HttpWebRequest.GetResponseAsync()
These methods are not supported on Windows Phone 8
Task-based networking using WebClient and HttpWebRequest still possible using
TaskFactory.FromAsync() and extension methods
Coming up later
Async support in WP8 Networking APIs
Connecting the Emulator
to Local Services
In Windows Phone 7.x, the emulator shared the networking of the Host PC
You could host services on your PC and access them from your code using
http://localhost...
In Windows Phone 8, the emulator is a Virtual machine running under Hyper-V
You cannot access services on your PC using http://localhost...
You must use the correct host name or raw IP address of your host PC in URIs

Windows Phone 8 Emulator and localhost
WCF Service Activation
If your service is a WCF service, you must also ensure that HTTP Activation is checked in
Turn Windows features on or off
Configuring Web Sites Running in Local IIS 8
Create your website or web service in Visual Studio 2012
Run it and it is configured to run in localhost:port
Note the port number. Here it is: 18009

Configuring Sites Running in IIS Express
STEP 1: Create Your Website or Web service

Remove your website (dont delete!) from the Visual Studio 2012 solution
Edit the file C:\Users\yourUsername\Documents\IISExpress\config\applicationhost.config
Find the <sites> section
Find the entry for the website or service you just created
Change
<binding protocol="http" bindingInformation="*:18009:localhost" />
to
<binding protocol="http" bindingInformation="*:18009:YourPCName" />
Save changes
Use Add Existing Website to add the website folder back into your solution
Configuring Sites Running in IIS Express
STEP 2: Modify Config to Run on a URI Using Your PC Name
From a Command Prompt (Run as Administrator), open the port in the Firewall:
netsh advfirewall firewall add rule name="IIS Express (non-SSL)" action=allow
protocol=TCP dir=in localport=18009
Also run the following at the command prompt:
netsh http add urlacl url=http://yourPC:18009/ user=everyone
Substitute yourPC with the host name of your Host PC
Substitute 8080 for the port where your service is running
Run it and access from your desktop browser Now it is hosted at YourPCName:1800
Configuring Sites Running in IIS Express
STEP 3: Open Port in the Firewall and Register URL
Useful References | How to: Specify a Port for the Development Server
http://msdn.microsoft.com/en-us/library/ms178109(v=VS.100).aspx
WebClient
Simple Http Operations WebClient
using System.Net;
...

WebClient client;

// Constructor
public MainPage()
{
...
client = new WebClient();
client.DownloadStringCompleted += client_DownloadStringCompleted;
}

void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
this.downloadedText = e.Result;
}

private void loadButton_Click(object sender, RoutedEventArgs e)
{
client.DownloadStringAsync(new Uri("http://MyServer/ServicesApplication/rssdump.xml"));
}
WebClient using async/await
No Task-based async methods have been added to WebClient
Async operation possible using custom extension methods, allowing usage such as:
using System.Net;
using System.Threading.Tasks;
...

private async void loadButton_Click(object sender, RoutedEventArgs e)
{
var client = new WebClient();
string response = await client.DownloadStringTaskAsync(
new Uri("http://MyServer/ServicesApplication/rssdump.xml"));
this.downloadedText = response;
}
Demo 1: Simple HTTP
Networking
with WebClient
More Control HttpWebRequest
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
var request = HttpWebRequest.Create("http://myServer:15500/NorthwindDataService.svc/Suppliers")
as HttpWebRequest;
request.Accept = "application/json;odata=verbose";
// Must pass the HttpWebRequest object in the state attached to this call
// Begin the request
request.BeginGetResponse(new AsyncCallback(GotResponse), request);
}

HttpWebRequest is a lower level API that allows access to the request and
response streams
That state object passed in the BeginGetResponse call must be the initiating
HttpWebREquest object or a custom state object containing the HttpWebRequest
HttpWebRequest Response Handling
private void GotResponse(IAsyncResult asynchronousResult)
{
try
{
string data;
// State of request is asynchronous
HttpWebRequest myHttpWebRequest = (HttpWebRequest)asynchronousResult.AsyncState; ;
using (HttpWebResponse response = (HttpWebResponse)myHttpWebRequest.EndGetResponse(asynchronousResult))
{
// Read the response into a Stream object.
System.IO.Stream responseStream = response.GetResponseStream();
using (var reader = new System.IO.StreamReader(responseStream))
{
data = reader.ReadToEnd();
}
responseStream.Close();
}

// Callback occurs on a background thread, so use Dispatcher to marshal back to the UI thread
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("Received payload of " + data.Length + " characters");
} );
}
catch (Exception e) ...
}
HttpWebRequest Error Handling
private void GotResponse(IAsyncResult asynchronousResult)
{
try
{
// Handle the Response
...
}
catch (Exception e)
{
var we = e.InnerException as WebException;
if (we != null)
{
var resp = we.Response as HttpWebResponse;
var code = resp.StatusCode;
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("RespCallback Exception raised! Message:" + we.Message +
"HTTP Status: " + we.Status);
});
}
else
throw;
}
}
HttpWebRequest Using TPL Pattern
private async void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
var request = HttpWebRequest.Create("http://rockstar:15500/NorthwindDataService.svc/Suppliers")
as HttpWebRequest;
request.Accept = "application/json;odata=verbose";
// Use the Task Parallel Library pattern
var factory = new TaskFactory();
var task = factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);

try
{
var response = await task;

// Read the response into a Stream object.
System.IO.Stream responseStream = response.GetResponseStream();
string data;
using (var reader = new System.IO.StreamReader(responseStream))
{
data = reader.ReadToEnd();
}
responseStream.Close();

MessageBox.Show("Received payload of " + data.Length + " characters");
}
catch (Exception ex)...
HttpWebRequest (TPL) Error Handling
private async void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
try
{
// Make the call and handle the Response
...
}
catch (Exception e)
{
var we = e.InnerException as WebException;
if (we != null)
{
var resp = we.Response as HttpWebResponse;
var code = resp.StatusCode;
MessageBox.Show("RespCallback Exception raised! Message:" + we.Message +
"HTTP Status: " + we.Status);
}
else
throw e;
}
}
Demo 2:
HttpWebRequest
Sockets
Sockets Support in Windows Phone OS 8.0
TCP
Connection-oriented
Reliable Communication
UDP Unicast, UDP Multicast
Connectionless
Not Reliable
New Features in 8.0!
IPV6 support
Listener Sockets
Windows.Networking.Sockets
Windows Phone Runtime API
Compatible with Windows 8 WinRT
Revamped API
Much more concise!

Web Services
Can Add Reference from Windows
Phone projects to automatically
generate proxy classes
ASMX should just work
WCF requires that you use
basicHttpBinding
WCF/ASMX Services
RESTful Web Services

Building them
Rather than building walled gardens, data should be published in a way that allows it to
reach the broadest range of mobile clients
Old-style ASMX SOAP 1.1 Web Services using ASP.NET or Windows Communication
Foundation (WCF) require clients to implement SOAP protocol
With Windows Phone 7 and Silverlight, we use WCF with BasicHttpBinding both on-premise
and as a Web Role in Windows Azure to publish our data from local and cloud-based data
sources like SQL Azure
Recommend using lightweight REST + JSON Web Services that are better optimized for
high-latency, slow, intermittent wireless data connections
WCF Data Services: OData
WCF Data Services provide an extensible tool for
publishing data using a REST-based interface
Publishes and consumes data using the OData web
protocol (http://www.odata.org)
Formatted in XML or JSON
WCF Data Services Client Library
(DataServicesClient) is a separate download from
NuGet
Adds Add Service Reference for OData V3 Services
<?xml version="1.0" encoding="utf-8"
standalone="yes" ?>
<service xml:base=
"http://odata.netflix.com/Catalog/ ">
<workspace>
<atom:title>Default</atom:title>
<collection href="Genres">
<atom:title>Genres</atom:title>
</collection>
<collection href="Titles">
<atom:title>Titles</atom:title>
</collection>

</workspace>
</service>
WCF Data Services 5.1
Download WCF Data services 5.1 Tools Installer to update item templates for server side
components
Major release: Adds support for new JSON Light serialization format
Generate Client Proxy
In most cases, Add Service Reference will just work
Alternatively, open a command prompt as administrator and navigate to
C:\Program Files (x86)\Microsoft WCF Data Services\5.0\tools\Phone
Run this command
DataSvcutil_WindowsPhone.exe /uri:http://odata.netflix.com/v2/Catalog/
/DataServiceCollection /Version:1.0/out:netflixClientTypes
Add generated file to your project
Fetching Data
public partial class NorthwindModel
{
NorthwindEntities context;
private DataServiceCollection<Customer> customers;

private override void LoadData()
{
context = new NorthwindEntities(new Uri("http://services.odata.org/V3/Northwind/Northwind.svc/"));
// Initialize the context and the binding collection
customers = new DataServiceCollection<Customer>(context);

// Define a LINQ query that returns all customers.
var query = from cust in context.Customers
select cust;

// Register for the LoadCompleted event.
customers.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(customers_LoadCompleted);

// Load the customers feed by executing the LINQ query.
customers.LoadAsync(query);
}
...
Fetching Data - LoadCompleted
36
...

void customers_LoadCompleted(object sender, LoadCompletedEventArgs e)
{
if (e.Error == null)
{
// Handling for a paged data feed.
if (customers.Continuation != null)
{
// Automatically load the next page.
customers.LoadNextPartialSetAsync();
}
else
{
foreach (Customer c in customers)
{
//Add each customer to our View Model collection
App.ViewModel.Customers.Add(new CustomerViewModel(){SelectedCustomer = c});
}
}
}
else
{
MessageBox.Show(string.Format("An error has occurred: {0}", e.Error.Message));
}
}
Demo 3:
OData Services
Network Information
and Efficiency
Making Decisions based on Data Connections
Mobile apps shouldnt diminish the user experience by trying to send or receive data in
the absence of network connectivity
Mobile apps should be intelligent about performing heavy data transfers or lightweight
remote method calls only when the appropriate data connection is available
With Windows Phone, we use the NetworkInterfaceType object to detect network type and
speed and the NetworkChange object to fire events when the network
state changes
Network Awareness

39
NetworkInformation in Windows Phone 8.0
In Microsoft.Phone.Net.NetworkInformation namespace:
Determine the Network Operator:
DeviceNetworkInformation.CellularMobileOperator
Determine the Network Capabilities:
DeviceNetworkInformation.IsNetworkAvailable
DeviceNetworkInformation.IsCellularDataEnabled
DeviceNetworkInformation.IsCellularDataRoamingEnabled
DeviceNetworkInformation.IsWiFiEnabled
In Windows.Networking.Connectivity namespace:
Get Information about the current internet connection
NetworkInformation.GetInternetConnectionProfile
Get Information about the NetworkAdapter objects currently connected to a network
NetworkInformation.GetLanIdentifiers
Determining the Current Internet Connection Type
private const int IANA_INTERFACE_TYPE_OTHER = 1;
private const int IANA_INTERFACE_TYPE_ETHERNET = 6;
private const int IANA_INTERFACE_TYPE_PPP = 23;
private const int IANA_INTERFACE_TYPE_WIFI = 71;
...
string network = string.Empty;
// Get current Internet Connection Profile.
ConnectionProfile internetConnectionProfile =
Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();

switch (internetConnectionProfile.NetworkAdapter.IanaInterfaceType)
{
case IANA_INTERFACE_TYPE_OTHER:
cost += "Network: Other"; break;
case IANA_INTERFACE_TYPE_ETHERNET:
cost += "Network: Ethernet"; break;
case IANA_INTERFACE_TYPE_WIFI:
cost += "Network: Wifi\r\n"; break;
default:
cost += "Network: Unknown\r\n"; break;
}
Tips for Network Efficiency
Mobile devices are often connected to poor quality network connections
Best chance of success in network data transfers achieved by
Keep data volumes as small as possible
Use the most compact data serialization available (If you can, use JSON instead of XML)
Avoid large data transfers
Avoid transferring redundant data
Design your protocol to only transfer precisely the data you need and no more

Demo 4: Wire Serialization
Wire Serialization Affects Payroll Size
Simple test case: download
30 data records
Each record just 12 fields
Measured bytes to transfer

Wire Serialization Format Size in Bytes
ODATA XML 73786
ODATA JSON 34030
REST + JSON 15540
REST + JSON GZip 8680
Implementing Compression on Windows Phone
Windows Phone does not support System.IO.Compression.GZipStream
Use third-party solutions instead
SharpZipLib is a popular C# compression library (http://sharpziplib.com/) on NuGet
SharpCompress is another (http://sharpcompress.codeplex.com/)
On Windows Phone OS 7.1, get GZipWebClient from NuGet
Replaces WebClient, but adds support for compression
Uses SharpZipLib internally
NuGet release for Windows Phone 8 not yet available (as of October 2012)
Until updated library released on NuGet, source is available online
HttpWebRequest With Compression
var request = HttpWebRequest.Create("http://yourPC:15500/NorthwindDataService.svc/Suppliers")
as HttpWebRequest;
request.Accept = "application/json;odata=verbose";
request.Headers["Accept_Encoding"] = "gzip";

// Use the Task Parallel Library pattern
var factory = new TaskFactory();
var task = factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);

var response = await task;

// Read the response into a Stream object.
System.IO.Stream responseStream = response.GetResponseStream();
string data;
var stream = new GZipInputStream(response.GetResponseStream());
using (var reader = new System.IO.StreamReader(stream))
{
data = reader.ReadToEnd();
}
responseStream.Close();
Compression with OData Client Library
private void EnableGZipResponses(DataServiceContext ctx)
{
ctx.WritingRequest += new EventHandler<ReadingWritingHttpMessageEventArgs>(
(_, args) =>
{
args.Headers["Accept-Encoding"] = "gzip";
} );
ctx.ReadingResponse += new EventHandler<ReadingWritingHttpMessageEventArgs>(
(_, args) =>
{
if (args.Headers.ContainsKey("Content-Encoding") &&
args.Headers["Content-Encoding"].Contains("gzip"))
{
args.Content = new GZipStream(args.Content);
}
} );
}
Reference: http://blogs.msdn.com/b/astoriateam/archive/2011/10/04/odata-compression-in-windows-phone-7-5-mango.aspx
Demo 5:
Compression
48
Data Sense
The Data Sense feature allows a user to specify the limits of their data plans and monitors their usage
Your app can use the information provided by the Data Sense APIs to change data usage behavior
Reduce data usage when the user is close to their data limits
Discontinue data usage when the user is over their limit
Or to postpone tasks that transfer data until a Wi-Fi connection is available
Data Sense is a feature that Network Operators optionally support
Provide a Data Sense app and Tiles to allow users to enter their data limits
Routes data via a proxy server in order to monitor data usage
If Data Sense is not enabled, you can still use the APIs to determine if the user is connected to WiFi or
is roaming, but you cannot determine the users data limits

Data Sense API

Using the Data Sense APIs
1. Get the Network Type from the
ConnectionProfile by calling NetworkInformation.
GetInternetConnectionClient
2. Get the NetworkCostType by calling
ConnectionProfile.GetConnectionCost
3. Get the ApproachingDataLimit,
OverDataLimit and Roaming properties of the
ConnectionProfile
If on WiFi, no need to limit data
usage
Returns Unknown, Unrestricted,
Fixed or Variable: If Unrestricted,
no need to limit data usage
If any are true, your app can
reduce or eliminate data usage
Responsible Data Usage in a Data Sense-Aware App

NetworkCostType ConnectionCost Responsible data usage Examples
Unrestricted Not applicable. No restrictions.
Stream high-definition video.
Download high-resolution
pictures.
Retrieve email attachments.
Fixed or Variable
All three of the following
properties are false.
ApproachingDataLimit
OverDataLimit
Roaming
No restrictions.

Stream high-definition video.
Download high-resolution
pictures.
Retrieve email attachments.

Fixed or Variable
or
Unknown

ApproachingDataLimit is true,
when NetworkCostType is Fixed
or Variable.

Not applicable when
NetworkCostType is Unknown.
Transfer less data.
Provide option to override.

Stream lower-quality video.
Download low-resolution
pictures.
Retrieve only email headers.
Postpone tasks that transfer
data.
Fixed or Variable
OverDataLimit or Roaming is
true
Dont transfer data.
Provide option to override.
Stop downloading video.
Stop downloading pictures.
Do not retrieve email.
Postpone tasks that transfer data.
Network Security
You can use SSL (https://...) to encrypt data communications with servers that have an SSL
server cert
Root certificates for the major Certificate Authorities (Digicert, Entrust, Verisign, etc) are
built into Windows Phone 8
Your app can simply access an https:// resource and the server certificate is
automatically verified and the encrypted connection set up
SSL Client certificates are not supported, so mutual authentication scenarios are not
possible
You can install a self-signed cert into the Windows Phone Certificate Store
Expose the .cer file on a share or website protected by authentication
Alllows you to access private servers secured by a self-signed server certificate
Encrypting the Communication
Authentication
As well as encrypting data in transit, you also need to authenticate the client to make sure
they are allowed to access the requested resource
For communications over the Internet, secure web services using Basic HTTP authentication
Transfers the username and password from client to server in clear text, so this must be
used in conjunction with SSL encryption
For Intranet web services, you can secure them using Windows or Digest authentication
Windows Phone 8 supports NTLM and Kerberos authentication

Adding Credentials to an HttpWebRequest
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
var request = HttpWebRequest.Create("http://myServer:15500/NorthwindDataService.svc/Suppliers")
as HttpWebRequest;
request.Credentials = new Credentials("username", "password"); // override allows domain to be specified

request.Accept = "application/json;odata=verbose";
// Must pass the HttpWebRequest object in the state attached to this call
// Begin the request
request.BeginGetResponse(new AsyncCallback(GotResponse), request);
}

Provide your own UI to request the credentials from the user
If you store the credentials, encrypt them using the ProtectedData class
Encrypting Sensitive Data Using ProtectedData
private void StoreCredentials()
{
// Convert the username and password to a byte[].
byte[] secretByte = Encoding.UTF8.GetBytes(TBusername.Text + "||" + TBpassword.Text);

// Encrypt the username by using the Protect() method.
byte[] protectedSecretByte = ProtectedData.Protect(secretByte, null);

// Create a file in the application's isolated storage.
IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream writestream =
new IsolatedStorageFileStream(FilePath, System.IO.FileMode.Create, System.IO.FileAccess.Write, file);

// Write data to the file.
Stream writer = new StreamWriter(writestream).BaseStream;
writer.Write(protectedSecretByte, 0, protectedSecretByte.Length);
writer.Close();
writestream.Close();
}
Decrypting Data Using ProtectedData
// Retrieve the protected data from isolated storage.
IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream readstream =
new IsolatedStorageFileStream(FilePath, System.IO.FileMode.Open, FileAccess.Read, file);

// Read the data from the file.
Stream reader = new StreamReader(readstream).BaseStream;
byte[] encryptedDataArray = new byte[reader.Length];

reader.Read(encryptedDataArray, 0, encryptedDataArray.Length);
reader.Close();
readstream.Close();

// Decrypt the data by using the Unprotect method.
byte[] clearTextBytes = ProtectedData.Unprotect(encryptedDataArray, null);

// Convert the byte array to string.
string data = Encoding.UTF8.GetString(clearTextBytes, 0, clearTextBytes.Length);
Storing Data in the Cloud
Live SDK
Windows Live SDK
Makes it easy to use SkyDrive in your
Windows Phone and Windows 8 apps
Live SDK also available for iOS and Android
Store data in the cloud in the Microsoft
Account users SkyDrive
Restriction on acceptable file types now
removed!
Share data between Windows 8 and mobile device apps
http://msdn.microsoft.com/en-us/live/default.aspx
Windows Azure Mobile Services
http://www.windowsazure.com/en-
us/develop/mobile/
Easily build a cloud backend for your app
Easy to create a Windows Azure database
accessed via RESTful services
Authentication against Microsoft Account,
Facebook, Twitter or Google
Push Notifications
Client SDKs for Windows 8, Windows Phone
and iOS Android coming soon
Great tutorials on the website


Demo :
Windows Azure Mobile Services
Summary
WebClient and HttpWebRequest for HTTP communications
Windows Phone has a sockets API to support connection-oriented and connectionless
TCP/IP and UDP/IP networking
Support for ASMX, WCF and REST Web Services
DataServicesClient for OData service access
Consider JSON serialization for maximum data transfer efficiency
Windows Phone 8 supports Basic, NTLM, digest and Kerberos authentication
Encrypt sensitive data on the phone using the ProtectedData class
Live SDK and Windows Azure Mobile Services ease integration with the cloud
The information herein is for informational
purposes only an represents the current view of
Microsoft Corporation as of the date of this
presentation. Because Microsoft must respond
to changing market conditions, it should not be
interpreted to be a commitment on the part of
Microsoft, and Microsoft cannot guarantee the
accuracy of any information provided after the
date of this presentation.
2012 Microsoft Corporation.
All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.
MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION
IN THIS PRESENTATION.

Vous aimerez peut-être aussi