/* wce-peer.c
   Copyright (C) 2005-2006 Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */

#include <windows.h>
#include <assert.h>
#include <aygshell.h>
#include <tchar.h>
#include <jni.h>
#include "resource.h"
#include "wce-peer.h"

/**
 * システムウインドウメッセージ
 */
#define SYSMSG_CREATE			(WM_USER+100)

#define SYSMSG_SET_VISIBLE		(WM_USER+200)
#define SYSMSG_TO_BACK			(WM_USER+201)
#define SYSMSG_TO_FRONT			(WM_USER+202)
#define SYSMSG_SET_BOUNDS		(WM_USER+203)
#define SYSMSG_SET_ENABLED		(WM_USER+204)
#define SYSMSG_DISPOSE			(WM_USER+205)
/* !!!! Mod PeteC 2006-06-20 */
#define SYSMSG_SET_FOCUS		(WM_USER+206)
/* !!!! End Mod PeteC 2006-06-20 */

#define SYSMSG_GET_FOCUS		(WM_USER+207)
#define SYSMSG_GET_WINDOW_RECT	(WM_USER+208)
#define SYSMSG_SET_BACKGROUND	(WM_USER+209)
#define SYSMSG_SET_FOREGROUND	(WM_USER+210)
#define SYSMSG_GET_BOUNDS		(WM_USER+211)

#define SYSMSG_SHOW_POPUPMENU	(WM_USER+300)

#define SYSMSG_SET_SCROLL_POSITION		(WM_USER+400)

/**
 * ピアのタイプ。
 * Java側のpeerコンポーネントに対応している
 */
#define WINDOW_PEER_FLAG		0x40000000
#define DIALOG_PEER_FLAG		(WINDOW_PEER_FLAG|0x80000000)

#define	BUTTON_PEER_TYPE		1
#define	CANVAS_PEER_TYPE		2
#define	CHECKBOX_PEER_TYPE		3
#define CHOICE_PEER_TYPE		4
#define DIALOG_PEER_TYPE		(DIALOG_PEER_FLAG)
#define FILE_DIALOG_PEER_TYPE	(6|DIALOG_PEER_FLAG)
#define FRAME_PEER_TYPE			(7|WINDOW_PEER_FLAG)
#define LABEL_PEER_TYPE			8
#define LIST_PEER_TYPE			9
#define PANEL_PEER_TYPE			10
#define SCROLLBAR_PEER_TYPE		11
#define SCROLL_PANE_PEER_TYPE	12
#define TEXT_AREA_PEER_TYPE		13
#define TEXT_FIELD_PEER_TYPE	14
#define WINDOW_PEER_TYPE		(WINDOW_PEER_FLAG)
//---------------------------------------------------

typedef struct native_component_t {
	/**
	 * タイプ
	 */
	int type;

	/**
	 * Peerオブジェクト本体
	 */
	jobject peer_object;
	
	/**
	 * HWND
	 */
	HWND hwnd;
	
	/**
	 * 背景色
	 */
	COLORREF	background;
	
	/**
	 * 背景色に使用するブラシ
	 */
	HBRUSH		backgroundBrush;

	/**
	 * 前面色
	 */
	COLORREF	foreground;
	
	/**
	 * サブクラス化した場合のデフォルトWndProc
	 */
	WNDPROC defaultWindowProc;
	
	/**
	 * カーソル
	 */
	HCURSOR hCursor;

	/**
	 * 表示対象となるポップアップメニューのハンドル
	 * （一時的に使用）
	 */
	HMENU hmenuPopup;
	
	//--- これ以降は peer のタイプごとに異なるデータ項目
	// 全種類のpeerを作成した後、整理する予定

	/**
	 * メニューバーのハンドル（Frame/Dialogの場合のみ使用）
	 */
	HWND hwndMB;

	/**
	 * SHACTIVATEINFO(Frame/Dialogの場合のみ使用）
	 */
	SHACTIVATEINFO sai;
	
	/**
	 * CheckboxGroupの参照(Checkboxの場合のみ使用）
	 */
	jobject checkboxGroup;

	/**
	 * TextAreaのスクロールバー有無(TextAreaの場合のみ使用）
	 */
	int scrollbarVisibility;
	
	/**
	 * 複数選択リストかどうか（Listの場合のみ使用）
	 */
	BOOL multi;

	/**
	 * スクロールバーの方向(Scrollbarの場合のみ使用）
	 */
	int scrollbarOrientation;

	/**
	 * スクロールバーの行増分(Scrollbarの場合にのみ使用）
	 */
	int scrollbarLineIncrement;

	/**
	 * スクロールバーのページ増分(Scrollbarの場合にのみ使用)
	 */
	int scrollbarPageIncrement;
	
	/**
	 * スクロールバー表示ポリシー（ScrollPaneの場合にのみ使用）
	 */
	int scrollPaneScrollbarDisplayPolicy;
} native_component;

/**
 * ウインドウの領域。
 */
typedef struct bounds_t {
	int x;
	int y;
	int width;
	int height;
} bounds;

/**
 * HINSTANCE
 */
HINSTANCE g_hInstance;

/**
 * システムウインドウハンドル
 */
HWND g_hSystemWnd;

/**
 * システムウインドウクラス名
 */
const _TCHAR* g_system_window_class_name = _T("gnu_java_awt_peer_wce_SystemWindow");

/**
 * ヘビーウェイトコンテナ用ウインドウクラス名
 * Canvas, Panel, ScrollPane, Window がこのウインドウクラスを使用する
 */
const _TCHAR* g_container_class_name = _T("gnu_java_awt_peer_wce_Container");

/**
 * 最後に WM_MOUSEMOVE メッセージを受け取ったウインドウ
 */
static HWND g_hwndLastMouseMoved;

/**
 * WCEToolkit.getFloatingFlags()の戻り値
 */
static jint g_floating_flags;

// --- static 関数の宣言 ---
static native_component* allocate_native_component(int type, jobject peer);
static void free_native_component(native_component* peer);
static jobject get_Component_of(JNIEnv* env, jobject peer_obj);
static void init_frame_style(HWND hWnd, jboolean undecorated);
static void init_dialog_style(HWND hWnd, jboolean undecorated);

/**
 * 現在時刻を返す
 */
// static jlong get_current_time();
#define get_current_time()	(0i64)

/**
 * Windows CEのキーコードを KeyEvent クラスで定義されたキーコードに変換する
 */
static jint to_java_keycode(WPARAM wparam);

/**
 * Windows CEのキーコードを KeyEvent クラスで定義されたキー位置に変換する
 */
static jint to_java_keylocation(WPARAM wparam);

/**
 * Windows CEのキー状態を InputEvent クラスで定義されたmodifier定数に変換する
 */
static jint get_InputEvent_modifiers();

static void initialize_components(JNIEnv* env);

/**
 * 指定されたpeerがWindowPeerであった場合、WCEWindowBoundsEvent をpostする
 */
static void post_WCEWindowBoundsEvent(JNIEnv* env, jobject peer_obj, LPRECT prect);
// --- static 関数の宣言 ここまで ---

/**
 * AWTError
 */
static jclass g_AWTError_class;

/**
 * WCEToolkit.run()内でのみ使用可能なJNIEnv
 */
JNIEnv* g_WCEToolkit_run_env;


//--- オブジェクト参照 ---
/**
 * Rectangleクラス
 */
jclass g_Rectangle_class;

/**
 * Rectangle(int x, int y, int width, int height)
 */
jmethodID g_Rectangle_constructor_id;

/**
 * Windowクラス
 */
jclass g_Window_class;

/**
 * Window.validate()メソッド
 */
jmethodID g_Window_validate_id;

/**
 * WCEButtonPeerクラス
 */
jclass g_WCEButtonPeer_class;

/**
 * WCEButtonPeer.postActionEvent()
 */
jmethodID g_WCEButtonPeer_postActionEvent_id;

/**
 * WCECheckboxPeerクラス
 */
jclass g_WCECheckboxPeer_class;

/**
 * WCECheckboxPeer.setState()
 */
jmethodID g_WCECheckboxPeer_setState_id;

/**
 * WCECheckboxPeer.postItemEvent()
 */
jmethodID g_WCECheckboxPeer_postItemEvent_id;

/**
 * WCECheckboxMenuItemPeerクラス
 */
jclass g_WCECheckboxMenuItemPeer_class;

/**
 * WCECheckboxMenuItemPeer.postItemEvent()
 */
jmethodID g_WCECheckboxMenuItemPeer_postItemEvent_id;

/**
 * WCEChoicePeerクラス
 */
jclass g_WCEChoicePeer_class;

/**
 * WCEChoicePeer.postItemEvent()
 */
jmethodID g_WCEChoicePeer_postItemEvent_id;

/**
 * WCEComponentPeerクラス
 */
jclass g_WCEComponentPeer_class;

 /**
 * WCEComponentPeer.component フィールドのID
 */
jfieldID g_WCEComponentPeer_component_id;

/**
 * WCEComponentPeer.postPaintEvent(int id, int x, int y, int width, int height);
 */
jmethodID g_WCEComponentPeer_postPaintEvent_id;

/**
 * WCEComponentPeer.postMouseEvent(int id, long when, int modifiers, int x, int y, int clickcount, boolean popupTrigger);
 */
jmethodID g_WCEComponentPeer_postMouseEvent_id;

/**
 * WCEComponentPeer.postFocusEvent(int id)
 */
jmethodID g_WCEComponentPeer_postFocusEvent_id;

/**
 * WCEComponentPeer.postKeyEvent()
 */
jmethodID g_WCEComponentPeer_postKeyEvent_id;

/**
 * WCEMenuComponentPeerクラス
 */
jclass g_WCEMenuComponentPeer_class;

 /**
 * WCEMenuComponentPeer.menuComponent フィールドのID
 */
jfieldID g_WCEMenuComponentPeer_menuComponent_id;

/**
 * WCEMenuItemPeerクラス
 */
jclass g_WCEMenuItemPeer_class;

/**
 * WCEMenuItemPeer.postActionEvent()
 */
jmethodID g_WCEMenuItemPeer_postActionEvent_id;

/**
 * WCEListPeerクラス
 */
jclass g_WCEListPeer_class;

/**
 * WCEListPeer.postActionEvent()
 */
jmethodID g_WCEListPeer_postActionEvent_id;

/**
 * WCEListPeer.postItemEvent()
 */
jmethodID g_WCEListPeer_postItemEvent_id;

/**
 * WCEScrollbarPeer
 */
jclass g_WCEScrollbarPeer_class;

/**
 * WCEScrollbarPeer.postAdjustmentEvent()
 */
jmethodID g_WCEScrollbarPeer_postAdjustmentEvent_id;

/**
 * WCEScrollPanePeer
 */
jclass g_WCEScrollPanePeer_class;

/**
 * WCEScrollPanePeer.updatePosition()
 */
jmethodID g_WCEScrollPanePeer_updatePosition_id;

/**
 * WCETextComponentPeer
 */
jclass g_WCETextComponentPeer_class;

/**
 * WCETextComponentPeer.postTextEvent()
 */
jmethodID g_WCETextComponentPeer_postTextEvent_id;

/**
 * WCEToolkitオブジェクト
 */
jobject g_WCEToolkit_instance;

/**
 * WCEToolkitクラス
 */
jclass g_WCEToolkit_class;

/**
 * WCEToolkit.handleNativeMessage(int,int,int,int)メソッド
 */
jmethodID g_WCEToolkit_handleNativeMessage_id;

/**
 * WCEToolkit定数値
 */
#define	WCEToolkit_FRAME_IS_FLOATING	1
#define	WCEToolkit_DIALOG_IS_FLOATING	2

/**
 * WCEWindowPeerクラス
 */
jclass g_WCEWindowPeer_class;

/**
 * WCEWindowPeer.postWindowEvent()
 */
jmethodID g_WCEWindowPeer_postWindowEvent_id;

/**
 * WCEWindowPeer.postWCEWindowBoundsEvent()
 */
jmethodID g_WCEWindowPeer_postWCEWindowBoundsEvent_id;

/**
 * ActionEvent定数値
 */
#define ActionEvent_ACTION_PERFORMED	1001L
//--- ActionEvent ---

/**
 * AdjustmentEvent定数値
 */
#define	AdjustmentEvent_ADJUSTMENT_VALUE_CHANGED	601
#define AdjustmentEvent_UNIT_INCREMENT	1
#define AdjustmentEvent_UNIT_DECREMENT	2
#define AdjustmentEvent_BLOCK_DECREMENT	3
#define AdjustmentEvent_BLOCK_INCREMENT	4
#define AdjustmentEvent_TRACK			5

/**
 * Cursor定数値
 */
#define Cursor_CROSSHAIR_CURSOR	1 
#define Cursor_CUSTOM_CURSOR	-1 
#define Cursor_DEFAULT_CURSOR	0 
#define Cursor_E_RESIZE_CURSOR	11 
#define Cursor_HAND_CURSOR	12 
#define Cursor_MOVE_CURSOR	13 
#define Cursor_N_RESIZE_CURSOR	8 
#define Cursor_NE_RESIZE_CURSOR	7 
#define Cursor_NW_RESIZE_CURSOR	6 
#define Cursor_S_RESIZE_CURSOR	9 
#define Cursor_SE_RESIZE_CURSOR	5 
#define Cursor_SW_RESIZE_CURSOR	4 
#define Cursor_TEXT_CURSOR	2 
#define Cursor_W_RESIZE_CURSOR	10 
#define Cursor_WAIT_CURSOR	3 


/**
 * FocusEvent定数値
 */
#define FocusEvent_FOCUS_GAINED	1004
#define FocusEvent_FOCUS_LOST	1005

/**
 * InputEvent定数値
 */
#define InputEvent_ALT_DOWN_MASK		512 
#define InputEvent_ALT_GRAPH_DOWN_MASK	8192 
#define InputEvent_ALT_GRAPH_MASK		32 
#define InputEvent_ALT_MASK				8 
#define InputEvent_BUTTON1_DOWN_MASK	1024 
#define InputEvent_BUTTON1_MASK			16 
#define InputEvent_BUTTON2_DOWN_MASK	2048 
#define InputEvent_BUTTON2_MASK			8 
#define InputEvent_BUTTON3_DOWN_MASK	4096 
#define InputEvent_BUTTON3_MASK			4 
#define InputEvent_CTRL_DOWN_MASK		128 
#define InputEvent_CTRL_MASK			2 
#define InputEvent_META_DOWN_MASK		256 
#define InputEvent_META_MASK			4 
#define InputEvent_SHIFT_DOWN_MASK		64 
#define InputEvent_SHIFT_MASK			1 



/**
 * KeyEvent定数値
 */
#define KeyEvent_KEY_TYPED		400
#define KeyEvent_KEY_PRESSED	401
#define KeyEvent_KEY_RELEASED	402

