April 28, 2009

How To: Handle dynamic format change in ReceiveConnection function on a renderer filter.

I was trying to correctly handle dynamic format change on my video null renderer and had fought against it for several days.

The following code snippet is my final work for handling dynamic format change, it seems to work fine, I hope so :p


STDMETHODIMP CNullRendererInputPin::ReceiveConnection(IPin * pConnector, const AM_MEDIA_TYPE *pmt)
{
  CAutoLock lock(m_pLock);

  CMediaType newMediaType(*pmt);

  HRESULT hr = E_FAIL;

  if(m_Connected && m_Connected == pConnector && newMediaType != m_mt)
  {
    do {

      hr = CheckMediaType(&newMediaType);
      if(FAILED(hr)) break;

      BITMAPINFO bmpinfo = {0};
      if(FORMAT_VideoInfo == pmt->formattype && 1 == pmt->bFixedSizeSamples)
      {
        VIDEOINFOHEADER* t = (VIDEOINFOHEADER*)(pmt->pbFormat);
        bmpinfo.bmiHeader = t->bmiHeader;
      }
      else if(FORMAT_VideoInfo2 == pmt->formattype && 1 == pmt->bFixedSizeSamples)
      {
        VIDEOINFOHEADER2* t = (VIDEOINFOHEADER2*)(pmt->pbFormat);
        bmpinfo.bmiHeader = t->bmiHeader;
      }
      else
      {
        hr = E_UNEXPECTED;
        break;
      }

      ALLOCATOR_PROPERTIES allocProperties = {0};
      {
        hr = m_pAllocator->GetProperties(&allocProperties);
        if(FAILED(hr)) break;

        allocProperties.cbBuffer = bmpinfo.bmiHeader.biSizeImage;
      }

      hr = SetMediaType(&newMediaType);
      if(FAILED(hr)) break;

      hr = m_pAllocator->Decommit();
      if(FAILED(hr)) break;

      {
        ALLOCATOR_PROPERTIES newAllocProperties = {0};
        hr = m_pAllocator->SetProperties(&allocProperties, &newAllocProperties);
        if(FAILED(hr)) break;
      }

      hr = m_pAllocator->Commit();
      if(FAILED(hr)) break;

      hr = S_OK;

    } while(false);
  }
  else
  {
    hr = CBasePin::ReceiveConnection(pConnector, pmt);
  }

  return hr;
}

April 15, 2009

Why will WCF client be disconnected after the connection idles for a long time?

The default receive timeout is 10 minutes, so WCF client will be disconnected after the idle time exceeded that limitation. What can I do if the connection needs to be kept alive?

Solution #1 - Server provides a dummy operation for client calls it regularly to let it not idle.

Solution #2 - Enable reliableSession and set receiveTimeout and inactivityTimeout to "infinite" in both the client and server.

The configuration snippet may like the following:

<system.serviceModel>
  <bindings>
    <wsHttpBinding>
      <binding name="WSHttpBinding" receiveTimeout="infinite">
        <reliableSession inactivityTimeout="infinite" enabled="true" />
      </binding>
    </wsHttpBinding>
  </bindings>
  <services>
  ...
  </services>
  ...
</system.serviceModel>

You can get more detail explanation in the following reference link.

Reference in MSDN:
Binding.ReceiveTimeout Property

Reference in Paulo Reichert's Blog
WCF Reliable Sessions Puzzle

April 10, 2009

How To: Detect Windows Media Center Version

If your program is depending on a specified version of Windows Media Center, just try the following code to identify Windows Media Center versions.

Sample Code:

//
// Get Windows Media Center version from registry
// Function return false if no media center is installed on your windows
//
// Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Media Center
// Registry value name: Ident
// Registry value data type: REG_SZ
//

bool GetMediaCenterIdent(wstring& wstrIdent)
{
  bool bRtn = false;

  HKEY hkResult = NULL;
  LONG lRetOpen = ::RegOpenKeyExW(
    HKEY_LOCAL_MACHINE,
    L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Media Center",
    NULL, KEY_READ, &hkResult);

  if(lRetOpen == ERROR_SUCCESS)
  {
    WCHAR wszRet[2048] = {0};
    DWORD type_1 = REG_SZ;
    DWORD cbData = sizeof(wszRet);

    LONG lRetQuery = ::RegQueryValueExW(hkResult, L"Ident", NULL,
      &type_1, (unsigned char *)wszRet, &cbData);
    if(lRetQuery == ERROR_SUCCESS)
    {
      wstrIdent = wszRet;
      bRtn = true;
    }
  }

  if(hkResult)
  {
    ::RegCloseKey(hkResult);
    hkResult = NULL;
  }

  return bRtn;
}

Ident value v.s Windows Media Center version

< 2.7 = Windows XP Media Center Edition 2002
2.7 or 2.8 = Windows XP Media Center Edition 2004
3.0 = Windows XP Media Center Edition 2005
3.1 = Windows XP Media Center Edition 2005 with Update Rollup 1
4.0 = Windows XP Media Center Edition 2005 with Update Rollup 2
5.0 = Windows Vista
5.1 = Windows Vista with Media Center TV Pack 2008
6.0 = Windows 7

Reference on MSDN:
Identifying Windows Media Center Versions

April 06, 2009

How To: Determine whether a 32-bits application is running on Windows 64-bits platform

WOW64 is the x86 emulator that allows 32-bit Windows-based applications to run seamlessly on 64-bit Windows.

Sample Code:

bool IsRunningOnWow64()
{
  BOOL bIsWow64 = FALSE;

  BOOL (WINAPI *fnIsWow64Process)(HANDLE, PBOOL);
  fnIsWow64Process = (BOOL(WINAPI*)(HANDLE, PBOOL))::GetProcAddress(
    ::GetModuleHandleW(L"kernel32"), "IsWow64Process");

  if(NULL != fnIsWow64Process)
    fnIsWow64Process(GetCurrentProcess(), &bIsWow64);

  return bIsWow64 ? true : false;
}

Reference on MSDN:
IsWow64Process Function

April 02, 2009

Read/Write Windows Registry on Windows 64-Bits Platforms

On Windows Vista 64-bits, there's a 32-bits emulator called WOW64 for 32-bits applications. A 32-bits application running on WOW64 uses the registry redirector, because the 64-bit version of an application may use different registry keys and values than the 32-bit version.

For 32-bits application:
On 64-bit platforms, it runs on WOW64 and accesses 32-bit registry (inside Wow6432Node).

For 64-bits application:
On 64-bit platforms, it runs natively and accesses 64-bit registry (not inside Wow6432Node).

Whatever, you can explicitly indicate which version of registry you want to access, just use RegOpenKeyEx function with KEY_WOW64_32KEY or KEY_WOW64_64KEY in the desired access rights parameter.

Example: A 32-bit application running on WOW64 accesses the 64-bit registry

HKEY hkResult = NULL;
REGSAM samDesired = KEY_READ | KEY_WOW64_64KEY;
LONG lRetOpen = ::RegOpenKeyExW(
  HKEY_LOCAL_MACHINE,
  L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Media Center",
  NULL, samDesired, &hkResult);


Reference on MSDN:
32-bit and 64-bit Application Data in the Registry