Thursday, November 26, 2009
iPhone Development for Beginners
Lesson 2: iPhone Tutorial - Creating Basic Buttons
Lesson 3: Cocoa Touch Tutorial: iPhone Application Example
Lesson 4: Beginner iPhone SDK Hello World Tutorial [Example & Code]
Lesson 5: iPhone Programming Tutorial – Beginner Interface Builder Hello World
Lesson 6: iPhone Programming Tutorial – UITableView Hello World
Lesson 7: iPhone Programming Tutorial – Connecting Code to An Interface Builder View
Lesson 8: iPhone Programming Tutorial – Populating UITableView With An NSArray
Lesson 9: Learn Objective-C
Destinator v9 for Android and Windows Mobile
Wednesday, November 25, 2009
Have you ever seen an iPhone program?
This is a file with the expected name - main. The file extension is m. :(
It just creates an application.
It is written in Objective-C. "C" is the last letter in this name. So you can imagine what does it mean.
Size of a class object
I found just a great article: Determining the Size of a Class Object.
So short and so simple.
The factors that determine the size of a class objects are the following:
- Size of all non-static data members
- Order of data members
- Byte alignment or byte padding
- Size of its immediate base class
- The existence of virtual functions.
- Compiler being used
- Mode of inheritance (virtual inheritance)
! a || b
if a is true, so NOT a is false and so when b is true, the entire expression is true.
if a is false, so NOT a is true, and b can be either true of false.
Thursday, November 19, 2009
RAPI: Detect Storage on Windows Mobile Device
Preface
How to detect the name of the internal storage or an SD-card on Windows Mobile device from the desktop application?I was surprised to find when found so trivial answer. If it was in an MSDN article, but it was not very obvious, so many people who tried to solve a problem of the coping a data from the desktop to the mobile devices connected to this desktop.
Enumerative Technique
In case you don’t have time, or you don’t want to spend your time asking people, or you didn’t get the answer from the people your asked, you will try to find a logical solution for your problem yourself and you will use the tools you have in your hands.So the task is to copy a big amount of data on the storage (SD-card or an internal storage) of the device connected to the desktop. Both, the computer and the device, are running Windows – Mobile and XP or Vista. So let’s use RAPI.
Remote API is a small set of functions that allows to create or remove files, folders, registry keys on the windows mobile device connected to the PC via ActiveSync or Windows Device Mobile Center.
I work with the mobile devices for many years and I know that the storage card inserted to the device in the File Explorer of the device is usually shown as “Storage Card” or “SD”, the internal storage has name “Internal Storage” or “My Flash Disk” or “Resident Flash”.
If my PC application via RAPI will check the existence of one of these folders on the device and copy my data into the detected folder, it will solve my question.
I propose for your attention the following console application demonstrating this approach:
#define WIN32_LEAN_AND_MEANThe application screenshot is here:
#include <rapi2.h>
#pragma comment(lib, "rapi.lib")
#pragma comment(lib, "rapiuuid.lib")
#include <cstdio>
static const DWORD s_nTime = 5000;
const static LPCWSTR s_szFolder = L"RAPITestFolder";
static const int s_nSD = 6;
const static LPCWSTR s_arrSD[s_nSD] =
{
L"Internal Storage",
L"ResidentFlash",
L"My Flash Disk",
L"Storage Card",
L"SD",
L""
};
int main()
{
RAPIINIT riCopy = { 0 };
riCopy.cbSize = sizeof(riCopy);
HRESULT hr = CeRapiInitEx(&riCopy);
if (FAILED(hr))
{
wprintf_s(L"Connection failed\n");
return 0;
}
DWORD nRapiInit = WaitForSingleObject(riCopy.heRapiInit,
s_nTime);
if (WAIT_OBJECT_0 != nRapiInit)
{
wprintf_s(L"Connection failed\n");
return 0;
}
LPCWSTR lpszSD = NULL;
int nCnt = 0;
WCHAR szDir[MAX_PATH];
BOOL bCreated = FALSE;
DWORD nError = 0;
while (nCnt < s_nSD)
{
lpszSD = s_arrSD[nCnt];
ZeroMemory(szDir, sizeof(WCHAR) * MAX_PATH);
_snwprintf_s(szDir, MAX_PATH,
L"\\%s\\%s", lpszSD, s_szFolder);
bCreated = CeCreateDirectory(szDir, NULL);
if (!bCreated)
{
nError = CeGetLastError();
if (nError == ERROR_ALREADY_EXISTS)
bCreated = TRUE;
}
if (bCreated)
{
wprintf_s(L"Found: %s\n", lpszSD);
CeRemoveDirectory(szDir);
}
nCnt++;
}
CeRapiUninit();
return 0;
}
I don’t know if you see the problem with this method, but our QA made few test on a Windows Mobile phone with pre-installed German support. Now you see – the name of the storage card was “Speicherkarte”. How it will be in French?
In a certain extend this method is acceptable only for the English speaking users. :)
Daemon
In my mobile application I don’t have a problem to detect my database located on the storage card. I look for a folder with the temporary attribute and check if there are my data files. I use the well-known API: FindFirstFile, FindNextFile and FindClose to enumerate all folders on the device.So I can make an executable, download it on the device and launch it via RAPI (CeCreateProcess). The executable (the daemon) will make a text report that I can upload to the PC and read.
I think I’ve seen this approach implemented. It even worked. But it is so… unprofessional. It looks like a trick made because the laziness of a leak of time or a knowledge – a programmer knows only a few functions in Win32 API and applies them everywhere because he’s lazy enough to open the book and read something new.
Of course there is a more modern way - make a DLL that will export a special function that can be called by CeRapiInvoke function. The example of such DLL that can be called via RAPI can be found on Native Mobile blog.
More details you can find in:
- MSDN: How To Use CeRapiInvoke()
- Dr. Dobb’s: The Windows CE 2.0 Remote API. The CeRapiInvoke API is a versatile tool
The Answer
The previous, a complicated enough method, enumerates the folders on the device and this information should be retrieved by a desktop application via RAPI. If I will decide to implement this approach, I will need to add one more project to my solution – the daemon DLL. I will have to sign this DLL in order to avoid the annoying question from Microsoft asking the user if he allows to launch this DLL from an unknown provider. It already smells bad.Can I enumerate the folders on the device via RAPI?
There is no CeFindFirstFile function. :(
But there is CeFindAllFiles!
I made a console application to check the function:
#define WIN32_LEAN_AND_MEANWith my HTC Touch Pro 2 phone this application gave me this result:
#include <rapi2.h>
#pragma comment(lib, "rapi.lib")
#pragma comment(lib, "rapiuuid.lib")
#include <cstdio>
static const DWORD s_nTime = 5000;
int main()
{
RAPIINIT riCopy = { 0 };
riCopy.cbSize = sizeof(riCopy);
HRESULT hr = CeRapiInitEx(&riCopy);
if (FAILED(hr))
{
wprintf_s(L"Connection failed\n");
return 0;
}
DWORD nRapiInit = WaitForSingleObject(riCopy.heRapiInit,
s_nTime);
if (WAIT_OBJECT_0 != nRapiInit)
{
wprintf_s(L"Connection failed\n");
return 0;
}
LPCE_FIND_DATA pData = NULL;
LPCWSTR lpszPath = L"\\*.*";
DWORD nFlags = FAF_FOLDERS_ONLY | FAF_NAME | FAF_ATTRIBUTES;
DWORD nCount = 0;
BOOL bRetrieved = CeFindAllFiles(lpszPath, nFlags, &nCount, &pData);
if (bRetrieved)
{
DWORD nCnt = 0;
do
{
if ((pData[nCnt].dwFileAttributes &
FILE_ATTRIBUTE_TEMPORARY) == FILE_ATTRIBUTE_TEMPORARY)
wprintf_s(L"Found: \\%s\n", pData[nCnt].cFileName);
nCnt++;
} while (nCnt < nCount);
}
if (pData != NULL)
CeRapiFreeBuffer(pData);
CeRapiUninit();
return 0;
}
Here is the screenshot from the phone itself:
Disclaimer
I’ve implemented the solution and have tested it on few Windows Mobile and CE devices. I was writing this article and launched Google to find more information about PInvoke (it was a mistake, I needed CeRapiInvoke). It always happens this way – I found an example in VB that uses exactly the same method of the temporary folder detection on CodeProject:Display device memory information using P/Invoke
Nothing is new. Soon Google will have “Generate Code” feature proving us with already implemented solutions for our development questions.
HTC Touch Pro 2
I’ve bought this phone. The first impression is very good.
It’s much better then my “old” HTC Diamond, but it is still not iPhone.
Tuesday, November 17, 2009
This web on iPhone
These are the screenshots from my iPhone. WMDeveloper looks on this phone nice.
Google helped to find out how to make the screenshots on iPhone:
- Hold the power off/on button
- Press on the main button.
The screenshot appears in the Photo Albums in Camera Rolls.
Google search works fine on the phone too. There is the voice search for “Destinator”:
It found “Destinator” said with Russian accent.
Will see how the HTC Touch Pro 2 looks like, but till now this is the best phone I’ve had (or wanted to have).
Microsoft Windows Marketplace for Windows Mobile 6 and 6.1
This information was published yesterday on The Windows Blog:
Eric Nelson in this article says that there are 800 applications available on the Marketplace and almost all these application already supports Windows Mobile 6.0 and 6.1. So the windows mobile developers can reach now 30 millions devices worldwide. More then 1,000 software vendors already registered on the marketplace.
Friday, November 13, 2009
Microsoft Marketplace news
Microsoft запустила свой маркетпласе 6 октября. Кажется, это уже считают большим фиаско. Сплетни говорят, что продано только около 400 програм за первый месяц.
Тем не менее Microsoft пытаются что-то улучшить. На блоге Mobile группы появилась информация, что теперь программу можно выбирать на персональном компьютере с веб-страницы:
http://marketplace.windowsphone.com/Default.aspx
затем она будет передана на телефон.
Motorola ожидает продать 100,000 телефонов Droid уже в ближайшие выходные, 1 миллион к концу года и 10 миллионов в следующем году.
Эта информация взята с AppleInsider:
Motorola Droid estimated to have sold 100,000 in first weekend
Verizon уже распродал половину 200,000 партии. Аналитики утверждают, что спрос только растет.
Для сравнения Apple продал более 3 миллионов своих 3GS телефонов в первые 3 дня. В следующем году ожидают 36 миллионов проданных iPhone.
Thursday, November 12, 2009
Win32: Adjust Window Rectangle
The article is published on Experts-Exchange:
Wednesday, November 11, 2009
Tuesday, November 10, 2009
String to double
C: strtod in stdlib.h
C++: strtod in cstdlib
I knew about atof.
But this function does not work with the strings like "20nn". So, for example, how to check if this conatins a valid double?
I made even a function and tested it in this code:
#include <cstdio>And then I see (thanks to EE), that there are a set of functions such as strtod, strtof, etc. Actually, I knew about strtol, so I could guess that should be also strtod. But I didn't. :)
#include <string>
bool is_valid_double(const char* str)
{
while (str && *str && *str == ' ')
str++;
if (*str && *str == '-')
str++;
while (str && *str)
{
if (!isdigit(*str) && (*str != '.'))
{
if (*str == ' ')
{
while (str && *str && *str == ' ')
str++;
if (!*str)
return true;
}
return false;
}
str++;
}
return true;
}
int main()
{
char sz[16] = { 0 };
sprintf(sz, "%f", 20.0);
bool b = is_valid_double(sz);
strcpy(sz, " 20.00");
b = is_valid_double(sz);
strcpy(sz, " 20.00 ");
b = is_valid_double(sz);
strcpy(sz, " -20.00 ");
b = is_valid_double(sz);
strcpy(sz, " --20.00");
b = is_valid_double(sz);
strcpy(sz, " 20.00 2");
b = is_valid_double(sz);
strcpy(sz, " 20nn ");
b = is_valid_double(sz);
return 0;
}
Window with a predefined client rectangle
The first application version I made just loaded the image into the memory, detected its size and created a popup window (WS_POPUP style) exactly of this size.
The QA said that it will be good, if the window will be moveable and sizeable. Ok. I added a caption and a frame. Now the image in the background is streched.
The first solution I found in Google - detect Window rectangle, then the client rectangle and the difference should be taken into a account when I set a rectangle for MoveWindow function:
HDC hDC = ::GetDC(NULL);Two variables cx and cy are the predefined size of the background image.
const int w = GetDeviceCaps(hDC, HORZRES);
const int h = GetDeviceCaps(hDC, VERTRES);
::ReleaseDC(NULL, hDC);
RECT rcClient, rcWindow;
GetClientRect(&rcClient);
GetWindowRect(&rcWindow);
m_Diff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
m_Diff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
cx += m_Diff.x;
cy += m_Diff.y;
RECT rect;
rect.left = (w >> 1) - (cx >> 1);
rect.top = (h >> 1) - (cy >> 1);
rect.right = rect.left + cx;
rect.bottom = rect.top + cy;
MoveWindow(&rect);
This code works. But something's wrong here. Let's use Google again. :)
Of course, there is a Win32 API function that does the job: AdjustWindowRectEx.
And here is the code:
BOOL Center(int cx, int cy, RECT& rect)This function above calculates the window rectangle for the predefined client area in the center of the desktop.
{
HDC hDC = ::GetDC(NULL);
const int w = GetDeviceCaps(hDC, HORZRES);
const int h = GetDeviceCaps(hDC, VERTRES);
::ReleaseDC(NULL, hDC);
rect.left = (w >> 1) - (cx >> 1);
rect.top = (h >> 1) - (cy >> 1);
rect.right = rect.left + cx;
rect.bottom = rect.top + cy;
AdjustWindowRectEx(&rect, s_nWndStyle, FALSE, s_nWndStyleEx);
return TRUE;
}
The function exists even for Windows Mobile and Windows CE: AdjustWindowRectEx. This MSDN article contains an example.
Now if you need to control the size of your window (do not allow to be smaller or bigger than the predefined size), you need to handle WM_GETMINMAXINFO message. For example, in the ATL-based application it will look as the following:
LRESULT OnGetMinMaxInfo(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)ptMinTrackSize in the MINMAXINFO structure is just a point, for example, set it as { 200, 200 } and the window cannot be smaller then 200x200.
{
LPMINMAXINFO pInfo = (LPMINMAXINFO)lParam;
if (pInfo != NULL)
{
pInfo->ptMinTrackSize = CPainter::GetMinSize();
}
return 0;
}
More information about this WM_GETMINMAXINFO you can find on The Old New Thing.
Monday, November 9, 2009
The Beginning
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
LPCWSTR s_szWndClassName = L"Small Window";
ATOM RegisterWndClass(HINSTANCE hInstance, LPCWSTR lpszWndClassName);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE,
LPWSTR, int nCmdShow)
{
HWND hWnd = NULL;
MSG msg = { 0 };
RegisterWndClass(hInstance, s_szWndClassName);
hWnd = CreateWindow(s_szWndClassName, s_szWndClassName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, NULL, hInstance, NULL);
if (hWnd != NULL)
{
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
ATOM RegisterWndClass(HINSTANCE hInstance, LPCWSTR lpszWndClassName)
{
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = lpszWndClassName;
return RegisterClassEx(&wcex);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Sunday, November 8, 2009
ATL, GDI+. PNG,...
Firstly, I have to say, that the CImage converts any image into 32 bit per pixel format, but it is just RGB (pre-muliplay alpha?). When CImage loads an image it copies the image data into an internal buffer. You can see everything yourself, if you will debug CImage methods such as Load from the stream, for example.
Secondly, I just included atlimage.h file header into my source code and got a bunch of dlls from which my application depends now. Including the dynamic run-time libraries, and GDI+, and something from the Windows Installer, and...
I very like ATL, I just love the style, but, probably, I will try to avoid using CImage in my projects.
For a fast and dirty job that does not require to load any data with alpha..., maybe, it is possible. CImage even has AlphaBlend function - it's just a wrapper for the Win API function. From my point view, it is just one more evidence of a bad design made for this class - from one side the class uses GDI+, from other side it uses GDI function to draw the image.
The original task was to load the PNG-file from the resources in an ATL-based application. I thought I solved it. It looked great - I made a template - CImageResource, that contain only one function - LoadFromResource. The objects I created in my application were like
CImageResource<CImage> m_Image;
I added a window background image to the resources and saw it's drawn in the application window. AlphaBlend method was used and everything was just fine.
The problems begun when I added a button image with the real visible alpha.
So finally the class CImageResource is not a template :). It looks so:
#pragma once
class CImageResource
{
Bitmap* m_pBitmap;
HGLOBAL m_hBlock;
public:
CImageResource() : m_pBitmap(NULL), m_hBlock(NULL) {}
~CImageResource() { Clear(); }
inline BOOL IsNull() const { return m_pBitmap == NULL; }
UINT GetWidth()
{
if (IsNull())
return 0;
return m_pBitmap->GetWidth();
}
UINT GetHeight()
{
if (IsNull())
return 0;
return m_pBitmap->GetHeight();
}
BOOL Draw(HDC hDC, int x, int y)
{
if (IsNull())
return FALSE;
Graphics graphics(hDC);
return graphics.DrawImage(m_pBitmap, x, y,
m_pBitmap->GetWidth(), m_pBitmap->GetHeight()) == Ok;
}
BOOL Draw(HDC hDC, RECT& rect)
{
if (IsNull())
return FALSE;
Graphics graphics(hDC);
return graphics.DrawImage(m_pBitmap, rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top) == Ok;
}
BOOL Load(LPCWSTR lpszFile)
{
Clear();
m_pBitmap = Bitmap::FromFile(lpszFile);
return m_pBitmap->GetLastStatus() == Ok;
}
BOOL LoadFromResource(UINT nResID)
{
Clear();
HMODULE hModule = GetModuleHandle(NULL);
HRSRC hResource = FindResource(hModule,
MAKEINTRESOURCE(nResID), L"IMAGES");
if (hResource == NULL)
return FALSE;
HGLOBAL hImage = LoadResource(hModule, hResource);
if (hImage == NULL)
return FALSE;
LPVOID pImage = LockResource(hImage);
if (pImage == NULL)
return FALSE;
HRESULT hr = E_FAIL;
int size = SizeofResource(hModule, hResource);
m_hBlock = GlobalAlloc(GMEM_MOVEABLE, size);
if (m_hBlock == NULL)
return FALSE;
LPVOID pBlock = GlobalLock(m_hBlock);
if (pBlock != NULL)
{
memmove(pBlock, pImage, size);
IStream* pStream = NULL;
if (CreateStreamOnHGlobal(m_hBlock, FALSE, &pStream) == S_OK)
{
m_pBitmap = Bitmap::FromStream(pStream);
pStream->Release();
if (m_pBitmap != NULL)
{
if (m_pBitmap->GetLastStatus() == Ok)
return TRUE;
}
delete m_pBitmap;
m_pBitmap = NULL;
}
GlobalUnlock(m_hBlock);
}
GlobalFree(m_hBlock);
m_hBlock = NULL;
return FALSE;
}
void Clear()
{
delete m_pBitmap;
m_pBitmap = NULL;
if (m_hBlock != NULL)
{
GlobalUnlock(m_hBlock);
GlobalFree(m_hBlock);
}
}
};
Now all images are loaded and drawn with the alpha. For drawing I use the GDI+ as well.
Here are few helpful links from CodeProject about this topic:
Joe Woodbury. Loading JPG & PNG resources using GDI+: http://www.codeproject.com/KB/GDI-plus/cgdiplusbitmap.aspx
Christian Graus. Starting with GDI+: http://www.codeproject.com/KB/GDI-plus/startinggdiplus.aspx
Darren Sessions. A user draw button that supports PNG files with transparency, for Visual C++ 6.0 and VS2005: http://www.codeproject.com/KB/buttons/GdipButton.aspx
Wednesday, November 4, 2009
Очередной Android
Ну... что Вам сказать... По-моему пока все андроиды хуже телефонов с Windows Mobile.
Наверное, безплатный Google Map Navigation это большой плюс. Зря Microsoft не довели свою навигационную историю до ума - мыкались кого купить, свои проэкты начали (NavReady), в конце все проспали.