
Monday, July 27, 2009
Odchytnutí zprávy WM_KEYDOWN v dialogu – Windows Mobile
V jednom předchozím článku jsem slíbil, že na blog dám i kód, který umožní ve Windows dialogu zachytit všechny stisknuté klávesy. Jak možná víte, dialog ve Windows je běžné okno (Window) s třídou (class) WC_DIALOG. K dialogu je přiřazena speciální funkce WNDPROC, která zajišťuje výchozí zpracování zpráv zaslaných formuláři (např. přechod mezi prvky dialogu pomocí klávesy TAB) a volá vývojářem aplikace určenou obslužnou funkci dialogu (DLGPROC). Jedním z nepříjemných důsledků tohoto modelu chování pro dialogy je, že nejsme schopni v DLGPROC odchytit a zpracovat zprávu o stisknutí tlačítka na klávesnici (WM_KEYDOWN).
Nechceme-li reimplementovat všechny vychytávky dialogů v našem vlastním “okně” (Window) a současně chceme i v dialogu odchytit zprávu WM_KEYDOWN, musíme výchozí WNDPROC obslužnou funkci při vytváření dialogu nahradit naší vlastní “proxy” WNDPROC funkcí.
BOOL CALLBACK DlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_INITDIALOG)
{
ChangeDialogWndProc(hWnd);
}
return true;
}
void ChangeDialogWndProc(HWND hwnd)
{
g_oldDlgdProc = (WNDPROC)GetWindowLong(hwnd, GWL_WNDPROC);
SetWindowLong(hwnd, GWL_WNDPROC, (LONG)&DlgWindowsProc);
}
V naší obslužné proceduře dialogu DlgProc při inicializaci dialogu (zpráva WM_INITDIALOG) voláme funkci ChangeDialogWndProc, která zaregistruje naší “proxy” WINDPROC funkci pomocí API SetWindowLong. Ještě předtím si uložíme do proměnné g_oldDlgdProc pointer na předchozí WNDPROC funkci, která je návratovou hodnotou API funkce GetWindowLong, když jí ve druhém argumentu předáme konstantu GWL_WNDPROC.
V naší “proxy” funkci WNDPROC odchytneme všechny potřebné zprávy a když chceme zachovat výchozí chování dialogu, předáme zprávu ke zpracování v předchozím kroku uložené výchozí Windows proceduře pro dialogy.
RESULT CALLBACK DlgWindowsProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_KEYDOWN)
{
//Do something with key
int key = (int) wParam;
}
return g_oldDlgdProc(hWnd, message, wParam, lParam);
}
Následuje jednoduchý příklad založený na standardní šabloně WM projektu.
// HookDialog.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "HookDialog.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE g_hInst; // current instance
HWND g_hWndMenuBar; // menu bar handle
WNDPROC g_oldDlgdProc;
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE, LPTSTR);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void ChangeDialogWndProc(HWND hwnd);
BOOL CALLBACK DlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK DlgWindowsProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
DialogBox(g_hInst, MAKEINTRESOURCE(IDD_POCKETPC_PORTRAIT), NULL, &DlgProc);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_HOOKDIALOG));
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = szWindowClass;
return RegisterClass(&wc);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
TCHAR szTitle[MAX_LOADSTRING]; // title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // main window class name
g_hInst = hInstance; // Store instance handle in our global variable
// SHInitExtraControls should be called once during your application's initialization to initialize any
// of the device specific controls such as CAPEDIT and SIPPREF.
SHInitExtraControls();
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_HOOKDIALOG, szWindowClass, MAX_LOADSTRING);
//If it is already running, then focus on the window, and exit
hWnd = FindWindow(szWindowClass, szTitle);
if (hWnd)
{
// set focus to foremost child window
// The "| 0x00000001" is used to bring any owned windows to the foreground and
// activate them.
SetForegroundWindow((HWND)((ULONG) hWnd | 0x00000001));
return 0;
}
if (!MyRegisterClass(hInstance, szWindowClass))
{
return FALSE;
}
hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_OK:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_CREATE:
SHMENUBARINFO mbi;
memset(&mbi, 0, sizeof(SHMENUBARINFO));
mbi.cbSize = sizeof(SHMENUBARINFO);
mbi.hwndParent = hWnd;
mbi.nToolBarId = IDR_MENU;
mbi.hInstRes = g_hInst;
if (!SHCreateMenuBar(&mbi))
{
g_hWndMenuBar = NULL;
}
else
{
g_hWndMenuBar = mbi.hwndMB;
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
CommandBar_Destroy(g_hWndMenuBar);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
BOOL CALLBACK DlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_INITDIALOG)
{
ChangeDialogWndProc(hWnd);
}
return true;
}
LRESULT CALLBACK DlgWindowsProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_KEYDOWN)
{
//Do something with key
int key = (int) wParam;
}
return g_oldDlgdProc(hWnd, message, wParam, lParam);
}
void ChangeDialogWndProc(HWND hwnd)
{
g_oldDlgdProc = (WNDPROC)GetWindowLong(hwnd, GWL_WNDPROC);
SetWindowLong(hwnd, GWL_WNDPROC, (LONG)&DlgWindowsProc);
}
Monday, July 27, 2009 11:29:07 AM (Central Europe Standard Time, UTC+01:00)
Compact .Net Framework | Nativní kód

