February 21, 2009

FORMAT_VideoInfo v.s. FORMAT_VideoInfo2

If the media type is FORMAT_VideoInfo, it means the format buffer is a VIDEOINFOHEADER struct; if the media type is FORMAT_VideoInfo2, it means the format buffer is a VIDEOINFOHEADER2 struct. So, what's different between VIDEOINFOHEADER and VIDEOINFOHEADER2?

VIDEOINFOHEADER and VIDEOINFOHEADER2 are very different, VIDEOINFOHEADER2 is not just an entended struct of VIDEOINFOHEADER. This means you cannot cast a pointer of VIDEOINFOHEADER2 to a pointer of VIDEOINFOHEADER.

INCORRECT:

if(pmt->formattype == FORMAT_VideoInfo || pmt->formattype == FORMAT_VideoInfo2)
{
    VIDEOINFOHEADER *pVIH = (VIDEOINFOHEADER*)pmt->pbFormat;
    // *** Wrong! ***
}

CORRECT:

if(pmt->formattype == FORMAT_VideoInfo)
{
    VIDEOINFOHEADER *pVIH = (VIDEOINFOHEADER*)pmt->pbFormat;
    // Now you can use pVIH.
}
else if(pmt->formattype == FORMAT_VideoInfo2)
{
    VIDEOINFOHEADER2 *pVIH = (VIDEOINFOHEADER2*)pmt->pbFormat;
    // Now you can use pVIH.
}

Reference in MSDN:

February 17, 2009

How To: Toggle / Next Bookmark in Visual C++

Bookmarking is a very useful feature of Visual C++ when you are coding, but the keyboard short cuts of this function is hard to remember. In the menu, you can find the short cuts of toggle and next bookmark are "Ctrl + K Ctrl +K" and "Ctrl + K Ctrl + N" respectively, but why do I need to press so many keys  just for toggle or next bookmark?

You can do it more easily, just use the following short cuts:

Toggle Bookmark - Ctrl + F2

Next Bookmark - F2

Wow! It is very easy to use, isn't it? Enjoy bookmarking feature during your coding time.

I have tried it on Visual C++ 6 / 2003 / 2005 / 2008, it works fine.
(Note: The key mapping of Visual Studio is set to default "Visual C++".)

Reference in This Site:

February 12, 2009

How To: STL String Case-insensitive Compare

This article is talking about how to do a case-insensitive compare for STL string and wstring, there're 2 ways to reach the goal.

Method #1: C Run-time Library - _stricmp() and _wcsicmp()

#include <string>

using namespace std;

string strUpperCase = "ABC";
string strLowerCase = "abc";
if(_stricmp(strUpperCase.c_str(), strLowerCase.c_str()) == 0)
// For wstring, use _wcsicmp() instead.
{
  // Do something you need
}


Method #2: STL Algorithm - transform()

#include <cctype>
#include <string>
#include <algorithm>

using namespace std;

// I make a helper function to compare string
bool CompareCaseInsensitive(string strFirst, string strSecond)
{
  // Convert both strings to upper case by transfrom() before compare.
  transform(strFirst.begin(), strFirst.end(), strFirst.begin(), toupper);
  transform(strSecond.begin(), strSecond.end(), strSecond.begin(), toupper);
  if(strFirst == strSecond) return true; else return false;
}

string strUpperCase = "ABC";
string strLowerCase = "abc";
if(CompareCaseInsensitive(strUpperCase, strLowerCase))
{
  // Do something you need
}


Reference in This Site:
How to convert STL string / wstring to upper / lower case?

Reference in MSDN:
_stricmp, _wcsicmp, _mbsicmp, _stricmp_l, _wcsicmp_l, _mbsicmp_l

January 19, 2009

More explanation of CoInitialize() and CoUninitialize()

In this article, I'll not talk about how it works about the COM's apartment model, but the coding practice.

