gt: 			int length = OS.GetWindowTextLength (handle);
context: /*******************************************************************************
   * Copyright (c) 2000, 2015 IBM Corporation and others.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *     IBM Corporation - initial API and implementation
   *******************************************************************************/
  package org.eclipse.swt.widgets;
  
  
  import org.eclipse.swt.internal.*;
  import org.eclipse.swt.internal.win32.*;
  import org.eclipse.swt.*;
  import org.eclipse.swt.graphics.*;
  import org.eclipse.swt.events.*;
  
  /**
   * Instances of this class are controls that allow the user
   * to choose an item from a list of items, or optionally 
   * enter a new value by typing it into an editable text
   * field. Often, <code>Combo</code>s are used in the same place
   * where a single selection <code>List</code> widget could
   * be used but space is limited. A <code>Combo</code> takes
   * less space than a <code>List</code> widget and shows
   * similar information.
   * <p>
   * Note: Since <code>Combo</code>s can contain both a list
   * and an editable text field, it is possible to confuse methods
   * which access one versus the other (compare for example,
   * <code>clearSelection()</code> and <code>deselectAll()</code>).
   * The API documentation is careful to indicate either "the
   * receiver's list" or the "the receiver's text field" to 
   * distinguish between the two cases.
   * </p><p>
   * Note that although this class is a subclass of <code>Composite</code>,
   * it does not make sense to add children to it, or set a layout on it.
   * </p>
   * <dl>
   * <dt><b>Styles:</b></dt>
   * <dd>DROP_DOWN, READ_ONLY, SIMPLE</dd>
   * <dt><b>Events:</b></dt>
   * <dd>DefaultSelection, Modify, Selection, Verify, OrientationChange</dd>
   * </dl>
   * <p>
   * Note: Only one of the styles DROP_DOWN and SIMPLE may be specified.
   * </p><p>
   * IMPORTANT: This class is <em>not</em> intended to be subclassed.
   * </p>
   *
   * @see List
   * @see <a href="http://www.eclipse.org/swt/snippets/#combo">Combo snippets</a>
   * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
   * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
   * @noextend This class is not intended to be subclassed by clients.
   */
  public class Combo extends Composite {
  	boolean noSelection, ignoreDefaultSelection, ignoreCharacter, ignoreModify, ignoreResize, lockText;
  	int scrollWidth, visibleCount;
  	long /*int*/ cbtHook;
  	String [] items = new String [0];
  	int[] segments;
  	int clearSegmentsCount = 0;
  
  	static final char LTR_MARK = '\u200e';
  	static final char RTL_MARK = '\u200f';
  	static final int VISIBLE_COUNT = 5;
  
  	/**
  	 * the operating system limit for the number of characters
  	 * that the text field in an instance of this class can hold
  	 */
  	public static final int LIMIT;
  	
  	/*
  	 * These values can be different on different platforms.
  	 * Therefore they are not initialized in the declaration
  	 * to stop the compiler from inlining.
  	 */
  	static {
  		LIMIT = OS.IsWinNT ? 0x7FFFFFFF : 0x7FFF;	
  	}
  	
  	/*
  	 * These are the undocumented control id's for the children of
  	 * a combo box.  Since there are no constants for these values,
  	 * they may change with different versions of Windows (but have
  	 * been the same since Windows 3.0).
  	 */
  	static final int CBID_LIST = 1000;
  	static final int CBID_EDIT = 1001;
  	static /*final*/ long /*int*/ EditProc, ListProc;
  	
  	static final long /*int*/ ComboProc;
  	static final TCHAR ComboClass = new TCHAR (0, "COMBOBOX", true);
  	static {
  		WNDCLASS lpWndClass = new WNDCLASS ();
  		OS.GetClassInfo (0, ComboClass, lpWndClass);
  		ComboProc = lpWndClass.lpfnWndProc;
  	}
  	
  /**
   * Constructs a new instance of this class given its parent
   * and a style value describing its behavior and appearance.
   * <p>
   * The style value is either one of the style constants defined in
   * class <code>SWT</code> which is applicable to instances of this
   * class, or must be built by <em>bitwise OR</em>'ing together 
   * (that is, using the <code>int</code> "|" operator) two or more
   * of those <code>SWT</code> style constants. The class description
   * lists the style constants that are applicable to the class.
   * Style bits are also inherited from superclasses.
   * </p>
   *
   * @param parent a composite control which will be the parent of the new instance (cannot be null)
   * @param style the style of control to construct
   *
   * @exception IllegalArgumentException <ul>
   *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
   * </ul>
   * @exception SWTException <ul>
   *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
   *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
   * </ul>
   *
   * @see SWT#DROP_DOWN
   * @see SWT#READ_ONLY
   * @see SWT#SIMPLE
   * @see Widget#checkSubclass
   * @see Widget#getStyle
   */
  public Combo (Composite parent, int style) {
  	super (parent, checkStyle (style));
  	/* This code is intentionally commented */
  	//if ((style & SWT.H_SCROLL) != 0) this.style |= SWT.H_SCROLL;
  	this.style |= SWT.H_SCROLL;
  }
  
  /**
   * Adds the argument to the end of the receiver's list.
   * <p>
   * Note: If control characters like '\n', '\t' etc. are used
   * in the string, then the behavior is platform dependent.
   * </p>
   * @param string the new item
   *
   * @exception IllegalArgumentException <ul>
   *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
   * </ul>
   * @exception SWTException <ul>
   *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
   *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
   * </ul>
   *
   * @see #add(String,int)
   */
  public void add (String string) {
  	checkWidget ();
  	if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
  	TCHAR buffer = new TCHAR (getCodePage (), string, true);
  	int result = (int)/*64*/OS.SendMessage (handle, OS.CB_ADDSTRING, 0, buffer);
  	if (result == OS.CB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED);
  	if (result == OS.CB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
  	if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, true);
  }
  
  /**
   * Adds the argument to the receiver's list at the given
   * zero-relative index.
   * <p>
   * Note: To add an item at the end of the list, use the
   * result of calling <code>getItemCount()</code> as the
   * index or use <code>add(String)</code>.
   * </p><p>
   * Also note, if control characters like '\n', '\t' etc. are used
   * in the string, then the behavior is platform dependent.
   * </p>
   *
   * @param string the new item
   * @param index the index for the item
   *
   * @exception IllegalArgumentException <ul>
   *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
   *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
   * </ul>
   * @exception SWTException <ul>
   *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
   *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
   * </ul>
   *
   * @see #add(String)
   */
  public void add (String string, int index) {
  	checkWidget ();
  	if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
  	int count = (int)/*64*/OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
  	if (!(0 <= index && index <= count)) {
  		error (SWT.ERROR_INVALID_RANGE);
  	}
  	TCHAR buffer = new TCHAR (getCodePage (), string, true);
  	int result = (int)/*64*/OS.SendMessage (handle, OS.CB_INSERTSTRING, index, buffer);
  	if (result == OS.CB_ERRSPACE || result == OS.CB_ERR) {
  		error (SWT.ERROR_ITEM_NOT_ADDED);
  	}
  	if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, true);
  }
  
  /**
   * Adds the listener to the collection of listeners who will
   * be notified when the receiver's text is modified, by sending
   * it one of the messages defined in the <code>ModifyListener</code>
   * interface.
   *
   * @param listener the listener which should be notified
   *
   * @exception IllegalArgumentException <ul>
   *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
   * </ul>
   * @exception SWTException <ul>
   *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
   *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
   * </ul>
   *
   * @see ModifyListener
   * @see #removeModifyListener
   */
  public void addModifyListener (ModifyListener listener) {
  	checkWidget ();
  	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
  	TypedListener typedListener = new TypedListener (listener);
  	addListener (SWT.Modify, typedListener);
  }
  
  /**
   * Adds a segment listener.
   * <p>
   * A <code>SegmentEvent</code> is sent whenever text content is being modified or
   * a segment listener is added or removed. You can 
   * customize the appearance of text by indicating certain characters to be inserted
   * at certain text offsets. This may be used for bidi purposes, e.g. when
   * adjacent segments of right-to-left text should not be reordered relative to
   * each other. 
   * E.g., multiple Java string literals in a right-to-left language
   * should generally remain in logical order to each other, that is, the
   * way they are stored.
   * </p>
   * <p>
   * <b>Warning</b>: This API is currently only implemented on Windows.
   * <code>SegmentEvent</code>s won't be sent on GTK and Cocoa.
   * </p>
   *
   * @param listener the listener which should be notified
   *
   * @exception IllegalArgumentException <ul>
   *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
   * </ul>
   * @exception SWTException <ul>
   *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
   *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
   * </ul>
   *
   * @see SegmentEvent
   * @see SegmentListener
   * @see #removeSegmentListener
   *
   * @since 3.103
   */
  public void addSegmentListener (SegmentListener listener) {
  	checkWidget ();
  	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
  	addListener (SWT.Segments, new TypedListener (listener));
  	int selection = OS.CB_ERR;
  	if (!noSelection) {
  		selection = (int)/*64*/OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
  	}
  	clearSegments (true);
  	applyEditSegments ();
  	applyListSegments ();
  	if (selection != OS.CB_ERR) {
  		OS.SendMessage (handle, OS.CB_SETCURSEL, selection, 0);
  	}
  }
  
  /**
   * Adds the listener to the collection of listeners who will
   * be notified when the user changes the receiver's selection, by sending
   * it one of the messages defined in the <code>SelectionListener</code>
   * interface.
   * <p>
   * <code>widgetSelected</code> is called when the user changes the combo's list selection.
   * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed the combo's text area.
   * </p>
   *
   * @param listener the listener which should be notified
   *
   * @exception IllegalArgumentException <ul>
   *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
   * </ul>
   * @exception SWTException <ul>
   *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
   *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
   * </ul>
   *
   * @see SelectionListener
   * @see #removeSelectionListener
   * @see SelectionEvent
   */
  public void addSelectionListener(SelectionListener listener) {
  	checkWidget ();
  	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
  	TypedListener typedListener = new TypedListener (listener);
  	addListener (SWT.Selection,typedListener);
  	addListener (SWT.DefaultSelection,typedListener);
  }
  
  /**
   * Adds the listener to the collection of listeners who will
   * be notified when the receiver's text is verified, by sending
   * it one of the messages defined in the <code>VerifyListener</code>
   * interface.
   *
   * @param listener the listener which should be notified
   *
   * @exception IllegalArgumentException <ul>
   *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
   * </ul>
   * @exception SWTException <ul>
   *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
   *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
   * </ul>
   *
   * @see VerifyListener
   * @see #removeVerifyListener
   * 
   * @since 3.1
   */
  public void addVerifyListener (VerifyListener listener) {
  	checkWidget ();
  	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
  	TypedListener typedListener = new TypedListener (listener);
  	addListener (SWT.Verify, typedListener);
  }
  
  void applyEditSegments () {
  	if (--clearSegmentsCount != 0) return;
  	if (!hooks (SWT.Segments) && !filters (SWT.Segments) && (state & HAS_AUTO_DIRECTION) == 0) return;
  	long /*int*/ hwndText = OS.GetDlgItem (handle, CBID_EDIT);
  	int length = OS.GetWindowTextLength (hwndText);
  	int cp = getCodePage ();
  	TCHAR buffer = new TCHAR (cp, length + 1);
  	if (length > 0) OS.GetWindowText (hwndText, buffer, length + 1);
  	String string = buffer.toString (0, length);
  	/* Get segments */
  	segments = null;
  	Event event = getSegments (string);
  	if (event == null || event.segments == null) return;
  	segments = event.segments;
  	int nSegments = segments.length; 
  	if (nSegments == 0) return;
  	char [] segmentsChars = event.segmentsChars;
  	int/*64*/ limit = (int/*64*/)OS.SendMessage (hwndText, OS.EM_GETLIMITTEXT, 0, 0) & 0x7fffffff;
  	OS.SendMessage (hwndText, OS.EM_SETLIMITTEXT, limit + Math.min (nSegments, LIMIT - limit), 0);
  	length += nSegments;
  	char [] newChars = new char [length + 1];
  	int charCount = 0, segmentCount = 0;
  	char defaultSeparator = getOrientation () == SWT.RIGHT_TO_LEFT ? RTL_MARK : LTR_MARK;
  	while (charCount < length) {
  		if (segmentCount < nSegments && charCount - segmentCount == segments [segmentCount]) {
  			char separator = segmentsChars != null && segmentsChars.length > segmentCount ? segmentsChars [segmentCount] : defaultSeparator;
  			newChars [charCount++] = separator;
  			segmentCount++;
  		} else if (string != null) {
  			newChars [charCount] = string.charAt (charCount++ - segmentCount);
  		}
  	}
  	while (segmentCount < nSegments) {
  		segments [segmentCount] = charCount - segmentCount;
  		char separator = segmentsChars != null && segmentsChars.length > segmentCount ? segmentsChars [segmentCount] : defaultSeparator;
  		newChars [charCount++] = separator;
  		segmentCount++;
  	}
  	/* Get the current selection */
  	int [] start = new int [1], end = new int [1];
  	OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
  	if (!OS.IsUnicode && OS.IsDBLocale) {
  		start [0] = mbcsToWcsPos (start [0]);
  		end [0] = mbcsToWcsPos (end [0]);
  	}
  	boolean oldIgnoreCharacter = ignoreCharacter, oldIgnoreModify = ignoreModify;
  	ignoreCharacter = ignoreModify = true;
  	/*
  	 * SetWindowText empties the undo buffer and disables undo menu item.
  	 * Sending OS.EM_REPLACESEL message instead.
  	 */
  	newChars [length] = 0;
  	buffer = new TCHAR (cp, newChars, false);
  	OS.SendMessage (hwndText, OS.EM_SETSEL, 0, -1);
  	long /*int*/ undo = OS.SendMessage (hwndText, OS.EM_CANUNDO, 0, 0);
  	OS.SendMessage (hwndText, OS.EM_REPLACESEL, undo, buffer);
  	/* Restore selection */
  	start [0] = translateOffset (start [0]);
  	end [0] = translateOffset (end [0]);
  	if (!OS.IsUnicode && OS.IsDBLocale) {
  		start [0] = wcsToMbcsPos (start [0]);
  		end [0] = wcsToMbcsPos (end [0]);
  	}
  	if (segmentsChars != null && segmentsChars.length > 0) {
  		/* 
  		 * In addition to enforcing the required direction by prepending a UCC (LRE
  		 * or RLE), also set the direction through a Window style.
  		 * This is to ensure correct caret movement, and makes sense even when the
  		 * UCC was added by an authentic SegmentListener.
  		 */
  		if (segmentsChars[0] == RLE) {
  			super.updateTextDirection(SWT.RIGHT_TO_LEFT);
  		} else if (segmentsChars[0] == LRE) {
  			super.updateTextDirection(SWT.LEFT_TO_RIGHT);
  		}
  	}
  	OS.SendMessage (hwndText, OS.EM_SETSEL, start [0], end [0]);
  	ignoreCharacter = oldIgnoreCharacter;
  	ignoreModify = oldIgnoreModify;
  }
  
  void applyListSegments () {
  	int count = (int)/*64*/OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
  	if (count == OS.CB_ERR) return;
  	boolean add = items.length != count;
  	if (add) items = new String [count];
  	int index = items.length;
  	int selection = OS.CB_ERR;
  	int cp = getCodePage ();
  	String string;
  	TCHAR buffer;
  	if (!noSelection) {
  		selection = (int)/*64*/OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
  	}
  	while (index-- > 0) {
  		buffer = null;
  	 	if (add) {
  			int length = (int)/*64*/OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, index, 0);
  			if (length == OS.CB_ERR) error (SWT.ERROR);
  			buffer = new TCHAR (cp, length + 1);
  			if (OS.SendMessage (handle, OS.CB_GETLBTEXT, index, buffer) == OS.CB_ERR) return;
  			items [index] = string = buffer.toString (0, length);
  	 	} else { 
  	 		string = items [index];
  	 	}
  		if (OS.SendMessage (handle, OS.CB_DELETESTRING, index, 0) == OS.CB_ERR) return;
  		if (buffer == null) buffer = new TCHAR (cp, string, true);
  		if (OS.SendMessage (handle, OS.CB_INSERTSTRING, index, buffer) == OS.CB_ERR) return;
  	}
  	if (selection != OS.CB_ERR) {
  		OS.SendMessage (handle, OS.CB_SETCURSEL, selection, 0);
  	}
  }
  
  long /*int*/ callWindowProc (long /*int*/ hwnd, int msg, long /*int*/ wParam, long /*int*/ lParam) {
  	if (handle == 0) return 0;
  	if (hwnd == handle) {
  		switch (msg) {
  			case OS.WM_SIZE: {
  				ignoreResize = true;
  				boolean oldLockText = lockText;
  				if ((style & SWT.READ_ONLY) == 0) lockText = true;
  				long /*int*/ result = OS.CallWindowProc (ComboProc, hwnd, msg, wParam, lParam);
  				if ((style & SWT.READ_ONLY) == 0) lockText = oldLockText;
  				ignoreResize = false;
  				return result;
  			}
  		}
  		return OS.CallWindowProc (ComboProc, hwnd, msg, wParam, lParam);
  	}
  	long /*int*/ hwndText = OS.GetDlgItem (handle, CBID_EDIT);
  	if (hwnd == hwndText) {
  		if (lockText && msg == OS.WM_SETTEXT) {
  			long /*int*/ hHeap = OS.GetProcessHeap ();
  