Using Memory Conversions for C++

The following code demonstrates how to implement memory conversions:

// include the LEAD Multimedia TOOLKIT header
#include "ltmm.h"

#include "resource.h"
#include <tchar.h>
#include <stdio.h>
#include <assert.h>

HINSTANCE g_hInstance; // application instance handle
IltmmConvert* g_pConvert; // convert object's interface pointer

// user defined message id used for conversion events
#define WM_CONVERTNOTIFY (WM_USER + 1000) 

//
// ConvertDlgProc
// starts the conversion process and provides status feedback
//
// controls: 
// IDC_CONVERTSTATUS - static control used for status messages
// IDC_CONVERTPROGRESS - static control used for conversion progress
// IDC_USERABORT - button control used to abort the conversion or exit the dialog

BOOL CALLBACK ConvertDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{
   TCHAR sz[256]; 
   BSTR bstr1; 
   BSTR bstr2; 
   HRESULT hr; 
   long state; 
   long type; 

   switch (msg) 
   {
   case WM_INITDIALOG: 
      // assign the notification window
      g_pConvert->SetNotifyWindow ((long) hwnd, WM_CONVERTNOTIFY); 
      
      // set the abort button text
      SetDlgItemText(hwnd, IDC_USERABORT, _T("Abort"));

   
      // start the conversion
      hr = g_pConvert->StartConvert ();

      if(FAILED(hr)) 
      {
         _stprintf(sz, _T("conversion error 0x%.8X"), lParam); 
         SetDlgItemText(hwnd, IDC_CONVERTSTATUS, sz); 
         UpdateWindow(GetDlgItem(hwnd, IDC_CONVERTSTATUS)); 
         SetDlgItemText(hwnd, IDC_USERABORT, _T("Exit"));
         MessageBeep(0); 
      }
      return TRUE; 
      break; 
   case WM_DESTROY: 
      // reset the notification window
      g_pConvert->SetNotifyWindow ((long) NULL, 0); 
#ifdef _DEBUG
   {
      long state, err, pc; 
      TCHAR sz[1024]; 
      
      // get the current state
      g_pConvert->get_State (&state); 
      
      // get the current state
      g_pConvert->get_ConvertError (&err); 

      // get the amount converted
      g_pConvert->get_PercentComplete(&pc); 
      
      _stprintf(sz, _T("state = %d, error = 0x%.8X, complete = %d%%"), state, err, pc); 
      MessageBox(NULL, sz, _T("debug"), MB_OK); 
   }
#endif
   
      break; 
   case WM_COMMAND: 
      switch (LOWORD(wParam)) 
      {
      case IDC_USERABORT: 
         // user abort... stop conversion
         g_pConvert->get_State (&state); 
         if(state == ltmmConvert_State_Running) 
            g_pConvert->StopConvert ();
         else
         {
            g_pConvert->get_ConvertError ((long*) &hr); 
            EndDialog(hwnd, (long) hr); 
         }
         return TRUE; 
         break; 
      }
      break; 
   case WM_CONVERTNOTIFY: 
      switch(wParam) 
      {
      case ltmmConvert_Notify_Started: 
         // indicate conversion has started
         g_pConvert->get_SourceType(&type); 
         switch(type) 
         {
         case ltmmConvert_Source_File: 
            g_pConvert->get_SourceFile(&bstr1); 
            break; 
         case ltmmConvert_Source_HGlobal: 
            bstr1 = SysAllocString(L"[hglobal]"); 
            break; 
         case ltmmConvert_Source_Array: 
            bstr1 = SysAllocString(L"[array]"); 
            break; 
         case ltmmConvert_Source_Object: 
            bstr1 = SysAllocString(L"[object]"); 
            break; 
         }
         g_pConvert->get_TargetType (&type); 
         switch(type) 
         {
         case ltmmConvert_Target_File: 
            g_pConvert->get_TargetFile (&bstr2); 
            break; 
         case ltmmConvert_Target_Array: 
            bstr2 = SysAllocString(L"[array]"); 
            break; 
         case ltmmConvert_Target_Object: 
            bstr2 = SysAllocString(L"[object]"); 
            break; 
         }
         _stprintf(sz, _T("recompressing '%ls' to '%ls'..."), bstr1, bstr2); 
         SysFreeString(bstr1); 
         SysFreeString(bstr2); 
         SetDlgItemText(hwnd, IDC_CONVERTSTATUS, sz); 
         UpdateWindow(GetDlgItem(hwnd, IDC_CONVERTSTATUS)); 
         break; 
      case ltmmConvert_Notify_Complete: 
         // indicate an conversion complete
         _stprintf(sz, _T("conversion complete"));
         SetDlgItemText(hwnd, IDC_CONVERTSTATUS, sz); 
         UpdateWindow(GetDlgItem(hwnd, IDC_CONVERTSTATUS)); 
         SetDlgItemText(hwnd, IDC_USERABORT, _T("Exit"));
         break; 
      case ltmmConvert_Notify_ErrorAbort: 
         // indicate an error
         _stprintf(sz, _T("conversion error 0x%.8X"), lParam); 
         SetDlgItemText(hwnd, IDC_CONVERTSTATUS, sz); 
         UpdateWindow(GetDlgItem(hwnd, IDC_CONVERTSTATUS)); 
         SetDlgItemText(hwnd, IDC_USERABORT, _T("Exit"));
         MessageBeep(0); 
         break; 
      case ltmmConvert_Notify_UserAbort: 
         // indicate user abort
         _stprintf(sz, _T("conversion aborted\n"));
         SetDlgItemText(hwnd, IDC_CONVERTSTATUS, sz); 
         UpdateWindow(GetDlgItem(hwnd, IDC_CONVERTSTATUS)); 
         SetDlgItemText(hwnd, IDC_USERABORT, _T("Exit"));
         MessageBeep(0); 
         break; 
      case ltmmConvert_Notify_Progress: 
         // indicate conversion progress
         _stprintf(sz, _T("%3d%% complete"), lParam); 
         SetDlgItemText(hwnd, IDC_CONVERTPROGRESS, sz); 
         UpdateWindow(GetDlgItem(hwnd, IDC_CONVERTPROGRESS)); 
         break; 
      }
      return TRUE; 
      break; 
   }
   return FALSE; 
}