Tuesday, April 14, 2009
Windows Mobile formulář přes celý displej - v nativním kódu
Na MSDN fórech jsem si všiml, že se vícekrát objevil dotaz, jak v nativním kódu vytvořit okno přes celou obrazovku, které se bude chovat jako formulář v Compact .Net Framework aplikaci při nastavení vlastnosti WindowState = Maximized.
API SHFullScreen sice přepne okno do celoobrazovkového režimu, ale při zobrazení SIPu se opět objeví taskbar. Při skrytí SIPu se okno vrátí do celoobrazovkového režimu. První, co mě napadlo, je skrýt samotný taskbar. Idea dobrá, mohli jsme mít jednoduché řešení, ale autoři Windows Mobile jako již tradičně řekli ne.
Po několika pokusech jsem zjistil, že jediné použitelné řešení představuje změna pozice a velikosti formuláře vždy, když odchytím zprávu WINDOWPOSCHANGED. To celé je korunováno opakovaným voláním SHFullScreen. Na řešení v Compact .Net Frameworku jsem se nedíval, abych si nekazil radost z vyřešeného úkolu, takže netuším, zda autoři CNF používají ještě nějaký další trik.
Níže naleznete příklad, který je založen na výchozí šabloně Smart Device Windows API projektu. Zajímavé části jsou zvýrazněny tučně. Tento postup lze samozřejmě jednoduše použít ve WTL nebo MFC.
Tady se ještě zeptám:
1) Jsou alespoń pro někoho z Vás tyto tipy/FAQ zajímavé? Já sám miluji přecházení mezi nativním a “managed” kódem, ale asi nemá smysl, abych tyto tipy psal na blog, jestliže o nativní kód (již) nikdo nestojí.Potom by stačílo, abych je nechal utopeny ve fóru o mobilních zařízeních, kde poslouží podobným individuím jako jsem já. V zásobě mám například často kladený dotaz, jak ve Windows Mobile dialogu zachytit WM_KEY zprávy.
I když sám si stále programování v (Compact) .Net frameworku bez dobré znalosti nativního kódu nedovedu představit - což je v roce 2009 možná tristní a nečekaná zpráva.
2) A obecnější dotaz – zajímají někoho z vás tipy pro Windows Mobile/Compact .Net Framework? Pro mě, jak asi tušíte, je programování pro WIN Mobile zařízení potěšení, a proto se podobné tipy objevují i na blogu, který píšu hlavně pro zábavu. I když většinu času jsem nyní strávil vývojem v Silverlightu, WPF, WCF a léčením roztomilých neštovic na zpočátku krásné tváři Linq2SQL, což znamená, že se na blogu se objeví i další témata, která se budou točit kolem návrhu různých typů aplikací a jako bonus odhalíme nejčastější průšvihy spojené s anemickými modely (i model-view-viewmodely
)aplikací.
// FullScreen.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "FullScreen.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE g_hInst; // current instance
HWND g_hWndMenuBar; // menu bar handle
RECT usedRect;
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE, LPTSTR);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
void MakeFullScreen();
void MakeFullScreen(HWND hWnd)
{
SetRect(&usedRect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
LONG windowWidth = usedRect.right - usedRect.left;
LONG windowHeight = usedRect.bottom - usedRect.top;
MoveWindow(hWnd,
usedRect.left,
usedRect.top,
windowWidth,
windowHeight,
FALSE);
//SIPINFO info;
//info.cbSize = sizeof(info);
//ZeroMemory(&info, sizeof(info));
//info.rcVisibleDesktop = usedRect;
//
//if (!::SipSetInfo(&info))
//{
// int error = GetLastError();
// return FALSE;
//}
SHFullScreen(hWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON);
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable;
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_FULLSCREEN));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_FULLSCREEN));
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = szWindowClass;
return RegisterClass(&wc);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
TCHAR szTitle[MAX_LOADSTRING]; // title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // main window class name
g_hInst = hInstance; // Store instance handle in our global variable
// SHInitExtraControls should be called once during your application's initialization to initialize any
// of the device specific controls such as CAPEDIT and SIPPREF.
SHInitExtraControls();
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_FULLSCREEN, szWindowClass, MAX_LOADSTRING);
//If it is already running, then focus on the window, and exit
hWnd = FindWindow(szWindowClass, szTitle);
if (hWnd)
{
// set focus to foremost child window
// The "| 0x00000001" is used to bring any owned windows to the foreground and
// activate them.
SetForegroundWindow((HWND)((ULONG) hWnd | 0x00000001));
return 0;
}
if (!MyRegisterClass(hInstance, szWindowClass))
{
return FALSE;
}
hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
// When the main window is created using CW_USEDEFAULT the height of the menubar (if one
// is created is not taken into account). So we resize the window after creating it
// if a menubar is present
if (g_hWndMenuBar)
{
RECT rc;
RECT rcMenuBar;
GetWindowRect(hWnd, &rc);
GetWindowRect(g_hWndMenuBar, &rcMenuBar);
rc.bottom -= (rcMenuBar.bottom - rcMenuBar.top);
MoveWindow(hWnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, FALSE);
}
ShowWindow(hWnd, nCmdShow);
//MakeFullScreen(hWnd);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
LPWINDOWPOS pos;
static SHACTIVATEINFO s_sai;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_HELP_ABOUT:
DialogBox(g_hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, About);
break;
case IDM_OK:
SendMessage (hWnd, WM_CLOSE, 0, 0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_CREATE:
SHMENUBARINFO mbi;
memset(&mbi, 0, sizeof(SHMENUBARINFO));
mbi.cbSize = sizeof(SHMENUBARINFO);
mbi.hwndParent = hWnd;
mbi.nToolBarId = IDR_MENU;
mbi.hInstRes = g_hInst;
if (!SHCreateMenuBar(&mbi))
{
g_hWndMenuBar = NULL;
}
else
{
g_hWndMenuBar = mbi.hwndMB;
}
// Initialize the shell activate info structure
memset(&s_sai, 0, sizeof (s_sai));
s_sai.cbSize = sizeof (s_sai);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
CommandBar_Destroy(g_hWndMenuBar);
PostQuitMessage(0);
break;
case WM_WINDOWPOSCHANGED:
pos = (LPWINDOWPOS) lParam;
if ((pos->cx != usedRect.right - usedRect.left) ||
(pos->cy != usedRect.bottom - usedRect.top))
{
MakeFullScreen(hWnd);
}
break;
case WM_ACTIVATE:
// Notify shell of our activate message
SHHandleWMActivate(hWnd, wParam, lParam, &s_sai, FALSE);
break;
case WM_SETTINGCHANGE:
SHHandleWMSettingChange(hWnd, wParam, lParam, &s_sai);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
// Create a Done button and size it.
SHINITDLGINFO shidi;
shidi.dwMask = SHIDIM_FLAGS;
shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_EMPTYMENU;
shidi.hDlg = hDlg;
SHInitDialog(&shidi);
}
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
case WM_CLOSE:
EndDialog(hDlg, message);
return TRUE;
}
return (INT_PTR)FALSE;
}
Tuesday, April 14, 2009 3:04:43 PM (Central Europe Standard Time, UTC+01:00)
Compact .Net Framework | Nativní kód

