簡単なモバイルアプリケーション開発10
〜 いまどこサービス
開発環境: Visual Studio 2008/SQL Server 2000
1.目次
2.目的
3.参考書
4.作り方
5.Willcom_03_側のアプリケーション開発
6.WEB からの検索
7.ダウンロード
8.まとめ
最近、仕事が忙しくって、妻が今どこにいるの?ご飯いるの?と心配してくれるのはうれしいのだけれど、返事する時間ももったいない。そこで、Willcom
03 の位置情報をデータベースにアップロードして、Web から位置情報を見れるようにしておけば・・・
ということで、位置情報を取得する方法はわかっているので、あとは実装するだけ。
注意:
- このサービスはベーター版です。こちらの都合で、いつ停止するわかかりません。
- このサービス、およびアプリケーションに対して、いかなる保証も行いません。
- 位置精度は、数十メートルの誤差があります。
-
Willcom
03 での自局番号、緯度、経度情報の取得
-
現在の緯度、経度の取得
4.1 基本的な動作
基本的な動作は、つぎのようになります。
4.2 Willcom 03 の位置情報の取得
Willcom 03 では、W-SIM
より、基地局の郵便番号、緯度、経度情報を取得することができます。この方法に関しては、参考文献(1)、(2) を参照してください。
ただし、Willcom の基地局の緯度、経度データは日本測地系なのですが、Google マップは
世界測地系で、少しずれが生じます。
http://www.k-erc.pref.kanagawa.jp/learning/gakusyuDB/chizu/I_HK/I_HK.htm 参照。
そこで、緯度、経度情報の日本測地系から世界測地系への返還が必要になります。
変換は、正確に行うためにはかなり大変なんですが、東京近辺での簡易変換式は次に載っていました。
http://homepage3.nifty.com/Nowral/02_DATUM/02_DATUM.html
このツールでは、この近似式を使用しています。なお、浮動小数点だと精度が足りないため、倍精度小数点で計算する必要があります。
double BWGS84 = latitude - 0.00010695D * latitude +
0.000017464D * longitude + 0.0046017D;
double LWGS84 = longitude - 0.000046038D * latitude - 0.000083043D *
longitude + 0.010040D;
4.3 データベースの作成
W03 で取得した経度、緯度情報をホスティングサーバーのデータベースにアップロードします。そのために、まず Location テーブルを作成します。
なお、ホスティングサーバーでは、SQL Server 2000, .NET Framework 2.0以上がサポートされている必要があります。
テーブルを作るスクリプトは、次の通り。
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Location]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[Location]
GO
CREATE TABLE [dbo].[Location] (
[ID] [int] IDENTITY (1, 1) NOT NULL ,
[GUID] [nvarchar] (50) COLLATE Japanese_CI_AS NOT NULL ,
[Latitude] [float] NULL ,
[Longitude] [float] NULL ,
[Date] [datetime] NOT NULL
) ON [PRIMARY]
GO
4.4 ストアドの作成
W03 で取得した経度、緯度情報をデータベースにアップロードしますが、同じ GUID がなければ INSERT、同じ GUID
があれば、UPDATEするようにします。そのために、つぎのようなストアドを作成しておきます。UPDATE時には、更新日(Date)を更新するようにします。
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[UpdateLocation]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[UpdateLocation]
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
CREATE PROCEDURE UpdateLocation
@GUID nvarchar(50),
@Latitude float,
@Longitude float
AS
IF EXISTS (SELECT * FROM Location WHERE GUID=@GUID)
UPDATE Location
SET Latitude = @Latitude, Longitude= @Longitude, Date=GetDate() WHERE GUID=@GUID
ELSE
INSERT INTO Location (GUID, Latitude, Longitude)
VALUES (@GUID, @Latitude, @Longitude)
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
4.5 データベースに緯度、経度情報をアップロードするための Web Service を作成します。
Willcom 03 からのデータベースの書き込みは、呼び出しが簡単な Web Service を使用します。ここで、作成したストアドにパラメータを渡して呼び出すようにします。
// Hosting
const string connectionString = "....";
[WebMethod]
public int UpdateLocation(string Guid, double latitude, double longitude)
{
SqlConnection sqlConn = new SqlConnection(connectionString);
SqlCommand sqlCmdStored = new SqlCommand("UpdateLocation");
sqlCmdStored.CommandType = System.Data.CommandType.StoredProcedure;
SqlParameter nvGuid = new SqlParameter("@GUID", SqlDbType.NVarChar, 50);
nvGuid.Value = Guid;
sqlCmdStored.Parameters.Add(nvGuid);
SqlParameter fLatitude = new SqlParameter("@Latitude", SqlDbType.Float);
fLatitude.Value = latitude;
sqlCmdStored.Parameters.Add(fLatitude);
SqlParameter fLongitude = new SqlParameter("@Longitude", SqlDbType.Float);
fLongitude.Value = longitude;
sqlCmdStored.Parameters.Add(fLongitude);
sqlConn.Open();
sqlCmdStored.Connection = sqlConn;
int res = sqlCmdStored.ExecuteNonQuery();
return res;
}
実行すると、次のような Web ページが起動します。そこで、適当な値を入れて、「起動」ボタンを押します。
データベース上で、次のように新しい行が挿入されていればOKです。
次に、次のように同じ Guid で値を変えて試してみます。
次のように、同じGuid の Latitude, Longitudeが更新されていれば OK です。
4.6 GUID を渡して、Google Map へのURL を返す Web Service を作成します。
次に、クライアントから GUID を渡して、その緯度、経度をデータベースから読みだし、Google Map の URLに変換して返す Web Service を作成します。
ここでは、単に SELECT * From Location WHERE GUID = @nvGuid というように
GUIDパラメータに一致する行を取得し、URLを組み立てて、Web Service の引数にして返してあげます。
// Hosting
const string connectionString = "....";
public string GetUrl(string Guid)
{
SqlConnection sqlConn = new SqlConnection(connectionString);
SqlCommand sqlSelect = new SqlCommand("SELECT * From Location WHERE GUID = @nvGuid");
sqlSelect.CommandType = System.Data.CommandType.Text;
SqlParameter nvGuid = new SqlParameter("@nvGuid", SqlDbType.NVarChar, 50);
nvGuid.Value = Guid;
nvGuid.SourceColumn = "nvGuid";
sqlSelect.Parameters.Add(nvGuid);
sqlConn.Open();
sqlSelect.Connection = sqlConn;
using (SqlDataReader dr = sqlSelect.ExecuteReader())
{
// http://maps.google.co.jp/maps?q=35.655152,+139.704444&hl=ja
if (dr.Read())
{
double latitude = (double)dr["Latitude"];
double longitude = (double)dr["Longitude"];
string url = "http://maps.google.co.jp/maps?q=" + latitude.ToString()
+ ",+" + longitude.ToString() + "&hl=ja";
return url;
}
}
return "";
}
実行すると、次のような Web ページが起動します。そこで、適当な値を入れて、「起動」ボタンを押します。
次のような結果が帰ってくれば OKです。
4.7 ホスティングサーバーに Web Service を発行
ここまでで、動作を確認したら、ホスティングサーバーに Web Service を発行します。
すると、Web Server に Virtual Directory が作成されます。ホストサーバーの Web
サーバー管理ツールから、この場所の Script 実行権を与えます。
以上で、http://uchukamen.com/w03location/w03location.asmx
への Web Service の発行が完了します。
Willcom 03 側のアプリケーションは、データベースへの書き込みをWeb Service化してあることにより、かなり簡単になります。
5.1 設定ファイルの書き込み、読み出し
設定ファイルの書き込み、読み出し部分です。最初は、電話番号で引こうと思いましたが、個人情報のこともあり、GUIDにしました。
using System;
using System.Text;
using System.Xml;
using System.Reflection;
using System.IO;
namespace uchukamen.WZero3
{
public class ConfigFile
{
# region プロパティ
private string guid = ""; // GUID
public string Guid
{
get { return guid; }
set { guid = value; }
}
private int interval = 10*60*1000; // 10分
public int Interval
{
get { return interval; }
set { interval = value; }
}
private bool update = true;
public bool Update
{
get { return update; }
set { update = value; }
}
private bool upload = true;
public bool Upload
{
get { return upload; }
set { upload = value; }
}
#endregion
private string configFilePath = GetCurrentDirectory() + "\\config.xml";
public ConfigFile()
{
// 初期値
interval = 10 * 60 * 1000; // 更新間隔 10分
update = true; // 地図を自動更新する
upload = true; // データをアップロードする
guid = System.Guid.NewGuid().ToString();
if (!File.Exists(configFilePath))
{
// 設定ファイルがないので、初期値を書き込む
WriteConfigFile();
}
else
{
// 設定ファイルから値を読み込む
ReadConfigFile();
}
}
public void WriteConfigFile()
{
using (XmlTextWriter xtw = new XmlTextWriter(configFilePath, Encoding.Unicode))
{
xtw.WriteStartElement("configuration");
xtw.WriteElementString("GUID", guid);
xtw.WriteElementString("更新間隔", interval.ToString());
xtw.WriteElementString("自動更新", update.ToString().ToLower());
xtw.WriteElementString("アップロード", upload.ToString().ToLower());
xtw.WriteEndElement();
xtw.Close();
}
}
public void ReadConfigFile()
{
try
{
using (XmlTextReader xtr = new XmlTextReader(configFilePath))
{
xtr.ReadStartElement("configuration");
guid = xtr.ReadElementString("GUID");
interval = xtr.ReadElementContentAsInt("更新間隔", "");
update = xtr.ReadElementContentAsBoolean("自動更新", "");
upload = xtr.ReadElementContentAsBoolean("アップロード", "");
xtr.Close();
}
}
catch (Exception)
{
// 設定ファイルにエラーがある場合は、無視して継続する
}
}
public static string GetCurrentDirectory()
{
string fqn = Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName;
FileInfo finfo = new FileInfo(fqn);
return finfo.DirectoryName;
}
string number;
private void GetNumberFromWSIM()
{
if (number != "")
return;
RasConn.Disconnect();
WZero3GetNumber getNum = new WZero3GetNumber();
getNum.Received = MyReceivedNum;
getNum.GetNumber();
}
private void MyReceivedNum(object o, EventArgs e)
{
number = ((WZero3GetNumber)o).Number;
}
}
}
5.2 設定ファイル用ダイアログ
設定ファイル用のダイアログです。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace uchukamen.WZero3
{
public partial class FormConfig : Form
{
public FormConfig()
{
InitializeComponent();
}
private string guid = "";
ConfigFile cf = new ConfigFile();
private void FormConfig_Load(object sender, EventArgs e)
{
try
{
guid = cf.Guid;
this.textBoxGUID.Text = cf.Guid;
this.numericUpDown1.Value = cf.Interval / 60 / 1000;
this.checkBoxUpdate.Checked = cf.Update;
this.checkBoxUpload.Checked = cf.Upload;
}
catch (Exception exc)
{
this.notification1.Caption = "Error";
this.notification1.Text = exc.Message;
}
}
private void buttonSave_Click(object sender, EventArgs e)
{
cf.Interval = (int)this.numericUpDown1.Value * 60 * 1000;
cf.Update = checkBoxUpdate.Checked;
cf.Upload = checkBoxUpload.Checked;
cf.WriteConfigFile();
}
}
}
5.3 メイン画面
メイン画面はいたって簡単。通常は、閉じておいてもバックグラウンドで動作して、位置情報をアップしてくれます。
基本動作は次のとおり。
- タイマーでセットした時間になったら、通信を切断
- 基地局の緯度、経度情報を読み出しをかける
- 読み出し終わりイベントが来たら、緯度、経度を世界測地系に変換する
- Web Service でデータベースに書き込む
Google Map で表示ボタン、メールで位置を送信が押された時の動作も、同様にGUID, 経度,
緯度情報をデータベースに書き込み、その後 Google Map を起動するか、メールで位置を送信するかの違いだけです。
ちょっとわかりにくいのが、WZero3Locatorクラスで、読み込みが完了した段階で LocationReceived
イベントが呼び出され、そこで緯度、経度情報を取得しているあたりです。これは、通信完了を待って、データを読み出すようにしてしまったので、こんなふうになっていますが、もう少しいい方法があるかもしれません。
WZero3Locator w3loc = new WZero3Locator();
w3loc.ReceivedLocation += LocationReceived;
w3loc.GetLocation();
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Reflection;
namespace uchukamen.WZero3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void menuItem1_Click(object sender, EventArgs e)
{
Application.Exit();
}
private string guid = "";
ConfigFile cf = null;
bool update;
bool upload;
private void Form1_Load(object sender, EventArgs e)
{
try
{
cf = new ConfigFile();
guid = cf.Guid;
this.timer1.Interval = cf.Interval;
update = cf.Update;
upload = cf.Upload;
}
catch (Exception exc)
{
this.textBox1.Text += exc.Message;
}
}
// 更新時間になった
private void timer1_Tick(object sender, EventArgs e)
{
UpdateLocation();
}
private void UpdateLocation()
{
try
{
// SIM 切断処理
this.textBox1.Text = "";
Cursor.Current = Cursors.WaitCursor;
this.buttonShowGMap.Enabled = false;
this.textBox1.Text += "SIM切断中\r\n";
RasConn.Disconnect();
this.textBox1.Text += "SIM切断完了\r\n";
// 基地局情報(郵便番号、緯度、経度)の取得処理
// エラーとなる場合が多いので、5回成功するまで繰り返す。
for (int i = 0; i < 5; i++)
{
try
{
this.textBox1.Text += "・";
WZero3Locator w3loc = new WZero3Locator();
w3loc.ReceivedLocation += LocationReceived;
w3loc.GetLocation();
// 例外が上がらなければ、成功したのでループから抜ける。
return;
}
catch (Exception exc)
{
this.textBox1.Text += exc.Message;
}
}
}
catch (RasConn.NoSimException)
{
this.textBox1.Text += "SIMが見つかりません。SIM を確認してください。\r\n";
}
catch (RasConn.SimOffException)
{
this.textBox1.Text += "SIMをオンにしてください\r\n";
}
catch (Exception exc)
{
textBox1.Text += exc.Message + "\r\n";
}
finally
{
Cursor.Current = Cursors.Default;
this.buttonShowGMap.Enabled = true;
}
}
double latitude; // 緯度:日本測地系
double longitude; // 経度:日本測地系
double wLatitude; // 緯度:世界測地系
double wLongitude; // 経度:世界測地系
private void LocationReceived(object o, EventArgs e)
{
latitude = ((WZero3Locator)o).FLatitude;
longitude = ((WZero3Locator)o).FLongitude;
this.textBox1.Text += "\r\n";
textBox1.Text += "位置取得:" + ((WZero3Locator)o).Latitude + ":" + ((WZero3Locator)o).Longitude + "\r\n";
// 緯度、経度の簡易変換を行う
ConvertJapanToWorld(latitude, longitude, out wLatitude, out wLongitude);
try
{
Cursor.Current = Cursors.WaitCursor;
this.buttonShowGMap.Enabled = false;
// データベースに書き込む
UpdateDatabse();
}
catch (Exception exc)
{
textBox1.Text += exc.Message;
}
finally
{
Cursor.Current = Cursors.Default;
this.buttonShowGMap.Enabled = true;
}
}
// グーグルマップを表示する
private void ShowGoogleMap()
{
string loc = string.Format("-URL \"?action=locn&a=@latlon:{0:F9},{1:F9}\"", wLatitude, wLongitude);
Debug.WriteLine(loc);
Process.Start(@"\Program Files\GoogleMaps\GoogleMaps.exe", loc);
}
private void UpdateDatabse()
{
UpdateLoc.W03Location svc = new UpdateLoc.W03Location();
svc.UpdateLocation(guid, wLatitude, wLongitude);
textBox1.Text += "データベースに登録完了\r\n";
}
// 緯度、経度の簡易変換を行う
// Google マップは 世界測地系、一方でWillcom の基地局データは日本測地系
// http://uchukamen.spaces.live.com/blog/cns!7CB203A44BF94940!673.entry?&_c02_owner=1
private void ConvertJapanToWorld(double latitude, double longitude, out double wLatitude, out double wLongitude)
{
wLatitude = latitude - 0.00010695d * latitude + 0.000017464d * longitude + 0.0046017d;
wLongitude = longitude - 0.000046038d * latitude - 0.000083043d * longitude + 0.010040d;
}
// About 表示
private void menuItemAbout_Click(object sender, EventArgs e)
{
FormAbout formAbout = new FormAbout();
formAbout.ShowDialog();
}
private void buttonShowGMap_Click(object sender, EventArgs e)
{
UpdateLocation();
// グーグルマップを表示する
ShowGoogleMap();
}
private void menuItemUpdate_Click(object sender, EventArgs e)
{
CheckNewVersion();
}
// ソフトウェアの更新をチェック
private void CheckNewVersion()
{
try
{
Cursor.Current = Cursors.WaitCursor;
Assembly assembly = Assembly.GetExecutingAssembly();
string currentVersion = assembly.GetName().Version.ToString();
com.uchukamen.Update update = new com.uchukamen.Update();
bool isLatest = update.IsLatest("W03DeGMap", currentVersion);
string version = update.LatestVersion("W03DeGMap");
if (isLatest)
MessageBox.Show("最新のバージョン Ver." + version + " です。", "Version");
else
{
DialogResult res = MessageBox.Show("最新のバージョンではありません。最新のバージョンは Ver." +
version + " です。OK を押すとダウンロードページを開きます。",
"Version", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1);
if (res == DialogResult.OK)
System.Diagnostics.Process.Start(update.GetUrl("W03DeGMap"), "");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "W03DeGMap",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
}
finally
{
Cursor.Current = Cursors.Default;
}
}
private void menuItemConfig_Click(object sender, EventArgs e)
{
FormConfig formConfig = new FormConfig();
DialogResult res = formConfig.ShowDialog();
if (res == DialogResult.OK)
{
cf = new ConfigFile();
guid = cf.Guid;
this.timer1.Interval = cf.Interval;
update = cf.Update;
upload = cf.Upload;
}
}
private void buttonSendMail_Click(object sender, EventArgs e)
{
UpdateLocation();
string url = "http://uchukamen.com/w03degooglemapweb/?GUID=" + guid;
Process.Start(@"\Windows\STMail.exe", "mailto:?subject=今このあたりにいます&body="+ url);
}
}
}
5.4 緯度、経度取得用のクラス
Willcom 03 の緯度、経度取得用のクラスです。WZero3 でも動きました。
using System;
using System.IO.Ports;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Threading;
namespace uchukamen.WZero3
{
class WZero3Locator
{
private SerialPort serialPort = new
SerialPort("COM1", 115200,
System.IO.Ports.Parity.None, 8);
public WZero3Locator()
{
serialPort.NewLine = "\r\n";
serialPort.DtrEnable = true;
serialPort.Handshake = Handshake.RequestToSend;
serialPort.RtsEnable = true;
serialPort.DataReceived += new
SerialDataReceivedEventHandler
(serialPort_DataReceived);
serialPort.PinChanged += new
SerialPinChangedEventHandler
(serialPort_PinChanged);
serialPort.ErrorReceived += new
SerialErrorReceivedEventHandler
(serialPort_ErrorReceived);
serialPort.Disposed += new EventHandler
(serialPort_Disposed);
serialPort.ReadTimeout = 1000;
serialPort.WriteTimeout = 1000;
}
public void Dispose()
{
serialPort.Dispose();
}
private void Send(string str)
{
while (serialPort.CtsHolding == true)
Thread.Sleep(100);
serialPort.WriteLine(str);
Debug.WriteLine(">>>>>>>>>>>>:" + str);
}
public enum DataType
{
Location, Number
}
public void GetLocation()
{
resultString = "";
if (serialPort.IsOpen == false)
serialPort.Open();
Send("AT@LBC1");
Send("AT@LBC?");
Send("AT@LBC2");
Send("AT");
serialPort.Close();
}
public void GetNumber()
{
resultString = "";
if (serialPort.IsOpen == false)
serialPort.Open();
Send("ATI6");
Send("AT");
serialPort.Close();
}
public EventHandler ReceivedLocation;
private void serialPort_Disposed
(object sender, EventArgs e)
{
Debug.WriteLine(resultString);
ParseLocationData(resultString);
ReceivedLocation(this, null);
}
private string resultString = "";
private void serialPort_DataReceived
(object sender, SerialDataReceivedEventArgs e)
{
string retStr = serialPort.ReadExisting();
Debug.WriteLine("<<<<<<<<<<<<\n" + retStr);
resultString += retStr;
}
private void serialPort_ErrorReceived
(object sender, SerialErrorReceivedEventArgs e)
{
Debug.WriteLine("serialPort_ErrorReceived");
}
private void serialPort_PinChanged
(object sender, SerialPinChangedEventArgs e)
{
Debug.WriteLine("serialPort_PinChanged: CTS="
+ serialPort.CtsHolding.ToString());
}
#region 郵便番号、緯度、経度のプロパティ
private string errString = "";
public string ErrString
{
get { return errString; }
}
private string zipCode;
public string ZipCode
{
get { return zipCode; }
}
private string latitude;
public string Latitude
{
get { return latitude; }
}
private string longitude;
public string Longitude
{
get { return longitude; }
}
private double fLatitude;
public double FLatitude
{
get { return fLatitude; }
}
private double fLongitude;
public double FLongitude
{
get { return fLongitude; }
}
private string number;
public string Number
{
get { return number; }
}
#endregion
#region 郵便番号、緯度、経度の文字列処理
public void ParseLocationData(string str)
{
zipCode = GetZipCode(str);
latitude = GetLatitude(str);
longitude = GetLongitude(str);
fLatitude = GetFloatLatitude(latitude);
fLongitude = GetFloatLongitude(longitude);
}
private double GetFloatLatitude(string latitude)
{
Regex regVal = new Regex("[0-9]+");
MatchCollection mcLatitude =
regVal.Matches(latitude);
return double.Parse(mcLatitude[0].Value)
+ (double.Parse(mcLatitude[1].Value)) / 60.0d
+ (double.Parse(mcLatitude[2].Value)) / 3600.0d;
}
private double GetFloatLongitude(string longitude)
{
Regex regVal = new Regex("[0-9]+");
MatchCollection mcLongitude =
regVal.Matches(longitude);
return double.Parse(mcLongitude[0].Value)
+ double.Parse(mcLongitude[1].Value) / 60.0d
+ double.Parse(mcLongitude[2].Value) / 3600.0d;
}
private string GetZipCode(string str)
{
Regex regZip = new
Regex("[0-9][0-9][0-9][0-9][0-9][0-9][0-9]");
Match match = regZip.Match(str);
if (!match.Success)
throw (new Exception("郵便番号の取得に失敗"));
return match.Value;
}
private string GetLatitude(string str)
{
Regex regLat = new
Regex("[NS][0-9]+:[0-9]+:[0-9]+");
Match match = regLat.Match(str);
if (!match.Success)
throw (new Exception("緯度の取得に失敗"));
return match.Value;
}
private string GetLongitude(string str)
{
Regex regLong = new
Regex("[EW][0-9]+:[0-9]+:[0-9]+");
Match match = regLong.Match(str);
if (!match.Success)
throw (new Exception("緯度の取得に失敗"));
return match.Value;
}
#endregion
}
}
5.5 通信切断部分
RAS 接続切断部分です。
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace uchukamen.WZero3
{
///
/// This class is based on code from "mikinder".
/// http://www.developersdex.com/vb/message.asp?p=2916&r=5643969
///
class RasConn
{
const int MAX_PATH = 260;
const int RAS_MaxDeviceType = 16;
const int RAS_MaxPhoneNumber = 128;
const int RAS_MaxEntryName = 20;
const int RAS_MaxDeviceName = 128;
const int SUCCESS = 0;
const int ERROR_NOT_ENOUGH_MEMORY = 8;
const int RASBASE = 600;
const int ERROR_BUFFER_TOO_SMALL = RASBASE + 3;
const int ERROR_INVALID_SIZE = RASBASE + 32;
#region DllImport
//// --- RASCONN data structure definition (refer to ras.h) --
//private const int RAS_MaxEntryName = 20;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct RASCONN
{
public int dwSize;
public IntPtr hrasconn;
[MarshalAs(UnmanagedType.ByValTStr,
SizeConst = RAS_MaxEntryName + 1)]
public string szEntryName;
}
// --------------------------------------------
[DllImport("coredll.dll", SetLastError =
true, CharSet = CharSet.Auto)]
private static extern uint RasEnumConnections(
[In, Out] RASCONN[] rasconn,
[In, Out] ref int cb,
[Out] out int connections);
[DllImport("coredll.dll")]
private static extern uint RasHangUp(IntPtr pRasConn);
#endregion
///
/// Returns all active RAS connections as
/// an array of data structure RASCONN
///
public static RASCONN[] GetAllConnections()
{
RASCONN[] tempConn = new RASCONN[1];
RASCONN[] allConnections = tempConn;
tempConn[0].dwSize = Marshal.SizeOf(typeof(RASCONN));
int lpcb = tempConn[0].dwSize;
int lpcConnections = 0;
uint ret = RasEnumConnections
(tempConn, ref lpcb, out lpcConnections);
if (ret == ERROR_INVALID_SIZE)
{
throw new Exception
("RAS: RASCONN data structure has invalid format");
}
else if (ret == ERROR_BUFFER_TOO_SMALL && lpcb != 0)
{
// first call returned that
// there are more than one connections
// and more memory is required
allConnections = new RASCONN[lpcb
/ Marshal.SizeOf(typeof(RASCONN))];
allConnections[0] = tempConn[0];
ret = RasEnumConnections(allConnections,
ref lpcb, out lpcConnections);
}
// Check errors
if (ret != SUCCESS)
{
throw new Exception("RAS returns error: " + ret);
}
if (lpcConnections > allConnections.Length)
{
throw new Exception
("RAS: error retrieving correct connection count");
}
else if (lpcConnections == 0)
{
// if there are no connections
// resize the data structure
allConnections = new RASCONN[0];
}
return allConnections;
}
///
/// Closes all active RAS connections
///
///
private static void CloseAllConnections()
{
RASCONN[] connections = GetAllConnections();
for (int i = 0; i < connections.Length; ++i)
{
RasHangUp(connections[i].hrasconn);
}
}
enum WSIMState { Normal = 0, NoSim = -2, Com = -3, Off = -7 };
// 0:Normal : 通常
//-2:NoSim : W-SIMなし
//-3:Com : 通信中
//-7:Off
[DllImport("shphonelib.dll", EntryPoint =
"?GetWsimStateInfo@CshphoneClientlib@@SAHXZ")]
public static extern int GetWsimStateInfo();
public class NoSimException: Exception
{
public NoSimException(string message): base(message)
{
}
}
public class SimOffException : Exception
{
public SimOffException(string message)
: base(message)
{
}
}
public static void Disconnect()
{
// SIMの状態を調べる
int result = GetWsimStateInfo();
if (result == (int)WSIMState.NoSim)
throw new NoSimException("W-SIMがありません。");
if (result == (int)WSIMState.Off)
throw new SimOffException("W-SIMがオフです。");
if (result == (int)WSIMState.Com)
{
// 通信中の場合は、緯度、経度情報を取得できない。
// このため、強制的に通信を切断する。
RasConn.CloseAllConnections();
// MSDN によると、切断後約3秒待つ必要がある。
for (int i = 0; i < 3; i++)
{
Thread.Sleep(1000);
if (GetWsimStateInfo() == (int)WSIMState.Normal)
break;
}
}
}
}
}
最後に、次のように GUID から Google Map を表示させるためのページを作成します。
Visual Studio で Web サイトを作成し、そこで、次のようにレイアウトします。
次に、次のような実装を行います。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebApplication1
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString.Count == 0)
return;
string guid = this.TextBox1.Text = Request.QueryString["GUID"];
com.uchukamen.W03Location w03 = new com.uchukamen.W03Location();
Response.Redirect(w03.GetUrl(guid));
}
protected void Button1_Click(object sender, EventArgs e)
{
com.uchukamen.W03Location w03 = new com.uchukamen.W03Location();
string s = w03.GetUrl(this.TextBox1.Text);
Response.Redirect(s);
}
}
}
ページがロードされた時に、 "http://uchukamen.com/w03degooglemapweb/?GUID=bb11c154-df7c-4dee-a0b8-9d11d599845c"
のように GUIDのクエリストリングが渡された場合には、GUIDを引数に W03Location
ウェブサービスを呼び出し、返り値としてURLを取得します。そして、そのURLへリダイレクトすることにより、Google Map を表示させます。
同様に、ボタンを押したときのイベントハンドラで、TextBox1のGUIDを取得し、同様に Google Map を表示させる処理を実装します。
こちらのページより、クライアントソフトをダウンロードしてください。
忙しくなると、逃避したくなる癖があるようですw