October 21, 2009

DLL (Dynamic-Link Library) Search Order

Are you sure that your program loads the DLLs expected? You may want to check the search order for loading the proper DLLs.

Standard Search Order (SafeDllSearchMode is enabled)
1. The directory from which the application loaded.
2. The system directory. Use the GetSystemDirectory function to get the path of this directory.
3. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
4. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
5. The current directory.
6. The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.

More Detail Information
Dynamic-Link Library Search Order

September 12, 2009

Mp4 Explorer

Brief Introdution
This software is a very helpful tool to inspect and see in details a mp4 file and it is open source. In my case, I was trying to write a program to convert certain video to be compatible with iPhone, but I had no idea about it. Then, I found this useful utility and used it to inspect the video structure of some compatible mp4 files.

Mp4 Explorer

You can download the program and its source code in the following web site:

Official Website - Mp4 Explorer
http://mp4explorer.codeplex.com/

August 26, 2009

How To: Get the Content of Certain Environment Variable, ie: %ProgramFiles%

Code Snippet

#include <windows.h>
#include <string>

using namespace std;

wstring GetContentFromEnvironmentVariable(const wstring& wstrVariable)
{
  // Get the content of %ProgramFiles%

  wstring wstrRtn;
  DWORD dwSize = ::GetEnvironmentVariableW(wstrVariable.c_str(), NULL, NULL);
  if(dwSize > 0)
  {
    wchar_t* wszContent = new wchar_t [dwSize];
    dwSize = ::GetEnvironmentVariableW(wstrVariable.c_str(), wszContent, dwSize);

    wstrRtn = wszContent;

    delete [] wszContent;
    wszContent = NULL;
 }

 return wstrRtn;
}

Reference on MSDN
GetEnvironmentVariable Function

July 30, 2009

How To: Get the Installation Directory of Windows Media Player

Code Snippet

bool GetWMPInstallDirectory(wstring& wstrDirectory)
{
  bool bOK = false;
  HKEY hkResult = NULL;

  LONG lRet = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE,
    L"SOFTWARE\\Microsoft\\MediaPlayer", NULL, NULL, &hkResult);

  if(lRet == ERROR_SUCCESS)
  {
    wchar_t wszRet[_MAX_PATH] = {0};
    DWORD type = REG_SZ;
    DWORD cbData = sizeof(wszRet);

    lRet = ::RegQueryValueExW(hkResult, L"Installation Directory",
      NULL, &type, (LPBYTE)wszRet, &cbData);

    if(lRet == ERROR_SUCCESS)
    {
      // We've got the installation directory of WMP
      wstrDirectory = wszRet;
      bOK = true;
    }

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

  return bOK;
}

June 12, 2009

How To: Disable General Protection Fault Dialog for Your Program

Abstraction
Are you using any 3rd-party componet or ActiveX, which is not stable enough, in your program? You will get a GPF dialog if the componet in your program goes abnormal. That is not your problem totally, but actually your program crashed. There's a Windows API to prevent showing GPF dialog, you may adapt this solution if the crash can be ignored.

Code Snippet

UINT uPrevErrMode = SetErrorMode(SEM_NOGPFAULTERRORBOX);

Do you not know what GPF is?

Windows Calendar Crash

Reference on MSDN

June 06, 2009