Monday, February 16, 2009
GSM Net Monitor verze 0.9.0
Homepage aplikace.
Instalační cab.
Návod na rozchození lokalizace pozice pomocí BTS

Změny ve verzi 0.0.9.
- Vylepšena stabilita aplikace. Pro znalce: Přesně řečeno, při startu pluginu se žádným způsobem nepracuje s RIL knihovnou. Pokud by při inicializaci pluginu byly stále na některých zařízeních potíže, zbývá už jen načítat RIL funkce dynamicky přes LoadLibrary.
- V souboru se zachycenými BTS se na každém řádku (poslední údaj) vypisuje informace o síti (network id). (ukázka -26.01.2009;12:41:26;18208;43649;-1;23001;) Přidáno na žádost lovců BTS.
Důležité:
Před instalací nové verze vypněte v aplikaci sledování sítě. Nejlépe starou verzi také sami deaktivujte v nastavení Today obrazovky a odnistalujte ji přes applet Přidat-Odebrat programy.
Protože se jedná o AlFA preview, doporučuji před instalaci Net Monitoru mít v zařízení např. SPB Pocket Plus a v něm aktivovaný safe boot - jestliže by vám "vytuhlo" zařízení, nebudete muset dělat HR (Hard Reset), protože můžete při startu zařízení dočasně deaktivovat Today pluginy.
Program pro jistotu ani nezkoušejte na zařízení, kde je nahráno TouchFlo, nebo jiný agresivní Today plugin. Riskujete zatuhnutí zařízení a je zbytečné mi potom psát dojemné maily, pokud nejste schopni si předtím udělat zálohu PDA nebo alespoň mít funkční safe-boot.
Po upgradu budete muset pravděpodobně znovu zadat svůj registrovaný email a přístupový kód. Pokud jste jej zapomněli, jděte na stránku http://gsmadmin.renestein.net a zadejte znovu svůj email. Aplikace vám nabídne opětovné zaslání emailu s přístupovým kódem.
Jestliže máte zařízení s VGA displejem, v pluginu jsou malé ikony a plugin je vykreslován na malé ploše. Plugin může být vykreslen na větší ploše - přes kontexové menu zobrazte Nastavení pluginu a změňte na záložce Základní nastavení preferovanou výšku na obrazovce Dnes. Ikony ale stejně zůstanou malé, proto chystám plnohotnotnou VGA verzi, do té doby lze plugin plně ovládat přes kontextové menu.

