/* Unit test suite for SHLWAPI Class ID functions
 *
 * Copyright 2003 Jon Griffiths
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdio.h>

#include "wine/test.h"
#include "winbase.h"
#include "winerror.h"
#include "winnls.h"
#include "winuser.h"
#include "initguid.h"
#include "shlguid.h"
#include "shobjidl.h"
#include "olectl.h"

DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);

/* This GUID has been removed from the PSDK */
DEFINE_OLEGUID(WINE_IID_IDelayedRelease,     0x000214EDL, 0, 0);

/* Function ptrs for ordinal calls */
static HMODULE hShlwapi = 0;
static BOOL (WINAPI *pSHLWAPI_269)(LPCSTR, CLSID *) = 0;
static DWORD (WINAPI *pSHLWAPI_23)(REFGUID, LPSTR, INT) = 0;

/* GUIDs to test */
static const GUID * TEST_guids[] = {
  &CLSID_ShellDesktop,
  &CLSID_ShellLink,
  &CATID_BrowsableShellExt,
  &CATID_BrowseInPlace,
  &CATID_DeskBand,
  &CATID_InfoBand,
  &CATID_CommBand,
  &FMTID_Intshcut,
  &FMTID_InternetSite,
  &CGID_Explorer,
  &CGID_ShellDocView,
  &CGID_ShellServiceObject,
  &CGID_ExplorerBarDoc,
  &IID_INewShortcutHookA,
  &IID_IShellIcon,
  &IID_IShellFolder,
  &IID_IShellExtInit,
  &IID_IShellPropSheetExt,
  &IID_IPersistFolder,
  &IID_IExtractIconA,
  &IID_IShellDetails,
  &WINE_IID_IDelayedRelease,
  &IID_IShellLinkA,
  &IID_IShellCopyHookA,
  &IID_IFileViewerA,
  &IID_ICommDlgBrowser,
  &IID_IEnumIDList,
  &IID_IFileViewerSite,
  &IID_IContextMenu2,
  &IID_IShellExecuteHookA,
  &IID_IPropSheetPage,
  &IID_INewShortcutHookW,
  &IID_IFileViewerW,
  &IID_IShellLinkW,
  &IID_IExtractIconW,
  &IID_IShellExecuteHookW,
  &IID_IShellCopyHookW,
  &IID_IRemoteComputer,
  &IID_IQueryInfo,
  &IID_IDockingWindow,
  &IID_IDockingWindowSite,
  &CLSID_NetworkPlaces,
  &CLSID_NetworkDomain,
  &CLSID_NetworkServer,
  &CLSID_NetworkShare,
  &CLSID_MyComputer,
  &CLSID_Internet,
  &CLSID_ShellFSFolder,
  &CLSID_RecycleBin,
  &CLSID_ControlPanel,
  &CLSID_Printers,
  &CLSID_MyDocuments,
  NULL
};

DEFINE_GUID(IID_Endianness, 0x01020304, 0x0506, 0x0708, 0x09, 0x0A, 0x0B,
            0x0C, 0x0D, 0x0E, 0x0F, 0x0A);

static void test_ClassIDs(void)
{
  const GUID **guids = TEST_guids;
  char szBuff[256];
  GUID guid;
  DWORD dwLen;
  BOOL bRet;
  int i = 0;
  int is_vista = 0;

  if (!pSHLWAPI_269 || !pSHLWAPI_23)
    return;

  while (*guids)
  {
    dwLen = pSHLWAPI_23(*guids, szBuff, 256);
    if (!i && dwLen == S_OK) is_vista = 1;  /* seems to return an HRESULT on vista */
    ok(dwLen == (is_vista ? S_OK : 39), "wrong size %u for id %d\n", dwLen, i);

    bRet = pSHLWAPI_269(szBuff, &guid);
    ok(bRet != FALSE, "created invalid string '%s'\n", szBuff);

    if (bRet)
      ok(IsEqualGUID(*guids, &guid), "GUID created wrong %d\n", i);

    guids++;
    i++;
  }

  /* Test endianness */
  dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 256);
  ok(dwLen == (is_vista ? S_OK : 39), "wrong size %u for IID_Endianness\n", dwLen);

  ok(!strcmp(szBuff, "{01020304-0506-0708-090A-0B0C0D0E0F0A}"),
     "Endianness Broken, got '%s'\n", szBuff);

  /* test lengths */
  szBuff[0] = ':';
  dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 0);
  ok(dwLen == (is_vista ? E_FAIL : 0), "accepted bad length\n");
  ok(szBuff[0] == ':', "wrote to buffer with no length\n");

  szBuff[0] = ':';
  dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 38);
  ok(dwLen == (is_vista ? E_FAIL : 0), "accepted bad length\n");
  ok(szBuff[0] == ':', "wrote to buffer with no length\n");

  szBuff[0] = ':';
  dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 39);
  ok(dwLen == (is_vista ? S_OK : 39), "rejected ok length\n");
  ok(szBuff[0] == '{', "Didn't write to buffer with ok length\n");

  /* Test string */
  strcpy(szBuff, "{xxx-");
  bRet = pSHLWAPI_269(szBuff, &guid);
  ok(bRet == FALSE, "accepted invalid string\n");

  dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 39);
  ok(dwLen == (is_vista ? S_OK : 39), "rejected ok length\n");
  ok(szBuff[0] == '{', "Didn't write to buffer with ok length\n");
}

static void test_CLSIDFromProgIDWrap(void)
{
    HRESULT (WINAPI *pCLSIDFromProgIDWrap)(LPCOLESTR,LPCLSID);
    CLSID clsid = IID_NULL;
    HRESULT hres;

    static const WCHAR wszStdPicture[] = {'S','t','d','P','i','c','t','u','r','e',0};

    pCLSIDFromProgIDWrap = (void*)GetProcAddress(hShlwapi,(char*)435);

    hres = pCLSIDFromProgIDWrap(wszStdPicture, &clsid);
    ok(hres == S_OK, "CLSIDFromProgIDWrap failed: %08x\n", hres);
    ok(IsEqualGUID(&CLSID_StdPicture, &clsid), "wrong clsid\n");

    hres = pCLSIDFromProgIDWrap(NULL, &clsid);
    ok(hres == E_INVALIDARG, "CLSIDFromProgIDWrap failed: %08x, expected E_INVALIDARG\n", hres);

    hres = pCLSIDFromProgIDWrap(wszStdPicture, NULL);
    ok(hres == E_INVALIDARG, "CLSIDFromProgIDWrap failed: %08x, expected E_INVALIDARG\n", hres);
}

START_TEST(clsid)
{
  hShlwapi = GetModuleHandleA("shlwapi.dll");

  /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
  if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
      win_skip("Too old shlwapi version\n");
      return;
  }

  pSHLWAPI_269 = (void*)GetProcAddress(hShlwapi, (LPSTR)269);
  pSHLWAPI_23 = (void*)GetProcAddress(hShlwapi, (LPSTR)23);

  test_ClassIDs();
  test_CLSIDFromProgIDWrap();
}