ページ

ラベル プログラミング の投稿を表示しています。 すべての投稿を表示
ラベル プログラミング の投稿を表示しています。 すべての投稿を表示

2019年2月2日土曜日

Cordovaでアプリ作成

これまでにCordovaの開発環境の準備をしてきましたので、まずは基本中の基本操作をしてサンプルアプリを作成してみます。構築メモはこちらから。

1. プロジェクト作成

cordova createコマンドでプロジェクトを作成します。

$ cordova create firstsample com.example.firstsample FirstSample -d
Using detached cordova-create
Creating a new cordova project.
Copying assets."

firstsample … ディレクトリ
com.example.firstsample … 逆引きドメインスタイル識別子
FirstSample … タイトル

現バージョン(8.1.2)では以下のようなフォルダ構成ができます。

$ ls -og --group-directories-first
total 5
drwxr-xr-x 1 0 Feb 2 20:18 hooks
drwxr-xr-x 1 0 Feb 2 20:18 platforms
drwxr-xr-x 1 0 Feb 2 20:18 plugins
drwxr-xr-x 1 0 Feb 2 20:18 res
drwxr-xr-x 1 0 Feb 2 20:18 www
-rw-r--r-- 1 991 Feb 2 20:18 config.xml
-rw-r--r-- 1 373 Feb 2 20:18 package.json

次にプラットフォームを追加します。私はAndroidしか使わないのでとりあえずそれだけ。

$ cordova platform add android

$ cordova platform ls
Installed platforms:
 android 7.1.4
Available platforms:
 browser ~5.0.1
 ios ~4.5.4
 osx ~4.0.1
 windows ~6.0.0

ここまでで最低限の準備はOKですかね。


2. Visual Studio Codeで使う

先ほど作ったプロジェクトフォルダをVSCodeで開きます。


左端のアクティビティバーのデバッグボタンをクリックします。
左上で「デバッグ」の構成が選択できますので、ここで歯車アイコンをクリックして「Cordova」を選択します。


当面はブラウザで作業を行いますので「Simulate Android in browser」を選択します。
デバッグ開始を行うと以下のようにブラウザが起動し初期画面が表示されました。


これであとはコードを加えて作っていく感じですね。


2019年1月20日日曜日

Ionicも使ってみる①

これまでCordovaの環境構築してビルド確認まで行いました。
さーさっそくアプリ開発のお勉強をと思って調べ始めていたのですが、Ionicなるフレームワークもこの際使ってみようかなと。


1. Ionicインストール

npmでIonicをインストールします。

C:\Users\Xxx>npm install ionic -g

C:\Users\Xxx>npm -v

現時点では4.8.0が入りました。


2. Gitインストール

IonicからGitを利用するようなので入れておきます。公式サイトからダウンロードします。



3. VSCode設定

このままでもコンソールからデバッグできますが、せっかく前回Visual Studio Codeを入れているのでそちらでデバッグできるようにしてみましょう。
まずVisual Studio Codeの拡張機能「Debugger for Chrome」をインストールします。直接関係ないですがコード補完機能とかありそうなので「Angular Language Service」も入れておきます。

次に[プロジェクトフォルダ]\.vscode\launch.jsonを開いて編集します。

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
       "name": "Launch Chrome",
      "url": "http://localhost:8100",
      "program": "sourceMaps": true,
      "webRoot": "${workspaceRoot}/src"
    }
  ]
}


環境整備も進んだのでそろそろプログラミングの勉強にうつりましょうかね。
とりあえず今日はここまで。

2019年1月15日火曜日

Cordova開発環境構築メモ②

先日Cordovaの開発環境を入れたつもりになっていましたが、これだけだとどうもビルド環境まではないみたい。先日のおさらいはこちらから。
ということで今日はビルド環境のまとめです。


1. OpenJDKインストール(不要のため後述参照!)

OracleJDKはもうねってことでOpenJDKでいきます。公式サイトからダウンロード。私がダウンロードしたときはJDK 11.0.1でした。