Monday, February 16, 2009 12:52:47 PM (Central Europe Standard Time, UTC+01:00)
Mobilitky | Nativní kód | Net Monitor

Wednesday, February 04, 2009
Textbox nepodporující výběr textu a další specialitky
Někdy se hodí mít textbox, u kterého je skrytý "caret" (netuší někdo, jak se termín caret překládá - pouze kurzor?) a současně nepodporuje označování textu. Také můžete chtít, aby se textbox choval podobně jako při nastavení vlastnosti ReadOnly na true, ale bez "zašedlého" zobrazení textboxu, což je většinou nechtěný průvodní jev textových polí označených pouze pro čtení.
Kód je pro Compact .Net Framework, nic vám ale nebrání přenést jej na "velký" NF. Ke zpracování Windows zpráv je použita třída NativeWindow, která je součástí OpenNetCF frameworku. Opravdu jen tato podivná sekvence zpracování Windows zpráv byla v CNF ta pravá.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using OpenNETCF.Windows.Forms;
namespace HideCaret
{
public class NativeTxtWrapper : NativeWindow
{
[DllImport("CoreDll.dll")]
private static extern bool ShowCaret(IntPtr hWnd);
[DllImport("CoreDll.dll")]
private static extern bool HideCaret(IntPtr hWnd);
private TextBox m_txtBox;
private bool m_hasFullFocus;
private const int WM_LBUTTONDOWN = 0x201;
private const int WM_KEYDOWN = 0x0100;
private const int WM_MOUSEMOVE = 0x0200;
private const int WM_CHAR = 0x0102;
private const int WM_COMMAND = 0x0111;
private const int WM_LBUTTONUP = 0x0202;
private const int WM_LBUTTONDBLCLK = 0x0203;
private const int WM_PAINT = 0x000F;
private const int WM_KILLFOCUS = 0x0008;
private const int WM_SETFOCUS = 0x0007;
public NativeTxtWrapper(TextBox txtBox)
{
init(txtBox);
m_hasFullFocus = false;
}
private void init(TextBox txtBox)
{
if (txtBox == null)
{
throw new ArgumentNullException("txtBox");
}
if (txtBox.Handle != IntPtr.Zero)
{
AssignHandle(txtBox.Handle);
}
txtBox.HandleCreated += ((sender, e) => AssignHandle(((Form)sender).Handle));
txtBox.HandleDestroyed += ((sender, e) => ReleaseHandle());
m_txtBox = txtBox;
}
protected override void WndProc(ref Microsoft.WindowsCE.Forms.Message m)
{
if (m.Msg == WM_CHAR)
{
m_hasFullFocus = true;
}
if (m.Msg == WM_MOUSEMOVE || m.Msg == WM_LBUTTONDBLCLK)
{
return;
}
if (((m.Msg == WM_LBUTTONUP) ||
(m.Msg == WM_LBUTTONDOWN)) && m_hasFullFocus)
{
return;
}
if (m.Msg == WM_SETFOCUS)
{
base.WndProc(ref m);
HideCaret(m_txtBox.Handle);
return;
//m_hasFocus = false;
}
if (m.Msg == WM_KILLFOCUS)
{
m_hasFullFocus = false;
}
base.WndProc(ref m);
}
}
}
Jestliže chcete textbox pouze pro čtení, stačí nepředat ke zpracování bázové třídě (base.WndProc) zprávu WM_CHAR.
Objektem NativeTxtWrapper lze oddekorovat jakýkoli textbox, nebo můžete vytvořit potomka třídy Textbox, který před klienty třídy skryje použití objektu NativeTextWrapper
private void Form1_Load(object sender, EventArgs e)
{
m_wrapper = new NativeTxtWrapper(textBox1);
textBox1.Focus();
}
Podobnou třídu mám i pro nativní projekty psané v MFC, možná se někomu z vás bude hodit. Přepsat kód do Windows API z MFC je také trivální.
#pragma once
#include "afxwin.h"
class CTextBoxEx :
public CEdit
{
private:
bool m_hasFullFocus;
public:
CTextBoxEx(void);
~CTextBoxEx(void);
virtual LRESULT WindowProc(UINT message, WPARAM wparam, LPARAM lparam);
};
#include "StdAfx.h"
#include "TextBoxEx.h"
CTextBoxEx::CTextBoxEx(void) : m_hasFullFocus(false)
{
}
CTextBoxEx::~CTextBoxEx(void)
{
}
LRESULT CTextBoxEx::WindowProc(UINT message, WPARAM wparam, LPARAM lparam)
{
//Readonly textbox
if (message == WM_CHAR)
{
return 1;
}
//end Readonly textbox
POINT mousePoint;
GetCursorPos(&mousePoint);
ScreenToClient(&mousePoint);
RECT clientRect;
GetClientRect(&clientRect);
BOOL isMouseInRect = PtInRect(&clientRect, mousePoint);
if (((message == WM_MOUSEMOVE) || (message == WM_LBUTTONDBLCLK)) && isMouseInRect)
{
return 1;
}
if (((message == WM_LBUTTONUP) ||
(message== WM_LBUTTONDOWN)) && m_hasFullFocus && isMouseInRect)
{
return 1;
}
if (message == WM_SETFOCUS)
{
m_hasFullFocus = true;
HideCaret();
return 1;
}
if (message == WM_KILLFOCUS)
{
m_hasFullFocus = false;
}
return CEdit::WindowProc(message, wparam, lparam);
}
Wednesday, February 04, 2009 4:52:26 PM (Central Europe Standard Time, UTC+01:00)
.NET Framework | Compact .Net Framework | Nativní kód | Windows Forms