#define KeyEvent_VK_ACCEPT 30 
#define KeyEvent_VK_ADD 107 
#define KeyEvent_VK_AGAIN 65481 
#define KeyEvent_VK_ALL_CANDIDATES 256 
#define KeyEvent_VK_ALPHANUMERIC 240 
#define KeyEvent_VK_ALT 18 
#define KeyEvent_VK_ALT_GRAPH 65406 
#define KeyEvent_VK_AMPERSAND 150 
#define KeyEvent_VK_ASTERISK 151 
#define KeyEvent_VK_AT 512 
#define KeyEvent_VK_BACK_QUOTE 192 
#define KeyEvent_VK_BACK_SLASH 92 
#define KeyEvent_VK_BACK_SPACE 8 
#define KeyEvent_VK_BRACELEFT 161 
#define KeyEvent_VK_BRACERIGHT 162 
#define KeyEvent_VK_CANCEL 3 
#define KeyEvent_VK_CAPS_LOCK 20 
#define KeyEvent_VK_CIRCUMFLEX 514 
#define KeyEvent_VK_CLEAR 12 
#define KeyEvent_VK_CLOSE_BRACKET 93 
#define KeyEvent_VK_CODE_INPUT 258 
#define KeyEvent_VK_COLON 513 
#define KeyEvent_VK_COMMA 44 
#define KeyEvent_VK_COMPOSE 65312 
#define KeyEvent_VK_CONTROL 17 
#define KeyEvent_VK_CONVERT 28 
#define KeyEvent_VK_COPY 65485 
#define KeyEvent_VK_CUT 65489 
#define KeyEvent_VK_DEAD_ABOVEDOT 134 
#define KeyEvent_VK_DEAD_ABOVERING 136 
#define KeyEvent_VK_DEAD_ACUTE 129 
#define KeyEvent_VK_DEAD_BREVE 133 
#define KeyEvent_VK_DEAD_CARON 138 
#define KeyEvent_VK_DEAD_CEDILLA 139 
#define KeyEvent_VK_DEAD_CIRCUMFLEX 130 
#define KeyEvent_VK_DEAD_DIAERESIS 135 
#define KeyEvent_VK_DEAD_DOUBLEACUTE 137 
#define KeyEvent_VK_DEAD_GRAVE 128 
#define KeyEvent_VK_DEAD_IOTA 141 
#define KeyEvent_VK_DEAD_MACRON 132 
#define KeyEvent_VK_DEAD_OGONEK 140 
#define KeyEvent_VK_DEAD_SEMIVOICED_SOUND 143 
#define KeyEvent_VK_DEAD_TILDE 131 
#define KeyEvent_VK_DEAD_VOICED_SOUND 142 
#define KeyEvent_VK_DECIMAL 110 
#define KeyEvent_VK_DELETE 127 
#define KeyEvent_VK_DIVIDE 111 
#define KeyEvent_VK_DOLLAR 515 
#define KeyEvent_VK_DOWN 40 
#define KeyEvent_VK_END 35 
#define KeyEvent_VK_ENTER 10 
#define KeyEvent_VK_EQUALS 61 
#define KeyEvent_VK_ESCAPE 27 
#define KeyEvent_VK_EURO_SIGN 516 
#define KeyEvent_VK_EXCLAMATION_MARK 517 
#define KeyEvent_VK_F1 112 
#define KeyEvent_VK_F10 121 
#define KeyEvent_VK_F11 122 
#define KeyEvent_VK_F12 123 
#define KeyEvent_VK_F13 61440 
#define KeyEvent_VK_F14 61441 
#define KeyEvent_VK_F15 61442 
#define KeyEvent_VK_F16 61443 
#define KeyEvent_VK_F17 61444 
#define KeyEvent_VK_F18 61445 
#define KeyEvent_VK_F19 61446 
#define KeyEvent_VK_F2 113 
#define KeyEvent_VK_F20 61447 
#define KeyEvent_VK_F21 61448 
#define KeyEvent_VK_F22 61449 
#define KeyEvent_VK_F23 61450 
#define KeyEvent_VK_F24 61451 
#define KeyEvent_VK_F3 114 
#define KeyEvent_VK_F4 115 
#define KeyEvent_VK_F5 116 
#define KeyEvent_VK_F6 117 
#define KeyEvent_VK_F7 118 
#define KeyEvent_VK_F8 119 
#define KeyEvent_VK_F9 120 
#define KeyEvent_VK_FINAL 24 
#define KeyEvent_VK_FIND 65488 
#define KeyEvent_VK_FULL_WIDTH 243 
#define KeyEvent_VK_GREATER 160 
#define KeyEvent_VK_HALF_WIDTH 244 
#define KeyEvent_VK_HELP 156 
#define KeyEvent_VK_HIRAGANA 242 
#define KeyEvent_VK_HOME 36 
#define KeyEvent_VK_INPUT_METHOD_ON_OFF 263 
#define KeyEvent_VK_INSERT 155 
#define KeyEvent_VK_INVERTED_EXCLAMATION_MARK 518 
#define KeyEvent_VK_JAPANESE_HIRAGANA 260 
#define KeyEvent_VK_JAPANESE_KATAKANA 259 
#define KeyEvent_VK_JAPANESE_ROMAN 261 
#define KeyEvent_VK_KANA 21 
#define KeyEvent_VK_KANA_LOCK 262 
#define KeyEvent_VK_KANJI 25 
#define KeyEvent_VK_KATAKANA 241 
#define KeyEvent_VK_KP_DOWN 225 
#define KeyEvent_VK_KP_LEFT 226 
#define KeyEvent_VK_KP_RIGHT 227 
#define KeyEvent_VK_KP_UP 224 
#define KeyEvent_VK_LEFT 37 
#define KeyEvent_VK_LEFT_PARENTHESIS 519 
#define KeyEvent_VK_LESS 153 
#define KeyEvent_VK_META 157 
#define KeyEvent_VK_MINUS 45 
#define KeyEvent_VK_MODECHANGE 31 
#define KeyEvent_VK_MULTIPLY 106 
#define KeyEvent_VK_NONCONVERT 29 
#define KeyEvent_VK_NUM_LOCK 144 
#define KeyEvent_VK_NUMBER_SIGN 520 
#define KeyEvent_VK_NUMPAD0 96 
#define KeyEvent_VK_NUMPAD1 97 
#define KeyEvent_VK_NUMPAD2 98 
#define KeyEvent_VK_NUMPAD3 99 
#define KeyEvent_VK_NUMPAD4 100 
#define KeyEvent_VK_NUMPAD5 101 
#define KeyEvent_VK_NUMPAD6 102 
#define KeyEvent_VK_NUMPAD7 103 
#define KeyEvent_VK_NUMPAD8 104 
#define KeyEvent_VK_NUMPAD9 105 
#define KeyEvent_VK_OPEN_BRACKET 91 
#define KeyEvent_VK_PAGE_DOWN 34 
#define KeyEvent_VK_PAGE_UP 33 
#define KeyEvent_VK_PASTE 65487 
#define KeyEvent_VK_PAUSE 19 
#define KeyEvent_VK_PERIOD 46 
#define KeyEvent_VK_PLUS 521 
#define KeyEvent_VK_PREVIOUS_CANDIDATE 257 
#define KeyEvent_VK_PRINTSCREEN 154 
#define KeyEvent_VK_PROPS 65482 
#define KeyEvent_VK_QUOTE 222 
#define KeyEvent_VK_QUOTEDBL 152 
#define KeyEvent_VK_RIGHT 39 
#define KeyEvent_VK_RIGHT_PARENTHESIS 522 
#define KeyEvent_VK_ROMAN_CHARACTERS 245 
#define KeyEvent_VK_SCROLL_LOCK 145 
#define KeyEvent_VK_SEMICOLON 59 
#define KeyEvent_VK_SEPARATER 108 
#define KeyEvent_VK_SEPARATOR 108 
#define KeyEvent_VK_SHIFT 16 
#define KeyEvent_VK_SLASH 47 
#define KeyEvent_VK_SPACE 32 
#define KeyEvent_VK_STOP 65480 
#define KeyEvent_VK_SUBTRACT 109 
#define KeyEvent_VK_TAB 9 
#define KeyEvent_VK_UNDEFINED 0 
#define KeyEvent_VK_UNDERSCORE 523 
#define KeyEvent_VK_UNDO 65483 
#define KeyEvent_VK_UP 38 
#define KeyEvent_CHAR_UNDEFINED 65535

#define KeyEvent_KEY_LOCATION_UNKNOWN 0 
#define KeyEvent_KEY_LOCATION_STANDARD 1 
#define KeyEvent_KEY_LOCATION_LEFT 2 
#define KeyEvent_KEY_LOCATION_RIGHT 3 
#define KeyEvent_KEY_LOCATION_NUMPAD 4 


/**
 * ItemEvent定数値
 */
#define	ItemEvent_SELECTED				1
#define	ItemEvent_DESELECTED			2
#define	ItemEvent_ITEM_STATE_CHANGED	701

/**
 * MouseEvent定数値
 */
#define MouseEvent_MOUSE_CLICKED	500L
#define MouseEvent_MOUSE_PRESSED	501L
#define MouseEvent_MOUSE_RELEASED	502L
#define MouseEvent_MOUSE_MOVED		503L
#define MouseEvent_MOUSE_ENTERED	504L
#define MouseEvent_MOUSE_EXITED		505L
#define MouseEvent_MOUSE_DRAGGED	506L
#define MouseEvent_BUTTON1_MASK 16L
#define MouseEvent_NOBUTTON 0L
#define MouseEvent_BUTTON1	1L
#define MouseEvent_BUTTON2	2L
#define MouseEvent_BUTTON3	3L
//--- MouseEvent end

/**
 * PaintEvent定数値
 */
#define PaintEvent_PAINT	800
#define PaintEvent_UPDATE	801
//--- PaintEvent end

/**
 * Scrollbar定数値
 */
#define Scrollbar_HORIZONTAL	0
#define Scrollbar_VERTICAL		1

/**
 * ScrollPane定数値
 */
#define ScrollPane_SCROLLBARS_AS_NEEDED	0
#define ScrollPane_SCROLLBARS_ALWAYS	1
#define ScrollPane_SCROLLBARS_NEVER		2

/**
 * TextArea定数値
 */
#define	TextArea_SCROLLBARS_BOTH			0
#define TextArea_SCROLLBARS_VERTICAL_ONLY	1
#define	TextArea_SCROLLBARS_HORIZONTAL_ONLY	2
#define TextArea_SCROLLBARS_NONE			3

/**
 * TextEvent定数値
 */
#define TextEvent_TEXT_VALUE_CHANGED	900

/**
 * WindowEvent定数
 */
#define  WindowEvent_WINDOW_OPENED			200 
#define  WindowEvent_WINDOW_CLOSING			201 
#define  WindowEvent_WINDOW_CLOSED			202 
#define  WindowEvent_WINDOW_ICONIFIED		203 
#define  WindowEvent_WINDOW_DEICONIFIED		204 
#define  WindowEvent_WINDOW_ACTIVATED		205 
#define  WindowEvent_WINDOW_DEACTIVATED		206 
#define  WindowEvent_WINDOW_GAINED_FOCUS	207 
#define  WindowEvent_WINDOW_LOST_FOCUS		208 
#define  WindowEvent_WINDOW_STATE_CHANGED	209 



/**
 * 同時に存在できるメニューアイテムの最大数
 */
#define	MAX_MENU_ITEMS	256

/**
 * メニューアイテム用のユニークID
 */
#define	MENU_ITEM_ID_FIRST	100
#define MENU_ITEM_ID_LAST	(MENU_ITEM_ID_FIRST+MAX_MENU_ITEMS)

/**
 * メニューアイテムのコマンドIDと、親メニューハンドルとの対応
 */
static HMENU g_menu_items[MAX_MENU_ITEMS];

/**
 * WM_ERASEBKGNDを無視する。
 * ScrollPaneで子Windowを移動させると、ちらついてしまうため、
 * このフラグを利用して背景の再描画を抑止する。
 */
static BOOL g_ignore_WM_ERASEBKGND;

/**
 * 各コントロールに付与するコマンドID
 */
#define	BUTTON_ID			(MENU_ITEM_ID_LAST+1)
#define CANVAS_ID			(MENU_ITEM_ID_LAST+2)
#define	CHECKBOX_ID			(MENU_ITEM_ID_LAST+3)
#define CHOICE_ID			(MENU_ITEM_ID_LAST+4)
#define LABEL_ID			(MENU_ITEM_ID_LAST+5)
#define LIST_ID				(MENU_ITEM_ID_LAST+6)
#define PANEL_ID			(MENU_ITEM_ID_LAST+7)
#define SCROLLBAR_ID		(MENU_ITEM_ID_LAST+8)
#define SCROLL_PANE_ID		(MENU_ITEM_ID_LAST+9)
#define TEXT_AREA_ID		(MENU_ITEM_ID_LAST+10)
#define TEXT_FIELD_ID		(MENU_ITEM_ID_LAST+11)

/**
 * ウインドウプロシージャ
 */
LRESULT CALLBACK WCEWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);
LRESULT CALLBACK SystemWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);

/**
 * ScrollPaneの子ウインドウを列挙するプロシージャ
 */
BOOL CALLBACK EnumScrollPaneChildProc(HWND hwnd , LPARAM lParam);

/**
 * DLLがロードされた時点で呼び出される。
 */
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
    switch(fdwReason)
    {
        case	DLL_PROCESS_ATTACH:
        	// グローバル変数に HINSTANCE を保存する
        	g_hInstance = hinstDLL;
			// スレッド関連の通知は不要
			DisableThreadLibraryCalls(hinstDLL);
            break;
    }
    return TRUE;
}

/**
 * コンポーネントへの参照を初期化する
 */
