private void OnCbSelectedIndexChanged(ComboBox cbCodePointRange, MyDataGridView dataGridViewCharacters,
			ref Button btnZoom, Font font, bool bIsLegacy)
		{
			string strValue = (string)cbCodePointRange.SelectedItem;
			if (String.IsNullOrEmpty(strValue))
				return;

			ResetCharMap(ref btnZoom, dataGridViewCharacters);

			RadioButton btnToCheck;
			UnicodeSubset aUS;
			if ((m_aUSM != null) && m_aUSM.TryGetValue(strValue, out aUS))
			{
				btnToCheck = radioButtonUnicodeSubsets;
				foreach (KeyValuePair<int, int> aRangeLength in aUS)
					InitializeCharMap(font, dataGridViewCharacters, aRangeLength.Key, aRangeLength.Value, 0, bIsLegacy);
			}
			else if (radioButtonByCodePoint.Checked)
			{
				btnToCheck = radioButtonByCodePoint;
				int nBeginningIndex = Convert.ToInt32(strValue.Substring(0, 4), 16);
				InitializeCharMap(font, dataGridViewCharacters, nBeginningIndex, 0x80, 0, bIsLegacy);
			}
			else
				return;

			// first see if this range has been added to our list of recently used ranges
			foreach (RadioButton btnUnicodeRange in flowLayoutPanelRecentRanges.Controls)
				if (btnUnicodeRange.Text == strValue)
				{
					flowLayoutPanelRecentRanges.Controls.SetChildIndex(btnUnicodeRange, 0);
					btnUnicodeRange.Checked = true;
					return; // found, so just return
				}

			// otherwise, add a radio button for this range so we can more easily go back to it
			RadioButton btn = new RadioButton();
			btn.AutoSize = true;
			btn.Name = "radioButton" + strValue;
			btn.TabStop = true;
			btn.Text = strValue;
			btn.UseVisualStyleBackColor = true;
			btn.Click += new EventHandler(btnUnicodeRange_Click);

			flowLayoutPanelRecentRanges.Controls.Add(btn);
			flowLayoutPanelRecentRanges.Controls.SetChildIndex(btn, 0);
			btn.Checked = true;
			btn.Tag = btnToCheck;
		}
		internal unsafe void GetAllPossibleGlyphIndices(MyDataGridView grid, Font font, int nBeginningCharacterIndex, int nNumPossibleChars,
			int nCodePage, bool bIsLegacy, out char[] achFullPossibleChars, out char[] achGlyIdxes)
		{
			IntPtr hWnd = IntPtr.Zero;
			IntPtr hFont = IntPtr.Zero;
			IntPtr hDC = IntPtr.Zero;
			IntPtr hOrigFont = IntPtr.Zero;
			int nCount = 0;

			try
			{
				hWnd = grid.Handle;
				hFont = font.ToHfont();
				hDC = GetDC(hWnd);
				hOrigFont = SelectObject(hDC, hFont);

				char* pGlyIdx = stackalloc char[nNumPossibleChars];

				// legacy (but not symbol) fonts behave differently
				if (bIsLegacy && (nCodePage != EncConverters.cnSymbolFontCodePage))
				{
					// fill a byte array with all possible ansi code points and then turn that into chars via
					//  the default system code page.
					byte[] abyCharValues = new byte[nNumPossibleChars];
					for (int i = 0; i < nNumPossibleChars; i++)
						abyCharValues[i] = (byte)i;

					fixed (byte* pTxt = abyCharValues)
					{
						nCount = GetGlyphIndicesA(hDC, pTxt, nNumPossibleChars, pGlyIdx, GGI_MARK_NONEXISTING_GLYPHS);
					}

					achFullPossibleChars = Encoding.GetEncoding(nCodePage).GetChars(abyCharValues);
				}
				else
				{
					achFullPossibleChars = new char[nNumPossibleChars];
					for (int i = 0; i < nNumPossibleChars; i++)
						achFullPossibleChars[i] = (char)(nBeginningCharacterIndex + i);

					fixed (char* pTxt = achFullPossibleChars)
					{
						nCount = GetGlyphIndicesW(hDC, pTxt, nNumPossibleChars, pGlyIdx, GGI_MARK_NONEXISTING_GLYPHS);
					}
				}

				achGlyIdxes = new char[nCount];
				for (int i = 0; i < nCount; i++)
					achGlyIdxes[i] = pGlyIdx[i];
			}
			finally
			{
				// release what we got
				SelectObject(hDC, hOrigFont);
				ReleaseDC(hWnd, hDC);
			}
		}
		private void OnCellMouseDown(MyDataGridView dataGridViewCharacters, ref Button btnZoom, Font font, TableLayoutPanel ZoomButtonParent,
			SendToEditorForms eOutputForm, bool bIsLegacy, DataGridViewCellMouseEventArgs e)
		{
			if ((e.RowIndex >= 0) && (e.ColumnIndex >= 0))
			{
				m_mbButtonDown = e.Button;

				DataGridViewCell aCell = dataGridViewCharacters.Rows[e.RowIndex].Cells[e.ColumnIndex];
				if (m_mbButtonDown == MouseButtons.Right)
				{
					// simply selecting the cell will trigger the zoom button update
					//  (but only if it's already activated)
					if (btnZoom == null)
						ShowZoomButton(ref btnZoom, font, ZoomButtonParent, eOutputForm, bIsLegacy, aCell);
					else if (!btnZoom.Visible)
						btnZoom.Show();

					// either way, select the cell
					aCell.Selected = true;
				}
			}
		}
		internal unsafe void InitializeCharMap(Font font, MyDataGridView grid, int nBeginningCharacterIndex, int nRangeLength, int nCodePage, bool bIsLegacy)
		{
			grid.DefaultCellStyle.Font = font;

			// for Legacy fonts, we don't do column and row headers and we do 256 chars
			const int cnGridItems = 16; // both row and column count
			int nNumRows = (nRangeLength + cnGridItems - 1) / cnGridItems;
			if (bIsLegacy)
				grid.ColumnHeadersVisible = grid.RowHeadersVisible = false;

			char[] achCharValues, achGlyIdxes;
			GetAllPossibleGlyphIndices(grid, font, nBeginningCharacterIndex, nRangeLength, nCodePage, bIsLegacy, out achCharValues, out achGlyIdxes);

			int nCharIndex = 0, nMaxIndex = Math.Min(achCharValues.Length, achGlyIdxes.Length);
			int jInit = nBeginningCharacterIndex % cnGridItems; // first time thru, skip to the correct character
			for (int i = 0; (i < nNumRows) && (nCharIndex < nMaxIndex); i++)
			{
				int nRowIndex = -1;
				DataGridViewRow theRow = null;
				if (!bIsLegacy)
				{
					nRowIndex = grid.Rows.Add();
					theRow = grid.Rows[nRowIndex];
					theRow.HeaderCell.Value = String.Format("{0:X4}", ((nBeginningCharacterIndex / cnGridItems) * cnGridItems) + (i * cnGridItems));
				}

				for (int j = jInit; j < cnGridItems; j++ )
				{
					nCharIndex = (i * cnGridItems) + j - jInit;
					if (nCharIndex < nMaxIndex)
					{
						// don't bother displaying anything if there isn't a real glyph
						char chGlyphIndex = achGlyIdxes[nCharIndex];
						if (chGlyphIndex != 0xFFFF)
						{
							// delay creating rows until they're needed (so we can skip the first two)
							//  unless we're displaying Unicode, in which case, we *have* to show all rows
							if (nRowIndex == -1)
							{
								nRowIndex = grid.Rows.Add();
								theRow = grid.Rows[nRowIndex];
							}

							// the code point for this character/glyph *is* the character index
							char ch = achCharValues[nCharIndex];    // Convert.ToChar(nCharIndex);
							DataGridViewCell aCell = theRow.Cells[j];
							aCell.Value = ch;
						}
					}
					else
						break;  // break out of the loop, because we're done.
				}

				jInit = 0;  // start at 0 on subsequent rows
			}
		}