About ant commands :
You can create your own command processor with ant (you are able to create elements and ant is able to process commands in ants way (using xml to join parts )
For example for search and replace there is a command that is mapped to java or to implemented in other language application
<replaceregexp file="file" match="pattern" replace="pattern"
flags="options"
byline="true|false" /> ;
it is actually a prepared a java class(s) that do the job
Is Ant depends on Java JRE or it is a separate native application? I think it is...
Probably that's why Java and Ant is so close...
I also would like to understand how preprocessor works in Eclipse. It may helps me with my tasks
Tuesday, January 4, 2011
Wednesday, December 22, 2010
Android Ant builder
Android build process is quite complicated
First of all it is based on ant script together with sdk tools and java apps aligned to ant.
Lets take a closer look to it
to create ant script manually just type:
cmd <enter>
if you don't have Android SDK folder in system PATH environmental variable - add it
set path=%path%;X:\android\android-sdk-windows-1.5_r3\tools
now you can create new or update existent eclipse project
(I assume that you like me create project in eclipse first and then, for some reason, you need to build your fancy application from command line
set current dir to your android project dir
cd c:\apps\myapp <enter>
android update project <enter>
now you have build.xml in your projects root folder
for now you can open them in eclipse but you cannot build (execute) ant script from eclipse
The problem is in java component that connect you build.xml ant script with platform dependent android ant script that located in SDK
for example for API level 8 it will be android_rules_r3.xml.
File contains a lot of comments about every section
but I'll explain some of them just for those who who know nothing about ant engine :)
Ant stuff
I will explain only things that I need to build android project manually
every project contains
<project name="myapps" default="<default target>" basedir=<path to your android project>
...
project>
nice to see basedir here because you are able to move you Ant script
main concept of ant is targets (like "release", "debug", "release-signed", ets.)
every target could have dependency on other targets
and targets could be public and private (hidden)
for example simple target:
<target name="help">
<echo>This project has extended helpecho>
target>
complex target
<target name="release" depends="resources, java_compiler, zip, sign, renameing">
target>
you can specify properties ( they are playing the same function as variables in other languages )
<property name="app.file.name" value="${build.prop.name}" />
let me explain this
you can read/ write app.file.name using ${app.file.name} sintax
in sample you define property and set value for it equal to value of build.prop.name property
you could override this prop value in build.properties file
lets call it first level of customization
you also able to define properties in build.properties and then load to project
<property file="build.properties"/>
Combination of both <property name.../> and <property file=.../> creates a list of properties that could be redefined in a separate settings file
Example:
<property name="one" value="ha-ha"/>
<property file="build.properties"/>
now we can move to targets and other xml elements
<taskdef name="setup" classname="com.android.ant.SetupTask"
classpathref="android.antlibs"/>
Defines a java class with a starting "main" point in com.android.ant.SetupTask.
reference android.antlibs - a link to path(s) where SetupTask could be found.
All android elements (tags) could use (execute) this application
using <setup>setup> tag
few more samples
<taskdef name="apkbuilder"
classname="com.android.ant.ApkBuilderTask"
classpathref="android.antlibs" />
<taskdef name="xpath"
classname="com.android.ant.XPathTask"
classpathref="android.antlibs" />
usage:
<xpath input="AndroidManifest.xml" expression="/manifest/@package"
output="manifest.package" />
<aaptexec executable="${aapt}"
command="package"
verbose="${verbose}"
manifest="AndroidManifest.xml"
androidjar="${android.jar}"
rfolder="${gen.absolute.dir}">
aaptexec>
if you command sequence that you have to use in different targets you could write a macro
definition:
<macrodef name="dex-helper">
<element name="external-libs" optional="yes" />
<element name="extra-parameters" optional="yes" />
<sequential>
<echo>Converting compiled files and external libraries into ${intermediate.dex.file}...echo>
sequential>
macrodef>usage:
<dex-helper />
or
<dex-helper>
<extra-parameters>
<arg value="--no-locals" />
extra-parameters>
<external-libs>
<fileset file="${emma.dir}/emma_device.jar" />
external-libs>
dex-helper/>
I hope you've got the idea.
Now about problem I met
for android platform 2.2 (API level 8)
if you open build script that contains external targets (targets that were defined in android_rules_r3.xml or other external files)
in eclipse. you've get ant compilation errors (unknown target)
if you run the same script (build.xml) from command promt - it works fine
for example in case with auto-generated build.xml
this one return error unknown help target if you open it in eclipse
after that you are not able to compile you app!!!
As a not very good solution is moving build.xml file outside project root dir in this case eclipce will not see it and you can add to get it working from command line
First of all it is based on ant script together with sdk tools and java apps aligned to ant.
Lets take a closer look to it
to create ant script manually just type:
cmd <enter>
if you don't have Android SDK folder in system PATH environmental variable - add it
set path=%path%;X:\android\android-sdk-windows-1.5_r3\tools
now you can create new or update existent eclipse project
(I assume that you like me create project in eclipse first and then, for some reason, you need to build your fancy application from command line
set current dir to your android project dir
cd c:\apps\myapp <enter>
android update project <enter>
now you have build.xml in your projects root folder
for now you can open them in eclipse but you cannot build (execute) ant script from eclipse
The problem is in java component that connect you build.xml ant script with platform dependent android ant script that located in SDK
for example for API level 8 it will be android_rules_r3.xml.
File contains a lot of comments about every section
but I'll explain some of them just for those who who know nothing about ant engine :)
Ant stuff
I will explain only things that I need to build android project manually
every project contains
<project name="myapps" default="<default target>" basedir=<path to your android project>
...
project>
nice to see basedir here because you are able to move you Ant script
main concept of ant is targets (like "release", "debug", "release-signed", ets.)
every target could have dependency on other targets
and targets could be public and private (hidden)
for example simple target:
<target name="help">
<echo>This project has extended helpecho>
target>
complex target
<target name="release" depends="resources, java_compiler, zip, sign, renameing">
target>
you can specify properties ( they are playing the same function as variables in other languages )
<property name="app.file.name" value="${build.prop.name}" />
let me explain this
you can read/ write app.file.name using ${app.file.name} sintax
in sample you define property and set value for it equal to value of build.prop.name property
you could override this prop value in build.properties file
lets call it first level of customization
you also able to define properties in build.properties and then load to project
<property file="build.properties"/>
Combination of both <property name.../> and <property file=.../> creates a list of properties that could be redefined in a separate settings file
Example:
<property name="one" value="ha-ha"/>
<property file="build.properties"/>
now we can move to targets and other xml elements
<taskdef name="setup" classname="com.android.ant.SetupTask"
classpathref="android.antlibs"/>
Defines a java class with a starting "main" point in com.android.ant.SetupTask.
reference android.antlibs - a link to path(s) where SetupTask could be found.
All android elements (tags) could use (execute) this application
using <setup>setup> tag
few more samples
<taskdef name="apkbuilder"
classname="com.android.ant.ApkBuilderTask"
classpathref="android.antlibs" />
<taskdef name="xpath"
classname="com.android.ant.XPathTask"
classpathref="android.antlibs" />
usage:
<xpath input="AndroidManifest.xml" expression="/manifest/@package"
output="manifest.package" />
<aaptexec executable="${aapt}"
command="package"
verbose="${verbose}"
manifest="AndroidManifest.xml"
androidjar="${android.jar}"
rfolder="${gen.absolute.dir}">
aaptexec>
if you command sequence that you have to use in different targets you could write a macro
definition:
<macrodef name="dex-helper">
<element name="external-libs" optional="yes" />
<element name="extra-parameters" optional="yes" />
<sequential>
<echo>Converting compiled files and external libraries into ${intermediate.dex.file}...echo>
sequential>
macrodef>usage:
<dex-helper />
or
<dex-helper>
<extra-parameters>
<arg value="--no-locals" />
extra-parameters>
<external-libs>
<fileset file="${emma.dir}/emma_device.jar" />
external-libs>
dex-helper/>
I hope you've got the idea.
Now about problem I met
for android platform 2.2 (API level 8)
if you open build script that contains external targets (targets that were defined in android_rules_r3.xml or other external files)
in eclipse. you've get ant compilation errors (unknown target)
if you run the same script (build.xml) from command promt - it works fine
for example in case with auto-generated build.xml
this one return error unknown help target if you open it in eclipse
after that you are not able to compile you app!!!
As a not very good solution is moving build.xml file outside project root dir in this case eclipce will not see it and you can add
Tuesday, November 30, 2010
Java final String optimisation
Some times I need a sub string of a string and I noticed that if you add final keyword, Java compiler makes a small optimization, isn't it?
For example :
String name = "this is a simple string";
String simple = name.substring(0,4);
Here Java creates two strings
but if you write this code in different way you get rid of one extra allocation
final String name = "this is a simple string";
final String simple = name.substring(0,4);
Both objects points to the same memory block and String object itself has a constant context
Am I right?
I am not sure about this conclusions, so, I will check it again when I have time.
If you know something how to use final for Strings and what exactly java compiler does,
I'll be pleased if someone share his knowledges in this area
For example :
String name = "this is a simple string";
String simple = name.substring(0,4);
Here Java creates two strings
but if you write this code in different way you get rid of one extra allocation
final String name = "this is a simple string";
final String simple = name.substring(0,4);
Both objects points to the same memory block and String object itself has a constant context
Am I right?
I am not sure about this conclusions, so, I will check it again when I have time.
If you know something how to use final for Strings and what exactly java compiler does,
I'll be pleased if someone share his knowledges in this area
Bugs aligned to CString
Today I noticed a funny thing. Class CString C++ sometimes works like class String in Java
For example :
Conclusion : don't mix API because you never know about class implementation.
Fix is simple, just use mText.Empty() or mText[n] to modify string and never (LPTSTR)(mText)[n]
For example :
class Example
{
CString mName;
public:
void setName(const CString & name)
{
mName = name;
}
void modify()
{
memset((VPVOID)(LPTSTR) mName,65,mName.GetLength()*sizeof(TCHAR));
}
}
class Other
{
// we set up this name somewere in code
public:
CString getName() const
{
return mName;
}
}
void main()
{
std::autoptr o1 =
std::autoptr(
new Other(_T("simple string")));
Example ex1;
ex.setName( o1->getName() );
ex.modyfy();
// here you will have empty string for o1 and for ex classes
// because it refers to the same string data in memory
// so both
classes will contain modified data
}
Conclusion : don't mix API because you never know about class implementation.
Fix is simple, just use mText.Empty() or mText[n] to modify string and never (LPTSTR)(mText)[n]
Saturday, July 24, 2010
Windows messaging system
How I understand windows messaging system
I have taken a look to MFC, WTL frameworks and desided to explain some moments aligned to window creation and user interaction on Windows API level
Creating a Window
To create window in Windows OS you call CreateWindow(className,...)
There is a enum of predefined classes
COMBOBOX, BUTTON, STATIC, LISTBOX and other default classes
As far as thay are already pressent in the system they asosiated with WindowProc. Actually every window class is asociated with windowProc inside OS.
What is window proc? it is just a function like below
INT_PTR CALLBACK MyDialog_DialogProc( HWND hwnd,
UINT messageId,
WPARAM wParam,
LPARAM lParam )
WindowProc is responsible for the window message processing. Thats why BUTTON for example looks like button :) , so to create a dialog not from window resources you need. To understand how OS GUI works lets create a dialog manually and not using resource file for that.
Creating Dialog window not from recources
1. register class
WNDCLASS wndClass = {0};
wndClass.lpfnWndProc = (WNDPROC)MyDialog_DialogProc;
wndClass.lpszClassName = L"DIALOG";
ATOM atom = RegisterClass(&wndClass);
HWND dialogHwnd = CreateWindow(L"DIALOG", L"MyDlg", ~WS_DLGFRAME & ~WS_CLIPSIBLINGS, 10,10, 200,200, NULL, (HMENU)0, instance, 0);
You can change this default WindowProc and this process is so calling subclassing
There is a lot of windows messages so if you don't need (or you don't want) to process all of them you need to call oldWindowProc to process messages that your new WindowProc doesn't process
I found that class "DIALOG" is not a default class in windows. This class creates when you are going to create a dialog based on recource file. When you create dialog from recource (using CreateDialog for example) this function register dialog class read resource file read styles inside dialog and raise WM_INITDIALOG and othe windows messages (WM_FONT is GWS_FONT defined) and after that call ShowWindow (if GWS_VISIBLE is defined)
all this steps is strictly synchronous because SendMessage is sync function.
How windows looks depends on window class and on windows style
Message handling
As you may know some messages are received in thread queue others processed directly in WindowProc so you will never get WM_SIZE using GetMessage() or similar function
But messages from mouse and keybord will be sent to system queue
for example for erlier created messages in the same thread we use:
MSG msg;
while (GetMessage(&msg,0,0,0))
{
TCHAR buffer[MAX_PATH] = {0};
TCHAR windowName[MAX_PATH] = {0};
GetWindowText( msg.hwnd, windowName, MAX_PATH);
swprintf(buffer,L"Handle [0x%X] WindowName [%s] Message: [0x%X] \n",msg.hwnd, windowName , msg.message);
OutputDebugString(buffer);
DispatchMessage(&msg);
}
Handle [0x0] WindowName [] Message: [0xC0B1]
Handle [0x0] WindowName [] Message: [0xC0B1]
Handle [0x60878] WindowName [MyDlg] Message: [0xF] // WM_PAINT
Handle [0x60870] WindowName [ClickMe] Message: [0xF] // WM_PAINT
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B7]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B9]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B9]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B9]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B9]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B9]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
from the log we can see that only WM_PAINT message we receive from GetMessage. Messages with 0 handle are messages not aligned to windows. There is also a CicMarshalWndAJCB but we didn't create window with such mane. I created only two windows "ClickMe" and "MyDlg" so what is "CicMarshalWndAJCB" for?
of cource when I move my mouse to that window I receive all mouse/keyboard input messages like WM_MOUSEMOVE WM_KEYDOWN and othe hardware messages
In the Internet I also could not find any information about that window , so if someone reading this could help, please do
To complete this article I put log in dialog window proc to better understand what messages come first
WindowProc Log
Handle [0x3B086A] Message: [0x24] //WM_GETMINMAXINFO
Handle [0x3B086A] Message: [0x81] //WM_NCCREATE
Handle [0x3B086A] Message: [0x83] //WM_NCCALCSIZE
Handle [0x3B086A] Message: [0x1] //WM_CREATE
Handle [0x3B086A] Message: [0xD] //WM_GETTEXT my call
Handle [0x3B086A] WindowName [MyDlg] Message: [0x1] //WM_CREATE we receive only one wm create but I put log just to be sure that windowname is MyDlg
Handle [0x3B086A] Message: [0x210] // WM_PARENTNOTIFY
Handle [0x3B086A] Message: [0x18] //WM_SHOWWINDOW
Handle [0x3B086A] Message: [0x46] // WM_WINDOWPOSCHANGING
Handle [0x3B086A] Message: [0x46] // WM_WINDOWPOSCHANGING // this call from thread
Handle [0x3B086A] Message: [0x1C] // WM_ACTIVATEAPP
Handle [0x3B086A] Message: [0x86] // WM_NCACTIVATE
Handle [0x3B086A] Message: [0xD] // WM_GETTEXT
Handle [0x3B086A] Message: [0x6] // WM_ACTIVATE
Handle [0x3B086A] Message: [0x7] // WM_SETFOCUS
Handle [0x3B086A] Message: [0x85] // WM_NCPAINT
Handle [0x3B086A] Message: [0xD] // WM_GETTEXT
Handle [0x3B086A] Message: [0x14] // WM_ERASEBKGND !! I have handled it
Handle [0x3B086A] Message: [0x47] // WM_WINDOWPOSCHANGED
Handle [0x3B086A] Message: [0x5] // WM_SIZE
Handle [0x3B086A] Message: [0x3] // WM_MOVE
Handle [0x3B086A] Message: [0x7F] // WM_GETICON
Handle [0x3B086A] Message: [0x7F] // WM_GETICON
Handle [0x3B086A] Message: [0x7F] // WM_GETICON
Handle [0x3B086A] Message: [0xF] // WM_PAINT
Handle [0x3B086A] Message: [0x135] // WM_CTLCOLORBTN ClickMe send this message to parent
So this mechanism works very good
all other stuff and errors and a lot of complains alligned to higher level of API in user mode. Teoretically it is possible to rewrite user mode API to have very simple and ea sy to use operating system. I think this is might be done by 3rd party vendows that works with Windows CE OS
I have taken a look to MFC, WTL frameworks and desided to explain some moments aligned to window creation and user interaction on Windows API level
Creating a Window
To create window in Windows OS you call CreateWindow(className,...)
There is a enum of predefined classes
COMBOBOX, BUTTON, STATIC, LISTBOX and other default classes
As far as thay are already pressent in the system they asosiated with WindowProc. Actually every window class is asociated with windowProc inside OS.
What is window proc? it is just a function like below
INT_PTR CALLBACK MyDialog_DialogProc( HWND hwnd,
UINT messageId,
WPARAM wParam,
LPARAM lParam )
WindowProc is responsible for the window message processing. Thats why BUTTON for example looks like button :) , so to create a dialog not from window resources you need. To understand how OS GUI works lets create a dialog manually and not using resource file for that.
Creating Dialog window not from recources
1. register class
WNDCLASS wndClass = {0};
wndClass.lpfnWndProc = (WNDPROC)MyDialog_DialogProc;
wndClass.lpszClassName = L"DIALOG";
ATOM atom = RegisterClass(&wndClass);
HWND dialogHwnd = CreateWindow(L"DIALOG", L"MyDlg", ~WS_DLGFRAME & ~WS_CLIPSIBLINGS, 10,10, 200,200, NULL, (HMENU)0, instance, 0);
2. write a WindowProc
INT_PTR CALLBACK MyDialog_DialogProc( HWND hwnd,
UINT messageId,
WPARAM wParam,
LPARAM lParam )
{
if (messageId == WM_CREATE)
{
// create button
HINSTANCE hInstance = GetModuleHandle(NULL);
HWND myButton = CreateWindow(L"BUTTON", L"ClickMe"
, WS_CHILD, 10,10, 100,20, hwnd
,(HMENU)1, hInstance,0);
, WS_CHILD, 10,10, 100,20, hwnd
,(HMENU)1, hInstance,0);
if (!myButton)
{
// log error
}
ShowWindow(myButton, SW_SHOWNORMAL);
// create othe controls if there is a need!
return TRUE;
}
return DefWindowProc( hwnd, messageId, wParam, lParam);
}
There is a lot of windows messages so if you don't need (or you don't want) to process all of them you need to call oldWindowProc to process messages that your new WindowProc doesn't process
I found that class "DIALOG" is not a default class in windows. This class creates when you are going to create a dialog based on recource file. When you create dialog from recource (using CreateDialog for example) this function register dialog class read resource file read styles inside dialog and raise WM_INITDIALOG and othe windows messages (WM_FONT is GWS_FONT defined) and after that call ShowWindow (if GWS_VISIBLE is defined)
all this steps is strictly synchronous because SendMessage is sync function.
How windows looks depends on window class and on windows style
Message handling
As you may know some messages are received in thread queue others processed directly in WindowProc so you will never get WM_SIZE using GetMessage() or similar function
But messages from mouse and keybord will be sent to system queue
for example for erlier created messages in the same thread we use:
MSG msg;
while (GetMessage(&msg,0,0,0))
{
TCHAR buffer[MAX_PATH] = {0};
TCHAR windowName[MAX_PATH] = {0};
GetWindowText( msg.hwnd, windowName, MAX_PATH);
swprintf(buffer,L"Handle [0x%X] WindowName [%s] Message: [0x%X] \n",msg.hwnd, windowName , msg.message);
OutputDebugString(buffer);
DispatchMessage(&msg);
}
GetMessage Log:
Handle [0x0] WindowName [] Message: [0xC0B1]
Handle [0x60878] WindowName [MyDlg] Message: [0xF] // WM_PAINT
Handle [0x60870] WindowName [ClickMe] Message: [0xF] // WM_PAINT
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B7]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B9]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B9]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B9]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B9]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B9]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
Handle [0x6086E] WindowName [CicMarshalWndAJCB] Message: [0xC0B6]
from the log we can see that only WM_PAINT message we receive from GetMessage. Messages with 0 handle are messages not aligned to windows. There is also a CicMarshalWndAJCB but we didn't create window with such mane. I created only two windows "ClickMe" and "MyDlg" so what is "CicMarshalWndAJCB" for?
of cource when I move my mouse to that window I receive all mouse/keyboard input messages like WM_MOUSEMOVE WM_KEYDOWN and othe hardware messages
In the Internet I also could not find any information about that window , so if someone reading this could help, please do
To complete this article I put log in dialog window proc to better understand what messages come first
WindowProc Log
Handle [0x3B086A] Message: [0x24] //WM_GETMINMAXINFO
Handle [0x3B086A] Message: [0x81] //WM_NCCREATE
Handle [0x3B086A] Message: [0x83] //WM_NCCALCSIZE
Handle [0x3B086A] Message: [0x1] //WM_CREATE
Handle [0x3B086A] Message: [0xD] //WM_GETTEXT my call
Handle [0x3B086A] WindowName [MyDlg] Message: [0x1] //WM_CREATE we receive only one wm create but I put log just to be sure that windowname is MyDlg
Handle [0x3B086A] Message: [0x210] // WM_PARENTNOTIFY
Handle [0x3B086A] Message: [0x18] //WM_SHOWWINDOW
Handle [0x3B086A] Message: [0x46] // WM_WINDOWPOSCHANGING
Handle [0x3B086A] Message: [0x46] // WM_WINDOWPOSCHANGING // this call from thread
Handle [0x3B086A] Message: [0x1C] // WM_ACTIVATEAPP
Handle [0x3B086A] Message: [0x86] // WM_NCACTIVATE
Handle [0x3B086A] Message: [0xD] // WM_GETTEXT
Handle [0x3B086A] Message: [0x6] // WM_ACTIVATE
Handle [0x3B086A] Message: [0x7] // WM_SETFOCUS
Handle [0x3B086A] Message: [0x85] // WM_NCPAINT
Handle [0x3B086A] Message: [0xD] // WM_GETTEXT
Handle [0x3B086A] Message: [0x14] // WM_ERASEBKGND !! I have handled it
Handle [0x3B086A] Message: [0x47] // WM_WINDOWPOSCHANGED
Handle [0x3B086A] Message: [0x5] // WM_SIZE
Handle [0x3B086A] Message: [0x3] // WM_MOVE
Handle [0x3B086A] Message: [0x7F] // WM_GETICON
Handle [0x3B086A] Message: [0x7F] // WM_GETICON
Handle [0x3B086A] Message: [0x7F] // WM_GETICON
Handle [0x3B086A] Message: [0xF] // WM_PAINT
Handle [0x3B086A] Message: [0x135] // WM_CTLCOLORBTN ClickMe send this message to parent
So this mechanism works very good
all other stuff and errors and a lot of complains alligned to higher level of API in user mode. Teoretically it is possible to rewrite user mode API to have very simple and ea sy to use operating system. I think this is might be done by 3rd party vendows that works with Windows CE OS
NDK Android
Working in Android in the native level is quite interesting
To start working under Windows platform you need
1. Cygwin you need version for Windows
2. Go to Android NDK framework and download NDK, SDK
3. Install Eclipce and ADT plugin
Also you need JDK 1.5 or 1.6 installed
To Edit C++ sources you could install CDT C/C++ plugin Eclipce or use Microsoft Viusal Studio or Notepad++ with c++ plugin
Also download Android cpp sources. Using sources as manual you will understand more about what android consist of and will be able to all native library or drivers to extend Android functionality
To start working under Windows platform you need
1. Cygwin you need version for Windows
2. Go to Android NDK framework and download NDK, SDK
3. Install Eclipce and ADT plugin
Also you need JDK 1.5 or 1.6 installed
To Edit C++ sources you could install CDT C/C++ plugin Eclipce or use Microsoft Viusal Studio or Notepad++ with c++ plugin
Also download Android cpp sources. Using sources as manual you will understand more about what android consist of and will be able to all native library or drivers to extend Android functionality
Saturday, June 5, 2010
Subclassing child window using WTL
To create custom control you may use WM_DRAW_ITEM but this message you will receive in DLGPROC
So you have to draw control not in his own procedure but in parent one.
To resolve this complexity you can use subclassing with the child control.
If you are using WTL - all need to do is create class dediven not from standard WTL controls with other template parameter
For example for ATL::CListBox use
class CListBoxEx;
typedef CWindowImpl< CListBoxEx, CWindow, CControlWinTraits> CMyListBox;
template <>
HWND CListBoxT::Create(HWND hWndParent, ATL::_U_RECT rect, LPCTSTR szWindowName,
DWORD dwStyle, DWORD dwExStyle,
ATL::_U_MENUorID MenuOrID, LPVOID lpCreateParam)
{
return CMyListBox::Create( hWndParent
, rect
, szWindowName
, dwStyle
, dwExStyle
, MenuOrID
, lpCreateParam);
}
template <>
CListBoxT::CListBoxT(HWND hParentHwnd)
:CMyListBox()
{
if (::IsWindow(hParentHwnd))
{
CMyListBox::SetParent(hParentHwnd);
}
}
class CListBoxEx :
public CListBoxT
{
...
}
This code allows you create a control and using Subclass-window replace WNDPROC for that control class
Now we can create or subclass a control
class CList_boxDialog : public CAppStdDialogResizeImpl,
public CUpdateUI,
public CMessageFilter, public CIdleHandler
{
...
LRESULT OnInitDialog(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
..
CWindow wnd = GetDlgItem(IDC_LIST_ADAPTERS);
mListBox.SubclassWindow(wnd);
mListBox.SetParent(m_hWnd);
mListBox.ResetContent();
mListBox.AddString(_T("First"));
mListBox.AddString(_T("Second"));
..
}
..
CListBoxEx mListBox;
}
Code above get controls window handle and WTL replace controls window procedure
You should allow all unhandled messages to pass to old WNDPROC to do it just return 'false' from
ProcessWindowMessage()
in CListBoxEx class:
BEGIN_MSG_MAP(CListBoxEx)
MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)
MESSAGE_HANDLER(OCM_MESUREITEM, OnMesureItem)
END_MSG_MAP()
Next step is message reflection
One of the most difficulties is to follow code in templates ..
In your CDialog class you need to reflect all messages so they will be handled in child control class
to reflect all unhanded messages use
class CMyDialog;
BEGIN_MSG_MAP(CMyDialog)
REFLECT_NOTIFICATIONS()
CHAIN_MSG_MAP(CAppStdDialogResizeImpl<CMyDialog>)END_MSG_MAP()
Now you should be able to receive OCM_XXX and handle them in child control
This trick allow you to hold code in one place and increase portability and reduce time to create applications
As usual people don't create GUI in C++ even for Windows CE, Mobile but who knows ;)
So you have to draw control not in his own procedure but in parent one.
To resolve this complexity you can use subclassing with the child control.
If you are using WTL - all need to do is create class dediven not from standard WTL controls with other template parameter
For example for ATL::CListBox use
class CListBoxEx;
typedef CWindowImpl< CListBoxEx, CWindow, CControlWinTraits> CMyListBox;
template <>
HWND CListBoxT
DWORD dwStyle, DWORD dwExStyle,
ATL::_U_MENUorID MenuOrID, LPVOID lpCreateParam)
{
return CMyListBox::Create( hWndParent
, rect
, szWindowName
, dwStyle
, dwExStyle
, MenuOrID
, lpCreateParam);
}
template <>
CListBoxT
:CMyListBox()
{
if (::IsWindow(hParentHwnd))
{
CMyListBox::SetParent(hParentHwnd);
}
}
class CListBoxEx :
public CListBoxT
{
...
}
This code allows you create a control and using Subclass-window replace WNDPROC for that control class
Now we can create or subclass a control
class CList_boxDialog : public CAppStdDialogResizeImpl
public CUpdateUI
public CMessageFilter, public CIdleHandler
{
...
LRESULT OnInitDialog(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
..
CWindow wnd = GetDlgItem(IDC_LIST_ADAPTERS);
mListBox.SubclassWindow(wnd);
mListBox.SetParent(m_hWnd);
mListBox.ResetContent();
mListBox.AddString(_T("First"));
mListBox.AddString(_T("Second"));
..
}
..
CListBoxEx mListBox;
}
Code above get controls window handle and WTL replace controls window procedure
You should allow all unhandled messages to pass to old WNDPROC to do it just return 'false' from
ProcessWindowMessage()
in CListBoxEx class:
BEGIN_MSG_MAP(CListBoxEx)
MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)
MESSAGE_HANDLER(OCM_MESUREITEM, OnMesureItem)
END_MSG_MAP()
Next step is message reflection
One of the most difficulties is to follow code in templates ..
In your CDialog class you need to reflect all messages so they will be handled in child control class
to reflect all unhanded messages use
class CMyDialog;
BEGIN_MSG_MAP(CMyDialog)
REFLECT_NOTIFICATIONS()
CHAIN_MSG_MAP(CAppStdDialogResizeImpl<CMyDialog>)END_MSG_MAP()
Now you should be able to receive OCM_XXX and handle them in child control
This trick allow you to hold code in one place and increase portability and reduce time to create applications
As usual people don't create GUI in C++ even for Windows CE, Mobile but who knows ;)
Subscribe to:
Posts (Atom)