Windows/x64のzipファイルをダウンロードします。
zipファイルを展開し任意の場所に配置します。私は「C:\Programs\openjdk\jdk-11.0.1」としておきました。あとは展開したフォルダ直下の「bin」フォルダの絶対パスを環境変数「Path」に追加します。

C:\Users\Xxx>java -version
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)

ちゃんと動いてますね。あとは環境変数「JAVA_HOME」に上位フォルダを設定しておきましょう。


2. Android SDKインストール

Android Studioを入れるみたいですね。公式サイトからダウンロードしてインストールしましょう。


まずAndroid Studioを起動します。初回起動は時間がかかるようですね。
最初に以下の画面が表示されますがAndroid Studio自体は利用しないので「Cancel」します。


再度表示されないよう「Do not re-run setup wizard」を選択して「OK」ボタンをクリックします。


本当は画面右下の「Configure」から「SDK Manager」を選択するとセットアップ画面が出てくるはずらしいのですが、何故か私の環境では出てきません。これは困った。


とりあえず同メニューから「Setting」を選択すると「Default Setting」画面が開きます。ここの「Android SDK Location」の横にある「Edit」リンクをクリックします。


すると「SDK Setup」画面が表示されましたので先に進んでみます。Installing画面で結構時間がかかりますね。根気よく待ちましょう。
完了後は元の画面に戻り必要なバージョンにチェックを付けて「Apply」ボタンをクリックします。

最後に環境変数「ANDROID_SDK」に「Android SDK Location」に設定されたパスを設定して完了です。


3. ビルド確認

ただここまで来てcordova buildコマンドで試してみたところ、JDKのバージョンが違うと怒られる・・・。結局Android Studio入れたときに同梱されていたJDK指定したらうまくいったというオチ。

「Path」への追加を「C:\Program Files\Android\Android Studio\jre\bin」に変え、「JAVA_HOME」を「C:\Program Files\Android\Android Studio\jre」に変えました。

なんだかなー。

2019年1月13日日曜日

Cordova開発環境構築メモ①

Androidのアプリでも作ってみたいなと思い、せっかくならクロスプラットフォーム開発ができるものがいいなということでCordovaにチャレンジしてみたいと思います。


1. Node.jsインストール

公式サイトからダウンロード。


私がダウンロードしたときのLTSは10.15.0でしたのでこれを入れました。
インストーラを起動し、すべてデフォルト設定のままインストール。

Your environment has been set up for using Node.js 10.15.0 (x64) and npm.

C:\Users\Xxx>node --version
v10.15.0

C:\Users\Xxx>npm --version
6.4.1

npmのバージョンは6.4.1みたいですね。


2. Cordovaインストール

npmでCordovaをインストールします。

C:\Users\Xxx>npm install -g cordova

C:\Users\Xxx>cordova -v
8.1.2 (cordova-lib@8.1.1)

現時点だと8.1.2が入るみたいですね。


3. Visual Studio Codeインストール

公式サイトからダウンロード。


私はUser Installerの64bit版を入れました。このときのバージョンは1.30.2のようです。
インストーラを起動しインストール。このままだと英語メニューなので日本語化しておきます。まずは拡張機能をインストール。
  1. サイドバーの「Entensions」ボタンをクリック
  2. 入力フォームで「Japanese Language Pack for Visual Studio Code」を選択してインストール


次に設定を日本語に。
  1. 「View」→「Comand Palette...」
  2. 「configure」と入力
  3. 「Configure Language」を選択
  4. 「locale.json」が開かれるので"en"と指定されているところを"ja"に変更して上書き保存
  5. Visual Studio Codeを再起動


これで日本語化できました。


4. Cordova Toolsインストール

日本語化のときと同様に拡張機能からCordova Toolsをインストールします。


インストール後は再読み込み&再起動しておきましょう。


5. まとめ

とりあえずここまでで使えるようにはなったはず。
次回は簡単なサンプルでも作って試してみますかね。以下に続く。

2017年11月17日金曜日

Play Frameworkを2.6で学びなおす

何となく以前少しだけかじった記憶があったようななかったようなPlay Frameworkですが、久しぶりに触ろうと思ったら記憶が完全に飛んでることに・・・。

ということで、最近Windows10に入れているBash on Ubuntu on Winowsがあるので、そこで使いながらもう一度触ってみようかと思います。