static void initialize_components(JNIEnv* env) {
#define CHECK_NONNULL(obj) { assert(obj); if (!obj) {  throw_AWTError(env, # obj " is NULL"); return; } }

	g_AWTError_class = (*env)->FindClass(env, "java/awt/AWTError");
	if (! g_AWTError_class) {
		return;
	}

	// WCEComponentPeer
	g_WCEComponentPeer_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCEComponentPeer");
	CHECK_NONNULL(g_WCEComponentPeer_class);

	g_WCEComponentPeer_component_id = (*env)->GetFieldID(env, g_WCEComponentPeer_class, "component", "Ljava/awt/Component;");
	CHECK_NONNULL(g_WCEComponentPeer_component_id);

	g_WCEComponentPeer_postMouseEvent_id
		= (*env)->GetMethodID(env,
							  g_WCEComponentPeer_class,
							  "postMouseEvent",
							  "(IIIIIZI)V");
	CHECK_NONNULL(g_WCEComponentPeer_postMouseEvent_id);

	g_WCEComponentPeer_postPaintEvent_id
		= (*env)->GetMethodID(env,
							  g_WCEComponentPeer_class,
							  "postPaintEvent",
							  "(IIIII)V");
	CHECK_NONNULL(g_WCEComponentPeer_postPaintEvent_id);

	g_WCEComponentPeer_postFocusEvent_id
		= (*env)->GetMethodID(env,
							  g_WCEComponentPeer_class,
							  "postFocusEvent",
							  "(IZLgnu/java/awt/peer/wce/WCEComponentPeer;)V");
	CHECK_NONNULL(g_WCEComponentPeer_postFocusEvent_id);

	g_WCEComponentPeer_postKeyEvent_id
		= (*env)->GetMethodID(env,
							  g_WCEComponentPeer_class,
							  "postKeyEvent",
							  "(IJIICI)V");
	CHECK_NONNULL(g_WCEComponentPeer_postKeyEvent_id);

	// WCEMenuComponentPeer
	g_WCEMenuComponentPeer_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCEMenuComponentPeer");
	CHECK_NONNULL(g_WCEMenuComponentPeer_class);

	g_WCEMenuComponentPeer_menuComponent_id
		= (*env)->GetFieldID(env, g_WCEMenuComponentPeer_class, "menuComponent", "Ljava/awt/MenuComponent;");
	CHECK_NONNULL(g_WCEMenuComponentPeer_menuComponent_id);
	
	// WCEMenuItemPeer
	g_WCEMenuItemPeer_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCEMenuItemPeer");
	CHECK_NONNULL(g_WCEMenuItemPeer_class);

	g_WCEMenuItemPeer_postActionEvent_id
		= (*env)->GetMethodID(env,
							  g_WCEMenuItemPeer_class,
							  "postActionEvent",
							  "(IJI)V");
	CHECK_NONNULL(g_WCEMenuItemPeer_postActionEvent_id);

	// WCECheckboxPeer
	g_WCECheckboxPeer_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCECheckboxPeer");
	CHECK_NONNULL(g_WCECheckboxPeer_class);

	g_WCECheckboxPeer_setState_id
		= (*env)->GetMethodID(env,
							  g_WCECheckboxPeer_class,
							  "setState",
							  "(Z)V");
	CHECK_NONNULL(g_WCECheckboxPeer_setState_id);

	g_WCECheckboxPeer_postItemEvent_id
		= (*env)->GetMethodID(env,
							  g_WCECheckboxPeer_class,
							  "postItemEvent",
							  "(Z)V");
	CHECK_NONNULL(g_WCECheckboxPeer_postItemEvent_id);

	// WCECheckboxMenuItemPeer
	g_WCECheckboxMenuItemPeer_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCECheckboxMenuItemPeer");
	CHECK_NONNULL(g_WCECheckboxMenuItemPeer_class);

	g_WCECheckboxMenuItemPeer_postItemEvent_id
		= (*env)->GetMethodID(env,
							  g_WCECheckboxMenuItemPeer_class,
							  "postItemEvent",
							  "(II)V");
	CHECK_NONNULL(g_WCECheckboxMenuItemPeer_postItemEvent_id);

	// WCEButtonPeerクラス
	g_WCEButtonPeer_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCEButtonPeer");
	CHECK_NONNULL(g_WCEButtonPeer_class);

	g_WCEButtonPeer_postActionEvent_id
		= (*env)->GetMethodID(env,
									g_WCEButtonPeer_class,
									"postActionEvent",
									"(IJI)V");
	CHECK_NONNULL(g_WCEButtonPeer_postActionEvent_id);

	// WCEChoicePeerクラス
	g_WCEChoicePeer_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCEChoicePeer");
	CHECK_NONNULL(g_WCEChoicePeer_class);

	g_WCEChoicePeer_postItemEvent_id
		= (*env)->GetMethodID(env,
									g_WCEChoicePeer_class,
									"postItemEvent",
									"(III)V");
	CHECK_NONNULL(g_WCEChoicePeer_postItemEvent_id);

	// WCEListPeerクラス
	g_WCEListPeer_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCEListPeer");
	CHECK_NONNULL(g_WCEListPeer_class);

	g_WCEListPeer_postActionEvent_id
		= (*env)->GetMethodID(env,
									g_WCEListPeer_class,
									"postActionEvent",
									"(IIJI)V");
	CHECK_NONNULL(g_WCEListPeer_postActionEvent_id);

	g_WCEListPeer_postItemEvent_id
		= (*env)->GetMethodID(env,
								    g_WCEListPeer_class,
									"postItemEvent",
									"(III)V");
	CHECK_NONNULL(g_WCEListPeer_postItemEvent_id);

	// WCEScrollbarPeerクラス
	g_WCEScrollbarPeer_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCEScrollbarPeer");
	CHECK_NONNULL(g_WCEScrollbarPeer_class);

	g_WCEScrollbarPeer_postAdjustmentEvent_id
		= (*env)->GetMethodID(env,
								    g_WCEScrollbarPeer_class,
									"postAdjustmentEvent",
									"(IIIZ)V");
	CHECK_NONNULL(g_WCEScrollbarPeer_postAdjustmentEvent_id);

	// WCEScrollPanePeerクラス
	g_WCEScrollPanePeer_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCEScrollPanePeer");
	CHECK_NONNULL(g_WCEScrollPanePeer_class);

	g_WCEScrollPanePeer_updatePosition_id = (*env)->GetMethodID(env,
																 g_WCEScrollPanePeer_class,
																 "updatePosition",
																 "(IIIZ)I");
	CHECK_NONNULL(g_WCEScrollPanePeer_updatePosition_id);

	// WCETextComponentPeerクラス
	g_WCETextComponentPeer_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCETextComponentPeer");
	CHECK_NONNULL(g_WCETextComponentPeer_class);

	g_WCETextComponentPeer_postTextEvent_id = (*env)->GetMethodID(env,
																 g_WCETextComponentPeer_class,
																 "postTextEvent",
																 "(I)V");
	CHECK_NONNULL(g_WCETextComponentPeer_postTextEvent_id);

	// WCEToolkit
	g_WCEToolkit_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCEToolkit");
	CHECK_NONNULL(g_WCEToolkit_class);

	g_WCEToolkit_handleNativeMessage_id
		= (*env)->GetMethodID(env, g_WCEToolkit_class, "handleNativeMessage", "(IIII)V");
	CHECK_NONNULL(g_WCEToolkit_handleNativeMessage_id);

	
	// WCEWindowPeer
	g_WCEWindowPeer_class = (*env)->FindClass(env, "gnu/java/awt/peer/wce/WCEWindowPeer");
	CHECK_NONNULL(g_WCEWindowPeer_class);

	g_WCEWindowPeer_postWindowEvent_id
		= (*env)->GetMethodID(env,
							  g_WCEWindowPeer_class,
							  "postWindowEvent",
							  "(ILgnu/java/awt/peer/wce/WCEComponentPeer;)V");
	CHECK_NONNULL(g_WCEWindowPeer_postWindowEvent_id);

	g_WCEWindowPeer_postWCEWindowBoundsEvent_id
		= (*env)->GetMethodID(env,
							  g_WCEWindowPeer_class,
							  "postWCEWindowBoundsEvent",
							  "(IIII)V");
	CHECK_NONNULL(g_WCEWindowPeer_postWCEWindowBoundsEvent_id);

	// Window
	g_Window_class = (*env)->FindClass(env, "java/awt/Window");
	CHECK_NONNULL(g_Window_class);

	g_Window_validate_id
		= (*env)->GetMethodID(env,
							  g_Window_class,
							  "validate",
							  "()V");
	CHECK_NONNULL(g_Window_validate_id);

	// Rectangleクラス
	g_Rectangle_class = (*env)->FindClass(env, "java/awt/Rectangle");
	CHECK_NONNULL(g_Rectangle_class);

	g_Rectangle_constructor_id =
		(*env)->GetMethodID(env,
								  g_Rectangle_class,
								  "<init>",
								  "(IIII)V");
	CHECK_NONNULL(g_Rectangle_constructor_id);

#undef CHECK_NONNULL
}

/**
 * 初期化処理を行う
 */
void init(JNIEnv* env) {
	initialize_components(env);

	{
		jmethodID mid = (*env)->GetStaticMethodID(env,
												  g_WCEToolkit_class,
												  "getFloatingFlags",
												  "()I");
		if (mid) {
			g_floating_flags = (*env)->CallStaticIntMethod(env,
														g_WCEToolkit_class,
														mid);
		}
	}
}

static void register_window_classes() {
	// ウインドウクラスの登録処理
	WNDCLASS wc = {0};
	wc.hInstance = g_hInstance;
	
	// サイズ変更時の処理は自前で行っている
	// wc.style			= CS_HREDRAW | CS_VREDRAW;

	// 背景描画処理は java.awt.Component.update() でも実施しているが、
	// ネイティブレベルで背景の再描画が必要になった場合には
	// このブラシが使用される
	// wc.hbrBackground	= GetStockObject(WHITE_BRUSH);

	// ヘビーウェイトコンテナに対応するクラスを登録する
	wc.lpfnWndProc		= WCEWndProc;
	wc.lpszClassName	= g_container_class_name;
	RegisterClass(&wc);

	// システムウインドウクラスを登録する
	wc.lpfnWndProc		= SystemWndProc;
	wc.lpszClassName	= g_system_window_class_name;
	RegisterClass(&wc);
}

/**
 * システムウインドウの初期化処理を行う
 */
void initialize_system_window(JNIEnv* env, jobject toolkit) {
	// ウインドウクラスを登録する
	register_window_classes();
	
	// システムウインドウを作成する
	g_hSystemWnd = CreateWindow(
						g_system_window_class_name,
						NULL,
						WS_POPUP,
						0, 0, 0, 0,
						NULL, 
						NULL, 
						g_hInstance,
						NULL);
	if (! g_hSystemWnd) {
		throw_AWTError(env, "Failed to create system window.");
		return;
	}

	g_WCEToolkit_run_env = env;
	g_WCEToolkit_instance = toolkit;
}


/**
 * ユニークなコマンドIDを生成する
 */
WORD create_menu_item_id(HMENU hmenuParent) {
	// ToDo: スレッドセーフにする必要がある
	int i;
	WORD id = 0;
	for (i = 0; i < MAX_MENU_ITEMS; ++i) {
		if (g_menu_items[i] == NULL) {
			g_menu_items[i] = hmenuParent;
			id = i + MENU_ITEM_ID_FIRST;
			break;
		}
	}
	assert(id != 0);

	return id;
}

/**
 * メニューに付与されたコマンドIDを破棄し、再利用可能とする
 */
void delete_menu_item_id(WORD id) {
	// ToDo:スレッドセーフにする
	int index;
	if (id == 0) {
		return;
	}
	index = id - MENU_ITEM_ID_FIRST;
	if (index >= MAX_MENU_ITEMS) {
		assert(FALSE);
		return;
	}
	g_menu_items[index] = NULL;
}

/**
 * 指定されたpeerオブジェクトが保持するComponentを返す
 */
static jobject get_Component_of(JNIEnv* env, jobject peer_obj) {
	// WCEComponentPeer.component フィールドを直接参照している
	return (*env)->GetObjectField(env, peer_obj, g_WCEComponentPeer_component_id);
}

/**
 * 指定されたMenuComponentPeerオブジェクトが保持するMenuComponentを返す
 */
static jobject get_MenuComponent_of(JNIEnv* env, jobject peer_obj) {
	return (*env)->GetObjectField(env, peer_obj, g_WCEMenuComponentPeer_menuComponent_id);
}

/**
 * 指定されたHWNDに対応するnative_component構造体を返す
 */
static native_component* get_native_component(HWND hwnd) {
	if (hwnd == NULL) {
		// エミュレータ上では問題ないが、実機ではGetWindowLong()に
		// NULLを渡してはいけない（アクセス違反が発生する）
		return NULL;
	}
	return (native_component*) GetWindowLong(hwnd, GWL_USERDATA);
}

/**
 * 指定されたpeerオブジェクトに対応するHWNDを返す
 */
HWND get_HWND(JNIEnv* env, jobject peer_obj) {
	HWND result = NULL;
	jclass clazz = (*env)->GetObjectClass(env, peer_obj);
	if (clazz) {
		jfieldID fid = (*env)->GetFieldID(env, clazz, "hwnd", "I");
		if (fid) {
			result = (HWND) (*env)->GetIntField(env, peer_obj, fid);
		}
	}
	return  result;
}

/**
 * 指定された native_component 構造体に対応するネイティブコンポーネントを
 * 作成する
 */
