Thursday, April 24, 2008
Windows XP SP3
Friday, April 11, 2008
Off to Seattle!
Friday, April 04, 2008
WTL Helper and VS 2008
Crino ROCKS!
Wednesday, April 02, 2008
Smartphone keyboard handling with GAPI
I found a solution for this problem that solves most of the issues above, but also uncovers some other issues. The solution is to call ImmAssociateContext() on your main window passing NULL as the HIMC parameter. This will remove the input context association from the window, and you get the keyboard back. But...
... now you have to handle the keyboard mappings yourself. That's the price you pay. On some devices this means having a mixed keyboard (numbers and alpha keys) so you must internally implement a keyboard map in order to make it work as the user expects. To make matters worse, the keyboard map is device dependent so you are in for a bit of work. Finally, I have found that on some devices you don't get all the keys, especially the special keys for mail and contacts. These devices seem to have these keys wired to launch the matching applications and not even GAPI seems to release them...
Monday, March 24, 2008
Smartphone display timeout
keybd_event(VK_NONAME, 0, KEYEVENTF_SILENT, 0);
This nasty little trick works but also forces your backlight to the maximum and you may not want it. What I really want to do is mimick going to the Power Management applet and setting the "Display time out" to "Never". With this setting, your Smartphone device will never go to sleep. So how do you achieve this? It's actually quite easy.
The display time out value is stored on the device registry under:
HKEY_CURRENT_USER\ControlPanel\Power
All you have to do is set the Display value (DWORD) to -1 and make the system know that the value changed. How do you break the news? Simple again:
PostMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0);
If you use this in your application to avoid the device from falling asleep (I also call SystemIdleTimerReset and SHIdleTimerReset every few seconds), please remember to set the value back to the original value.
Insomnia rules!
Monday, March 17, 2008
Windows Mobile Remote Control - Published
Friday, March 07, 2008
My first hours with VS 2008
Don't worry - if I have anything to gripe about, you will know it.
Wednesday, March 05, 2008
Installing VS 2008
Installation went as smothly as possible except for a mysterious shutdown at the end. I was not present, so I cannot tell you what happened but I suspect that the Vodafone 3G card is playing tricks on me. Again.
After installing, I looked at the C drive to check for free space and was appalled to see that it was below 50%. After installing Vista SP1, my C drive used space magically shrunk and has been growing very fast ever since. The culprit? System restore points! After clearing them I got back to post SP1 install conditions. Cool, my disk is back.
Tuesday, March 04, 2008
Raffael's Blog
WMDC woes
There is an alternative that I have not tested yet and was pointed to me by Mark Arteaga on the PocketPC FAQ site. Anyway this should be an easier experience, especially for people like me who need to connect to everything, from Pocket PC 2003 devices to the latest WM6 devices throwing in a few bizzare Windows CE 5 GPS devices in between...
Monday, February 25, 2008
Windows Mobile Remote Control
Now I must add some way to send the special device keys, like the phone and left / right selection buttons.
Saturday, February 23, 2008
Windows Mobile Developer Center
On another note, I will be working throughout this weekend on a Windows Mobile remote control server (something like Pocket Controller). After writing the screen grabber tool, this is an extension I really want to have a go at. Will post the results here as they become available.
Monday, February 11, 2008
Remote Screen Grabber
One of the things I tried out during the development of this code to send mouse events to the device. When the user clicked the desktop screen with the device screen capture, a mouse message would be sent to the device via a different remote call. Although a bit crude, it was possible to remotely control the device (with some notable exceptions...). So this set my mind in motion (again) and now I'm writing a streamed version of the RAPI DLL so that it accepts commands from the desktop (such as mouse messages and even keyboard presses) and returns device screens to the desktop. I will post the code when it is ready (and working).
Thursday, February 07, 2008
Interview
Tuesday, February 05, 2008
Windows Mobile Screen Capture
Searching the net for source code samples turned nothing (blame Live and Google). The best approach I got was from a CodeProject article but the proposed GDI method does not work on Windows Mobile because the CAPTUREBLT flag is not supported. This means that I needed another solution.
GAPI seemed to be a very good candidate. It has a very simple API and I had used it in the past, but it is now declared deprecated by Microsoft and I was prompted to use Direct Draw instead. Willing to learn a bit more about this technology, I decided to give it a go and spent a couple of hours reading through MSDN docs to figure out how this can be done. As it turned out, it's very simple.
To capture the device screen using Direct Draw you need to follow these simple steps (I will write an article on this illustrating a desktop tool to capture the device screen via RAPI):
- Initialize Direct Draw using the DirectDrawCreate function using NULL as the first parameter.
- Set the cooperative level to DDSCL_NORMAL. This is enough for accessing the primary surface in read-only mode.
- Create the primary surface using this code.
- Get the surface's HDC and use it to create a compatible DC.
- Create a compatible bitmap using the screen dimensions and select it to the compatible DC.
- Blit from the surface DC to the compatible DC using BitBlt.
- Done! The compatible bitmap now contains the device's screen capture.
I wrote this using a DIBSection in order to marshal it via a RAPI call and was able to deserialize it on the desktop and display the device screen capture. I'm planning to use this same marshalling technique to implement a remote file browser using the device's own system image list.
Stay tuned for the article!
Monday, February 04, 2008
Vista SP1 around the corner
Wednesday, January 30, 2008
Remote File Viewer
WTL on MSDN Magazine
Friday, January 18, 2008
The collapsible toolbar
After a bit of a rush trying to amend my own lack of testing before publishing new product releases (I should know better at 42...) I will also start looking at what it takes to implement the "Consumer Templates-less" OLE DB library for Windows CE (and Win32, why not?).
Thursday, January 10, 2008
DBPROP_SSCE_TEMPFILE_MAX_SIZE
Tuesday, January 08, 2008
New year, new life
The community project that I chose to focus on is to create a replacement for the ATL OLE DB Consumer Templates. More and more I see native code developers looking for an easier way to access SQL Compact Edition databases from C++, and my solution for tweaking the PPC 2003 SDK header files does not feel right. Besides, Microsoft does not ship the Consumer Templates header files anymore so this must mean that this code is not supported (but is it licensed?). Developing a new library for OLE DB on devices will surely be an interesting challenge and will keep me busy writing code and publishing articles throughout 2008.
Once again, thank you Microsoft for the fifth MVP award!
Sunday, December 09, 2007
Detecting the SDF file version
The alternative way to detect the SDF file version is by reading a few signature bytes on the file. Just open the file, set the read location at offset 16 and read the 32 bit int there. The following values will tell you the file version:
2.0: 0x73616261
3.0: 0x002dd714
3.5: 0x00357b9d
I wrote a very simple .NET CF 2.0 application to illustrate this. The download link is this. If you find any SDF file that fails this test, please let me know.
Friday, December 07, 2007
WM6 GPSID problem workaround
Monday, November 26, 2007
COM Port Enumeration
The only problem with this very simple method is that it does not enumerate the Microsoft Bluetooth stack emulated COM ports. If you create a partnership with a device that has the serial port profile, you will be able to assign a free COM port to it. This COM port works like any regular serial port but does not show up in the list of active drivers on the registry. Microsoft decided to enumerate all Bluetooth virtual COM ports under HKEY_LOCAL_MACHINE\
Software\Microsoft\Bluetooth\Serial\Ports. To find all available COM ports you must enumerate all the child keys and look for the Port value under each key.
Interestingly, the Widcomm stack does put the virtual COM ports where they should be (or at least where I expected them to be).
Tuesday, November 20, 2007
VS2008 Install Heads Up
Monday, November 19, 2007
Thursday, November 15, 2007
Windows Live
Monday, November 12, 2007
Performance Improvements in VS 2005
Wednesday, November 07, 2007
Carousel Demo
The main frame approach would implement the carousel code in the main frame allowing it to correctly resize the child window and even allowing the application to change the child view (like in a property sheet). With this approach it might also be easier to implement a means to change the location of the bar whan the screen is rotated. In fact, the carousel looks much nicer in a vertical position when you rotate your screen to landscape (right or left would be up to you).
Implementing this as a toolbar control would have the advantage of allowing the developer to reuse the code outside the main window, especially on dialogs and modified property sheets...
While I think about what to do, please do take a look at the code. The icons were "created" with Axialis IconWorkshop, one of the best icon editors around. Please note that these icons can only be used by registered users of the product and I'm not sure that you can reuse them on your applications.
Wednesday, October 31, 2007
GradientFill and a memory DC with a viewport
WTL 8.0 does a lot for you and I found myself having more work creating the icons for the sample than actually implementing the code... I started by using the CMemoryDC class which worked beautifully until I used GradientFill. All other GDI functions work correctly, but the gradient refused to appear correctly or at all. Interestingly, when the carousel strip was set at the top of the client window it would paint correctly, but would fail at the bottom.
Looking at CMemoryDC's source code I found that the constructor sets a viewport origin in order to cope with any rectangle. When setting the carousel strip at the top, the gradient would show up because the viewport origin would match the child window's (0,0), but fail when set to the bottom because the viewport origin would be different.
I ended up by using a slightly modified version of CMemoryDC, by removing the SetViewportOrg call on the constructor and zeroing the source bitmap coordinates at the destructor's BitBlt call. The carousel now works correctly on all four window edges (top, bottom, left and right).
Presently the carousel is implemented as a child view window but I'm looking at ways to make it work as a toolbar.
HTC P3300 GPS problems (again)
Friday, October 26, 2007
Access 2007 woes
As you already know I'm an OLEDB freak, and I use it for all native code database access I write both on the device and on the desktop. Last year I did write a sizeable amount of code for my data synchrnization component (Data Port Sync) and this targeted the JET 4.0 database engine. The code I wrote implemented both the Access database preparation and also change tracking. Database preparation involves creating a few extra tables and adding two columns to every tracked table. This looks pretty simple to do using straight SQL, but when I consistently failed to create self generating "replication id" columns (the SQL equivalent of the uniqueidentifier type with the rowguidcol property) I turned to the low-level
ITableDefinitionWithConstraints OLEDB interface to do all the table creation work. The code is not nice to see, but it is effective and gave me an added bonus: I can hide the tables from the user. To add the extra columns to the tracked tables, I used the
ITableDefinition interface.
Recently I started to get requests from my customers to support the new Access 2007 file format on my data transfer products. Changing the provider from Microsoft.Jet.OLEDB.4.0 to Microsoft.ACE.OLEDB.12.0 did the trick quite nicely because Microsoft kept all the other connection string properties untouched. BTW: where can I find a reference to all the properties and most importantly, where are the new header files for OLEDB?
The first implementation of the Access 2007 database engine was shipped on the Data Port Console release. Although it does not create the mdb or accdb files (yet), it successfully imports and exports data to and from the various SDF formats.
Going back to the desktop synchronization code (which will eventually see its way into the Console) I recently began to write a small desktop agent for simple desktop scenarios. Putting the new code to work was quite easy until I decided to test the code against an Access 2007 database. I picked up the old Northwind sample and converted it to the new engine only to find that my preparation code would fail miserably. There were no issues when the tracking columns were created, but it proved next to impossible to create the tracking tables: the engine would throw an E_FAIL error with a very strange OLEDB error description: "Could not find field." Period. I changed every possible factor that could be causing this: column names, the table name, absence or presence of delimiter brackets. Nothing would work. Out of desperation, I replaced the code with a straight SQL DDL command only to be greeted with a similar error: "Could not find field 'SID'." I beg your pardon? There is no 'SID' in my command! Has Access gone mad?
No, Access is working perfectly but the accdb file seems to be corrupt. After reverting all the code back to what it was, I decided to create a new accdb from scratch and then import new data from an SDF using the Console. After running it through the preparation code there was no error! Is the database conversion code broken in Access 2007?
Bottom line: don't convert mdb to accdb. Create a new accdb and then import the old data into it. Sigh.
Friday, October 19, 2007
The edit control under Windows Mobile 2003 and 5.0
This problem was quickly solved by adding the OnKeyDown message handler to the CCeEdit class and forcing the control to set the focus to the parent window whenever an up or down navigation keys are detected. Voilá!
Thursday, October 18, 2007
A list-based form for Windows Mobile
Next two projects: port this thing to WTL and start writing an OLE DB class library for Windows Mobile. This second project is necessary because Microsoft no longer ships the atloledbcli.h file on the SDKs and this must mean something...
Thursday, October 11, 2007
Bug in the FormListSample
Solution: On the CFormListCtrl::OnDestroy method, set the m_iEdit member variable to -1 after calling ShowEditor.
Meanwhile, I added some code to handle edit control resizing when the screen is rotated. The code can be found on the same location.
Monday, October 08, 2007
The list-based form control
Soon we learned that ADOCE would be deprecated and so I started to look at the ATL OLE DB consumer templates. This is a great technology and I still fail to understand why it is not present on the WM5 and WM6 SDKs. In my code, I use an adapted version of the header file you get on the Pocket PC 2003 SDK but to be honest I don't like this approach (I will come back to this issue in a future post).
On the user interface side, we already had a very nice alternative to dialogs: the list-based form control used by the Pocket Outlook Contacts application. Not only this is an intuitive control for the user, it also promised to be easy for a developer to use: no designer needed to be involved, you just specified the list of items to edit and fired the object.
The big problem with this control was that there was no API for it so I had to write one. Back then I was using MFC big time due to the compiler support for it on eVC3 and eVC4. Now I am not so sure that MFC is a good option for native user interfaces and I'm leaning towards WTL. You now have great tool support in VS 2005 with the WTL Helper tool which I am using on a daily basis and with great results.
So I eventually wrote an MFC control to implement a list-based form and in the process I threw in couple of goodies such as grouping, context menus for managing the items, control notifications and a few other bells and whistles. After a recent request of fellow MVP Christian Forsberg for a similar control, I decided to go back to my 4 year old code, adapt it to VS 2005 and publish it. I had to do more work than expected because nowadays there are lots of devices that have a keyboard, display in landscape and even have VGA screens! Back then I was used to portrait QVGA screens and no keyboard, so some changes were in order.
Before I publish this code as an article, I decided to preview it here so you get a chance to look at it and let me know what you think. Download FormListSample.zip
Thursday, September 20, 2007
Supporting SQL Compact 3.5
DBPROP_SSCE_DBENCRYPTIONMODE. Now your header file can be used for 2.0, 3.0 and 3.5!
What this means for me is that SQL Compact 3.5 will be supported by the release version of Data Port Console and I will also issue a last version of DesktopSqlCe that will also support the new database engine. This will be the only game in town for .NET 2.0 desktop applications that must support both the 3.0 and the 3.5 database formats (without code changes, of course).
Cool!
Friday, September 07, 2007
SQL Compact 3.5 Beta 2 and VS2005
Now back to work.
Friday, August 31, 2007
Database Diagrams for Data Port Console
Tuesday, August 21, 2007
ZIP and RAPI - The article
Sunday, August 19, 2007
ZIP and RAPI - Yes, it's faster
So I decided to take a harder look at the code and found the culprit: WriteFile latency. The function was being called way too often and sometimes with small sets of data. If you look at the code, you will see that WriteFile is called when either the decompression input or output buffers are emptied. This is wrong. The call must only be made when the output buffer is empty and not when the input buffer is. When the input buffer is emptied it must be refilled from the RAPI stream and the output buffer should not be flushed, otherwise we risk flushing a small amout of data expending one WriteFile call.
The final result is now ready and is consistently faster than the PC decompression approach. Try it!
Friday, August 17, 2007
ZIP and RAPI - Is it worth it?
To make this work I changed the CeUnzip project in order to support calling a RAPI extension and added an extra mandatory command line argument: -i for expanding on the PC from a ZIP file on the device and -e for the exact opposite operation. It's here that I make the remote call to the RAPI extension DLL. Please note that the two projects use different versions of the unzip.cpp file. I will correct this before publishing an article that describes in greater detail the inner workings of the code.
How about results? Is this really faster than using an on-the-fly decompression algorithm on the PC and using CeWriteFile to write the decompressed data on the device?
My first results were very disappointing. When compared to an installer application I wrote for a customer that decompresses on the PC and writes to the device, I consistently got worse timings. The only remedy that made the device DLL run as fast as the PC was to increase the IRAPIStream read buffer size to 128 or 256 KB. As a matter of fact, RAPI read latency is a big issue here. Before giving up I looked at the particular ZIP file I was using to test: it was quite large and had a relatively small compression ratio. Maybe this explains something?
My next test was to use a very high compression ratio ZIP file and run the same tests (expanding it to the device using the two different approaces). This ZIP file was built from a very large SDF file which almost disappeared when compressed: 193 KB to only 3 KB. Now the results were a bit different...
Depending on the device, the DLL expansion was from 2 to 4.5 times faster than the PC's. This means that for compression ratios closer to 1 it is (almost) indifferent which approach to use, but when the ZIP compression ratios get larger, it's far better to use the server DLL.
Sunday, August 12, 2007
ZIP and RAPI
Recently I had to use this code to write a specialized device installer (no cabs) for a consumer application that runs on all sorts of devices. This installer was designed to extract files from a ZIP on the desktop and copy the extracted files to the device over an ActiveSync connection. I used Zip Utils to extract the data and RAPI to copy the expanded files to the device. This works but can be slow on some devices. Wouldn't it be great if I could expand the files on the device while having the source ZIP file on the PC? I would surely make the whole thing faster because the RAPI transport times are a big bottleneck in this whole process.
Due to time constraints, the installer is now shipping like this: data is expanded on the PC and copied to the device. Now I'm starting to write an application that will update the device code and data. Interestingly most of the static data is stored on ZIP files on the device and the updater must extract specific files on the ZIPs in order to know some details. The problem is that some of these ZIP files are over 2 MB and copying them to the PC just to extract one tiny file is out of the question due to slow transfer times.
No options here: I had to roll up my sleeves and started to read Lucien's code in order to see what could be done. This was no walk in the park because he uses a very packed code indentation, and understanding the code was not easy at first. Then I noted that all the ZIP file access methods were neatly encapsulated in specific functions (like lufopen, lufread and so on) so it would be quite easy to replace the desktop file access functions with RAPI's.
My approach was to expand the LUFILE structure and include a set of function pointers that would be initialized with the regular API when the ZIP file is on the PC and with RAPI's when the ZIP file is on the device. After 20 minutes the code was working and I was able to write a very simple command line unzipper (get the code here).
Now I want to solve the first problem I had: efficiently unzipping a file to a CE device. This will require a RAPI DLL on the device that will have all the decompression code. When this is ready I will publish the results in an article. Stay tuned.
Friday, August 03, 2007
Bitten by the desktop GC
While running perfectly in Debug mode, the error almost always showed up in Release mode. When exporting very short databases or single tables it might not show up. But when I tried to export the Northwind sample the Console would bomb exporting one of the largest tables (Order Details or Orders). The keyword here is random because as it turned out, the error was being caused by the garbage collector (well, my bad code was causing it - the GC just made it apparent).
The Access database code was implemented in C++ with a similar approach as DesktopSqlCe's low-level classes: there are separate classes for the table structure and the table cursor. In order to open a base table cursor and insert data on the table (no SQL is used for data manipulation) the code creates a table object and "opens" it returning a "rowset" object. My mistake was to have the table class include an ATL CTable-derived object, not a pointer to it. The CTable-derived class contains all the accessor and rowset logic that are used by the rowset object. Making it static is a bad idea because the desktop .NET GC did not know about this and kills the table object because it thinks it is no longer needed. After all the only active object is the rowset... Now you see the problem: by killing the table, the rowset is implicitly killed as well because it shares an object that is statically owned by the table. Closing the rowset means that a few internal pointers will be deleted and set to NULL. Bang! Am I smart or what? (The answer is "No").
I uploaded a revised Beta 4 that solves this issue, so if you installed the one I uploaded yesterday please replace it with the new one.
Thursday, August 02, 2007
Data Port Console 1.0 Beta 4 available for download
What's next? Primeworks.Data - the merger between DesktopSqlCe and Data Port Sync with a few "benefits" such as the ability to make P2P connections via Bluetooth or WiFi between two devices. Also I will add support for the JET (ACE) engines on the desktop server and will publish the services via a muti-threaded Windows Sockets server (I don't anticipate the need for IOCP anytime soon because there will be few concurrent connections).
The new Beta 4 can be downloaded from here.
Monday, July 30, 2007
Bluetooth Service Publishing
After being able to find a device with the service you want to consume, you can connect to that device using Windows Sockets. The reverse process involves publishing a service for other devices to consume and to serve requests using WS. Unfortunately the SDK has no means (nor explanation) on how to create an SDP record. Platform Builder users have the BTHNSCREATE sample to play with, but what about us, mere SDK users? Looks like Microsoft thinks this is something that should only concern people designing new Windows CE or Windows Mobile devices. I sincerely hope not and I'd rather think this is a design oversight. Why would I need such a thing?
Well, one of my plans is to provide P2P support for my products. If you look around the newsgroups you will see lots of people asking for an SDF-only synchronization package. This will require that two SDF files can "talk" to one another. I already support having a PC talk to an SDF file on a device, but what about having one device talk to another? A year ago I actually achieved this using WiFi, but this is not the correct protocol for ad-hoc P2P scenarios - Bluetooth is better. So if I want to support this scenario, I must publish a new Bluetooth service. Yes, of course I could use emulated COM ports and the code already supports serial communications. But I want the real thing: a dedicated service with its own GUID.
So how am I going to circumvent this? Most likely I will use Doug Boling's solution: use a templated SDP record and fill in the gaps (not nice, I know). What really bugs me is that the Widcomm stack makes it so much easier to publish a new service...
Wednesday, July 25, 2007
SHMENUBAR and MF_GRAYED
While working for the new Microsoft Bluetooth device inquiry and service discovery (these seem to be the appropriate Bluetooth terms) I found out that Sergey Solozhentsev's WTL Helper tool works like a charm in Windows Mobile projects under VS 2005. All of the message handling functions for the main frame window were generated with this tool and it makes it very easy to write all the UI code - this tool just rocks.
Today I found out about something that does not seem to be documented anywhere: when using the SHMENUBAR resource, never specify a menu resource with a grayed (MF_GRAYED) menu item - the menu will not show up. The WTL code is very straight forward and uses the SHCreateMenuBar API, so this was not where the problem lied. After removing the grayed style from the resource editor the menu magically showed up! So is this a bug on the shell or on the compiler?
Monday, July 23, 2007
Back to Bluetooth the WTL way
I'm coming back to writing about Bluetooth on Windows Mobile devices and this time I'm exploring the Microsoft stack. Using MFC code I had written almost a year ago, I'm now turning to WTL to rewrite the sample for the article. So far I can tell you that the Windows Mobile WTL wizard looks quite competent at generating the basic application code. More impressions on this experience will be published here. Stay tuned.
Tuesday, July 03, 2007
CeGetDiskFreeSpaceEx - II
typedef struct _DISKSPACE
{
ULARGE_INTEGER uliFreeUser,
uliTotalSize,
uliTotalFree;
} DISKSPACE;
__declspec(dllexport)
int DevGetDiskFreeSpace(DWORD cbInput, BYTE* pInput,
DWORD* pcbOutput, BYTE** ppOutput,
LPVOID pReserved)
{
DISKSPACE ds;
BOOL bOk;
bOk = GetDiskFreeSpaceEx((LPCTSTR)pInput, &ds.uliFreeUser,
&ds.uliTotalSize, &ds.uliTotalFree);
if(bOk)
{
*ppOutput = (BYTE*)LocalAlloc(LPTR, sizeof(ds));
memcpy(*ppOutput, &ds, sizeof(ds));
*pcbOutput = sizeof(ds);
}
return 0;
}
Of course, you need to put this in a device DLL and consume it as a blocking RAPI call.
Friday, June 29, 2007
CeGetDiskFreeSpaceEx
During my furious searches on the net, I found an obscure thread posted by someone from Microsoft stating that this API is only exposed from ActiveSync versions 4.0 onwards.
Tuesday, June 26, 2007
Data Port Console 1.0 Beta 3 available for download
Next up is to enable the serial port connectivity for Bluetooth emulated COM ports (the code is there, just needs a little work). I would like to have a native Bluetooth connectivity option in order to make it simpler for users to set up their devices, but this will imply going back to my Bluetooth code (which I started to write for this very purpose...).
Where do I want to go last? Device P2P. In a few days I will start working on the DesktopSqlCe successor that will also run on devices, so your mobile applications will be able to consume SQL Compact Edition databases locally or on a nearby device.
Back to work.
(*) This is not a real Beta. I will keep adding features to the application while it is almost ready to go live and after that as well. Beta status will stop when data can be exported to an Access database and when the number of errors is reduced to a sane minimum.
Monday, June 25, 2007
Primary Key or Index? ROWGUIDCOL or Guid.NewGuid()?
Looking for more performance material to publish about SQL Compact Edition, I found myself testing the performance of GUIDs when inserting on an indexed table. Performance will be marginally slower when you insert a GUID on a PRIMARY KEY column than when inserting it on a UNIQUE INDEX. In a 10,000 row insert sample it can be as low as half a second, but nevertheless this is an interesting result: PKs are slower.
Now, if you remove the ROWGUIDCOL property from the UNIQUEIDENTIFIER column and start generating the GUID values yourself, be prepared for a big surprise: the insertion time tripled (10.5 to 30.7 seconds on my battle-scarred JasJar). Is the Guid.NewGuid() function that slow?
Change MSI name in VS2005
The solution for this is to manually open the .vdproj file and edit it on a regular text editor (Notepad will do). Now search for the "OutputFilename" string under the configuration name of your choice (by default you will see "Debug" and "Release" under the "Configurations" group, but your project may have other configurations), and change the MSI file name. Save the file, open the project in VS2005 and rebuild.
Request for Orcas: can Microsoft please make this property available on the IDE?
EDIT: Someone smarter than me just showed me the way... Thanks, Pedro!
Tuesday, June 12, 2007
More troubles installing WTL Wizards in Vista
Then I decided to install Sergey Solozhentsev's WTL Helper tool. No issues again (nice!). This great tool requires that you download and install a new WTL Wizard from Sergey's website. Instead for using a JScript file to install everything, Sergey's Wizard uses an MSI file, and this is when I felt the iron grip of Vista security again: the MSI just would not install reporting an error number 2739. My friend Google pointed me in the right direction, first to understand what this error means, and what to do about it.
For your information, I did not remove the JScript key but merely renamed it. Running the msiexec /i command from the admin command window did the rest of the trick.
Friday, June 08, 2007
Data Port Console 1.0 Beta 2 available for download
One of the features I added for this Beta was a special request of Alberto Silva: the ability to edit the query data grid (when the user enters an "updatable" SELECT). Behind the scenes, the code just uses a SqlCeCommandBuilder to create the necessary commands (displayed on the notes tab) and these are used for updating (use the save button). You can also filter the grid by selecting the row state and the changes can be rolled back row by row (before updating, of course).
Comments and suggestions are welcome!
Monday, June 04, 2007
Tuning SQL Compact Edition Insert Performance
Wednesday, May 30, 2007
DBPROP_SSCE_MAXBUFFERSIZE
For now, keep this in your mind: increasing the value of DBPROP_SSCE_MAXBUFFERSIZE may actually help your database perform better.
Sunday, May 27, 2007
MFC Revisited
I (re)started developing for mobile devices in MFC and that was a very interesting experience. In those days the best PDA around was a Compaq iPAQ 3870 with Bluetooth and your development environment of chioce was eVC3. MFC seemed to be an obvious choice due to tool support but there were a few shortcomings. The frameworks imposes a document-view model that sometimes you have to fight against. Documentation was scarce (yes, the online help was bad) and your best resource was to read the MFC source files. This was how I got to understand how the framework was designed and why the tap-and-hold always made the dots circle twice. Interestingly you can see this behavior in a lot of the most recent devices on the Settings applets meaning that these are written in MFC (and the double circling bug is still there - sigh).
There is one good reason why you should not use MFC: it is slow. I understood this when I was working on the SqlCeSpy code and found that MFC would refresh a virtual list view noticeably slower than other applications, especially the ones written in ATL. MFC's message handling mechanism is a bit complex and convoluted meaning that when you need to handle a reflected message it gets bounced back and forth before it actually gets to where it is needed. The result for me was a slow refresh of the virtual list view. So slow in fact that it prompted me to write a grid-like control using virtual methods instead of reflected notification messages. Come to think of it, I never published this code...
So what is the best choice? As far as I can tell, when handling a user interface in native code, your best choice is to use WTL, ATL's extension now freely available from sourceforge. The thunk mechanism for handling the message maps make it very fast and efficient to process windows messages and applications tend to be both faster and smaller (compared to the statically linked MFC applications). Also, you feel like having much better control of what is going on and the templated approach is very elegant, although it requires conquering a steeper learning curve. But once you're there, you're hooked.
Thursday, May 24, 2007
Installing the WTL 7.5 Application Wizards in VS 2005 under Vista
It's not that difficult, but took some time to reverse-engineer what the script was doing. The first thing you need to do is to locate the VS application wizards directory. In my case it's in:
C:\Program Files\Microsoft Visual Studio 8\VC\vcprojects
Under this directory you must create a new one named WTL (what else?). Now go to the directory where you installed the WTL 7.5 files and copy the following files:
WTLAppWiz.ico
WTLAppWiz.vsz
to the vcprojects directory. You will need administrator clearance to do this. Now change the security settings of WTLAppWiz.vsz to allow editing. Change it so it looks like this:
VSWIZARD 7.0
Wizard=VsWizard.VsWizardEngine.8.0
Param="WIZARD_NAME = WTLAppWiz"
Param="WIZARD_VERSION = 8.0"
Param="ABSOLUTE_PATH = D:\src\WTL75\AppWiz\Files"
Param="FALLBACK_LCID = 1033"
Replace the D: path with your own WTL 7.5 directory. Finally, copy the WTLAppWiz.vsdir file to the WTL directory you created before and, going through the same security checks you did for the vsz file, change it so it reads:
..\WTLAppWiz.vsz ATL/WTL Application Wizard1An application that uses the Windows Template Library. 67774096#1154
You are done.
Tuesday, May 22, 2007
Data Port Console 1.0 Beta 1 available for download
There are some new features wothy of notice:
- Connection breakups are detected and handled. This means that if you inadvertently break the USB connection both the desktop and the device will gracefully recover (the device may take a few seconds before it becomes responsive, but this is a RAPI issue).
- The device component is now manually installed from a specific menu. I have included a very comprehensive set of device cabs: Pocket PC 2003, Windows Mobile 5 (both Pocket PC and Smartphone), Windows CE 4.2 (all CPUs) and Windows CE 5.0 (all CPUs). Hopefully the WM5 cab will install correctly on WM6 devices.
- The new version of DesktopSqlCe (1.8) is included (the console is built on top of DesktopSqlCe 1.8) and the Gold will ship with a single user license of this component. This means that if you just want to use the component in one PC (the same where the Console is installed) you will not have to pay the extra DesktopSqlCe license.
I'm really interested in reading your opinions on this product and what features you would add / remove / change.
Sunday, May 20, 2007
Diagnosing cab installations
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\AppMgr\ReportErrors = (DWORD)1
Thursday, May 17, 2007
The dangers of not terminating your strings
My first approach was to use the text conversion functions (wcstombs and mbstowcs). This way I had only one set of conversion functions (I mean converting from text to a GUID, to a DBTIMESTAMP and so forth). After the first tests the customer complained about stability: the data would be written to the database but the component DLL crashed almost consistently.
Back to the eVC4 debugger (now running on my Vista box in a Parallels virtual machine) I was confronted with an ugly beast. After successfully running the code, the whole thing would blast into hyperspace when closing the data source object (yes, that's the last thing you close). Hunting the bug forced me to look everywhere (even in the tested ATL OLE DB code). The thing was nowhere to be found. Often times I had to hard reset the debug device in order to get it back to its feet. Not a nice thing...
Bugs like these "smell" like memory issues: you write to a wild pointer and you may destroy some very fundamental data structures in your application. Needless to say that you are in for some unexpected outcomes.
I did not kill the bug directly. Instead, I rewrote the code so as to avoid text conversions. After running the new code for the first time the whole thing just behaved correctly. So should we avoid the text conversion functions altogether? Absolutely not! Just be wiser than me when you use them and make sure the converted strings are terminated. An unterminated string may cause this kind of problems in your application. So beware: you can either add one to the source string length or you can do that to the target string and make sure the buffer is zeroed before the conversion. Or you can do both.
Saturday, April 21, 2007
What was the last inserted IDENTITY value?
Wednesday, April 11, 2007
Installing CAB files from desktop .NET
The code I wrote for the installer is quite simple and I decided to write a short article on this. You can read it here.
Monday, April 09, 2007
Who put SQL CE 3.1 in my C:\Windows\System32?
Microsoft.SQLLITE.MOBILE.OLEDB.3.0
Say what!?!? SQLLITE???
P.S.: Yes, it looks like it is causing trouble: IAlterIndex does not work in my PC even after reinstalling SQL Compact Edition 3.1...
Saturday, March 24, 2007
SQL Compact Edition Insert Performance
The demo that caused most impact on my presentation was a benchmark between four different approaches to bulk data insertion on a SQL Compact Edition database. As you are probably guessing, using native code and OLE DB was the fastest scenario but the SqlCeResultSet also puts out a very decent performance.
To better illustrate this (and also to release the code to the public), I published an article that explains the benchmark and shows how wrong you can be if you don't use the correct approach...
Friday, March 02, 2007
Sunday, February 25, 2007
The Bluetooth sources
Requests for the Bluetooth code and article have not stopped, though so I decided to post links to the unedited versions of the C++ and C# sources. Before I get to fully comment the code and write a proper article, what you see is what you get. The sources are divided into 3 ZIP files:
Bluetooth.zip - Contains a sample C# WM5 application that enumerates devices and services. Also contains the Primeworks.Bluetooth class library.
msbts.zip - The low-level Microsoft Bluetooth stack wrapper.
wcbts.zip - The low-level Widcomm Bluetooth stack wrapper.
Now, I can take my time and write the full length article. All your comments and suggestions are welcome.
Sunday, February 18, 2007
Handling the Power Button
I finally got the eToken from Verisign. From now on I will be able to digitally sign my device DLL and CAB files in order to make life so much easier for my customers. I hope to have the first CAB for Windows Mobile 5 (Pocket PC) out next week.
Monday, February 05, 2007
An unexpectedly good experience
Well, I have to admit that I wasted a lot of my time procrastinating... After contacting Verisign for the first time on January the 31st, I got the full approval today. Instead of a heavy bureaucratic process, I was only asked for a telephone bill copy. After emailing it last Friday, I got the approval early this morning.
This is still not an inexpensive service, but it certainly is easy to purchase!
Tuesday, January 30, 2007
Installing a CE MAPI filter
There is a better way, though: the messaging application can be closed with a simple WM_CLOSE message sent to the right window. To find that window, use the FindWindow API with the "Inbox.MainWnd" class name. Once you close the messaging application, you can register and unregister the DLL without resetting the device. Nice.
Wednesday, January 24, 2007
Read-only SDF files
Friday, January 19, 2007
Reading the GPS port on the HTC P3300
Recently I had to tackle the built-in GPS serial port of the HTC P3300 and got a big surprise: my code wouldn't work! In fact, no characters were being buffered by the thread code meaning that the consuming application was receiving no data... After a close examination of what was going on in the thread code, I realised that no events were being generated by the serial port, namely the EV_RXCHAR that is used to signal that the serial port has characters to deliver. Interestingly, if you use the ReadFile API with a reasonable set ot timeouts you will be able to read data.
It is baffling to se how unreliably hardware support for common stuff like serial ports can be implemented. I'm still trying to figure out why HTC implemented it this way...
Friday, January 12, 2007
Recognition
Time to update eVC4?
[Edit]
Well, this was *my* error, not eVC4's... Shame on me.
Friday, January 05, 2007
RAPI Data Throttling
The connection speed can be so slow to the point where loading a very large table from the iPAQ 2210 (on a CF card) to the new Console may take several minutes. In the case of the huge table I discussed before, this means a 15 minute load time. If you think like I do, this is unnacceptable. So how can we speed up the communication between the device and the desktop? Easy: ZIP it!
In my particular case this was quite easy. All of my remote database access products use the same device DLL that communicates with the desktop via RAPI, TCP/IP or even the serial port. Data is packaged in messages of varying sizes and, depending on their semantics, they are either dispatched immediately or grouped together in a 64 KB buffer and sent when it fills up. This seems to be the optimal size for RAPI connections (according to one slide deck from MEDC 2005). So what happens if you compress this buffer before sending it? In my case the data transfer time was cut to a third. Now the behemoth table downloads to the desktop in under 5 minutes.
Finally, the ZIP library I'm using was found in CodeProject. This code allows me to compress and uncompress to a memory buffer, making it perfect for my own purposes.
Friday, December 15, 2006
1946
My apologies for the off-topic, but this flight sim just looks GREAT. I've been trying to fly IL2 FB only to find that no matter what plane I fly, I'm a damned turkey. If you are on to WW2 flight sims like me (addicted since the venerable SWOTL) 1946 has got to be your next toy - just take a look at the trailers (drool).
Thursday, December 14, 2006
How fast can you delete?
How about deleting? The same principles apply, actually. Use a base table cursor and (if possible) drop the indexes. But what if you have to selectively delete a large number of rows in a very large table? Well, you will need an index to seek the rows to delete. You pick up the next row to delete (given a unique row ID), seek it and delete it. Simple? No. This apparently simple process can become a real headache as I have just learned.
The scenario is simple: a very large database (around 50 MB) stored on a very fast (80x) CF card. I'm given a text file containing a very large set of GUID values that correspond to rows in a table (around 150K rows) to delete. The table has 6 indexes and a PK. How fast can we go on an iPAQ 2210 (my wartime machine) deleting al the rows? We cannot just do a DELETE FROM because this is a selective algorithm - it just happens to be deleting all of the rows (the same result would apply of you were deleting most of them).
Anywhere from 7 minutes to several hours... Really. Is this an issue with the CF card? No - this is repeatable on other devices with different flash cards. Is this an issue with the indexes? Partly - if you remove all indexes but the GUID you will get better performance, but this is a restriction of the problem: I cannot drop the indexes (after all, the algorithm does not know how many rows it is supposed to delete). Is this an issue with SQL CE? No - after all there is a scenario where you delete all the rows in 7 minutes (roughly the same as the DELETE FROM command takes).
As it turns out, this is an issue with the order with which you feed the GUID values to the algorithm. The 7 minutes run was achieved with an unsorted set of GUID values (randomly fed) where the several hours run (actually this is a projection because I stopped the bastard after 30 minutes and only 25K rows deleted) was ran when the GUID values were sorted. Yes, you read correctly - sorted.
So if you are in a similar scenario, please make sure you are not deleting the rows in the same order of the index you are seeking them on. It will kill your performance.
Why does this happen? B-tree algorithms, anyone?
Thursday, November 30, 2006
Renaming a SQL CE Table From a .NET CF Application
Wednesday, November 29, 2006
ALTER TABLE / ALTER COLUMN
If you compare the 2.0 BOL with the 3.0 BOL you see no difference. The same syntax is supported with the same limitations. Well, actually not.
With SQL CE 3.0 you can change a column data type using an ALTER TABLE command. The Syntax is very simple:
ALTER TABLE table ALTER COLUMN column type
I just got a confirmation from Microsoft that this is missing from the documentation so you should see it included in future versions.
Implications of this discovery are very important to me, especially for the SQL CE table editor in Data Port Console (now in Draft 11):
- Editing tables for SQL CE 3.0 just got easier. Instead of recreating a table every time a user requests a change in column data types, I only need to generate an appropriate SQL command and I'm done with it.
- Now, how do I keep backwards compatibility with SQL CE 2.0? Well, I don't. When using the SQL CE 2.0 engine the Console code will have to recreate the table (and hope the user has the missing msdadc.dll on the device - a highly unlikely scenario).
Back to the VS2005 editor...
Thursday, November 23, 2006
Biting the DB_NUMERIC bullet
Well, you avoid biting the bullet until you definitely have to do it. Right now I'm working on a native code text-to-SDF conversion tool for a customer and one of the types I need to handle is the dreaded numeric.
It's interesting that this is a very popular type due to the fact that it represents a fixed-precision number. What's more, you get to define the precision. The downside to this type is its sheer size: 19 bytes! As a matter of fact, a numeric value is represented as a DB_NUMERIC structure. If you look it up either on MSDN or on oledb.h, you will see what I'm talking about. The damned thing is a monster.
Now my problem was to deserialize a text representation of a numeric value and store it in a DB_NUMERIC structure so I could feed it to the SQL CE OLE DB provider. If you are thinking about using the IDataConvert interface then you can forget it because Microsoft does not provide the msdadc.dll file anymore, so you have to convert the beast by yourself.
Firstly I tried a two tier approach: convert the text to a double and then convert the double to a DB_NUMERIC (there's some code out there that does this). You have to be careful with rounding to get the conversion done, but it works... slowly.
My second approach was actually based on the first one, but I removed most of the floating point calculations. It is fast but limited to numbers with a precision of 18 digits. Take a look:
bool CDbNumeric::Parse(LPCTSTR pszText)
{
__int64 big = 0;
LPCTSTR pCur;
int nScale = -1;
int i;
for(pCur = pszText; *pCur == ' '; ++pCur)
;
if(*pCur == '-')
{
++pCur;
sign = 0;
}
else
sign = 1;
for(; *pCur && nScale; ++pCur, --nScale)
{
if(IsNumeric(*pCur))
{
big = big * 10 + (*pCur - '0');
}
else if(*pCur == '.')
{
if(nScale > 0)
return false;
nScale = scale + 1;
}
else
return false;
}
memset(val, 0, sizeof(val));
for(i = 0; i < 16 && big != 0; ++i)
{
val[i] = (BYTE)(big & 0xFF);
big >>= 8;
}
return true;
}
It's faster, believe me.
Tuesday, November 14, 2006
Just another database?
SQL Server Everywhere: Just Another Database?
Thursday, November 09, 2006
Thank you Rui!
Data Port Console Draft 6
Tuesday, November 07, 2006
Data Port Console Draft 5
Anybody else out there with some bright ideas?
Monday, November 06, 2006
Microsoft SQL Server 2005 Compact Edition RC1
JScript support on Windows Mobile
Thursday, November 02, 2006
Draft 3 Notes
The new RemSqlCe.dll (marked as 1.50.xxxx) now supports multiple databases per physical connection. I was looking forward to implement this new feature some time ago. It was not quite necessary for products like the Wizard where you actually process one device database per connection. With DesktopSqlCe I started to feel the need to implement this but as the sales took off I simply got too busy supporting my customers cleaning off some very stupid bugs, and this was delayed.
I finally decided to rewrite the console and implementing this feature was on the top of my to-do list. Designing the multi-database support code was quite easy: I extracted most of the code that was on a single monolithic server and implemented it in a separate class. This new server class is instantiated whenever a new database is created or an existing one is opened, and a pointer to it is stored in an internal array of 256 elements (I believe you will never need to open 256 databases on a device at the same time, will you?). When you open a database using the Draft 3 code you can see the server index in the database properties window. If you get a -1 after opening the database then you are using an older version of RemSqlCe.dll - please replace it. Note that the index value will not automatically refresh after opening the database. To do so, please select another node in the tree and select the database node again.
Please send all your comments and suggestions to this forum. The best ideas will get a free license. What do you think should be in this product?
- Integrated import / export features?
- If so, what formats should I support?
- What database editing features are the most important for you?
- Should I implement some sort of SQL Command batch processing?
- Do you want to manage other Microsoft databases from this console?
- Should I integrate the Data Port Sync features?
Let's hear it from you!
Wednesday, November 01, 2006
Data Port Console Draft 3
- Export the table data to an Excel sheet and
- Specify database open and creation properties
As always, remember that this is not a product yet. Most of the features you will see on the menus will not work. Although my tests have shown that the data handling is now stable (the underlying native code DLLs have been revamped to support multiple connections per Pipe), please refrain to use your production SDF files with this and use copies instead.
Tuesday, October 31, 2006
SQL Server Compact Edition
Looks like I will have to change all my product's documentation...
Tuesday, October 24, 2006
Data Port Console Draft 1
So why am I posting this? I want your feedback on how the product should evolve and I am ready to give away free licenses for the best feature ideas. Use the special forum to express yourself.
Wednesday, October 18, 2006
Handling multiple databases
One of the biggest improvements you will see is that the code now handles multiple databases per connection (DesktopSqlCe users - this will also apply to you). As a matter of fact, and as you should expect, the whole product is based on DesktopSqlCe and I am using this as an excuse to add more features to the component.
The versions so far used to tie up the Pipe (physical connection) to the SqlCeDatabase in a one-to-one relationship. No more! Now you can have more than one SqlCeDatabase object per Pipe even on a RAPI connection. This enables some interesting scenarios indeed, and the first consumer for this one will be the new Console. Stay tuned for the incoming Draft 1.
Monday, October 16, 2006
SQL CE Console Updated (1.3.700)
With SQL CE 2.0 there are no problems because the clever OLE DB provider allows you to overwite the generated value.
SQL Mobile, on the other hand, has a mean OLE DB engine - the only way you can influence the next IDENTITY value is by altering the column's seed through either a SQL command or a low-level OLE DB interface (my solution).
To avoid changing the IDENTITY seed for every copied row I use an optimization algorithm that keeps track of the next value and only alters the column if there is a difference between the value to write and the automatically generated one. This is actually a variation of the same algorithm found in Data Port Wizard.
For all you SQL CE Console users, here's the latest download.
Thursday, October 12, 2006
Accessing SQL Mobile-specific column properties
Wednesday, September 27, 2006
SQL Syntax Highlighting
SELECT * FROM Customers
Fonts and colors are applied as you write and now I want to extend the editor to support auto-completion. Instead of purchasing a costly component, I decided to adapt the code on this article:
Syntax highlighting textbox written in C#
The code has some bugs and gotchas, but it is easy to use and adapt to VS 2005.
Saturday, September 23, 2006
Data Port Console
Combine this with the new .NET Framework 2.0 features such as a better data grid, and I am actually getting very good results and very fast. Looks like .NET is actually delivering its promise: fast time-to-market with a solid framework to support your application.
P.S.: Yes, I know it hogs memory and the CPU with what some native code purists would call needless cycles. But I'm not sure I would be able to do this as fast as I am doing now with either MFC or WTL. Anyway, the core of the code - remote database access - is still native code. The more I think of it, the more I like this combination: native code for the performance bits and managed code for the UI and managing the user environment. A killer!