//
// SetAVIRecompression
// sets up LEAD video compression, MP3 audio compression, and AVI file output
//
// hwndParent = parent window for compressor property dialog boxes
//
HRESULT SetAVIRecompression(HWND hwndParent) 
{
   IltmmCompressors* pCompressors; 
   long index; 
   VARIANT_BOOL f; 
   BSTR bstr; 

   // select the LEAD video compressor
   g_pConvert->get_VideoCompressors (&pCompressors); 
   bstr = SysAllocString(L"@device:sw:{33D9A760-90C8-11D0-BD43-00A0C911CE86}\\LEAD MCMP/MJPEG Codec A COmpressor combined with a DECompressor, or encoder and a decoder, which allows you to both compress and decompress that same data.COmpressor Also known as an encoder, this is a module or algorithm to compress data. Playing that data back requires a decompressor, or decoder. combined with a DECompressor, or encoder Also known as compressor, this is a module or algorithm to compress data. Playing that data back requires a decompressor, or decoder. and a decoder Also known as a decompressor, this is a module or algorithm to decompress data., which allows you to both compress and decompress that same data. (2.0)");
   pCompressors->Find(bstr, &index); 
   SysFreeString(bstr); 

   if(index < 0) 
   {
      // compressor isn't registered
      pCompressors->Release();
      return E_FAIL; 
   }
   pCompressors->put_Selection (index); 
   pCompressors->Release();
   
   
   // select the MP3 audio video compressor
   g_pConvert->get_AudioCompressors (&pCompressors); 
   bstr = SysAllocString(L"@device:cm:{33D9A761-90C8-11D0-BD43-00A0C911CE86}\\85MPEG Layer-3");
   pCompressors->Find(bstr, &index); 
   SysFreeString(bstr); 
   if(index < 0) 
   {
      // compressor isn't registered
      pCompressors->Release();
      return E_FAIL; 
   }
   pCompressors->put_Selection (index); 
   pCompressors->Release();

   // set output format to AVI
   g_pConvert->put_TargetFormat (ltmmConvert_TargetFormat_Avi); 

#ifdef _DEBUG
   {
      long v;
      g_pConvert->get_TargetFormat(&v);
      assert(v == ltmmConvert_TargetFormat_Avi);
   }
#endif
   // set video compressor properties
   g_pConvert->HasDialog (ltmmConvert_Dlg_VideoCompressor, &f); 
   if(f) 
      g_pConvert->ShowDialog(ltmmConvert_Dlg_VideoCompressor, (long) hwndParent); 
   
   // set audio compressor properties
   g_pConvert->HasDialog (ltmmConvert_Dlg_AudioCompressor, &f); 
   if(f) 
      g_pConvert->ShowDialog(ltmmConvert_Dlg_AudioCompressor, (long) hwndParent); 

   return S_OK; 
}