まずは右も左も分からないので、参考にさせていただいたサイトを片っ端からメモ的に。最初はsbtについて理解しないと。
今後、この投稿を拡充していこうかなと考えています。

2016年8月26日金曜日

やっぱりJNI

一時期JNAに凝ってましたが、やっぱり何だかんだでJNIのほうが取り回しやすいなと感じている今日この頃。
なもんで、超簡単なサンプルを載せておきます。(転用は自己責任でお願いします。)


<C++>

#include "jnisample_JniSample.h"
#include <iostream>

class Sample {
public:
  Sample() {
    std::cout << "constructor" << std::endl;
  }
  ~Sample() {
    std::cout << "destructor" << std::endl;
  }
};

#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     jnisample_JniSample
 * Method:    open
 * Signature: (Ljava/lang/String;)J
 */
JNIEXPORT jlong JNICALL Java_jnisample_JniSample_open
  (JNIEnv *env, jobject obj, jstring jconf)
{
  const char *conf = env->GetStringUTFChars(jconf, 0);
  Sample *obj = new Sample();
  env->ReleaseStringUTFChars(jconf, conf);
  return (jlong)obj;
}

/*
 * Class:     jnisample_JniSample
 * Method:    close
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_jnisample_JniSample_close
  (JNIEnv *env, jobject obj, jlong jhandle)
{
  delete (Sample *)jhandle;
}

#ifdef __cplusplus
}
#endif


<Java>

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package jnisample;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 */
public class JniSample {
    
    private long handle;
    
    static {
        System.loadLibrary("native_sample");
    }
    
    public JniSample(String conf) {
        handle = open(conf);
    }
    
    public void close() {
        close(handle);
    }
    
    private native long open(String conf);
    private native void close(long handle);

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        JniSample obj = new JniSample("hoge");
        System.out.println("object created.");
        obj.close();
        System.out.println("program end.");
    }
    
}



Java側のコード書いたあとで、

>javah -classpath classes jnisample.JniSample

こんなするとネイティブライブラリのヘッダができますので、あとは中身の実装をするだけです。

2015年11月8日日曜日

WebSocketでファイルアップロード

前回WebSocketを少しいじったので、今回は少し拡張してファイルアップロードを実現してみました。

まずサーバ側はファイル名を受け取るようにしてみました。ちと面倒だったのでテキストメッセージでファイル名を受けたときにファイルをオープンして、ファイルのクローズは切断時に行ってます。(ちなみにGlassFish上で動作させてます。)

--------------------------------------------------
package sample; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.logging.Level; import java.util.logging.Logger; import javax.websocket.OnOpen; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/endpoint") public class NewWSEndpoint { private static FileChannel channel = null; @OnOpen public void onOpen(Session session){ System.out.println("OnOpen"); } @OnClose public void onClose(Session session){ try { System.out.println("OnClose"); channel.close(); } catch (IOException ex) { Logger.getLogger(NewWSEndpoint.class.getName()).log(Level.SEVERE, null, ex); } } @OnMessage public String onMessage(Session session, String message) { try { System.out.println("OnMessage String = " + message); channel = new FileOutputStream(new File("../logs/" + message)).getChannel(); } catch (FileNotFoundException ex) { Logger.getLogger(NewWSEndpoint.class.getName()).log(Level.SEVERE, null, ex); } return null; } @OnMessage public void onMessage(Session session, ByteBuffer byteBuffer) { try { System.out.println("OnMessage binary = " + byteBuffer.toString()); channel.write(byteBuffer); } catch (IOException ex) { Logger.getLogger(NewWSEndpoint.class.getName()).log(Level.SEVERE, null, ex); } } @OnError public void onError(Throwable t) { System.out.println("OnError"); } } --------------------------------------------------

HTMLはシンプルにこんな感じ。
ファイルをドラッグ&ドロップして指定する形を取りました。