static void create_window(HWND hwndParent, native_component* peer) {
	switch (peer->type) {
	case BUTTON_PEER_TYPE:
		{
			peer->hwnd = CreateWindow(_T("BUTTON"),
									  NULL,
									  WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  hwndParent,
									  (HMENU) BUTTON_ID,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
			peer->defaultWindowProc = (WNDPROC) SetWindowLong(peer->hwnd, GWL_WNDPROC, (LONG) WCEWndProc);
		}
		break;

	case CHECKBOX_PEER_TYPE:
		{	
			DWORD style;
			if (peer->checkboxGroup) {
				style = BS_RADIOBUTTON;
			} else {
				style = BS_CHECKBOX;
			}
			peer->hwnd = CreateWindow(_T("BUTTON"),
									  NULL,
									  WS_CHILD | WS_VISIBLE | style,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  hwndParent,
									  (HMENU) CHECKBOX_ID,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
			peer->defaultWindowProc = (WNDPROC) SetWindowLong(peer->hwnd, GWL_WNDPROC, (LONG) WCEWndProc);
		}
		break;
	
	case CHOICE_PEER_TYPE:
		// コンボボックスを作成する
		{	
			peer->hwnd = CreateWindow(_T("COMBOBOX"),
									  NULL,
									  WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | CBS_DROPDOWNLIST,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  hwndParent,
									  (HMENU) CHOICE_ID,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
			peer->defaultWindowProc = (WNDPROC) SetWindowLong(peer->hwnd, GWL_WNDPROC, (LONG) WCEWndProc);
		}
		break;
	
	case DIALOG_PEER_TYPE:
		{
			SHMENUBARINFO mbi = {0};
			peer->hwnd = CreateWindow(g_container_class_name,
									  NULL,
									  WS_NONAVDONEBUTTON,	// 左上の×ボタンを無効にしておく
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  NULL,
									  NULL,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);

			// 空のメニューバーを作成する
			mbi.cbSize     = sizeof(SHMENUBARINFO);
			mbi.hwndParent = peer->hwnd;
			mbi.dwFlags    = SHCMBF_EMPTYBAR;
			mbi.hInstRes   = g_hInstance;

			if (SHCreateMenuBar(&mbi)) {
				RECT rc;
				RECT rcMenuBar;
				peer->hwndMB = mbi.hwndMB;
				GetWindowRect(peer->hwnd, &rc);
				GetWindowRect(peer->hwndMB, &rcMenuBar);
				rc.bottom -= (rcMenuBar.bottom - rcMenuBar.top);
				MoveWindow(peer->hwnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, FALSE);
			}
		}
		break;

	case FILE_DIALOG_PEER_TYPE:
		{
			// これはダミーのウインドウであり、表示されることはない
			peer->hwnd = CreateWindow(g_container_class_name,
									  NULL,
									  WS_DISABLED,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  NULL,
									  NULL,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
		}
		break;

	case FRAME_PEER_TYPE:
		// Frameに対応するウインドウを作成
		{
			SHMENUBARINFO mbi = {0};

			peer->hwnd = CreateWindow(g_container_class_name,
									  _T("Frame"),
									  WS_CLIPCHILDREN,	// WS_VISIBLEを指定すると表示されてしまうので副作用のなさそうなフラグを指定しておく
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  NULL,
									  NULL,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
			
			// メニューバーを作成する
			mbi.cbSize     = sizeof(SHMENUBARINFO);
			mbi.hwndParent = peer->hwnd;
			mbi.nToolBarId = IDM_MENU;
			mbi.hInstRes   = g_hInstance;

			if (SHCreateMenuBar(&mbi)) {
				RECT rc;
				RECT rcMenuBar;
				peer->hwndMB = mbi.hwndMB;
				GetWindowRect(peer->hwnd, &rc);
				GetWindowRect(peer->hwndMB, &rcMenuBar);
				rc.bottom -= (rcMenuBar.bottom - rcMenuBar.top);
				MoveWindow(peer->hwnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, FALSE);
			}
		}
		break;

	case LABEL_PEER_TYPE:
		// Staticウインドウを作成する
		{
			peer->hwnd = CreateWindow(_T("STATIC"),
									  NULL,
									  WS_CHILD | WS_VISIBLE | SS_NOPREFIX | SS_LEFT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  hwndParent,
									  (HMENU) LABEL_ID,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
			peer->defaultWindowProc = (WNDPROC) SetWindowLong(peer->hwnd, GWL_WNDPROC, (LONG) WCEWndProc);
		}
		break;
	
	case CANVAS_PEER_TYPE:
		{
			peer->hwnd = CreateWindow(g_container_class_name,
									  _T("Canvas"),
									  WS_CHILD | WS_VISIBLE,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  hwndParent,
									  (HMENU) CANVAS_ID,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
		}
		break;

	case PANEL_PEER_TYPE:
		{
			peer->hwnd = CreateWindow(g_container_class_name,
									  _T("Panel"),
									  WS_CHILD | WS_VISIBLE,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  hwndParent,
									  (HMENU) PANEL_ID,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
		}
		break;

	case LIST_PEER_TYPE:
		// Listに対応するウインドウを作成
		// WPARAM - 親Windowのハンドル
		// LPARAM - native_component*
		{
			DWORD style = peer->multi ? LBS_MULTIPLESEL : 0;
			peer->hwnd = CreateWindow(_T("LISTBOX"),
									  NULL,
									  style | WS_CHILD | WS_BORDER | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  hwndParent,
									  (HMENU) LIST_ID,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
			peer->defaultWindowProc = (WNDPROC) SetWindowLong(peer->hwnd, GWL_WNDPROC, (LONG) WCEWndProc);
		}
		break;

	case SCROLLBAR_PEER_TYPE:
		// Scrollbarに対応するウインドウを作成
		{
			DWORD style = peer->scrollbarOrientation == Scrollbar_HORIZONTAL ? SBS_HORZ : SBS_VERT;
			peer->hwnd = CreateWindow(_T("SCROLLBAR"),
									  NULL,
									  style | WS_CHILD | WS_VISIBLE,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  hwndParent,
									  (HMENU) SCROLLBAR_ID,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
			// サブクラス化する
			peer->defaultWindowProc = (WNDPROC) SetWindowLong(peer->hwnd, GWL_WNDPROC, (LONG) WCEWndProc);
		}
		break;

	case SCROLL_PANE_PEER_TYPE:
		// ScrollPaneに対応するネイティブウインドウを作成する
		{
			DWORD style;
			if (peer->scrollPaneScrollbarDisplayPolicy != ScrollPane_SCROLLBARS_NEVER) {
				style = WS_VSCROLL | WS_HSCROLL;
			} else {
				style = 0;
			}
			peer->hwnd = CreateWindow(g_container_class_name,
									  _T("ScrollPane"),
									  style | WS_BORDER | WS_CHILD | WS_VISIBLE,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  hwndParent,
									  (HMENU) PANEL_ID,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
		}
		break;

	case TEXT_FIELD_PEER_TYPE:
		// TEXT_FIELDに対応するウインドウを作成
		{
			peer->hwnd = CreateWindow(_T("EDIT"),
									  NULL,
									  WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  hwndParent,
									  (HMENU) TEXT_FIELD_ID,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
			peer->defaultWindowProc = (WNDPROC) SetWindowLong(peer->hwnd, GWL_WNDPROC, (LONG) WCEWndProc);
		}
		break;
	
	case TEXT_AREA_PEER_TYPE:
		// TEXT_AREAに対応するウインドウを作成
		{
			DWORD style = ES_AUTOVSCROLL;
			switch (peer->scrollbarVisibility) {
			case TextArea_SCROLLBARS_VERTICAL_ONLY:
				style |= WS_VSCROLL;
				break;
			case TextArea_SCROLLBARS_HORIZONTAL_ONLY:
				style |= (WS_HSCROLL | ES_AUTOHSCROLL);
				break;

			case TextArea_SCROLLBARS_NONE:
				// ほかにフラグは付加しない
				break;

			default:
			// case TextArea_SCROLLBARS_BOTH:
				style = (WS_HSCROLL | WS_VSCROLL | ES_AUTOHSCROLL);
				break;
			}

			peer->hwnd = CreateWindow(_T("EDIT"),
									  NULL,
									  style | WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP | ES_MULTILINE,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  hwndParent,
									  (HMENU) TEXT_AREA_ID,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
			peer->defaultWindowProc = (WNDPROC) SetWindowLong(peer->hwnd, GWL_WNDPROC, (LONG) WCEWndProc);
		}
		break;

	case WINDOW_PEER_TYPE:
		{
			peer->hwnd = CreateWindow(g_container_class_name,
									  NULL,
									  WS_POPUP,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  CW_USEDEFAULT,
									  NULL,
									  NULL,
									  g_hInstance,
									  NULL);
			SetWindowLong(peer->hwnd, GWL_USERDATA, (LONG) peer);
		}
		break;
	}
}

/**
 * 指定されたRECTで示された領域について、指定されたウインドウおよび子ウインドウ
 * の領域を「有効化」する
 */
/*
 ScrollPaneで利用することを想定していたが、ScrollWindowEx()でうまく
 イメージが転送できないため、コメントアウトしている

static void validate_rect(HWND hwndParent, LPRECT lprect) {
	// EnumChildWindow()がないので、GetWindow()をループで呼び出す
	HWND hwndChild = GetWindow(hwndParent, GW_CHILD);
	while (hwndChild && hwndChild != hwndParent) {
		RECT clientRect = *lprect;
		MapWindowPoints(NULL,
						hwndChild,
						(LPPOINT) &clientRect,
						2);
		ValidateRect(hwndChild, &clientRect);
		hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
	}
}
*/


/**
 * システムウインドウプロシージャ
 */
LRESULT CALLBACK SystemWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
	switch (msg) {
	case SYSMSG_CREATE:
		{	
			HWND hwndParent = (HWND) wp;
			native_component* peer = (native_component*) lp;
			create_window(hwndParent, peer);
		}
		break;

	case SYSMSG_SET_VISIBLE:
		// ウインドウ可視状態変更メッセージ
		// WPARAM - 表示(TRUE)/非表示(FALSE)
		// LPARAM - 変更対象となるウインドウのHWND
		{
			HWND hTargetWnd = (HWND) lp;
			BOOL visible = (BOOL) wp;
			if (visible) {
				ShowWindow(hTargetWnd, SW_SHOW);
				UpdateWindow(hTargetWnd);
			} else {
				ShowWindow(hTargetWnd, SW_HIDE);
			}
		}
		break;

	case SYSMSG_TO_BACK:
		// ウインドウを最前面に移動する
		// WPARAM - 未使用
		// LPARAM - HWND
		{
			HWND hTargetWnd = (HWND) lp;
			SetWindowPos(hTargetWnd,
						 HWND_BOTTOM,
						 0, 0, 0, 0,
						 SWP_NOSIZE | SWP_NOMOVE);
		}
		break;

	case SYSMSG_TO_FRONT:
		// ウインドウを最前面に移動する
		// WPARAM - 未使用
		// LPARAM - HWND
		{
			HWND hTargetWnd = (HWND) lp;
			SetForegroundWindow(hTargetWnd);
		}
		break;

/* !!!! Mod PeteC 2006-06-20 */
	case SYSMSG_SET_FOCUS:
		{
			HWND hTargetWnd = (HWND) lp;
			SetFocus(hTargetWnd);
		}
		break;
/* !!!! End Mod PeteC 2006-06-20 */
	
	case SYSMSG_GET_FOCUS:
		// フォーカスを保持しているウインドのハンドルを得る
		// WPARAM - HWND*
		// LPARAM - 未使用
		{
			HWND* p = (HWND*) wp;
			*p = GetFocus();
		}
		break;

	case SYSMSG_SET_BOUNDS:
		// ウインドウのサイズを変更する
		// WPARAM - bounds*
		// LPARAM - HWND
		{
			HWND hTargetWnd = (HWND) lp;
			bounds* b = (bounds *) wp;
			RECT rect;
			UINT uFlags = SWP_NOZORDER | SWP_NOOWNERZORDER;
			GetWindowRect(hTargetWnd, &rect);
			if (rect.left == b->x && rect.top == b->y) {
				// 移動しない場合
				uFlags |= SWP_NOMOVE;
			}
			if ((rect.right - rect.left) == b->width
					&& (rect.bottom - rect.top) == b->height) {
				uFlags |= SWP_NOSIZE;
			}

			SetWindowPos(hTargetWnd,
						 NULL,
						 b->x,
						 b->y,
						 b->width,
						 b->height,

						 uFlags);
		}
		break;

	case SYSMSG_SET_ENABLED:
		// ウインドウの有効／無効状態を変更する
		// WPARAM - TRUE 有効 FALSE 無効
		// LPARAM - HWND
		{
			HWND hTargetWnd = (HWND) lp;
			BOOL enabled = (BOOL) wp;
			EnableWindow(hTargetWnd, enabled);
		}
		break;

	case SYSMSG_DISPOSE:
		// ウインドウを破棄する
		// WPARAM - 未使用
		// LPARAM - HWND
		{
			HWND hTargetWnd = (HWND) lp;
			native_component* target_peer = get_native_component(hTargetWnd);
			if (target_peer != NULL) {
				if (target_peer->backgroundBrush != NULL) {
					// 背景用のブラシを削除する
					DeleteObject(target_peer->backgroundBrush);
				}
				if (target_peer->defaultWindowProc != NULL) {
					// サブクラス化していた場合は、本来のウインドウプロシージャに
					// 戻しておく
					SetWindowLong(hTargetWnd, GWL_WNDPROC, (LONG) target_peer->defaultWindowProc);
				}
				
				// native_component 構造体とウインドウとの関連付けを削除した後
				// 構造体のメモリを解放する
				SetWindowLong(hTargetWnd, GWL_USERDATA, 0);
				free(target_peer);
			}
			DestroyWindow(hTargetWnd);
		}
		break;
	
	case SYSMSG_GET_WINDOW_RECT:
		// ウインドウの画面上における座標を取得する
		// WPARAM - RECT*
		// LPARAM - HWND
		{
			HWND hTargetWnd = (HWND) lp;
			LPRECT prect = (LPRECT) wp;
			GetWindowRect(hTargetWnd, prect);
		}
		break;
	
	case SYSMSG_SET_BACKGROUND:
		// 背景色を設定する
		// WPARAM - color (jobject)
		// LPARAM - HWND
		{
			HWND hTargetWnd = (HWND) lp;
			native_component* peer = get_native_component(hTargetWnd);
			COLORREF color = (COLORREF) wp;
			peer->background = color;
			if (peer->backgroundBrush) {
				DeleteObject(peer->backgroundBrush);
				peer->backgroundBrush = NULL;
			}
			// 変更をすぐに反映する
			InvalidateRect(hTargetWnd, NULL, TRUE);
			UpdateWindow(hTargetWnd);

		}
		break;

	case SYSMSG_SET_FOREGROUND:
		// 前面色を設定する
		// WPARAM - color (jobject)
		// LPARAM - HWND
		{
			HWND hTargetWnd = (HWND) lp;
			native_component* peer = get_native_component(hTargetWnd);
			COLORREF color = (COLORREF) wp;
			peer->foreground = color;
			// 変更をすぐに反映する
			InvalidateRect(hTargetWnd, NULL, FALSE);
			UpdateWindow(hTargetWnd);
		}
		break;
	
	case SYSMSG_SHOW_POPUPMENU:
		// ポップアップメニューを表示する
		// WPARAM - native_component
		// LPARAM - 表示する座標
		{
			native_component* peer = (native_component*) wp;

			// ポップアップメニューを表示する
			TrackPopupMenu(
					   peer->hmenuPopup,
					   0,
					   LOWORD(lp),
					   HIWORD(lp),
					   0,
					   peer->hwnd,
					   NULL);
		}
		break;

	case SYSMSG_SET_SCROLL_POSITION:
		// スクロール位置を設定する
		// WPARAM - ScrollPanePeerのHWND
		// LPARAM - LOWORD(LPARAM) - x座標
		//          HIWORD(LPARAM) - y座標
		{
			RECT rect;
			int dx, dy;
			int x = LOWORD(lp);
			int y = HIWORD(lp);
			HWND hwndScrollPane = (HWND) wp;
			HWND hwndChild = GetWindow(hwndScrollPane, GW_CHILD);
			
			GetWindowRect(hwndChild, &rect);
			ScreenToClient(hwndScrollPane, (LPPOINT)&rect);
			dx = -rect.left - x;
			dy = -rect.top - y;

			// 子Windowの位置を変更する
			SetWindowPos(hwndChild,
						 NULL,
						 -x,
						 -y,
						 0,
						 0,
						 SWP_NOSIZE | SWP_NOZORDER);

			// 画面上のイメージを転送する
			// この方法がうまくいけば、g_ignore_WM_ERASEBKGNDフラグを廃止
			// できるのだが、うまくいかないため現在コメントアウトしている。
/*
			ScrollWindowEx(hwndScrollPane,
						   -dx,
						   -dy,
						   NULL,
						   NULL,
						   NULL,
						   NULL,
						   0);
			// 子Windowの領域を有効化する
			GetClientRect(hwndScrollPane, &rect);
			OffsetRect(&rect, dx, dy);
			MapWindowPoints(hwndScrollPane,
							NULL,
							(LPPOINT) &rect,
							2);
			validate_rect(hwndChild, &rect);
*/
			// バックグラウンドの再描画を抑止して、
			// 子Windowを再描画する
			g_ignore_WM_ERASEBKGND = TRUE;
			UpdateWindow(hwndChild);
			g_ignore_WM_ERASEBKGND = FALSE;
		}
		break;

	case SYSMSG_GET_BOUNDS:
		// ウインドウのサイズを変更する
		// WPARAM - bounds*
		// LPARAM - HWND
		{
			HWND hTargetWnd = (HWND) lp;
			bounds* b = (bounds *) wp;
			RECT rect;
			GetWindowRect(hTargetWnd, &rect);
			b->x = rect.left;
			b->y = rect.top;
			b->width = (rect.right - rect.left);
			b->height = (rect.bottom - rect.top);
		}
		break;

	case WM_DESTROY:
		// 終了処理
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, msg, wp, lp);
	}
	return 0;
}

/**
 * ウインドウプロシージャ
 */
LRESULT CALLBACK WCEWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
	LRESULT result;
	native_component* peer = get_native_component(hWnd);
	if (peer == NULL) {
		// peerオブジェクトの関連付けが行われていない間は
		// イベント送信処理を行わない
		return DefWindowProc(hWnd, msg, wp, lp);
	}

	switch (msg) {

	case WM_ERASEBKGND:
		{
			if (peer->defaultWindowProc) {
				CallWindowProc(peer->defaultWindowProc, hWnd, msg, wp, lp);
			} else {
				if (! g_ignore_WM_ERASEBKGND) {
					RECT rect;
					GetClientRect(hWnd, &rect);
					if (! peer->backgroundBrush) {
						peer->backgroundBrush = CreateSolidBrush(peer->background);
					}
					FillRect((HDC) wp, &rect, peer->backgroundBrush);
				}
			}
			result = TRUE;
		}
		break;

	case WM_PAINT:
		{
			int id;
			RECT updateRect;
			// 描画が必要な領域を取得するために、GetUpdateRect()を呼び出す
			GetUpdateRect(hWnd, &updateRect, FALSE);
			if (peer->defaultWindowProc != NULL) {
				// サブクラス化していた場合は、本来のウインドウプロシージャを呼び出す
				result = CallWindowProc(peer->defaultWindowProc, hWnd, msg, wp, lp);
				// PaintEvent.UPDATE を送ると、Component.update()の背景塗りつぶし処理で
				// 上書きされてしまうため、常に PaintEvent.PAINT を送る
				id = PaintEvent_PAINT;

			} else {
				PAINTSTRUCT ps;
				HDC hdc = BeginPaint(hWnd, &ps);
				if (ps.fErase) {
					// PaintEvent.UPDATE を送る
					id = PaintEvent_UPDATE;
				} else {
					// 消去が必要ない場合は、PaintEvent.PAINT を送る
					id = PaintEvent_PAINT;
				}
				EndPaint(hWnd, &ps);
			}
			// PaintEvent送信処理を行う
			(*g_WCEToolkit_run_env)->CallVoidMethod(g_WCEToolkit_run_env,
													peer->peer_object,
													g_WCEComponentPeer_postPaintEvent_id,
													id,									// id
													updateRect.left,					// x
													updateRect.top,						// y
													updateRect.right - updateRect.left,	// width
													updateRect.bottom - updateRect.top	// height
												);
		}
		break;
	
	case WM_CTLCOLORSTATIC:
	case WM_CTLCOLORBTN:
	case WM_CTLCOLOREDIT:
	case WM_CTLCOLORSCROLLBAR:
		// コントロールの色を設定する
		{
			HDC hdc = (HDC) wp;
			native_component* target_peer = get_native_component((HWND) lp);
			if (target_peer != NULL) {
				SetTextColor(hdc, target_peer->foreground);
				SetBkColor(hdc, target_peer->background);
				if (target_peer->backgroundBrush == NULL) {
					// 背景塗りつぶし用のブラシを作成する
					target_peer->backgroundBrush = CreateSolidBrush(target_peer->background);
				}
				result = (LRESULT) target_peer->backgroundBrush;
			} else {
				result = 0;
			}
		}
		break;
	
	case WM_SETCURSOR:
		// カーソル設定メッセージ
		{
			native_component* nc = get_native_component((HWND) wp);
			if (nc != NULL && HIWORD(lp) != 0) {
				HCURSOR hCursor = nc->hCursor;
				SetCursor(hCursor);
				result = (hCursor != NULL);
			} else {
				result = FALSE;
			}
		}
		break;

	case WM_CLOSE:
		// ここでは処理を行わない
		result = 1;
		break;

	case WM_ACTIVATE:
		if (((peer->type == FRAME_PEER_TYPE) && (g_floating_flags & WCEToolkit_FRAME_IS_FLOATING) == 0)
				|| (peer->type == DIALOG_PEER_TYPE && (g_floating_flags & WCEToolkit_DIALOG_IS_FLOATING) == 0)) {
			SHHandleWMActivate(hWnd, wp, lp, &peer->sai, FALSE);
			result = 0;
		}
		break;

	case WM_SETTINGCHANGE:
		if (((peer->type == FRAME_PEER_TYPE) && (g_floating_flags & WCEToolkit_FRAME_IS_FLOATING) == 0)
				|| (peer->type == DIALOG_PEER_TYPE && (g_floating_flags & WCEToolkit_DIALOG_IS_FLOATING) == 0)) {
			SHHandleWMSettingChange(hWnd, wp, lp, &peer->sai);
			result = 0;
		}
     	break;

	default:
		{
			if (peer->defaultWindowProc != NULL) {
				// サブクラス化していた場合は、本来のウインドウプロシージャを呼び出す
				result = CallWindowProc(peer->defaultWindowProc, hWnd, msg, wp, lp);
			} else {
				// サブクラス化していない場合は、デフォルトの処理を行う
				result = DefWindowProc(hWnd, msg, wp, lp);
			}
		}
	}
	// WCEToolkit.handleNativeMessage()を呼ぶ
	(*g_WCEToolkit_run_env)->CallVoidMethod(g_WCEToolkit_run_env,
											g_WCEToolkit_instance,
											g_WCEToolkit_handleNativeMessage_id,
											hWnd,
											msg,
											wp,
											lp);
	return result;
}

/**
 * Scrollbarのスクロールイベント処理
 * WM_VSCROLL/WM_HSCROLL受信時点で呼び出される
 */
static void scrollbar_handle_scroll(JNIEnv* env, native_component* scrollbar_peer, int msg, HWND hwndScrollbar, WORD request) {
	BOOL adjusting = FALSE;
	int adjustingPos;
	int type;
	SCROLLINFO si = {0};

	// スクロールバーの状態を取得する
	si.cbSize = sizeof(SCROLLINFO);
	si.fMask = SIF_ALL;
	GetScrollInfo(hwndScrollbar, SB_CTL, &si);

	switch (request) {
	// リクエスト別の処理を行う
	case SB_LINEUP:
		si.nPos -= scrollbar_peer->scrollbarLineIncrement;
		type = AdjustmentEvent_UNIT_DECREMENT;
		break;

	case SB_LINEDOWN:
		si.nPos += scrollbar_peer->scrollbarLineIncrement;
		type = AdjustmentEvent_UNIT_INCREMENT;
		break;

	case SB_PAGEUP:
		si.nPos -= scrollbar_peer->scrollbarPageIncrement;
		type = AdjustmentEvent_BLOCK_DECREMENT;
		break;

	case SB_PAGEDOWN:
		si.nPos += scrollbar_peer->scrollbarPageIncrement;
		type = AdjustmentEvent_BLOCK_INCREMENT;
		break;

	case SB_THUMBPOSITION:
		// 値を補正する
		si.nPos = si.nTrackPos + si.nMin;
		type = AdjustmentEvent_TRACK;
		break;

	case SB_THUMBTRACK:
		// 移動中の座標を取得する
		adjusting = TRUE;
		adjustingPos = si.nTrackPos;
		break;
	}

	// ポジションを再調整する
	if (! adjusting) {
		if (si.nPos > (int) (si.nMax - max(si.nPage - 1, 0))) {
			si.nPos = (int) (si.nMax - max(si.nPage - 1, 0));
		} else if (si.nPos < si.nMin) {
			si.nPos = si.nMin;
		}
		// スクロールバーの位置を設定する
		si.fMask = SIF_POS;
		SetScrollInfo(hwndScrollbar,
					  SB_CTL,
					  &si,
					  TRUE);

	}
	// WCEScrollbarPeer.postAdjustmentEvent()を呼び出す
	(*env)->CallVoidMethod(env,
						   scrollbar_peer->peer_object,
						   g_WCEScrollbarPeer_postAdjustmentEvent_id,
						   AdjustmentEvent_ADJUSTMENT_VALUE_CHANGED,	// id
						   type,										// type
						   (adjusting ? adjustingPos : si.nPos),		// value
						   adjusting);									// isAdjusting

}

/**
 * ScrollPaneのスクロールイベント処理
 * WM_VSCROLL/WM_HSCROLL受信時点で呼び出される
 */
static void scroll_pane_handle_scroll(JNIEnv* env, native_component* scrollpane_peer, int msg, HWND hwndScrollPane, WORD request) {
	BOOL adjusting = FALSE;
	int type;
	int orgpos;
	// int diffpos;
	SCROLLINFO si = {0};

	// スクロールバーの状態を取得する
	si.cbSize = sizeof(SCROLLINFO);
	si.fMask = SIF_ALL;
	GetScrollInfo(hwndScrollPane,
				 (msg == WM_VSCROLL ? SB_VERT : SB_HORZ),
				 &si);

	orgpos = si.nPos;
	switch (request) {
	// リクエスト別の処理を行う
	case SB_LINEUP:
		type = AdjustmentEvent_UNIT_DECREMENT;
		break;

	case SB_LINEDOWN:
		type = AdjustmentEvent_UNIT_INCREMENT;
		break;

	case SB_PAGEUP:
		type = AdjustmentEvent_BLOCK_DECREMENT;
		break;

	case SB_PAGEDOWN:
		type = AdjustmentEvent_BLOCK_INCREMENT;
		break;

	case SB_THUMBPOSITION:
		// 値を補正する
		orgpos = si.nTrackPos + si.nMin;
		type = AdjustmentEvent_TRACK;
		break;

	case SB_THUMBTRACK:
		// 移動中の座標を取得する
		type = AdjustmentEvent_TRACK;
		adjusting = TRUE;
		orgpos = si.nTrackPos;
		break;

	default:
		return;
	}

	// ポジションを調整する
	si.nPos = (*env)->CallIntMethod(env,
									 scrollpane_peer->peer_object,
									 g_WCEScrollPanePeer_updatePosition_id,
									 (msg == WM_VSCROLL ? Scrollbar_VERTICAL : Scrollbar_HORIZONTAL),
									 type,
									 orgpos,
									 adjusting);
	if (! adjusting) {
		// スクロールバーの位置を設定する
		si.fMask = SIF_POS;
		SetScrollInfo(hwndScrollPane,
					  (msg == WM_VSCROLL ? SB_VERT : SB_HORZ),
					  &si,
					  TRUE);

	}
	// スクロールさせる
/*
	diffpos = orgpos - si.nPos;
	if (diffpos) {
		HWND hwndChild = GetWindow(hwndScrollPane, GW_CHILD);
		if (hwndChild) {
			// ウインドウをスクロールさせる
			ScrollWindowEx(hwndChild,
						  (msg == WM_HSCROLL ? diffpos : 0),
						  (msg == WM_VSCROLL ? diffpos : 0),
						   NULL,
						   NULL,
						   NULL,
						   NULL,
						   SW_SCROLLCHILDREN);
		}
	}
*/
	{
		RECT rect;
		int x, y;
		HWND hwndChild = GetWindow(hwndScrollPane, GW_CHILD);
		GetWindowRect(hwndChild, &rect);
		ScreenToClient(hwndScrollPane, (LPPOINT)&rect);
		x = (msg == WM_HSCROLL) ? si.nPos : -rect.left;
		y = (msg == WM_VSCROLL) ? si.nPos : -rect.top;

		SendMessage(g_hSystemWnd,
					SYSMSG_SET_SCROLL_POSITION,
					(WPARAM) hwndScrollPane,
					(LPARAM) ((y << 16) | (x & 0xFFFF)));
	}
}

/**
 * イベント処理
 */
void handle_native_message(JNIEnv* env, HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
	native_component* peer = get_native_component(hWnd);
	switch (msg) {
	case WM_MOVE:
	case WM_SIZE:
		// ウインドウのサイズ変更が発生した
		{
			RECT rect;
			jobject peer_obj;
		
			// イベントを送信する
			GetWindowRect(hWnd, &rect);
			peer_obj = peer->peer_object;
			post_WCEWindowBoundsEvent(env, peer_obj, &rect);
		}
		break;

	case WM_MOUSEMOVE:
		{
			jint id = (GetCapture() ? MouseEvent_MOUSE_DRAGGED : MouseEvent_MOUSE_MOVED);
			// マウスイベントを発生させる
			(*env)->CallVoidMethod(env,
								   peer->peer_object,
								   g_WCEComponentPeer_postMouseEvent_id,
									id,							// id
									0,							// modifiers
									LOWORD(lp),					// x
									HIWORD(lp),					// y
									0,							// clickcount
									FALSE,						// popupTrigger
									MouseEvent_NOBUTTON);		// button

			// MOUSE_EXITED, MOUSE_ENTEREDを発生させる必要があるかを調べる
			if (g_hwndLastMouseMoved != hWnd) {
				native_component* last_peer = get_native_component(g_hwndLastMouseMoved);
				if (last_peer) {
					// MouseEvent.MOUSE_EXITEDを持つMouseEventをpostする
					POINT point;
					point.x = LOWORD(lp);
					point.y = HIWORD(lp);
					ClientToScreen(hWnd, &point);
					ScreenToClient(g_hwndLastMouseMoved, &point);
					(*env)->CallVoidMethod(
									env,
								    last_peer->peer_object,
								    g_WCEComponentPeer_postMouseEvent_id,
									MouseEvent_MOUSE_EXITED,	// id
									0,							// modifiers
									point.x,					// x
									point.y,					// y
									0,							// clickcount
									FALSE,						// popupTrigger
									MouseEvent_NOBUTTON);		// button
				}
				// MouseEvent.MOUSE_ENTEREDを持つMouseEventをpostする
				(*env)->CallVoidMethod(
								env,
								peer->peer_object,
								g_WCEComponentPeer_postMouseEvent_id,
								MouseEvent_MOUSE_ENTERED,	// id
								0,							// modifiers
								LOWORD(lp),					// x
								HIWORD(lp),					// y
								0,							// clickcount
								FALSE,						// popupTrigger
								MouseEvent_NOBUTTON);		// button
				
				g_hwndLastMouseMoved = hWnd;
			}
		}
		break;

	case WM_LBUTTONDOWN:
		// マウス左ボタン（スタイラスによるタップ）
		// マウスイベントを発生させる
		{
			SHRGINFO rg = {0};
			jint modifiers = get_InputEvent_modifiers();
			modifiers |= (InputEvent_BUTTON1_DOWN_MASK
							| InputEvent_BUTTON1_MASK);

			// 最初に、MouseEvent.MouseMovedを送信する
			// （プログラムによっては、マウスの動きが「連続している」ことを期待しているものがあるため、
			//  　「マウスが動いて、そこでクリックされた」という動きをシミュレートする必要がある）
			(*env)->CallVoidMethod(env,
								   peer->peer_object,
								   g_WCEComponentPeer_postMouseEvent_id,
									MouseEvent_MOUSE_MOVED,		// id
									0,							// modifiers
									LOWORD(lp),					// x
									HIWORD(lp),					// y
									0,							// clickcount
									FALSE,						// popupTrigger
									MouseEvent_NOBUTTON);		// button

			// MOUSE_EXITED, MOUSE_ENTEREDを発生させる必要があるかを調べる
			if (g_hwndLastMouseMoved != hWnd) {
				native_component* last_peer = get_native_component(g_hwndLastMouseMoved);
				if (last_peer) {
					// MouseEvent.MOUSE_EXITEDを持つMouseEventをpostする
					POINT point;
					point.x = LOWORD(lp);
					point.y = HIWORD(lp);
					ClientToScreen(hWnd, &point);
					ScreenToClient(g_hwndLastMouseMoved, &point);
					(*env)->CallVoidMethod(
									env,
								    last_peer->peer_object,
								    g_WCEComponentPeer_postMouseEvent_id,
									MouseEvent_MOUSE_EXITED,	// id
									0,							// modifiers
									point.x,					// x
									point.y,					// y
									0,							// clickcount
									FALSE,						// popupTrigger
									MouseEvent_NOBUTTON);		// button
				}
				// MouseEvent.MOUSE_ENTEREDを持つMouseEventをpostする
				(*env)->CallVoidMethod(
								env,
								peer->peer_object,
								g_WCEComponentPeer_postMouseEvent_id,
								MouseEvent_MOUSE_ENTERED,	// id
								0,							// modifiers
								LOWORD(lp),					// x
								HIWORD(lp),					// y
								0,							// clickcount
								FALSE,						// popupTrigger
								MouseEvent_NOBUTTON);		// button
				
				g_hwndLastMouseMoved = hWnd;
			}

			// MouseEvent.MOUSE_PRESSEDを送信する
			(*env)->CallVoidMethod(
							env,
							peer->peer_object,
							g_WCEComponentPeer_postMouseEvent_id,
							MouseEvent_MOUSE_PRESSED,	// id
							modifiers,					// modifiers
							LOWORD(lp),					// x
							HIWORD(lp),					// y
							1,							// clickcount
							JNI_FALSE,					// popupTrigger
							MouseEvent_BUTTON1);		// button

			// タップ＆ホールドを判定する
			rg.cbSize = sizeof(SHRGINFO);
			rg.hwndClient = peer->hwnd;
			rg.ptDown.x = LOWORD(lp);
			rg.ptDown.y = HIWORD(lp);
			rg.dwFlags  = SHRG_RETURNCMD;
			if (SHRecognizeGesture(&rg) == GN_CONTEXTMENU) {
				// Windows上の動作にあわせるため、BUTTON2 がダウン・アップされたという
				// イベントを送る
				(*env)->CallVoidMethod(
								env,
								peer->peer_object,
								g_WCEComponentPeer_postMouseEvent_id,
								MouseEvent_MOUSE_PRESSED,	// id
								(InputEvent_BUTTON2_DOWN_MASK
									| InputEvent_BUTTON2_MASK),	// modifiers
								LOWORD(lp),					// x
								HIWORD(lp),					// y
								1,							// clickcount
								JNI_FALSE,					// popupTrigger
								MouseEvent_BUTTON2);		// button
				(*env)->CallVoidMethod(
								env,
								peer->peer_object,
								g_WCEComponentPeer_postMouseEvent_id,
								MouseEvent_MOUSE_RELEASED,	// id
								(InputEvent_BUTTON2_DOWN_MASK
									| InputEvent_BUTTON2_MASK),	// modifiers
								LOWORD(lp),					// x
								HIWORD(lp),					// y
								1,							// clickcount
								JNI_TRUE,					// popupTrigger
								MouseEvent_BUTTON2);		// button

			}

			// マウスキャプチャがされていない場合、キャプチャを開始する
			if (! GetCapture()) {
				SetCapture(hWnd);
			}
		}
		break;

	case WM_LBUTTONUP:
		{
			jint modifiers = get_InputEvent_modifiers();
			modifiers |= (InputEvent_BUTTON1_DOWN_MASK
							| InputEvent_BUTTON1_MASK);
			// マウス左ボタン（スタイラスによるタップ）
			// マウスイベントを発生させる
			(*env)->CallVoidMethod(
							env,
							peer->peer_object,
							g_WCEComponentPeer_postMouseEvent_id,
							MouseEvent_MOUSE_RELEASED,	// id
							modifiers,					// modifiers
							LOWORD(lp),					// x
							HIWORD(lp),					// y
							1,							// clickcount
							FALSE,						// popupTrigger
							MouseEvent_BUTTON1);		// button
			// 無条件にCLICKEDを発生させる（改良が必要）
			(*env)->CallVoidMethod(
							env,
							peer->peer_object,
							g_WCEComponentPeer_postMouseEvent_id,
							MouseEvent_MOUSE_CLICKED,	// id
							modifiers,					// modifiers
							LOWORD(lp),					// x
							HIWORD(lp),					// y
							1,							// clickcount
							FALSE,						// popupTrigger
							MouseEvent_BUTTON1);		// button
			
			// マウスキャプチャを終了する
			if (GetCapture() == hWnd) {
				ReleaseCapture();
			}
		}
		break;
	
	case WM_NOTIFY:
		{
			WORD notify_code = HIWORD(wp);
			WORD id = LOWORD(wp);
			HWND hwndControl = (HWND) lp;
		}
		break;
	
	case WM_VSCROLL:
	case WM_HSCROLL:
		// スクロールメッセージ
		{	
			// ScrollbarまたはScrollPaneの場合にのみ処理を行う
			native_component* nc = get_native_component(hWnd);
			if (nc != NULL) {
				if (nc->type == SCROLL_PANE_PEER_TYPE) {
					scroll_pane_handle_scroll(env, nc, msg, hWnd, LOWORD(wp));
				} else {
					nc = get_native_component((HWND) lp);
					if (nc != NULL && nc->type == SCROLLBAR_PEER_TYPE) {
						scrollbar_handle_scroll(env, nc, msg, (HWND) lp, LOWORD(wp));
					}
				}
			}
		}
		break;

	case WM_COMMAND:
		{
			WORD notify_code = HIWORD(wp);
			WORD id = LOWORD(wp);
			if (notify_code == 0 && (id >= MENU_ITEM_ID_FIRST && id <= MENU_ITEM_ID_LAST)) {
				// メニューが選択された
				HMENU hMenu = g_menu_items[id - MENU_ITEM_ID_FIRST];
				if (hMenu) {
					MENUITEMINFO mii = {0};
					mii.cbSize = sizeof(MENUITEMINFO);
					mii.fMask = MIIM_DATA | MIIM_STATE;
					if (GetMenuItemInfo(hMenu, id, FALSE, &mii)) {
						jobject peer_obj = (jobject) mii.dwItemData;
						if (peer_obj != NULL) {
							if ((*env)->IsInstanceOf(env, peer_obj, g_WCECheckboxMenuItemPeer_class)) {
								// WCECheckboxMenuItemPeerの場合はチェック状態を変更する
								BOOL checked = FALSE;
								UINT stat = MF_BYCOMMAND;
								if ((mii.fState & MFS_CHECKED) == 0) {
									stat |= MF_CHECKED;
									checked = TRUE;
								}
								CheckMenuItem(hMenu, id, stat);
								// ItemEventをpostする
								(*env)->CallVoidMethod(env,
													   peer_obj,
													   g_WCECheckboxMenuItemPeer_postItemEvent_id,
													   ItemEvent_ITEM_STATE_CHANGED,	// id
													   (checked ? ItemEvent_SELECTED : ItemEvent_DESELECTED));
							}
							// ActionEventをpostする
							(*env)->CallVoidMethod(env,
												   peer_obj,						// this
												   g_WCEMenuItemPeer_postActionEvent_id,
												   ActionEvent_ACTION_PERFORMED,	// id
												   get_current_time(),				// when
												   0);								// modifires
						}
					}
				}
			} else if (notify_code == BN_CLICKED && id == BUTTON_ID) {
				// ボタンがクリックされた
				HWND hwndControl;
				native_component* control_peer;
				hwndControl = (HWND) lp;
				control_peer = get_native_component(hwndControl);
				if (control_peer->type == BUTTON_PEER_TYPE) {
					HWND hwndButton = control_peer->hwnd;
					// ActionEventをpostする
					(*env)->CallVoidMethod(env,
										   control_peer->peer_object,
										   g_WCEButtonPeer_postActionEvent_id,
										   ActionEvent_ACTION_PERFORMED,	// id
										   get_current_time(),				// when
										   0);								// modifiers
				}
			} else if (id == CHECKBOX_ID) {
				// チェックボックス／ラジオボタンの処理
				BOOL checked;
				HWND hwndControl = (HWND) lp;
				native_component* control_peer = get_native_component(hwndControl);
				checked = SendMessage(control_peer->hwnd, BM_GETCHECK, 0, 0);
				if (control_peer->checkboxGroup == NULL
					|| (control_peer->checkboxGroup != NULL && ! checked)) {
					// チェックボックス または チェックされていないラジオボタン
					// 状態を反転させてpeer.setState()を呼び出す
					jboolean state = checked ? JNI_FALSE : JNI_TRUE;
					(*env)->CallVoidMethod(env,
										   control_peer->peer_object,
										   g_WCECheckboxPeer_setState_id,
										   state);
					// postItemEvent()を呼び出す（ItemEventがpostされる）
					(*env)->CallVoidMethod(env,
										   control_peer->peer_object,
										   g_WCECheckboxPeer_postItemEvent_id,
										   state);
				}
			} else if ((id == TEXT_AREA_ID || id == TEXT_FIELD_ID) && notify_code == EN_UPDATE) {
				// テキストの内容が変更された
				// TextEventをpostする
				HWND hwndControl = (HWND) lp;
				native_component* control_peer = get_native_component(hwndControl);
				(*env)->CallVoidMethod(env,
									   control_peer->peer_object,
									   g_WCETextComponentPeer_postTextEvent_id,
									   TextEvent_TEXT_VALUE_CHANGED);	// id
			} else if (id == CHOICE_ID) {
				// java.awt.Choice
				if (notify_code == CBN_SELCHANGE) {
					// ItemEventをpostする
					HWND hwndCombo = (HWND) lp;
					native_component* control_peer = get_native_component(hwndCombo);
					int index = (int) SendMessage(hwndCombo,
												  CB_GETCURSEL,
												  0,
												  0);
					(*env)->CallVoidMethod(env,
										   control_peer->peer_object,
										   g_WCEChoicePeer_postItemEvent_id,
										   ItemEvent_ITEM_STATE_CHANGED,
										   index,
										   ItemEvent_SELECTED);

				}
			} else if (id == LIST_ID) {
				HWND hwndControl = (HWND) lp;
				native_component* control_peer = get_native_component(hwndControl);
				switch (notify_code) {
				case LBN_DBLCLK:
					// ダブルクリックされた
					{
						// ActionEventをpostする
						int index = SendMessage(hwndControl, LB_GETCURSEL, 0, 0);
						(*env)->CallVoidMethod(env,
											   control_peer->peer_object,
											   g_WCEListPeer_postActionEvent_id,
											   ActionEvent_ACTION_PERFORMED,		// id
											   index,								// index
											   get_current_time(),					// when,
											   0);									// modifiers
					}
				break;
				
				case LBN_SELCHANGE:
					// 選択位置が変更された
					{
						// カレントインデックスを取得する
						int state_change;
						int index = SendMessage(hwndControl, LB_GETCURSEL, 0, 0);
						int selected = SendMessage(hwndControl, LB_GETSEL, (WPARAM) index, 0);
						if (control_peer->multi && ! selected) {
							state_change = ItemEvent_DESELECTED;
						} else {
							state_change = ItemEvent_SELECTED;
						}
						// ItemEventをpostする
						(*env)->CallVoidMethod(env,
											   control_peer->peer_object,
											   g_WCEListPeer_postItemEvent_id,
											   ItemEvent_ITEM_STATE_CHANGED,
											   index,
											   state_change);
					}
				break;
				}

			}
		}
		break;
	
	case WM_SETFOCUS:
		{
			native_component* nc = get_native_component((HWND) wp);
			jobject opposite_peer = (nc != NULL) ? nc->peer_object : NULL;
			if ((peer->type & WINDOW_PEER_FLAG) != 0) {
				// Windowの場合は、WindowEventを発生させる
				(*env)->CallVoidMethod(env,
									   peer->peer_object,
									   g_WCEWindowPeer_postWindowEvent_id,
									   WindowEvent_WINDOW_GAINED_FOCUS,
									   opposite_peer);
			} else {
				// FocusEventを発生させる
				(*env)->CallVoidMethod(env,
									   peer->peer_object,
									   g_WCEComponentPeer_postFocusEvent_id,
									   FocusEvent_FOCUS_GAINED,
									   JNI_FALSE,
									   opposite_peer);
			}
		}
		break;

	case WM_KILLFOCUS:
		{
			native_component* nc = get_native_component((HWND) wp);
			jobject opposite_peer = (nc != NULL) ? nc->peer_object : NULL;
			if ((peer->type & WINDOW_PEER_FLAG) != 0) {
				// Windowの場合は、WindowEventを発生させる
				(*env)->CallVoidMethod(env,
									   peer->peer_object,
									   g_WCEWindowPeer_postWindowEvent_id,
									   WindowEvent_WINDOW_LOST_FOCUS,
									   opposite_peer);
			} else {
				// FocusEventを発生させる
				(*env)->CallVoidMethod(env,
									   peer->peer_object,
									   g_WCEComponentPeer_postFocusEvent_id,
									   FocusEvent_FOCUS_LOST,
									   JNI_FALSE,
									   opposite_peer);
			}
		}
		break;

	case WM_KEYDOWN:
	case WM_KEYUP:
		{
			int java_keycode = to_java_keycode(wp);
			int java_keylocation = to_java_keylocation(wp);
			int java_modifiers = get_InputEvent_modifiers();

			(*env)->CallVoidMethod(env,
								   peer->peer_object,
								   g_WCEComponentPeer_postKeyEvent_id,
								   (msg == WM_KEYDOWN) ? KeyEvent_KEY_PRESSED : KeyEvent_KEY_RELEASED,					// id
								   get_current_time(),					// when
								   java_modifiers,						// modifiers
								   java_keycode,						// keyCode
								   KeyEvent_CHAR_UNDEFINED,				// keyChar
								   java_keylocation);					// keyLocation

		}
		break;
	
	case WM_CHAR:
		{
			int java_modifiers = get_InputEvent_modifiers();
			(*env)->CallVoidMethod(env,
								   peer->peer_object,
								   g_WCEComponentPeer_postKeyEvent_id,
								   KeyEvent_KEY_TYPED,					// id
								   get_current_time(),					// when
								   java_modifiers,						// modifiers
								   KeyEvent_VK_UNDEFINED,				// keyCode
								   (jchar) wp,							// keyChar
								   KeyEvent_KEY_LOCATION_UNKNOWN);		// keyLocation
		}
		break;

	case WM_CLOSE:
		if ((peer->type & WINDOW_PEER_FLAG) != 0) {
			// Window派生クラスに対しては、WindowEvent(WINDOW_CLOSING)を送る
			(*env)->CallVoidMethod(env,
								   peer->peer_object,
								   g_WCEWindowPeer_postWindowEvent_id,
								   WindowEvent_WINDOW_CLOSING,
								   NULL);
		}
		break;

	}
}

/**
 * 指定されたpeerがWindowPeerであった場合、WCEWindowPeer.postWCEWindowBoundsEvent()
 * を呼び出す
 */
static void post_WCEWindowBoundsEvent(JNIEnv* env, jobject peer_obj, LPRECT prect) {
	if ((*env)->IsInstanceOf(env, peer_obj, g_WCEWindowPeer_class)) {
		// postWCEWindowBoundsEvent()を呼び出す
		(*env)->CallVoidMethod(env,
							   peer_obj,
							   g_WCEWindowPeer_postWCEWindowBoundsEvent_id,
							   prect->left,
							   prect->top,
							   prect->right - prect->left,
							   prect->bottom - prect->top);
	}
}

/**
 * Buttonに対応するネイティブコンポーネントを作成する
 */
HWND create_native_button(jobject peer, HWND hwndParent, int x, int y, int width, int height) {
	bounds b;
	native_component* cp = allocate_native_component(BUTTON_PEER_TYPE, peer);
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	b.x = x;
	b.y = y;
	b.width = width;
	b.height = height;
	SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) cp->hwnd);
	return cp->hwnd;
}

/**
 * Canvasに対応するネイティブコンポーネントを作成する
 */
HWND create_native_canvas(jobject peer, HWND hwndParent, int x, int y, int width, int height) {
	bounds b;
	native_component* cp = allocate_native_component(CANVAS_PEER_TYPE, peer);
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	b.x = x;
	b.y = y;
	b.width = width;
	b.height = height;
	SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) cp->hwnd);
	return cp->hwnd;
}

/**
 * Checkboxに対応するネイティブコンポーネントを作成する
 */
HWND create_native_checkbox(jobject peer, HWND hwndParent, int x, int y, int width, int height, jobject checkboxGroup) {
	bounds b;
	native_component* cp = allocate_native_component(CHECKBOX_PEER_TYPE, peer);
	cp->checkboxGroup = checkboxGroup;
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	b.x = x;
	b.y = y;
	b.width = width;
	b.height = height;
	SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) cp->hwnd);
	return cp->hwnd;
}

/**
 * Choiceに対応するネイティブコンポーネントを作成する
 */
HWND create_native_choice(jobject peer, HWND hwndParent, int x, int y, int width, int height) {
	bounds b;
	native_component* cp = allocate_native_component(CHOICE_PEER_TYPE, peer);
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	b.x = x;
	b.y = y;
	b.width = width;
	b.height = height;
	SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) cp->hwnd);
	return cp->hwnd;
}

/**
 * Dialogに対応するネイティブコンポーネントを作成する
 */
HWND create_native_dialog(jobject peer, HWND hwndParent, jint x, jint y, jint width, jint height, jboolean undecorated) {
	bounds b;

	native_component* cp = allocate_native_component(DIALOG_PEER_TYPE, peer);
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	// ウインドウスタイルを初期化する
	undecorated = undecorated
				|| ((g_floating_flags & WCEToolkit_DIALOG_IS_FLOATING) == 0);
	init_dialog_style(cp->hwnd, undecorated);

	if (g_floating_flags & WCEToolkit_DIALOG_IS_FLOATING) {
		b.x = x;
		b.y = y;
		b.width = width;
		b.height = height;
		SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) cp->hwnd);
	}

	return cp->hwnd;
}