Wednesday, July 30, 2008
GSM Net Monitor verze 0.7.0. Alfa
Homepage aplikace.
Instalační cab.
Návod na rozchození lokalizace pozice pomocí BTS
Změny ve verzi 0.0.7.
- Odstraněna chyba, která se mohla vyskytnout při odesílání požadavku na server => Net Monitor vypisoval chybu 2 (špatné formátování).
Důležité:
Před instalací nové verze vypněte v aplikaci sledování sítě.
Protože se jedná o AlFA preview, doporučuji před instalaci Net Monitoru mít v zařízení např. SPB Pocket Plus a v něm aktivovaný safe boot - jestliže by vám "vytuhlo" zařízení, nebudete muset dělat HR (Hard Reset), protože můžete při startu zařízení dočasně deaktivovat Today pluginy.
Po upgradu budete muset pravděpodobně znovu zadat svůj registrovaný email a přístupový kód. Pokud jste jej zapomněli, jděte na stránku http://gsmadmin.renestein.net a zadejte znovu svůj email. Aplikace vám nabídne opětovné zaslání emailu.
Wednesday, July 30, 2008 4:06:40 PM (Central Europe Standard Time, UTC+01:00)
Mobilitky | Nativní kód | Net Monitor

Monday, July 28, 2008
Technologie použité při vývoji Net Monitoru
V mailu jsem dostal dotaz, v "čem je napsán" GSM Net Monitor. Možná to bude zajímat i někoho dalšího, protože v Net Monitoru se potkává paleolit s postmodernim věkem . :) Při vývoji aplikace si uvědomíte nejen, kde vám .Net Framework šetří práci, ale i to, kde by jeho režie byla spíš na obtíž, a v čem exceluje C++. Soukromý povzdech: C# generika je skvělá, ale C++ šablony u mě kralují...
Serverová část - databáze MSSQL 2005, ASP.NET 3.5, Windows Communication Foundation 3.5 s podporou toho, čemu se podivně říká REST, LINQ s vlastními "extenzními" metodami, jazyk C#.
Klientská část na PDA - pouze Windows API - protože jsem chtěl, aby aplikace neměla přehnané paměťové nároky, nepoužil jsem ani COM XML parser od Microsoftu a jen doufám, že Windows CE team portuje desktopovou knihovnu XmlLite. Jazyk C++.
Monday, July 28, 2008 10:11:54 AM (Central Europe Standard Time, UTC+01:00)
Mobilitky | Nativní kód | Net Monitor