--------------------------------------------------
<html> <head> <title>JavaEE7 WebSocket Test</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script type="text/javascript" src="app.js"></script> </head> <body> <section id="main"> <div id="drop" style="width:500px; height:150px; padding:10px; border:3px solid" ondragover="onDragOver(event)" ondrop="onDrop(event)">ここにファイルをドロップして下さい</div> <div id="disp" ></div> </section> </body> </html> --------------------------------------------------

JavaScriptはこんな感じ。
指定されたファイルを読み込みバイナリとして送信します。

--------------------------------------------------
if (!window.File) { window.alert("このブラウザではFile APIが使えません"); } function onDrop(event) { var files = event.dataTransfer.files; var disp = document.getElementById("disp"); for (var i = 0; i < files.length; i++) { var f = files[i]; var socket = new WebSocket("ws://localhost:8080/TestWebSocket/endpoint"); socket.onopen = function() { var reader = new FileReader(); reader.onload = function(){ var binary = new Uint8Array(reader.result); socket.send(f.name); socket.send(binary.buffer); socket.close(); disp.innerHTML = f.name + "[" + f.size + "byte]" + "アップロード完了"; }; reader.readAsArrayBuffer(f); }; } event.preventDefault(); } function onDragOver(event) { event.preventDefault(); } --------------------------------------------------

あとは大きなファイルでも経過を表示したりできるように分割送信とかするといいでしょうね。

2015年10月17日土曜日

JavaEE7でWebSocket

ここのところお仕事が忙しくてなかなかプログラムで遊ぶことがなかったのですが、今日は雨で子供たちの予定がなくなったのでお勉強がてらいじってみました。

お題は「JavaEE7でWebSocket」です。
バイナリデータをWebSocketサーバで受けたいなというのがそもそもの思いです。

サーバ側はこんなです。

--------------------------------------------------
package sample; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.websocket.OnOpen; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/endpoint") public class NewWSEndpoint { private static FileChannel channel = null; @OnOpen public void onOpen(Session session){ try { channel = new FileOutputStream(new File("output.dat")).getChannel(); System.out.println("OnOpen"); } catch (FileNotFoundException ex) { Logger.getLogger(NewWSEndpoint.class.getName()).log(Level.SEVERE, null, ex); } } @OnClose public void onClose(Session session){ try { channel.close(); System.out.println("OnClose"); } catch (IOException ex) { Logger.getLogger(NewWSEndpoint.class.getName()).log(Level.SEVERE, null, ex); } } @OnMessage public String onMessage(Session session, String message) { System.out.println("OnMessage String = " + message); return null; } @OnMessage public void onMessage(Session session, ByteBuffer byteBuffer) { try { channel.write(byteBuffer); System.out.println("OnMessage binary = " + byteBuffer.toString()); } catch (IOException ex) { Logger.getLogger(NewWSEndpoint.class.getName()).log(Level.SEVERE, null, ex); } } @OnError public void onError(Throwable t) { System.out.println("OnError"); } } --------------------------------------------------

接続を受けたときにファイルを生成し、バイナリデータを受けたときに書きだし、切断を検出したときにファイルをクローズするというシンプルなものです。ちなみにテキストデータを受けたときはprintlnしてるだけです。

これを試すクライアント側です。とりあえず簡単に試したいのでJavaScriptにしてみました。