/**
 * FileDialogに対応するネイティブコンポーネントを作成する
 */
HWND create_native_file_dialog(jobject peer, HWND hwndParent, int x, int y, int width, int height) {
	native_component* cp = allocate_native_component(FILE_DIALOG_PEER_TYPE, peer);
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	return cp->hwnd;
}

/**
 * Frameに対応するネイティブコンポーネントを作成する
 */
HWND create_native_frame(jobject peer, HWND hwndParent, jint x, jint y, jint width, jint height, jboolean undecorated) {
	bounds b;

	native_component* cp = allocate_native_component(FRAME_PEER_TYPE, peer);
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	
	// ウインドウスタイルを初期化する
	undecorated = undecorated
				|| ((g_floating_flags & WCEToolkit_FRAME_IS_FLOATING) == 0);
	init_frame_style(cp->hwnd, undecorated);

	if (g_floating_flags & WCEToolkit_FRAME_IS_FLOATING) {
		b.x = x;
		b.y = y;
		b.width = width;
		b.height = height;
		SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) cp->hwnd);
	}
	
	return cp->hwnd;
}

/**
 * Labelに対応するネイティブコンポーネントを作成する
 */
HWND create_native_label(jobject peer, HWND hwndParent, int x, int y, int width, int height) {
	bounds b;
	native_component* cp = allocate_native_component(LABEL_PEER_TYPE, peer);
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	b.x = x;
	b.y = y;
	b.width = width;
	b.height = height;
	SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) cp->hwnd);

	return cp->hwnd;
}