CoInitializeEx() provides the same functionality as CoInitialize() except it provides a parameter to specify the thread's apartment model. So, MSDN recommands us to call CoInitializeEx() instead of CoInitialize().

For using CoInitializeEx(), we also need to follow the same rules as CoInitialize(), I mentioned in the previous article.

The following examples explain how to use CoInitializeEx() and CoUninitialize():

Example #1: CoInitializeEx() will return S_FALSE if the COM library was loaded.

void main()
{
  HRESULT hr = E_FAIL;

  // The first call
  hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); // hr = S_OK

  // The second call
  hr = CoInitialize(NULL); // hr = S_FALSE, CoInitialize(NULL) = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)

  // ... skip ...

  // For the second call
  CoUninitialize();

  // For the first call
  CoUninitialize(); // COM library will be unloaded
}

Example #2: CoInitializeEx() will return RPC_E_CHANGED_MODE if a previous call to CoInitializeEx() specified a different apartment model

void main()
{
  HRESULT hr = E_FAIL;

  // The first call
  hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); // hr = S_OK

  // The second call
  hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); // hr = RPC_E_CHANGED_MODE, the thread's apartment model is still the single thread apartment.

  // ... skip ...

  // NOTE: We do not need to call CoUninitialize() if the corresponding call made by CoInitializeEx() returns error.

  // For the first call
  CoUninitialize(); // COM library will be unloaded
}

January 18, 2009

A clear explanation of CoInitialize() and CoUninitialize()

As you know, when you are using DirectShow or the other COM-based components, the first thing you have to do is calling CoInitialize() to initialize the COM library.

Furthermore, there are several rules you should follow. Now, I will give you a clear explanation here.

Rule #1: For each thread, you have to call CoInitialize() before you call any of the COM library funtions except CoGetMalloc() and the memory allocation functions.

Rule #2: For each successful call made by CoInitialize(), you have to call CoUninitialize() to free the COM library.

Rule #3: Do not call CoInitialize() or CoUninitialize() from the DllMain() function.

Rule #4: The first thread in the application that calls CoInitialize() must be the last thread to call CoUninitialize().


Reference in MSDN:
CoInitialize

January 15, 2009

fatal error RC1015: cannot open include file 'activex.ver'.

Error Message:

fatal error RC1015: cannot open include file 'activex.ver'.

When compile the DirectShow filter sample in DXSDK, you may get the above error message.

Root Cause:

The resource file(.rc) includes <activex.ver> and <activex.rcv>, but compiler cannot find them.

Solution:

activex.ver and activex.rcv are in %DXSDK%\Samples\C++\DirectShow\BaseClasses
(%DXSDK% is your dx sdk installed directory.)

Add the above path to "VC++ Directories" of your VC++ setting,
or add it to "Additional Include Directories" of your project setting.

January 10, 2009

How to correctly call HttpOpenRequest() with specified accept types?

Windows API: (Wininet)

HINTERNET HttpOpenRequest(
  __in  HINTERNET hConnect,
  __in  LPCTSTR lpszVerb,
  __in  LPCTSTR lpszObjectName,
  __in  LPCTSTR lpszVersion,
  __in  LPCTSTR lpszReferer,
  __in  LPCTSTR *lplpszAcceptTypes,
  __in  DWORD dwFlags,
  __in  DWORD_PTR dwContext
);

Tips:
lplpszAcceptTypes is not a pointer to a null-terminated string, it is a pointer to a null-terminated array of strings. 

Sample Code:

// A null-terminated array of null-terminated strings
const char* lplpszAcceptTypes[] = {"text/*", NULL}; // Accept only text documents

HINTERNET  hHttpFile = HttpOpenRequestA(
  hConnect,
  "GET",
  "/TextDocument",
  HTTP_VERSION,
  NULL,
  lplpszAcceptTypes,
  INTERNET_FLAG_DONT_CACHE, 1);

Reference in MSDN: