Monday, September 17, 2007

If you've ever tried to play a media file in your own managed application on a generic CE device then you know just how utterly painful it can be.  Often develoeprs resort to ugly hacks involving sending Media Player key strokes and trying to hide its menus and buttons.

Well no more!  We've just released a new control for managed developers that allows you to drop the video on your form where you want then control playback from a sensible API.  We've even created a nice sample application that provides an example of what you can do with the control.

 

Get more info here.

 

9/17/2007 12:20:21 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0]  | 
 Thursday, September 06, 2007

So we've already gotten a submission for this month's coding competiton called FlowFx, and I must say it's pretty damned nice.  I'd say this one sets the bar for the quality of what needs to be submitted.

Take a look at the video of the UI in action.

Enter your Windows Mobile or Embedded code for a change to win some cool prizes this month and every month at http://community.opennetcf.com

9/6/2007 6:29:24 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0]  | 
 Tuesday, September 04, 2007

Today we were working on some final testing of a new app and I was irritated by the About Form's behavior of generice CE devices.  When we went to display the form, we'd get the ugly "expanding rectangle" animation of the Form opening, and even worse, when we closed it it would animate the close, then animate the re-opeing of the main form.

Unfortunately the Compact Framework give us absolutely nothing for controlling this behavior (hello?  Windows Mobile isn't the only platform the CF is used on....).  So we have to work around it.

Add the following to your form (or a utility class is what we actually used, as we called this from multiple places):

private const int WS_EX_NOANIMATION = 0x04000000;
private const int GWL_EX_STYLE = -20;

[DllImport("Coredll.dll", SetLastError=true)]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

[DllImport("coredll.dll", SetLastError=true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

internal static void StopAnimation(Form form)
{
    int style = GetWindowLong(form.Handle, GWL_EX_STYLE);
    style |= WS_EX_NOANIMATION;
    SetWindowLong(form.Handle, GWL_EX_STYLE, style);
}

Then simply call StopAnimation in your Form's constructor immediately after InitializeComponent is called:

public Form1()
{
    InitializeComponent();
    StopAnimation(this);
}

We'll probably add this to the next release of the Smart Device Framework.

9/4/2007 4:41:52 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0]  | 

This morning OpenNETCF announced a new web initiative - our Community Web Site. I'll spare you explaining it in detail here, as it's on the front page of the site, but we've got articles and white papers, a public SVN server for shared-source projects and a monthly coding competition. This month we're giving away a copy of Studio 2005 professional and a Windows Mobile 5.0 device of your choice.

To come are Forums and a Wiki.

Let us know what you think.

9/4/2007 10:42:06 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0]  | 
 Thursday, July 05, 2007

Not surprisingly, our initial release of the OpenTimeCE library (a utility to allow developers to port code using the time_t, mktime, etc APIs to Windows CE) has some bugs in it.  First releases are rarely bug free.  What was really nice was that these fixes were purely community driven.  We'd received some "reports" in the past that there were bugs, but finally today someone (thanks Ben Murdoch) sent in a fully patched source file, so we rolled it into the code base and re-released it. It just goes to show that an open-source mindset and a Microsoft product *can* indeed not just co-exist, but provide something beneficial.

 

7/5/2007 4:43:21 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [1]  | 
 Tuesday, June 26, 2007

Like most developers, I have tons of small code samples and snippets lying around.  I'm starting to go through them in order to post what might be useful to others.

Here's one that I wrote about 5 years ago when I had a customer complaining about the speed of parsing an XML document using MSXML.  Of course this test simply confirmed that yes, MSXML is molasses-in-January slow and that if raw speed is what you want, then something like Expat is a better route to go.  However the test is a reasonably good sample of how you might use the DOMDocument from a C++ application.

As always, the code is an as-is sample.  uSe it at your own risk.

#include <windows.h>
#include "objbase.h"
#include "oleauto.h"
#include "MSXML.h"
#include "ATLBASE.h"
#import "msxml.dll" named_guids raw_interfaces_only

TCHAR *xmlfile = _T("\\test.xml");
using namespace MSXML;

void GetCurrentDirectory(TCHAR *szDirectory);


int WINAPI WinMain(    HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPTSTR lpCmdLine,
                    int nCmdShow)
{
    MSXML::IXMLDOMDocument      *iXMLDoc          = NULL;
    HRESULT                     hr;
    VARIANT_BOOL                b;
    int                         et                = 0;
    HANDLE                      hFile             = NULL;
    DWORD                       wsize, dwhigh     = 0;
    TCHAR                       filename[MAX_PATH];
    MEMORYSTATUS                ms;
    BYTE                        *buffer           = NULL;
    TCHAR                       *wbuffer          = NULL;
    DWORD                       dwRead            = 0;
    DWORD                       toalloc           = 0;
    int                         i;
    CComBSTR                    *bstr;

    _tprintf(_T("Starting XML Benchmark...\n"));
    _tprintf(_T("Creating DOMDocument..."));

    // start COM
    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

    // create a DOMDocument
    hr = CoCreateInstance (MSXML::CLSID_DOMDocument, NULL,
                 CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
                 MSXML::IID_IXMLDOMDocument,(LPVOID *)&iXMLDoc);

    // check for success
    if(!iXMLDoc)
    {
        _tprintf(_T("failed (hr = %i)\n"), hr);
        goto exit;
    }

    _tprintf(_T("ok\n"));

    // synchronous operation
    iXMLDoc->put_async(VARIANT_FALSE);

    // get the data file - pull from the same directory as our app
    GetCurrentDirectory(filename);
    _tcscat(filename, xmlfile);
    _tprintf(_T("Opening XML file (%s)..."), filename);

    hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

    if(hFile == INVALID_HANDLE_VALUE)
    {
        _tprintf(_T("failed (err = %i)\n"), GetLastError());
        goto exit;
    }

    // determine the file size
    dwsize = GetFileSize(hFile, &dwhigh);

    _tprintf(_T("ok\n"));

    // check available memory
    ms.dwLength = sizeof(MEMORYSTATUS);
    GlobalMemoryStatus(&ms);

    // either 1/3 available memory or file size, whichever is less
    toalloc = (dwsize > (ms.dwAvailPhys / 3)) ? (ms.dwAvailPhys / 3) : dwsize;

    _tprintf(_T("Allocating %i bytes..."), toalloc);
    
    //alocate buffers. data is ANSI, loadXML requires Unicode
    buffer = (BYTE *)LocalAlloc(LPTR, toalloc);
    wbuffer = (TCHAR *)LocalAlloc(LPTR, toalloc * sizeof(TCHAR) + 1);

    // check for success
    if((buffer == NULL) || (wbuffer == NULL))
    {
        _tprintf(_T("failed (err = %i)\n"), GetLastError());
        goto exit;
    }

    _tprintf(_T("ok\nReading %i bytes..."), toalloc);
    
    // fill the RAM buffer with data
    ReadFile(hFile, &buffer[0], toalloc, &dwRead, NULL);

    // lazy man's ANSI to Unicode conversion
    // this is NOT recommended for production code, don't cut and paste!!
    for(i = 0 ; i < (int)toalloc ; i++)
    {
        wbuffer[i] = buffer[i];
    }
    wbuffer[i] = '\0';
    bstr = new CComBSTR(wbuffer);

    _tprintf(_T("ok\nLoading %i bytes into DOMDocument..."), toalloc);

    // get a start time
    et = GetTickCount();

    // load the xml
    hr = iXMLDoc->loadXML(*bstr, &b);

    // determine ET
    et = GetTickCount() - et;

    // check for load failure
    if(!b)
    {
        _tprintf(_T("failed (hr = %i)\n"), hr);
        _tprintf(_T("GetLastError = %i\n"), GetLastError());
        goto exit;
    }

    _tprintf(_T("done.\n\nET = %i ms\n\n"), et);

exit:
    // release the DOMDocument
    iXMLDoc->Release();

    // release the file
    CloseHandle(hFile);

    // release COM
    CoUninitialize();

    _tprintf(_T("Exiting XML Benchmark in 5 seconds...\n"));
    
    // free buffers
    if(buffer)
        LocalFree(buffer);
    
    if(wbuffer)
        LocalFree(wbuffer);

    // wait to allow display to persist for a while
    Sleep(5000);

    return 0;
}

void GetCurrentDirectory(TCHAR *szDirectory)
{
    TCHAR *p, *p2;

    // get current directory
    GetModuleFileName(NULL, szDirectory, MAX_PATH);

    // trim off the exe name
    p = _tcsstr(szDirectory, _T("\\"));

    if(p == NULL)
    {
        // no slash found - return root?
        _tcscpy(szDirectory, _T("\\"));
        
        return;
    }

    while( p != NULL)
    {
        p2 = p + 1;
        p = _tcsstr(p2, _T("\\"));
    }

    // null terminate to crop
    p2--;
    *p2 = '\0';

    return;
}

6/26/2007 4:16:45 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0]  |