/**
 * Listに対応するネイティブコンポーネントを作成する
 */
HWND create_native_list(jobject peer, HWND hwndParent, int x, int y, int width, int height, BOOL multi) {
	bounds b;
	native_component* cp = allocate_native_component(LIST_PEER_TYPE, peer);
	cp->multi = multi;
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	b.x = x;
	b.y = y;
	b.width = width;
	b.height = height;
	SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) cp->hwnd);
	return cp->hwnd;
}

/**
 * Panelに対応するネイティブコンポーネントを作成する
 */
HWND create_native_panel(jobject peer, HWND hwndParent, int x, int y, int width, int height) {
	bounds b;
	native_component* cp = allocate_native_component(PANEL_PEER_TYPE, peer);
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	b.x = x;
	b.y = y;
	b.width = width;
	b.height = height;
	SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) cp->hwnd);
	return cp->hwnd;
}

/**
 * Scrollbarに対応するネイティブコンポーネントを作成する
 */
HWND create_native_scrollbar(jobject peer, HWND hwndParent, int x, int y, int width, int height, int orientation) {
	native_component* cp = allocate_native_component(SCROLLBAR_PEER_TYPE, peer);
	// 垂直／水平種別を設定する
	cp->scrollbarOrientation = orientation;
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	return cp->hwnd;
}