--------------------------------------------------
<html> <head> <title>JavaEE7 WebSocket Test</title> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script type="text/javascript"> var socket; $(document).ready(function(){ socket = new WebSocket("ws://localhost:8080/TestWebSocket/endpoint"); $('#send').click(function(){ // テキストボックスから文字列取得 var text = $('#message').val(); // テキスト送信 socket.send(text); // 文字列のアスキーコードを代入 var length = text.length; var binary = new Uint8Array(length); for (var i = 0; i < length; i++) { binary[i] = text[i]; } // バイナリ送信 socket.send(binary.buffer); }); }); </script> </head> <body> <input id="message" type="text" /> <button id="send">Send</button> <div id="messages"> </div> </body> </html> --------------------------------------------------

それにしても非常に少ないソースコードでサーバが実現できますね。すばらしい。

2015年3月30日月曜日

Play2で簡単WebSocket

今回はPlay FrameworkでWebSocketに挑戦します。今回準備するのは以下の二つ。
  • Play Framework 2.3
  • jQuery 2.1.3
Play2は以前使ったのでこちらを参照ください。
jQueryは公式サイトからダウンロードしましょう。ダウンロードしたファイルはプロジェクト配下の \public\javascripts にコピーします。

さて今回はできるだけシンプルなサンプルを心がけました。特に何かの役に立つものではないですが、仕組みの理解を優先したつもりです(が分かりにくかったらゴメンなさい・・・)。

まずはアクセス方法から。

--------------------------------------------------
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# Home page
GET     /                           controllers.Application.index()
GET     /message                    controllers.Application.message()

# Map static resources from the /public folder to the /assets URL path
GET     /assets/*file               controllers.Assets.at(path="/public", file)
--------------------------------------------------

/messageを追加しました。これで"ws://localhost:9000/message"でWebSocket接続が可能になります。(localhostの部分は適当に読み替えてください。)

次にindex.scala.htmlです。

--------------------------------------------------
@(message: String)

@main("WebSocket Sample") {

    <p>@message</p>
    <div id="text"></div>
    <p></p>
    <input type="button" value="Start" onClick="start()">
    <input type="button" value="Stop" onClick="stop()"><p>
    <form name="form">
    <input type="text" name="message" value="サンプルテキスト">
    <input type="button" value="Send" onClick="send()">
    </form>

}
--------------------------------------------------

今回はStartボタンでWebSocket接続を行い、Sendボタンでテキストボックスの文字列をサーバに送信、StopボタンでWebSocketを切断するといった操作を実現します。

--------------------------------------------------
var connection = null;

function start() {

$("#text").text("");
connection = new WebSocket("ws://localhost:9000/message");
connection.onopen = function() {
log("connected.");
}
connection.onerror = function(event) {
log("error.");
}
connection.onclose = function(event) {
log("closed.");
}
connection.onmessage = function(event) {
log(event.data);
}
}

function stop() {
connection.close();
}

function send() {
connection.send(document.form.message.value);
}

function log(message) {
$("#text").append(message + "<br>");
}
--------------------------------------------------

ここで・・・まだURLをベタ書きしてます・・・。うまく置き換えれるはずなのですが、まだちゃんとやってないです。
ちなみにログ的に動作状況を確認するために文字列はボタンの上部分のdivタグ内にテキストを追加していってます。
最後はコントローラ部分。ここがPlay2でWebSocketするときの肝の部分ですね。

--------------------------------------------------
package controllers;

import play.Logger;
import play.libs.F.Callback;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.WebSocket;
import views.html.index;

public class Application extends Controller {

    public static Result index() {
        return ok(index.render("WebSocket Sample."));
    }

    public static WebSocket message() {
return new WebSocket() {
      @Override
    public void onReady(final WebSocket.In in, final WebSocket.Out out) {
      Logger.debug("connected.");
      in.onMessage(new Connection(out));
    }
  };
    }

    public static class Connection implements Callback {

     private WebSocket.Out out;

     public Connection(WebSocket.Out out) {
       this.out = out;
     }

     @Override
     public void invoke(String event) {
    Logger.debug(event);
    for (int i=0; i<5; i++) {
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      out.write(event);
    }
  }
    }
}
--------------------------------------------------

index()で最初の画面を表示します。まー特に変わったところはないです。
message()が問題のWebSocketの接続を受けるメソッドです。index()と異なりWebSocketを返します。このときにWebSocket.Inにその後のメッセージを受信するためのコールバックオブジェクトを登録し、返信用のWebSocket.Outオブジェクトを保存しておきます。
コールバックオブジェクトではメッセージ受信用のハンドラをオーバーライドします。このサンプルでは受け取った文字列を1秒ごとに5回クライアントに返送しています。この部分を実際の処理に書き換えるといろいろ出来そうですね。

あとはもう少しコードをキレイにしたり切断時の処理のことを考えておけばそれなりに使えそうです。いやーそれにしても世の中便利になったもんだ。

2015年3月2日月曜日

ICUのスタティックライブラリ

ちと作成中のプログラムで文字コード変換したかったのでICU(International Components for Unicode)を使ってみることにしました。
ただ、ここからダウンロードできるバイナリはDLL形式なので、できればスタティックリンクしたいのでどうすればいいかなと調べていたところ、以下のサイトで解説してくれていました。

http://jumble-note.blogspot.jp/2013/01/icucmsvcicu.html

こちらを元に私は「54.1」というバージョンで試してみました。
このバージョンでは以下を試すことで成功しました。
  • 「構成の種類」をdllからlibに変更
  • プリプロセッサ「U_STATIC_IMPLEMENTATION」を追加
  • 出力ファイル名を変更
  • icudt.libを生成
では具体的な説明をしましょう。
まずallinone.slnを開き、ソリューションエクスプローラーで「構成の種類」で「ダイナミック ライブラリ (.dll)」となっているプロジェクトをすべて「スタティック ライブラリ (.lib)」にします。


次にソリューションエクスプローラーで「makedata」プロジェクト”以外”のプロジェクトをすべて選んで、プリプロセッサの定義に「U_STATIC_IMPLEMENTATION」を追加します。


お次は出力ファイル名を変更。これをしないとダメらしい。よく確認していないですが、詳細は↑のサイトをご覧ください。


これを5つのプロジェクトに対して実施します。

 common → icuuc
 i18n → icuin
 io → icuio
 layout → icule
 layoutex → iculx

最後にicudt.libを作ります。「VS2013 x64 Cross Tools コマンドプロンプト」を使います。以下はデバッグ版を作成する例です。(ファイルタイトルの最後に「d」を付けるのを忘れずに。)


これで出来上がった六つのファイルを使用したいアプリケーションでリンクするだけです。
ちなみにICUはいろんな文字コードの変換ができますが、利用するコードが少ない場合には、以下のサイトでカスタマイズできます。

http://apps.icu-project.org/datacustom/

以下のサイトで解説してくれています。

http://qiita.com/shimacpyon/items/652281d6b28572fd434d

私はShift-JISからUTF-8への変換しかしなかったので非常に参考になりました!

2014年12月29日月曜日

JNAは楽チン♪

Javaのプログラムで部分的にC/C++で実装したいということはよくあるかと思います。でもJNIって何か面倒なイメージが・・・。
(慣れてしまえば、って感じなのかもしれませんが。)

そこで便利なのがJNA。JNIで実装しなければいけない面倒なコードをだいぶ省略できるようです。
ただ、超簡単なサンプルはよく見かけるのですが、ほんのちょっとインタフェースを複雑にしたりすると意外とサンプルって見かけないものですよね。(検索の仕方が下手なのかもしれませんが・・・
なものでちょこっとC/C++側とJava側のサンプルを作ってみました。

コメント等はそのうち気が向いたら補足するとして、とりあえずコードだけ載せておきます。
構造体やコールバック関数が使えればだいたいのことはできるんじゃないかな?というレベルのものです。日本語扱うときだと環境によっては注意が必要でしょうね。

ちなみに私が使ったJNAのバージョンは4.1.0です。コードを見ていただくと分かりますがWindows上で試してました。

なお、あくまでサンプルコードなので当方では一切の責任を持ちません。皆様の責任の範囲でご参照ください。

--------------------------------------------------
<C/C++側>

#include
#include

struct SampleContext {
  int member;
};
typedef SampleContext* SampleHandle;

struct SampleStruct {
  char member[1024];
};

extern "C" {

__declspec(dllexport) SampleHandle function_open(SampleStruct *arg)
{
  SampleContext *context = (SampleHandle)new SampleContext;
  context->member = atoi(arg->member);
  return (SampleHandle)context;
}

__declspec(dllexport) void function_run(SampleHandle arg, void(*callback)(SampleHandle))
{
  SampleContext *context = (SampleContext *)arg;
  std::cout << "   start: " << context->member << std::endl;
  (*callback)(arg);
  std::cout << "     end: " << context->member << std::endl;
}

__declspec(dllexport) int function_get(SampleHandle arg)
{
  SampleContext *context = (SampleContext *)arg;
  return context->member;
}

__declspec(dllexport) void function_close(SampleHandle arg)
{
  SampleContext *context = (SampleContext *)arg;
  delete context;
}

}
--------------------------------------------------
<Java側>

package sample_jna;

import java.util.Arrays;
import java.util.List;

import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import com.sun.jna.Structure;

public class SampleJna {
  public static class SampleStruct extends Structure {
    public byte [] member = "12345".getBytes();
      @Override
      protected List getFieldOrder() {
          return Arrays.asList ("member");
      }
      public SampleStruct() {
        super();
      }
  }

  public static class SampleHandle extends PointerType {
    public SampleHandle() {
      super();
    }
    public SampleHandle(Pointer address) {
      super(address);
    }
  }

  public interface SampleCallback extends Callback {
    public void invoke(SampleHandle arg);
  }

  public interface SampleLibrary extends Library {
    SampleLibrary INSTANCE = (SampleLibrary)Native.loadLibrary("sample_library", SampleLibrary.class);
    SampleHandle function_open(SampleStruct arg);
    void function_run(SampleHandle arg, SampleCallback callback);
    int function_get(SampleHandle arg);
    void function_close(SampleHandle arg);
  }

  public static class UserCallback implements SampleCallback {
    public void invoke(SampleHandle arg) {
      String message = "callback: " + SampleLibrary.INSTANCE.function_get(arg);
      System.out.println(message);
    }
  }

  public static void main(String[] args) {
    SampleStruct struct = new SampleStruct();
    UserCallback callback = new UserCallback();

    SampleHandle handle = SampleLibrary.INSTANCE.function_open(struct);
    SampleLibrary.INSTANCE.function_run(handle, callback);
    SampleLibrary.INSTANCE.function_close(handle);
  }
}
--------------------------------------------------

実行結果はこんな感じ。

   start: 12345
callback: 12345
     end: 12345

ちゃんとコールバック関数内でもコンテキスト内部の情報が取れてますね。

2014年3月1日土曜日

MinGWの64bit版を準備

先日JuliusのDLL化までは試しに実施してみた。でも動くかどうかの確認ができていない。本来はC言語のレベルで確認すべきところでしょうが、遊びで試しているのもあるので今回の目的であるJavaの環境でいっきに試してみようと思ったところで、自分のパソコンにセットアップしているJavaが64bit版であることに気づく。

さてどうしようか。やっぱりJuliusを64bitでビルドしてみようかな。
ということでまずはMinGWの64bitをインストールしてみることにします。

1. ダウンロードと配置

まず以下のサイトから探します。ビルド済みのバイナリがあるといいなー。
メニューの「Mingw-builds Project」の「Windows 64」のリンク先に移動し、私がダウンロードしたときは4.8.2が最新でしたのでそのバージョンにします。
今回私はthread-posixのseh(Structured Exception Handling)を使います。あまり調べていないので特に選んだ理由はありません。ということでダウンロードしたのは以下のファイル
  • x86_64-4.8.2-release-posix-seh-rt_v3-rev2.7z
今度はMSYSも欲しいので準備します。でもMSYSはまだ64bitの整備が整っていない気配がしますね。とりあえず以下のサイトからゲットすることにします。
「External binary packages (Win64 hosted) / MSYS (32-bit)」に移動して、私は以下をダウンロードしました。
  • MSYS-20111123.zip
mingw64を\bin直下に配置し、msysは32bit版にならってmingw64の直下にmsys\1.0を作成し、その中に展開したmsys直下のフォルダ/ファイル類を配置しました。

2. 環境整備

次に使いやすくしておきます。Linuxの文化になじんでいないためあまりよくわかりません。とりあえずいろんなサイトみて、以下のような準備をしておきました。
  1. minttyを使ってみようかと思いますので「--mintty」で起動するショートカットを作成。
  2. HOMEディレクトリを変更する場合、環境変数HOMEに指定するとシェルが起動したときのホームが変わります。
  3. 日本語表示と入力に対応したいので.inputrcの該当箇所を以下に書き換えます。
    set kanji-code sjis
    set output-meta on
    set convert-meta off
  4. マウント設定してパスを参照しやすくします。
    C:\bin\mingw64\msys\1.0\etcにfstabファイルを以下の内容で記載します。(サンプルファイルが同フォルダにありました。)
    C:/bin/mingw64 /mingw
  5. 最後に環境変数とかの設定。まずは.profileにこの程度で。
    alias ls='ls --color=auto --show-control-chars'
    PATH=.:/mingw/bin:/bin:
なお主に参考にさせていただいたサイトはこちら。

2008年8月29日金曜日

WTLでスライダーバーを使いたい

今日はWTLにチャレンジ
スライダーバーを使おうとしてMSG_WM_HSCROLLマクロを埋め込んだところ、なにやら未解決のメソッドが出てきた。
そこでよくatlcrack.hを見ると以下のコメントが、

// Note about message maps with cracked handlers:
// For ATL 3.0, a message map using cracked handlers MUST use BEGIN_MSG_MAP_EX.
// For ATL 7.0 or higher, you can use BEGIN_MSG_MAP for CWindowImpl/CDialogImpl derived classes,
// but must use BEGIN_MSG_MAP_EX for classes that don't derive from CWindowImpl/CDialogImpl.

BEGIN_MSG_MAPをBEGIN_MSG_MAP_EXに置き換えたら見事ビルドが通りました。
使い方は以下みたいな感じ。

class CMainDlg : public CDialogImpl<CMainDlg>, public CUpdateUI<CMainDlg>,
        public CMessageFilter, public CIdleHandler
{
private:
    CTrackBarCtrl    track_bar;    // トラックバー

…中略…

    BEGIN_MSG_MAP_EX(CMainDlg)
        MSG_WM_HSCROLL(OnHScroll)
        MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
        MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
    END_MSG_MAP()

    void OnHScroll(int nCode, short nPos, HWND hWnd)
    {
        CTrackBarCtrl trackbar = hWnd;
        ATLTRACE("%d\n", trackbar.GetPos());
    }

    LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
    {


…中略…


        // コントロール設定
        track_bar = GetDlgItem(IDC_SLIDER_MAIN);

        // スライダーバーの初期化
        track_bar.SetRange(0, 32767);    // 値の範囲(32767が最大値)
        track_bar.SetTicFreq(3276);        // 解像度
        track_bar.SetPageSize(3276);    // PageUp/PageDown での移動量
        track_bar.SetLineSize(328);        // カーソルキーでの移動量

        return TRUE;
    }


…中略…




}


2008年8月23日土曜日

Visual C++ 2008 Express EditionでWTLを使おう!

このページでは主に以下の手順についての概要をまとめてあります。
ただ正直細かい点はあまり覚えてないので省略してたりもします。(^^;


    1. Visual C++ 2008 Express Editionをインストール
    2. Microsoft Platform SDKをインストール
    3. WTL8.0をインストール






1. Visual C++ 2008 Express Editionをインストール



特に大変なことはありません。ウイザードに沿ってインストールを進めます。
ちなみに私は以前マイクロソフトのサイトからダウンロードしていたものを使用しました。

2. Microsoft Platform SDKをインストール





Windows Server 2003 SP1 Platform SDK ISO Installを使ってインストールします。
インストール後に、VC++2008の[ツール]->[オプション]からオプション設定ダイアログを開き、include・libのパスを設定します。
[プロジェクトおよびソリューション]->[VC++ ディレクトリ]->[ディレクトリを表示するプロジェクト]->[インクルード ファイル]

3. WTL8.0をインストール



SOURCEFORGE.NETより最新版を入手します。


(1) 自己解凍書庫を展開したものを任意のフォルダに移動します。


(2) 移動後に、VC++2008の[ツール]->[オプション]からオプション設定ダイアログを開き、includeのパスを設定します。
[プロジェクトおよびソリューション]->[VC++ ディレクトリ]->[ディレクトリを表示するプロジェクト]->[インクルード ファイル]


(3) セットアップスクリプトをVC++2008EE用に編集します。

- setup80x.jsをコピーしてsetup90x.jsというファイルを作成します。
- setup90x.jsをテキストファイルで開いて、「8.0」という文字列を「9.0」に置換します。
- setup90x.jsを保存して閉じます。
- setup90x.jsを実行し、セットアップが完了します。