Monday, July 07, 2008
Víte, u kolika českých BTS už zná Google jejich přibližnou polohu? Aneb Google Maps Mobile
Google má ve svém program Google Maps Mobile užitečnou funkci pro přibližné určení polohy bez použití GPS. Volba "Moje Poloha" se pokusí o lokalizaci na základě pozice GSM buňky (buněk), ke které je momentálně přihlášen váš mobilní telefon. Od počátku bylo zřejmé, že Google musí sbírat informace o pozici GSM buněk "za pochodu", protože žádné oficiální, a navíc celosvětové, databáze BTS neexistují. Google tedy pravděpodobně na své servery anonymně odesílá informace o aktuální GSM buňce společně s GPS souřadnicemi vždy, když v GM Mobile zapnete GPS. Viz také diskuze pod článkem na Navigovat.cz, který upozorňoval na novou verzi GM Mobile. Dohady potvrdil i můj pokus, kdy jsem několikrát na místech, kde aplikace GM Mobile nejprve sveřepě odmítala zobrazit pozici na základě buňky, pustil GPS, a za několik hodin/dní jsem již byl lokalizován jen přes funkci "Moje poloha".
A jak je na tom Google dnes (7. 7. 2008) s "pokrytím" v ČR? Do statistiky jsou zahrnuty jen buňky v GSM síti (ne UMTS) společností T-Mobile, O2 a Vodafone, jejichž (neoficiální) seznamy naleznete na gsmweb.cz. Celkový počet GSM buněk, u nichž jsem zjištoval "pokrytí" Googlem, je tedy dán součtem evidovaných GSM buněk v odpovídajících seznamech na gsmweb.cz.
Celkem sledováno GSM buněk: 34 773
Z toho buněk s GPS souřadnicemi: 19 435
T-Mobile celkem buněk / z toho s GPS souřadnicemi: 11 060 / 6 379
O2 celkem buněk/z toho s GPS souřadnicemi: 11588 / 6 838
Vodafone celkem buněk/z toho s GPS souřadnicemi: 12125 / 6218
Prosím, neptejte se, jak jsem se k těmto údajům dostal, stejně vám to neřeknu ani nenapíšu. :) A do Googlu asi také nemá cenu psát. :)
Monday, July 07, 2008 6:50:45 PM (Central Europe Standard Time, UTC+01:00)
Mobilitky | Nativní kód