/**
 * ScrollPaneに対応するネイティブコンポーネントを作成する
 */
HWND create_native_scroll_pane(jobject peer, HWND hwndParent, int x, int y, int width, int height, int policy) {
	native_component* nc = allocate_native_component(SCROLL_PANE_PEER_TYPE, peer);
	nc->scrollPaneScrollbarDisplayPolicy = policy;
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) nc);
	return nc->hwnd;
}

/**
 * TextFieldに対応するネイティブコンポーネントを作成する
 */
HWND create_native_text_field(jobject peer, HWND hwndParent, int x, int y, int width, int height) {
	bounds b;
	native_component* cp = allocate_native_component(TEXT_FIELD_PEER_TYPE, peer);
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	b.x = x;
	b.y = y;
	b.width = width;
	b.height = height;
	SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) cp->hwnd);
	return cp->hwnd;
}

/**
 * TextAreaに対応するネイティブコンポーネントを作成する
 */
HWND create_native_text_area(jobject peer, HWND hwndParent, int x, int y, int width, int height, int scrollbarVisibility) {
	bounds b;
	native_component* cp = allocate_native_component(TEXT_AREA_PEER_TYPE, peer);
	cp->scrollbarVisibility = scrollbarVisibility;
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, (WPARAM) hwndParent, (LPARAM) cp);
	b.x = x;
	b.y = y;
	b.width = width;
	b.height = height;
	SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) cp->hwnd);

	return cp->hwnd;
}

/**
 * Windowに対応するネイティブコンポーネントを作成する
 */
HWND create_native_window(jobject peer, HWND hwndParent, int x, int y, int width, int height) {
	bounds b;
	native_component* cp = allocate_native_component(WINDOW_PEER_TYPE, peer);
	SendMessage(g_hSystemWnd, SYSMSG_CREATE, 0, (LPARAM) cp);
	b.x = x;
	b.y = y;
	b.width = width;
	b.height = height;
	SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) cp->hwnd);
	return cp->hwnd;
}

/**
 * native_component構造体を作成する
 */
static native_component* allocate_native_component(int type, jobject peer) {
	native_component* cp = (native_component*) calloc(sizeof(native_component), 1);
	cp->type = type;
	cp->peer_object = peer;
	cp->sai.cbSize = sizeof(cp->sai);
	return cp;
}

/**
 * native_component構造体を削除する
 */
static void free_native_component(native_component* cp) {
	free(cp);
}

/**
 * 指定されたコンポーネントの表示状態を変更する
 */
void set_visible(JNIEnv* env, HWND hwnd, BOOL visible) {
	SendMessage(g_hSystemWnd, SYSMSG_SET_VISIBLE, (WPARAM) visible, (LPARAM) hwnd);
}

/**
 * 指定されたウインドウを最背面に移動する
 */
void to_back(JNIEnv* env, HWND hwnd) {
	SendMessage(g_hSystemWnd, SYSMSG_TO_BACK, 0, (LPARAM) hwnd);
}

/**
 * 指定されたウインドウを最前面に移動する
 */
void to_front(JNIEnv* env, HWND hwnd) {
	SendMessage(g_hSystemWnd, SYSMSG_TO_FRONT, 0, (LPARAM) hwnd);
}

/**
 * ウインドウの有効／無効を切り替える
 */
void set_enabled(JNIEnv* env, HWND hwnd, BOOL enabled) {
	SendMessage(g_hSystemWnd, SYSMSG_SET_ENABLED, (WPARAM) enabled, (LPARAM) hwnd);
}

/**
 * ウインドウのサイズを変更する
 */
void set_bounds(JNIEnv* env, HWND hwnd, int x, int y, int width, int height) {
	bounds b;
	b.x = x;
	b.y = y;
	b.width = width;
	b.height = height;
	SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) hwnd);
}

/**
 * ウインドウのサイズを取得する
 * (現在未使用）
 */
void get_bounds(JNIEnv* env, HWND hwnd, int* px, int* py, int* width, int* height) {
	bounds b;
	SendMessage(g_hSystemWnd, SYSMSG_SET_BOUNDS, (WPARAM) &b, (LPARAM) hwnd);
	*px = b.x;
	*py = b.y;
	*width = b.width;
	*height = b.height;
}

/* !!!! Mod PeteC 2006-06-20 */
void set_focus(HWND hwnd)
{
	SendMessage(g_hSystemWnd, SYSMSG_SET_FOCUS, 0, (LPARAM) hwnd);
}
/* !!!! End Mod PeteC 2006-06-20 */

HWND get_focus()
{
	HWND hwnd;
	SendMessage(g_hSystemWnd, SYSMSG_GET_FOCUS, (WPARAM) &hwnd, 0);
	return hwnd;
}

/**
 * ウインドウを破棄する
 */
void dispose(JNIEnv* env, jobject peer_obj, HWND hwnd) {
	SendMessage(g_hSystemWnd, SYSMSG_DISPOSE, 0, (LPARAM) hwnd);
	(*env)->DeleteGlobalRef(env, peer_obj);
}

/**
 * ウインドウの画面上における座標を返す
 */
jobject get_location_on_screen(JNIEnv* env, HWND hwnd) {
	RECT rect;
	jclass clazz;
	jmethodID constructor_id;

	SendMessage(g_hSystemWnd, SYSMSG_GET_WINDOW_RECT, (WPARAM) &rect, (LPARAM) hwnd);
	
	// Pointオブジェクトを生成する
	clazz = (*env)->FindClass(env, "java/awt/Point");
	if (! clazz) {
		throw_AWTError(env, "Failed to load java.awt.Point");
		return NULL;
	}
	constructor_id = (*env)->GetMethodID(env, clazz, "<init>", "(II)V");
	if (! constructor_id) {
		throw_AWTError(env, "Failed to get constructor id");
		return NULL;
	}

	return (*env)->NewObject(env,
							  clazz,
							  constructor_id,
							  rect.left,
							  rect.top);

}

/**
 * 背景色を設定する
 */
void set_background(JNIEnv* env, jobject peer_obj, HWND hwnd, jint rgb) {
	SendMessage(g_hSystemWnd, SYSMSG_SET_BACKGROUND, (WPARAM) TO_COLORREF(rgb), (LPARAM) hwnd);
}

/**
 * 前面色を設定する
 */
void set_foreground(JNIEnv* env, jobject peer_obj, HWND hwnd, jint rgb) {
	SendMessage(g_hSystemWnd, SYSMSG_SET_FOREGROUND, (WPARAM) TO_COLORREF(rgb), (LPARAM) hwnd);
}

/**
 * 指定されたHWNDに対応するメニューバーのウインドウハンドルを返す
 * メニューバーを持たない場合はNULLを返す。
 */
HWND get_menu_bar_of(HWND hwnd) {
	native_component* peer = get_native_component(hwnd);
	HWND hwndMB = NULL;
	if (peer != NULL) {
		hwndMB = peer->hwndMB;
	}
	return hwndMB;
}

/**
 * ポップアップメニューを表示する
 */
void show_popup_menu(JNIEnv* env, jobject peer_obj, HWND hwnd, HMENU hmenu, int x, int y) {
	native_component* peer = get_native_component(hwnd);
	peer->hmenuPopup = hmenu;
	// ブロックしてしまうのを避けるため、SendMessage()ではなくPostMessage()を使用する
	PostMessage(g_hSystemWnd, SYSMSG_SHOW_POPUPMENU, (WPARAM) peer, MAKELPARAM(x, y));
}

/**
 * 指定されたCheckboxに対して、CheckboxGroupを設定する
 */
void set_checkbox_group(HWND hwnd, jobject checkboxGroup) {
	native_component* peer = get_native_component(hwnd);
	if (peer != NULL) {
		if (peer->checkboxGroup == NULL) {
			if (checkboxGroup != NULL) {
				// チェックボックスからラジオボタンに変更する
				DWORD style;
				assert(hwnd);
				style = GetWindowLong(hwnd, GWL_STYLE);
				style &= ~BS_CHECKBOX;
				style |= BS_RADIOBUTTON;
				SetWindowLong(hwnd, GWL_STYLE, style);
			}
		} else {
			if (checkboxGroup == NULL) {
				// ラジオボタンからチェックボックスに変更する
				DWORD style;
				assert(hwnd);
				style = GetWindowLong(hwnd, GWL_STYLE);
				style &= ~BS_RADIOBUTTON;
				style |= BS_CHECKBOX;
				SetWindowLong(hwnd, GWL_STYLE, style);
			}
		}
		peer->checkboxGroup = checkboxGroup;
	}
}

/**
 * jstringの内容を_TCHAR*に変換する
 * この関数の戻り値は malloc() で確保されているので、不要になった時点でfree()を使用して
 * 解放する必要がある
 */
_TCHAR* get_string_chars(JNIEnv* env, jstring str) {
	jint length = (*env)->GetStringLength(env, str);
	_TCHAR* buff = (_TCHAR*) malloc(sizeof(_TCHAR) * (length + 1));
	if (buff) {
		const _TCHAR* tmp = (*env)->GetStringChars(env, str, NULL);
		_tcsncpy(buff, tmp, length);
		buff[length] = _T('\0');
		(*env)->ReleaseStringChars(env, str, tmp);
	}	
	return buff;
}

