2011年10月31日月曜日

.NETからGoogleドキュメントAPIを使ってみる

.NETプログラムからGoogleドキュメントにアクセスするライブラリを使ってみました。
Google CodeからGoogle Data API Setupをダウンロードしてインストールします。



開発環境から.NETのプロジェクトを作成し、
(インストールパス)\Google\Google Data API SDK\RedistにあるマネージDLLを参照に追加します。

今回はとりあえず以下のDLLを使ってみます。
Google.GData.Client
Google.GData.Documents
Google.GData.Spreadsheets

以下はスプレッドシートを開くコードです。
# "Spread sheet Title"が開くドキュメント名です。


Dim ssrv As New SpreadsheetsService("hoge-service")
Dim sq As New SpreadsheetQuery()

ssrv.setUserCredentials(mUserName, mPassword)

sq.Title = "Spread sheet Title" ' 検索対象のスプレッドシート名

Dim feed As SpreadsheetFeed = ssrv.Query(sq)

If 0 < feed.Entries.Count Then
     Dim ss As SpreadsheetEntry = CType(feed.Entries(0), SpreadsheetEntry)

End If


これでスプレッドシートへの参照が取得できました。
次にシートの中のセルを更新してみます。

Protected Overrides Sub UpdateSheet( _
    ByVal srv As SpreadsheetsService, _
ByVal ss As SpreadsheetEntry)

Dim sq As New SpreadsheetQuery()

If ss.Worksheets.Entries.Count = 0 Then Return

Dim ws As WorksheetEntry = CType(ss.Worksheets.Entries(0), WorksheetEntry)

' ワークシート上から範囲にあるセルの集合を取得します
Dim cq As New CellQuery(ws.CellFeedLink)
cq.Range = "A1:C3" ' セル範囲
cq.ReturnEmpty = ReturnEmptyCells.yes ' 空のセルも列挙する

Dim ce As CellFeed = srv.Query(cq)

For i As Integer = 0 To ce.Entries.Count - 1
Dim cell As CellEntry = CType(ce.Entries(i), CellEntry)

' セルの値を表示
If cell.Value IsNot Nothing Then
MsgBox(cell.Value.ToString)

    End If

' 値を変更して更新
cell.InputValue = "セル(" & cell.Column.ToString & "," & cell.Row.ToString & ")"
cell.Update()
Next

End Sub



上記コードはセルごとにUpdateしています。
Updateメソッドで毎回POST送信するため、いくつものセルを一括更新するには向きません。
そのような場合にはバッチ更新を使います。

Protected Overrides Sub UpdateSheet( _
ByVal srv As SpreadsheetsService, _
ByVal ss As SpreadsheetEntry)

Dim sq As New SpreadsheetQuery()

If ss.Worksheets.Entries.Count = 0 Then Return

Dim ws As WorksheetEntry = CType(ss.Worksheets.Entries(0), WorksheetEntry)
        Dim cq As New CellQuery(ws.CellFeedLink)

cq.Range = "A1:C3"
cq.ReturnEmpty = ReturnEmptyCells.yes

Dim ce As CellFeed = srv.Query(cq)

' 更新バッチ作成

Dim updateCells As CellFeed = ws.QueryCellFeed()
Dim batch As New GDataBatchEntryData(GDataBatchOperationType.update)
Dim batchFeed As AtomFeed = New AtomFeed(updateCells)

For Each cell As CellEntry In ce.Entries

If cell.Value IsNot Nothing Then
MsgBox(cell.Value.ToString)
End If

cell.InputValue = "セル(" & cell.Column.ToString & "," & cell.Row.ToString & ")"
cell.BatchData = batch

batchFeed.Entries.Add(cell)

Next


' バッチ実行
Dim rseult As CellFeed = CType(srv.Batch(batchFeed, New Uri(updateCells.Batch)), CellFeed)

For Each entry As CellEntry In rseult.Entries
If entry.BatchData.Status.Code <> 200 Then
Throw New Exception("Cell update for " + entry.BatchData.Id + " failed!")
    End If
Next

End Sub



開発ガイド(Developer's Guide: .NET)
Javaなど各言語ごとにガイドが用意されています。

2011年10月26日水曜日

pixivデビューしました

半年前から3D CGの勉強をはじめ、ようやく公開できるレベルの作品が
できたのでpixivデビューしました。モデリングにはMetasequioaを使っています。
(最初はフリー版を使い、ブーリアン等のプラグイン機能を使うためシェアウェア版に移行しました)

半年前、始めたばかり頃のモデリングの様子。形がオモチャっぽいですね。

何度か作り直し、ようやく実物に近づきました。


VIDROというGIレンダラで出力するご覧のとおり。

最終的にはVue9 Espritという3D景観ソフトを使って出力しました。
Metasequoiaからはオブジェクトを3ds形式で出力すると綺麗にインポートできます。
(「左右軸を反転」が必要)

海や太陽光などリアルな質感を持つ風景を簡単に作成できます。

ちなみにこのCGはアニメFORTUNE ARTERIALに出てきたシーンをモチーフにしています。
名鉄2000系ミュースカイ(もどき)の列車が珠津大橋を渡り、潮見湾に浮かぶ珠津島へ向かいます。

2011年10月16日日曜日

Mono 2.10.XでMutexがおかしい

.NETアプリをMono(Microsoft .NET Frameworkのopen sourceなimplementation)で動かそうと思い、MonoDevelop 2.8.1でbuildし実行!と思ったら不可解な現象に遭遇。
どうやらThreading.Mutexを作成し、初回のWaitOneでfalseが返されることがあるようだ・・・ナニコレ(;´Д`)
以下のコードをMono 2.10.6で実行すると、最初のWaitOneがfalseを返してくる。
(40%くらいの確率でループ内の最初の1,2回だけfalseが返り、後はちゃんとtrueが返ってくる)
とりあえずtrueになるまでリトライすればOKということにしておこう。
(後、Thread.Sleepが全く効いてない現象も発生。P/InvokeでSleep API何かおかしい?)


using System;
using System.Threading;


namespace MutexBugTest
{
    class MainClass
    {
        private static Mutex mLockStatus = new Mutex();


        public static void Main (string[] args)
        {
            for(int i=0;i<100;++i)
            {
                if (!mLockStatus.WaitOne(5000))
                    Console.WriteLine("WaitOne is returned false. #" + i.ToString());       
                else
                    mLockStatus.ReleaseMutex();
            }
        }
    }
}