//
// RecompressArray
// recompresses array to array using the LEAD video and MP3 audio compressors
//
// 1. the source file is preloaded into a source array
// 2. the source array is recompressed to a target array
// 3. the target array is written to the target file
//
// pszSource = source file path
// pszTarget = target file path
//
HRESULT RecompressArray(LPCTSTR pszSource, LPCTSTR pszTarget) 
{
   HRESULT hr; 
   HANDLE hfile;   
   DWORD size, cb; 
   void* buffer; 
   VARIANT var; 
   SAFEARRAY* psaSource; 
   SAFEARRAY* psaTarget; 

   // open the source file
   hfile = CreateFile(pszSource, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 
   if(hfile == INVALID_HANDLE_VALUE) 
      return E_FAIL; 

   // allocate same-sized SAFEARRAY
   size = GetFileSize(hfile, NULL); 
   
   psaSource = SafeArrayCreateVector(VT_UI1, 0, size); 
   if(!psaSource) 
   {
      CloseHandle(hfile); 
      return E_OUTOFMEMORY; 
   }

   // read entire source into array
   SafeArrayAccessData(psaSource, (void**) &buffer); 
   if(!ReadFile(hfile, buffer, size, &cb, NULL) || cb != size) 
   {
      SafeArrayUnaccessData(psaSource); 
      CloseHandle(hfile); 
      SafeArrayDestroy(psaSource); 
      return E_FAIL; 
   }
   SafeArrayUnaccessData(psaSource); 

   // close file
   CloseHandle(hfile); 
      
   // assign the source array
   VariantInit(&var); 
   V_VT(&var) = (VT_ARRAY | VT_UI1); 
   V_ARRAY(&var) = psaSource; 
   
   hr = g_pConvert->put_SourceArray (var); 
   if(FAILED(hr)) 
   {
      SafeArrayDestroy(psaSource); 
      return hr; 
   }


#ifdef _DEBUG
   {
      VARIANT var;
      VariantInit(&var);
      g_pConvert->get_SourceArray(&var);
      assert(var.vt == (VT_ARRAY | VT_UI1));
   }
#endif
   // create the target array
   psaTarget = SafeArrayCreateVector(VT_UI1, 0, 0); 
   if(!psaTarget) 
   {
      g_pConvert->ResetSource ();
      SafeArrayDestroy(psaSource); 
      return E_OUTOFMEMORY; 
   }

   // assign the target array
   VariantInit(&var); 
   V_VT(&var) = (VT_ARRAY | VT_UI1); 
   V_ARRAY(&var) = psaTarget; 
   
   hr = g_pConvert->put_TargetArray (var); 
   if(FAILED(hr)) 
   {
      g_pConvert->ResetSource ();
      SafeArrayDestroy(psaSource); 
      SafeArrayDestroy(psaTarget); 
      return hr; 
   }
   

#ifdef _DEBUG
   {
      VARIANT var;
      VariantInit(&var);
      g_pConvert->get_TargetArray(&var);
      assert(var.vt == (VT_ARRAY | VT_UI1));
   }
#endif
   // setup AVI recompression
   hr = SetAVIRecompression(NULL); 
   if(FAILED(hr)) 
   {
      g_pConvert->ResetTarget ();
      g_pConvert->ResetSource ();
      SafeArrayDestroy(psaSource); 
      SafeArrayDestroy(psaTarget); 
      return hr; 
   }

   // do conversion
   hr = (HRESULT) DialogBox(g_hInstance, (LPCTSTR)IDD_CONVERTDLG, NULL, ConvertDlgProc); 
   
   
   // kill the convert objects interest in the arrays
   g_pConvert->ResetTarget ();
   g_pConvert->ResetSource ();

   // don't need the source anymore
   SafeArrayDestroy(psaSource); 

   // return if the conversion failed
   if(FAILED(hr)) 
   {
      SafeArrayDestroy(psaTarget); 
      return hr; 
   }
   
   // write the output to file
   hfile = CreateFile(pszTarget, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); 
   if(hfile == INVALID_HANDLE_VALUE) 
   {
      SafeArrayDestroy(psaTarget); 
      return E_FAIL; 
   }
   SafeArrayAccessData(psaTarget, (void**) &buffer); 
   if(!WriteFile(hfile, buffer, psaTarget->rgsabound[0].cElements, &cb, NULL) || cb != psaTarget->rgsabound[0].cElements) 
   {
      SafeArrayUnaccessData(psaTarget); 
      CloseHandle(hfile); 
      SafeArrayDestroy(psaTarget); 
      return E_FAIL; 
   }
   SafeArrayUnaccessData(psaTarget); 
   CloseHandle(hfile); 

   SafeArrayDestroy(psaTarget); 

   return hr; 
}

//
// RecompressHGlobal
// recompresses from global memory to a file using the LEAD video and MP3 audio compressors
//
// 1. the source file is preloaded into global memory
// 2. the source memory is recompressed to the target file
//
// pszSource = source file path
// pszTarget = target file path
//
HRESULT RecompressHGlobal(LPCTSTR pszSource, LPCTSTR pszTarget) 
{
   HRESULT hr; 
   HANDLE hfile;   
   BSTR bstr; 
   DWORD size, cb; 
   void* buffer; 
   HGLOBAL hglobal; 
#ifndef _UNICODE
   WCHAR wsz[MAX_PATH]; 
#endif

   // open the source file
   hfile = CreateFile(pszSource, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 
   if(hfile == INVALID_HANDLE_VALUE) 
      return E_FAIL; 

   // allocate same-sized buffer
   size = GetFileSize(hfile, NULL); 
   
   hglobal = GlobalAlloc(GMEM_MOVEABLE, size); 
   if(!hglobal) 
   {
      CloseHandle(hfile); 
      return E_OUTOFMEMORY; 
   }

   // read entire source into buffer
   buffer = GlobalLock(hglobal); 
   if(!ReadFile(hfile, buffer, size, &cb, NULL) || cb != size) 
   {
      GlobalUnlock(hglobal); 
      CloseHandle(hfile); 
      GlobalFree(hglobal); 
      return E_FAIL; 
   }
   GlobalUnlock(hglobal); 

   // close file
   CloseHandle(hfile); 
      
   // assign the source buffer
   hr = g_pConvert->put_SourceHGlobal ((long) hglobal); 
   if(FAILED(hr)) 
   {
      GlobalFree(hglobal); 
      return hr; 
   }


#ifdef _DEBUG
   {
      HGLOBAL hGlobal;
      g_pConvert->get_SourceHGlobal((long*) &hGlobal);
      assert(hGlobal != NULL);
   }
#endif
   // set target file
#ifdef _UNICODE
   bstr = SysAllocString(pszTarget); 
#else
   swprintf(wsz, L"%hs", pszTarget); 
   bstr = SysAllocString(wsz); 
#endif
   hr = g_pConvert->put_TargetFile (bstr); 
   SysFreeString(bstr); 
   if(FAILED(hr)) 
   {
      g_pConvert->ResetSource ();
      GlobalFree(hglobal); 
      return hr; 
   }
   // setup AVI recompression
   hr = SetAVIRecompression(NULL); 
   if(FAILED(hr)) 
   {
      g_pConvert->ResetSource ();
      GlobalFree(hglobal); 
      return hr; 
   }

   // do conversion
   hr = (HRESULT) DialogBox(g_hInstance, (LPCTSTR)IDD_CONVERTDLG, NULL, ConvertDlgProc); 
   
   g_pConvert->ResetSource ();
   GlobalFree(hglobal); 

   return hr; 
}


int APIENTRY WinMain(HINSTANCE hInstance, 
                HINSTANCE hPrevInstance, 
                LPSTR      lpCmdLine, 
                int      nCmdShow) 
{
   HRESULT hr; 
   
   g_hInstance = hInstance; 

   // initialize COM library
   hr = CoInitialize(NULL); 
   if(FAILED(hr)) 
      goto error; 

   
   // create the convert object
   hr = CoCreateInstance(CLSID_ltmmConvert, NULL, CLSCTX_INPROC_SERVER, IID_IltmmConvert, (void**) &g_pConvert); 
   if(FAILED(hr)) 
      goto error; 
   
   
   hr = RecompressArray(_T("c:\\source.avi"), _T("c:\\target1.avi"));
   if(FAILED(hr)) 
      goto error; 

   hr = RecompressHGlobal(_T("c:\\source.avi"), _T("c:\\target2.avi"));
   if(FAILED(hr)) 
      goto error; 


error: 
   // cleanup

   if(g_pConvert) 
      g_pConvert->Release();

   CoUninitialize();
   
   return 0; 
}