So, you're coding a Mobile 5 app that uses Microsoft's canned camera
dialog (because let's face it, DirectShow is not much fun), but you
want to do
most of your work in Compact Framework version 1 (let's all thank
Microsoft for not shipping CF2 in time to be included with most mobile
devices). Well, this can easily be done with a small amount of C++ code
and a bit of interop.
The first thing you need to know is that, although Microsoft didn't
get CF2 onto most Mobile 5 devices, they DID get that Camera Dialog in
there. So the
camera dialog is actually available on all Mobile 5 devices (as far as
I know). The next thing you need to know is that the Win32 function
you'll need is
called SHCameraCapture(). This function is well documented in the MSDN libraries, etc.
The general approach to take is to code up a small C++ DLL to make the SHCameraCapture()
call. You'll likely want to wrap the
call in your own C++ DLL to simplify the interop calls from CF1. Beware
the limitations of interop marshaling in CF1, CF2 interop is MUCH
nicer. Here is a bit of sample code that might resemble a couple of the
entry points in such a DLL:
//---------------------------------------------------------------------------------------------
extern "C" SCANRCAMERA_API WCHAR* fnCameraCapture(
WCHAR* szInitialDir, WCHAR* szDefaultFileName, WCHAR* szTitle, int iWidth, int iHeight)
{
WCHAR* szResultImagePath = new WCHAR[MAX_PATH];
memset(szResultImagePath, '\0', MAX_PATH);
HRESULT hResult;
SHCAMERACAPTURE shcc;
ZeroMemory(&shcc, sizeof(shcc));
shcc.cbSize = sizeof(shcc);
shcc.hwndOwner = GetActiveWindow();
shcc.pszInitialDir = szInitialDir;
shcc.pszDefaultFileName = szDefaultFileName;
shcc.pszTitle = szTitle;
shcc.nResolutionWidth = iWidth;
shcc.nResolutionHeight = iHeight;
shcc.Mode = CAMERACAPTURE_MODE_STILL;
shcc.StillQuality = CAMERACAPTURE_STILLQUALITY_HIGH;
// Display the Camera Capture dialog.
hResult = SHCameraCapture(&shcc);
if(hResult != S_OK) { return(NULL); }
wcscpy(szResultImagePath, shcc.szFile);
return(szResultImagePath);
}
//---------------------------------------------------------------------------------------------
extern "C" SCANRCAMERA_API void fnFreeMemory(void *p) {
delete(p);
}
You will likely notice the odd "free memory" method my DLL is
exposing. This is my favored way to make sure I'm dealing with
allocated memory correctly while interoping from CF1. It's best to try
not to leak too much memory while haphazardly bouncing back and forth
between managed and unmanaged code. This will make more sense after
having a look at the sample C# code that uses this DLL.
// Import the DLL entry points
[DllImport(@"CF1Camera.dll")]
public static extern IntPtr fnCameraCapture(
String initialDir, String defaultFileName, String windowTitle, int imageWidth, int imageHeight);
[DllImport(@"CF1Camera.dll")]
public static extern void fnFreeMemory(IntPtr p);
// At some point later use your DLL
IntPtr imagePathPtr = fnCameraCapture(@"\Temp", "test.jpg", "Camera DLL Test", 800, 600);
if(imagePathPtr == IntPtr.Zero) {
int win32ErrorCode = Marshal.GetLastWin32Error();
throw (new ApplicationException("fnCameraCapture() failed. Error code: " + win32ErrorCode.ToString()));
}
string imagePath = Marshal.PtrToStringUni(imagePathPtr);
fnFreeMemory(imagePathPtr);
And there you go. You've just used the pre-packaged camera dialog to
capture an image from CF1. Like I say, PInvoking from CF2 is a lot
nicer. You could work your way through doing a direct PInvoke to SHCameraCapture() from CF1, but I found this approach
to be much easier.
-Todd