/**
 * スクロールバーの行増分を設定する
 */
void set_scrollbar_line_increment(HWND hwndScroll, int inc) {
	native_component* peer = get_native_component(hwndScroll);
	if (peer != NULL) {
		peer->scrollbarLineIncrement = inc;
	}
}

/**
 * スクロールバーのページ増分を設定する
 */
void set_scrollbar_page_increment(HWND hwndScroll, int inc) {
	native_component* peer = get_native_component(hwndScroll);
	if (peer != NULL) {
		peer->scrollbarPageIncrement = inc;
	}
}

/**
 * 指定されたデバイスコンテキストを初期化する。
 */
void init_DC(HDC hdc) {
	// 背景モードを変更する
	SetBkMode(hdc, TRANSPARENT);
}

/**
 * ScrollPaneのスクロールバーに関するパラメタを設定する
 */
void set_scroll_pane_scrollbar_parameters(HWND hwnd,
										  int scrollbarType,
										  int maximum,
										  int visibleAmount) {
	native_component* nc = get_native_component(hwnd);
	if (! nc) {
		return;
	}
	if (nc->scrollPaneScrollbarDisplayPolicy == ScrollPane_SCROLLBARS_AS_NEEDED
			&& visibleAmount >= maximum) {
		// スクロールバーを消す
		// Windows CE側でも自動的にスクロールバーを消してくれるが、
		// ScrollPaneの実装とWindows CEの判断基準がことなるため、
		// 明示的に消す必要がある
		DWORD mask = (scrollbarType == Scrollbar_VERTICAL) ? WS_VSCROLL
															: WS_HSCROLL;
		DWORD style = GetWindowLong(hwnd, GWL_STYLE);
		style &= ~mask;
		SetWindowLong(hwnd, GWL_STYLE, style);

	} else if (nc->scrollPaneScrollbarDisplayPolicy != ScrollPane_SCROLLBARS_NEVER) {
		// 一度スクロールバーを表示させる
		SCROLLINFO si = {0};
		DWORD style = (DWORD) GetWindowLong(hwnd, GWL_STYLE);
		style |= (scrollbarType == Scrollbar_VERTICAL) ? WS_VSCROLL
														: WS_HSCROLL;
		SetWindowLong(hwnd, GWL_STYLE, style);

		// スクロールバーのパラメタを設定する
		si.cbSize = sizeof(SCROLLINFO);
		si.nMin = 0;
		si.nMax = maximum;
		si.nPage = visibleAmount;
		si.fMask = SIF_PAGE | SIF_RANGE;
		if (nc->scrollPaneScrollbarDisplayPolicy == ScrollPane_SCROLLBARS_ALWAYS) {
			// スクロールバーを常時表示とする
			si.fMask |= SIF_DISABLENOSCROLL;
		}
		SetScrollInfo(hwnd,
					 (scrollbarType == Scrollbar_VERTICAL ? SB_VERT : SB_HORZ),
					 &si,
					 TRUE);
	}
}

/**
 * ScrollPaneのスクロール位置を設定する
 */
void set_scroll_pane_scroll_position(HWND hwnd, int oldX, int oldY, int newX, int newY) {
	HWND hwndChild = GetWindow(hwnd, GW_CHILD);
	SCROLLINFO si = {0};
	DWORD style;

	if (hwndChild) {
		int dx = oldX - newX;
		int dy = oldY - newY;
		if (dx || dy) {
/*
			ScrollWindowEx(hwndChild,
						   dx,
						   dy,
						   NULL,
						   NULL,
						   NULL,
						   NULL,
						   SW_SCROLLCHILDREN);
*/
			LPARAM lp = (newY << 16 | (newX & 0xFFFF));
			SendMessage(g_hSystemWnd,
						SYSMSG_SET_SCROLL_POSITION,
						(WPARAM) hwnd,
						lp);
		}
	}
	// スクロールバーの位置を設定しなおす
	style = (DWORD) GetWindowLong(hwnd, GWL_STYLE);
	si.cbSize = sizeof(SCROLLINFO);
	si.fMask = SIF_POS;
	if (style & WS_VSCROLL) {
		// 垂直スクロールバー
		si.nPos = newY;
		SetScrollInfo(hwnd,
					  SB_VERT,
					  &si,
					  TRUE);
	}
	if (style & WS_HSCROLL) {
		// 水平クロールバー
		si.nPos = newX;
		SetScrollInfo(hwnd,
					  SB_HORZ,
					  &si,
					  TRUE);
	}
}

/**
 * Dialogの表示／非表示を切り替える
 */
void set_dialog_visible(HWND hwnd, BOOL visible, BOOL modal) {
	native_component* nc = get_native_component(hwnd);
	if (nc) {
		if (visible) {
			// ウインドウを表示状態にする
			SendMessage(g_hSystemWnd, SYSMSG_SET_VISIBLE, (WPARAM) TRUE, (LPARAM) hwnd);
			SendMessage(g_hSystemWnd, SYSMSG_TO_FRONT, 0, (LPARAM) hwnd);				
			if (modal) {
				// アプリケーションのトップレベルウインドウを全て無効化する
				/// ...
			}
		} else {
			// ウインドウを非表示にする
			SendMessage(g_hSystemWnd, SYSMSG_SET_VISIBLE, (WPARAM) FALSE, (LPARAM) hwnd);
			if (modal) {
				// アプリケーションのトップレベルウインドウを全て有効化する
				/// ...

			}
		}
	}
}

/**
 * Componentのカーソルを設定する
 */
void set_cursor(HWND hwnd, int type) {
	native_component* nc = get_native_component(hwnd);
	if (nc != NULL) {
		HCURSOR hCursor = NULL;
		switch (type) {
		case Cursor_CROSSHAIR_CURSOR:
			hCursor = LoadCursor(NULL, IDC_CROSS);
			break;
		
		case Cursor_W_RESIZE_CURSOR:
		case Cursor_E_RESIZE_CURSOR:
			hCursor = LoadCursor(NULL, IDC_SIZEWE);
			break;

		case Cursor_N_RESIZE_CURSOR:
		case Cursor_S_RESIZE_CURSOR:
			hCursor = LoadCursor(NULL, IDC_SIZENS);
			break;
		
		case Cursor_NE_RESIZE_CURSOR:
		case Cursor_SW_RESIZE_CURSOR:
			hCursor = LoadCursor(NULL, IDC_SIZENESW);
			break;

		case Cursor_NW_RESIZE_CURSOR:
		case Cursor_SE_RESIZE_CURSOR:
			hCursor = LoadCursor(NULL, IDC_SIZENWSE);
			break;

		case Cursor_HAND_CURSOR:
			hCursor = LoadCursor(NULL, IDC_HAND);
			break;

		case Cursor_MOVE_CURSOR:
			hCursor = LoadCursor(NULL, IDC_SIZEALL);
			break;
		
		case Cursor_WAIT_CURSOR:
			hCursor = LoadCursor(NULL, IDC_WAIT);
			break;

		}

		nc->hCursor = hCursor;
	}
}

/**
 * Componentのフォントを設定する
 */
void set_font(HWND hwnd, HFONT hFont) {
	native_component* nc = get_native_component(hwnd);
	if (nc != NULL) {
		SendMessage(hwnd, WM_SETFONT, (WPARAM) hFont, MAKELPARAM(TRUE, 0));
	}
}

/**
 * 指定された文字列の大きさを得る
 */
void get_text_extent_point(HWND hwnd, const _TCHAR* text, SIZE* psize) {
	HDC hdc;
	HFONT hFont, hOldFont;

	// 文字列のサイズを取得する
	hdc = GetDC(hwnd);
	hFont = (HFONT) SendMessage(hwnd, WM_GETFONT, 0, 0);
	hOldFont = (HFONT) SelectObject(hdc, hFont);
	GetTextExtentPoint(hdc, text, _tcslen(text), psize);
	SelectObject(hdc, hOldFont);
	ReleaseDC(hwnd, hdc);
}

/**
 * Windows CEのキーコードを KeyEvent クラスで定義されたキーコードに変換する
 */
static jint to_java_keycode(WPARAM wparam) {
	jint code;
	switch (wparam) {
	case VK_BACK:
		code = KeyEvent_VK_BACK_SPACE;
		break;

	case VK_CAPITAL:
		code = KeyEvent_VK_CAPS_LOCK;
		break;
	
	case VK_CONTROL:
	case VK_LCONTROL:
	case VK_RCONTROL:
		code = KeyEvent_VK_CONTROL;
		break;

	case VK_CONVERT:
		code = KeyEvent_VK_CONVERT;
		break;

	case VK_DELETE:
		code = KeyEvent_VK_DELETE;
		break;

	case VK_DOWN:
		code = KeyEvent_VK_DOWN;
		break;

	case VK_END:
		code = KeyEvent_VK_END;
		break;

	case VK_ESCAPE:
		code = KeyEvent_VK_ESCAPE;
		break;

	case VK_F1:
	case VK_F2:
	case VK_F3:
	case VK_F4:
	case VK_F5:
	case VK_F6:
	case VK_F7:
	case VK_F8:
	case VK_F9:
	case VK_F10:
	case VK_F11:
	case VK_F12:
		code = (jint) wparam;
		break;

	case VK_F13:
	case VK_F14:
	case VK_F15:
	case VK_F16:
	case VK_F17:
	case VK_F18:
	case VK_F19:
	case VK_F20:
	case VK_F21:
	case VK_F22:
	case VK_F23:
	case VK_F24:
		code = (jint) KeyEvent_VK_F13 + (wparam - VK_F13);
		break;

	case VK_HOME:
		code = KeyEvent_VK_HOME;
		break;

	case VK_INSERT:
		code = KeyEvent_VK_INSERT;
		break;

	case VK_LEFT:
		code = KeyEvent_VK_LEFT;
		break;

	case VK_MENU:
	case VK_LMENU:
	case VK_RMENU:
		code = KeyEvent_VK_ALT;
		break;

	case VK_NEXT:
		code = KeyEvent_VK_PAGE_DOWN;
		break;

	case VK_NUMPAD0:
	case VK_NUMPAD1:
	case VK_NUMPAD2:
	case VK_NUMPAD3:
	case VK_NUMPAD4:
	case VK_NUMPAD5:
	case VK_NUMPAD6:
	case VK_NUMPAD7:
	case VK_NUMPAD8:
	case VK_NUMPAD9:
	case VK_MULTIPLY:
	case VK_ADD:
	case VK_SEPARATOR:
	case VK_SUBTRACT:
	case VK_DECIMAL:
	case VK_DIVIDE:
		// Windows CEのコードとKeyEventの定数が同一
		code = (jint) wparam;
		break;

	case VK_PAUSE:
		code = KeyEvent_VK_PAUSE;
		break;

	case VK_PRIOR:
		code = KeyEvent_VK_PAGE_UP;
		break;
	
	case VK_RETURN:
		code = KeyEvent_VK_ENTER;
		break;

	case VK_RIGHT:
		code = KeyEvent_VK_RIGHT;
		break;

	case VK_SHIFT:
	case VK_LSHIFT:
	case VK_RSHIFT:
		code = KeyEvent_VK_SHIFT;
		break;
	
	case VK_SPACE:
		code = KeyEvent_VK_SPACE;
		break;

	case VK_UP:
		code = KeyEvent_VK_UP;
		break;
		
	case VK_TAB:
		code = KeyEvent_VK_TAB;
		break;

	default:
		// WPARAMの値をそのままコードに入れておく
		code = (jint) wparam;
		break;
	}
	return code;
}

/**
 * Windows CEのキーコードを KeyEvent クラスで定義されたキー位置に変換する
 */
static jint to_java_keylocation(WPARAM wparam) {
	jint location;

	switch (wparam) {
	case VK_LCONTROL:
	case VK_LMENU:
	case VK_LSHIFT:
		location = KeyEvent_KEY_LOCATION_LEFT;
		break;

	case VK_RCONTROL:
	case VK_RMENU:
	case VK_RSHIFT:
		location = KeyEvent_KEY_LOCATION_RIGHT;
		break;

	case VK_NUMPAD0:
	case VK_NUMPAD1:
	case VK_NUMPAD2:
	case VK_NUMPAD3:
	case VK_NUMPAD4:
	case VK_NUMPAD5:
	case VK_NUMPAD6:
	case VK_NUMPAD7:
	case VK_NUMPAD8:
	case VK_NUMPAD9:
	case VK_MULTIPLY:
	case VK_ADD:
	case VK_SEPARATOR:
	case VK_SUBTRACT:
	case VK_DECIMAL:
	case VK_DIVIDE:
		location = KeyEvent_KEY_LOCATION_NUMPAD;
		break;

	default:
		location = KeyEvent_KEY_LOCATION_STANDARD;
		break;
	}

	return location;
}

/**
 * Windows CEのキー状態を InputEvent クラスで定義されたmodifier定数に変換する
 */
static jint get_InputEvent_modifiers() {
	jint modifiers = 0;
	SHORT state;

	state = GetKeyState(VK_SHIFT);
	if (state) {
		modifiers |= InputEvent_SHIFT_DOWN_MASK;
	}
	state = GetKeyState(VK_CONTROL);
	if (state) {
		modifiers |= InputEvent_CTRL_DOWN_MASK;
	}
	state = GetKeyState(VK_MENU);
	if (state) {
		modifiers |= InputEvent_ALT_DOWN_MASK;
	}
	return modifiers;
}

/**
 * AWTErrorをthrowする
 */
void throw_AWTError(JNIEnv* env, const char* message) {
	// AWTErrorをthrowする
	(*env)->ThrowNew(env, g_AWTError_class, message);
}


/**
 * 指定されたFrameに対応するWindowのスタイルを初期化する
 */
static void init_frame_style(HWND hWnd, jboolean undecorated) {
	LONG lStyle = WS_CLIPCHILDREN;
	if (! undecorated) {
		// スタイルを追加する
		lStyle |= WS_CAPTION
				| WS_THICKFRAME
				| WS_SYSMENU
				| WS_MAXIMIZEBOX;
	}
	SetWindowLong(hWnd, GWL_STYLE, lStyle);
}

/**
 * 指定されたDialogに対応するWindowのスタイルを初期化する
 */
static void init_dialog_style(HWND hWnd, jboolean undecorated) {
	LONG lStyle = WS_NONAVDONEBUTTON;
	if (! undecorated) {
		// スタイルを設定する
		lStyle = WS_CAPTION
				| WS_THICKFRAME
				| WS_SYSMENU
				| WS_MAXIMIZEBOX;
	}
	SetWindowLong(hWnd, GWL_STYLE, lStyle);
}

/**
 * 指定されたウインドウに対応するメニューバーの表示／非表示を切り替える
 * 指定されたウインドウがメニューバーを持たない場合には何もしない
 */
void set_menu_bar_visible(HWND hwndFrame, BOOL visible) {
	native_component* nc = get_native_component(hwndFrame);
	if (nc->hwndMB) {
		ShowWindow(nc->hwndMB, (visible ? SW_SHOW : SW_HIDE));
	}
}