Wednesday, May 28, 2008

Thursday, January 10, 2008
Wifi profily verze 0.0.4
Verze 0.0.4.
Stáhnout cab: !!!Důležité: Není povoleno cab soubor dále redistribuovat nebo vystavovat na svých stránkách - musí být stažen z mých stránek!!!
Diskuze k programu:
1) Sjednocení EN a CZ verze - podpora pro libovolné množství dalších jazyků.
Aplikace se spustí v angličtině, do češtiny se přepnete vybráním položky Language menu a zvolením CZ v dalším dialogu.
2) Možnost nastavení internetové http proxy. Podpora vrácení se k poslednímu stavu připojení před aplikací proxy. Abyste požívali proxy v Pocket IE a dalších programech, musíte nastavit u wifi sítě, že se připojuje k profilu work. Nové nastavení vás připojí přes proxy na internet - nechci zabíhat do detailů, "global wide proxy" jsou poměrně komplikovaná záležitost a pro jejich programové nastavení neexistuje pořádná dokumentace. :(
Pokud bude zájem, mohu přidat socks proxy.
3) Možnost samostatně z menu nebo i u každého profilu nastavit, zda se má wifi odpojit při vypnutí zařízení. Upozorňuji, že u některých zařízení musíte pro uplatnění hodnot (podobně jako je tomu při zapínání wifi) sami zapnout wifi po soft resetu z manažera připojení před nastavením způsobu odpojování wifi.
4) Možnost spustit po aplikaci profilu (resp. po připojení k wifi síti - platné SSID) libovolný program. Jestliže není wifi síť připojena nebo nelze detekovat připojení k wifi síti, je program spuštěn po uplynuti 20 s.
Pro program je možné zadat příkazový řádek. V příští verzi nebudete muset zadávat cestu k programu sami do textového pole, ale v dialogu si program sami vyberete.
5) Možnost vytvořit si zástupce přímo pro profil (např. v Total Commanderu CE) - profil lze aplikovat vytvořením zástupce s příkazem v následujícím tvaru.
"<Cesta k exe>" <Nazev profilu>
Tedy např. tento zástupce aktivuje profil s názvem MujProfil.
"\Storage Card\Program Files\RStein\WifiProfiles\RStein.WifiProfiles3.exe" MujProfil
6) Možnost nainstalovat aplikaci na SD kartu.
7) Volba v profilu, zda má být po aktivaci profilu zapnuta wifi.
8) Po zvolení DHCP=Ano jsou nepoužívané volby v konfiguraci profilu skryty.
Za nesprávné používání aplikace ani za možné vzniklé škody a následné hard resety nenesu žádnou odpovědnost! To pro jistotu připomínám . :)
Enjoy :)
Thursday, January 10, 2008 8:40:54 PM (Central Europe Standard Time, UTC+01:00)
Mobilitky | Nativní kód | Wifi Profiles Windows Mobile