Read/Write Windows Registry on Windows 64-Bits Platforms (C# Version)

Abstraction
How does a 32-bits(x64) program running on Windows 64-bits(x64) access the 64-bits registry? In C#, you can use P/Invoke to call RegOpenKeyEx function with KEY_WOW64_KEY to access the 64-bits registry.

Code Snippet

//
// This is a C# example to get the version of Windows Media Center on Windows 7 64-bits.
//

class RegQueryValueDemo
{
  [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegOpenKeyExW", SetLastError = true)]
  public static extern int RegOpenKeyEx(UIntPtr hKey, string subKey, uint options, int sam, out UIntPtr phkResult);
  public static UIntPtr HKEY_CURRENT_USER = (UIntPtr)0x80000001;
  public static UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
  public static int KEY_QUERY_VALUE = 0x0001;
  public static int KEY_SET_VALUE = 0x0002;
  public static int KEY_CREATE_SUB_KEY = 0x0004;
  public static int KEY_ENUMERATE_SUB_KEYS = 0x0008;
  public static int KEY_WOW64_64KEY = 0x0100;
  public static int KEY_WOW64_32KEY = 0x0200;

  [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegQueryValueExW", SetLastError = true)]
  public static extern int RegQueryValueEx(UIntPtr hKey, string lpValueName, int lpReserved, out uint lpType,
    StringBuilder lpData, ref int lpcbData);

  public string GetMCEIdent()
  {
    UIntPtr regKeyHandle;
    if (RegOpenKeyEx(
    HKEY_LOCAL_MACHINE,
    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Media Center",
    0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, out regKeyHandle) == 0)
    {
      uint type;

      StringBuilder stringBuilder = new StringBuilder(2048);
      int cbData = stringBuilder.Capacity;
      if (RegQueryValueEx(regKeyHandle, "Ident", 0, out type, stringBuilder, ref cbData) == 0)
      {
        return stringBuilder.ToString();
      }
    }

    return string.Empty;
  }
}


Find a C++ version?
Read/Write Windows Registry on Windows 64-Bits Platforms

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

May 24, 2009

How To: A Web Page Interacts with a Embedded Web Browser Control

If your application contains a web browser control to show certain web page, can the web page interact with your application by script language? Yes, it can.

There's a sample on MSDN, it's very short but clear, please refer to the following link:

Reference on MSDN

May 20, 2009

Windows Media ASF Viewer

Windows Media® ASF Viewer 9 Series is a tool for inspecting the contents of files (such as .asf. .wma, and .wmv file) to make sure they meet the requirements of the Advanced Systems Format (ASF) specification. -- Microsoft


Brief Introduction
This tool is very helpful for analyzing the contents of ASF files, it helps us to know the media structure and content easily. I was trying to encode WMV using Windows Media Format SDK, and this tool really helped me to verify the output content.

Download from Microsoft

May 14, 2009

How To: Extracting the embedded album art from a MP3 / WMA

I'm using Windows Media Sync Reader in Windows Media Format SDK to get the album art from id3 tag of a MP3, it can also get from a WMA.

Code Snippet:

#include <windows.h>
#include <wmsdk.h>
#include <atlbase.h>

#pragma comment(lib, "wmvcore.lib")

bool ExtractEmbeddedAlbumArt(LPCWSTR wszAudioFile)
{
  bool bOK = false;

  WM_PICTURE* pPicture = NULL;;

  do {

    CComPtr<IWMSyncReader> pIWMSyncReader;
    if(FAILED(WMCreateSyncReader(NULL, 0, &pIWMSyncReader))) break;

    if(FAILED(pIWMSyncReader->Open(wszAudioFile))) break;

    CComPtr<IWMHeaderInfo3> pIWMHeaderInfo3;
    if(FAILED(pIWMSyncReader->QueryInterface(&pIWMHeaderInfo3))) break;

    WMT_ATTR_DATATYPE wmtDataType = WMT_TYPE_BINARY;
    WORD wStreamNum = 0;
    WORD wLength = 0;
    if(FAILED(pIWMHeaderInfo3->GetAttributeByName(
      &wStreamNum, g_wszWMPicture, &wmtDataType, NULL, &wLength))) break;

    pPicture = (WM_PICTURE*)new BYTE[wLength];

    if(FAILED(pIWMHeaderInfo3->GetAttributeByName(
      &wStreamNum, g_wszWMPicture, &wmtDataType, (BYTE*)pPicture, &wLength))) break;

    bOK = true;

  } while(false);

  if(pPicture)
  {
    //
    // TODO: Save the picture or do something with it
    //

    delete [] (BYTE*)pPicture;
    pPicture = NULL;
  }

  return bOK;
}

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

March 10, 2009

Where can I find the list of installed ACM codecs on Vista?

It has moved to a strange place on Vista. Do the following steps to see the list:

1. Click on Windows Media Player 11 -> Help -> About -> Technical Support Information

2. It will generate "Support Information for Windows Media Player" and look under "Audio Codecs".

You can also see the information about windows media player binaries and the list of video codecs.

Reference:

March 04, 2009

error C3861: 'CoInitializeEx': identifier not found, even with argument-dependent lookup

You may get the following errors when trying to call CoInitializeEx(NULL, COINIT_MULTITHREADED).
 
error C2065: 'COINIT_MULTITHREADED' : undeclared identifier
error C3861: 'CoInitializeEx': identifier not found, even with argument-dependent lookup

The article in MSDN says "You must include the #define _WIN32_DCOM preprocessor directive at the beginning of your code to be able to use CoInitializeEx."

Look at the code snap in ObjBase.h:

#if (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM) // DCOM

WINOLEAPI  CoInitializeEx(IN LPVOID pvReserved, IN DWORD dwCoInit);
WINOLEAPI  CoGetCallerTID( LPDWORD lpdwTID );

#endif // DCOM

So, you need to follow the above rule if you want to call CoInitializeEx, of course you also need to include <objbase.h>.

Reference in MSDN:

March 01, 2009

Why is the media sample upside down after convert its buffer data from YUV to RGB?

Question
I converted the buffer of a media sample from YUY2 to RGB24 pixel by pixel, and then I got a upside-down image. What's wrong with it?

Answer
The definition of the biHeight field of BITMAPINFOHEADER depends the the biCompression field of BITMAPINFOHEADER.

If the bitmap is uncompressed RGB format, the positive biHeight value means the image is bottom-up image; if the bitmap is one of YUV formats such as YUY2, UYVY, and YV12, the image is top-down oriented and the sign of biHeight value must be ignored.

So, I need to do a vertical flip to get a correct image after convert buffer data from YUY2 to RGB24.

You can get more detail information in FOURCC.org: Bitmap Orientation and biHeight

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:

January 01, 2009

How to get the last modified date of a file in C++?

On Win32 platform, you can get the attribute information of a file easily by just calling GetFileAttributesEx().
The information you got includes creation time, last access time, and last write time (last modified date).

Windows API:

BOOL WINAPI GetFileAttributesEx(
  __in   LPCTSTR lpFileName,
  __in   GET_FILEEX_INFO_LEVELS fInfoLevelId,
  __out  LPVOID lpFileInformation
);

Sample Code:

WIN32_FILE_ATTRIBUTE_DATA fileAttrData = {0};
GetFileAttributesExW(L"C:\\abc.txt, GetFileExInfoStandard, &fileAttrData);
// GetFileAttributesExA for non-unicode

FILETIME ftLastModifiedDate = fileAttrData.ftLastWriteTime;

Reference in This Site:

Reference in MSDN: