Introduction
This article demonstrates how to work around unreliability problems when using SHCameraCapture
or the CameraCaptureDialog
.
Background
This mini-series is a pair of articles on two scenarios using SHCameraCapture
.
The first one is called Using SHCameraCapture from a C++ Pocket PC 2003 Application. It describes the steps needed to access the SHCameraCapture API from a C++ project built for a Pocket PC 2003 device.
The second one is called What to do if SHCameraCapture Returns E_FAIL? In this article, I describe my experiences with the API, and the way I could work around it in the end.
In the previous article, I described how to compile SHCameraCapture
for a Pocket PC application. It works, but it is unreliable. Often, the call returns E_FAIL
(but not E_OUTOFMEMORY
).
From web posts I found, I understood it is not a problem with the above solution, but is related to memory issues. In our case, the occurrences of E_FAIL
increased with memory pressure, with image size, and also with the “complexity” of the application, where capture was called. Also, while SHCameraCapture
was failing from our application, the same camera dialog could be used just fine by pressing the hardware capture button on the device.
My hunch was that the problem was caused by memory fragmentation: there may be 10MB of free space on the device, but if it is broken into smaller chunks, the capture application can’t allocate 1MB (for a 640x480x24 bits image) contiguous memory to store the image before compressing it to a small JPEG file.
But, in Pocket PC, each process gets its own virtual memory space; that would explain why a separate application runs fine. So, I decided to put the capturing on a separate process.
I created a wrapper application for the camera capture that takes the image parameters from the command line, returns the status information as application exit codes, and always stores the captured image under the same file name. The result is cool: since then I experienced no E_FAIL
s whatsoever.
Using the code
This implementation (of the wrapper) uses CF1. CF1 or CF2 is built into Windows Mobile 5 and 6 devices, so we don’t have to download extra code. For earlier devices (such as Pocket PC 2003), the camera API is not available anyway, so CF1 is a safe bet. (If you want, you can easily implement the same behavior with a small Win32 or MFC application.)
You can download the complete capture wrapper solution for Visual Studio 2005 here. The supplied implementation supports still images only, with resolutions of 320x240, 640x480, and 1280x960. If you want, you can extend it with a few more command line arguments to support video as well.
Here is the code that invokes the camera capture wrapper application and processes results:
HRESULT hr = E_FAIL;
PROCESS_INFORMATION pi;
LPSTARTUPINFOW psi = NULL;
BOOL bExec = FALSE;
HINSTANCE hInstance = GetModuleHandle(NULL);
TCHAR strMsg[MSGBUFLEN+1];
TCHAR strCaption[MSGBUFLEN+1];
HANDLE hProc = NULL;
DWORD nCaptureAppExitCode;
CString strCaptureAppNameWithPath;
strCaptureAppNameWithPath.Format( _T("%s\\%s"),
Utils::GetAppBasePath(), CAPTURE_APP_NAME );
CString strCommandLineArgs;
strCommandLineArgs.Format( _T("/dir=\\Captures /res=1280x960 /stillquality=high") );
bExec = CreateProcess( (LPCTSTR)strCaptureAppNameWithPath, (LPCTSTR)strCommandLineArgs,
NULL, NULL, NULL, 0, NULL, NULL, psi, &pi );
if (!bExec)
{
LoadString(hInstance, IDS_COULD_NOT_START_CAPTUREAPP, strMsg, MSGBUFLEN);
MessageBox ( NULL, strMsg, strCaption, MB_ICONEXCLAMATION | MB_OK );
hr = E_FAIL;
} else
{
hProc = OpenProcess ( 0, FALSE, pi.dwProcessId );
WaitForSingleObject( hProc, INFINITE );
GetExitCodeProcess ( hProc, &nCaptureAppExitCode );
switch ( nCaptureAppExitCode )
{
case CAPTURE_EXITCODE_OK:
hr = S_OK;
strFileName = CAPTURE_IMAGE_NAME;
break;
case CAPTURE_EXITCODE_CANCELLED:
case CAPTURE_EXITCODE_ARGERROR:
default:
hr = S_OK;
strFileName = _T("");
break;
} } return hr;
The above sample (that invokes the wrapper application) uses C++ and MFC. As I looked around the web, I found that the problem is not limited to native applications, so the same approach may be applied to .NET Compact Framework applications as well.