// @pymethod |PyIKnownFolderManager|RegisterFolder|Defines a new known folder
PyObject *PyIKnownFolderManager::RegisterFolder(PyObject *self, PyObject *args)
{
	IKnownFolderManager *pIKFM = GetI(self);
	if ( pIKFM == NULL )
		return NULL;
	IID kfid;
	PyObject *obdef;
	// @pyparm <o PyIID>|id||GUID used to identify the new known folder
	// @pyparm dict|Definition||Dictionary containing info to be placed in a KNOWNFOLDER_DEFINITION struct
	// @comm <om PyIKnownFolder.GetFolderDefinition> can be used to get a template dictionary
	KNOWNFOLDER_DEFINITION def;
	ZeroMemory(&def, sizeof(def));
	if ( !PyArg_ParseTuple(args, "O&O:RegisterFolder", PyWinObject_AsIID, &kfid, &obdef))
		return NULL;
	if (!PyWinObject_AsKNOWNFOLDER_DEFINITION(obdef, def))
		return NULL;
	HRESULT hr;
	PY_INTERFACE_PRECALL;
	hr = pIKFM->RegisterFolder(kfid, &def);
	PY_INTERFACE_POSTCALL;
	FreeKnownFolderDefinitionFields(&def);
	if ( FAILED(hr) )
		return PyCom_BuildPyException(hr, pIKFM, IID_IKnownFolderManager);
	Py_INCREF(Py_None);
	return Py_None;
}
BOOL PyWinObject_AsKNOWNFOLDER_DEFINITION(PyObject *obdef, KNOWNFOLDER_DEFINITION& def)
{
	static char *keywords[] = {"Category", "Name", "Description", "Parent",
		"RelativePath", "ParsingName", "Tooltip", "LocalizedName", "Icon",
		"Security", "Attributes", "Flags", "Type", NULL};
	ZeroMemory(&def, sizeof(def));
	if (!PyDict_Check(obdef)){
		PyErr_SetString(PyExc_TypeError, "KNOWNFOLDER_DEFINITION requires a dict");
		return FALSE;
		}
	TmpPyObject obdummy = PyTuple_New(0);
	if (obdummy == NULL)
		return FALSE;
	PyObject *obName, *obDescription, *obRelativePath,
		*obParsingName, *obTooltip, *obLocalizedName, *obIcon, *obSecurity;
	if (!PyArg_ParseTupleAndKeywords(obdummy, obdef, "iOOO&OOOOOOkiO&", keywords,
		&def.category,
		&obName,
		&obDescription,
		PyWinObject_AsIID, &def.fidParent,
		&obRelativePath, &obParsingName, &obTooltip,
		&obLocalizedName, &obIcon, &obSecurity,
		&def.dwAttributes, &def.kfdFlags,
		PyWinObject_AsIID, &def.ftidType))
		return FALSE;
	BOOL ret = PyWinObject_AsTaskAllocatedWCHAR(obName, &def.pszName, FALSE)
			&& PyWinObject_AsTaskAllocatedWCHAR(obDescription, &def.pszDescription, FALSE)
			&& PyWinObject_AsTaskAllocatedWCHAR(obRelativePath, &def.pszRelativePath, TRUE)
			&& PyWinObject_AsTaskAllocatedWCHAR(obParsingName, &def.pszParsingName, TRUE)
			&& PyWinObject_AsTaskAllocatedWCHAR(obTooltip, &def.pszTooltip, TRUE)
			&& PyWinObject_AsTaskAllocatedWCHAR(obLocalizedName, &def.pszLocalizedName, TRUE)
			&& PyWinObject_AsTaskAllocatedWCHAR(obIcon, &def.pszIcon, TRUE)
			&& PyWinObject_AsTaskAllocatedWCHAR(obSecurity, &def.pszSecurity, TRUE);
	if (!ret)
		FreeKnownFolderDefinitionFields(&def);
	return ret;
}
void EnumAndDumpKnownFolders(DWORD *pdwKFCount, PCWSTR pszNameSrchStr, REFKNOWNFOLDERID kfidSearch)
{
    *pdwKFCount = 0;
    IKnownFolderManager *pkfm = NULL;
    HRESULT hr = CoCreateInstance(CLSID_KnownFolderManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pkfm));
    if (SUCCEEDED(hr))
    {
        KNOWNFOLDERID *rgKFIDs = NULL;
        UINT cKFIDs = 0;
        hr = pkfm->GetFolderIds(&rgKFIDs, &cKFIDs);
        if (SUCCEEDED(hr))
        {
            WCHAR szKFIDGuid[GUID_SIZE];
            IKnownFolder *pkfCurrent = NULL;
            for (UINT i = 0; i < cKFIDs; ++i)
            {
                // if we are searching for a specific GUID, make sure we match before going
                // any further.  GUID_NULL means "show all."
                if (kfidSearch == GUID_NULL || kfidSearch == rgKFIDs[i])
                {
                    StringFromGUID2(rgKFIDs[i], szKFIDGuid, ARRAYSIZE(szKFIDGuid));
                    hr = pkfm->GetFolder(rgKFIDs[i], &pkfCurrent);
                    if (SUCCEEDED(hr))
                    {
                        KNOWNFOLDERID kfid;
                        hr = pkfCurrent->GetId(&kfid);
                        if (FAILED(hr))
                        {
                            wprintf(L"IKnownFolder::GetId() failed for %s!  hr=0x%x\n", szKFIDGuid, hr);
                        }

                        KNOWNFOLDER_DEFINITION kfd;
                        hr = pkfCurrent->GetFolderDefinition(&kfd);
                        if (FAILED(hr))
                        {
                            wprintf(L"IKnownFolderManager::GetFolderDefinition() failed hr=0x%x KNOWNFOLDERID=%s", hr, szKFIDGuid);
                        }
                        else
                        {
                            BOOL fDumpThisFolder = TRUE;
                            if (pszNameSrchStr)
                            {
                                if (NULL == wcsstr(kfd.pszName, pszNameSrchStr))
                                {
                                    fDumpThisFolder = FALSE;
                                }
                            }

                            if (fDumpThisFolder)
                            {
                                ++*pdwKFCount;
                                DumpKnownFolderDef(kfid, kfd);
                                DumpKnownFolderInfo(pkfCurrent);
                            }

                            FreeKnownFolderDefinitionFields(&kfd);
                        }

                        pkfCurrent->Release();
                    }
                    else
                    {
                        wprintf(L"IKnownFolderManager::GetFolder() failed for %s  hr=0x%x\n", szKFIDGuid, hr);
                    }
                }
            }
            CoTaskMemFree(rgKFIDs);
        }
        pkfm->Release();
    }
}
int main(int, char *[])
{
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    if (SUCCEEDED(hr))
    {
        int iArgs = 0;
        PWSTR *ppszArgs = CommandLineToArgvW(GetCommandLineW(), &iArgs);

        KNOWNFOLDERID kfid = GUID_NULL;
        KNOWNFOLDER_DEFINITION kfd = {};

        ACTION_TYPE at;
        PWSTR pszFindForPath = NULL;
        if (ParseAndValidateCommandLine(ppszArgs, iArgs, &at, &kfid, &kfd, &pszFindForPath))
        {
            switch (at)
            {
            case ACT_REGISTER:
                {
                    if (GUID_NULL == kfid)
                    {
                        CoCreateGuid(&kfid);
                    }

                    CompleteKnownFolderDef(&kfd);
                    hr = RegisterKnownFolder(kfid, &kfd);
                    if (S_OK == hr)
                    {
                        // we create our knownfolder with SHGetKnownFolderPath() so that the shell will write
                        // the desktop.ini file in the folder.  This is how our customizations
                        // (i.e.: pszIcon, pszTooltip and pszLocalizedName) get picked up by explorer.
                        PWSTR pszPath = NULL;
                        hr = SHGetKnownFolderPath(kfid, KF_FLAG_CREATE | KF_FLAG_INIT, NULL, &pszPath);
                        if (S_OK != hr)
                        {
                            wprintf(L"SHGetKnownFolderPath(KF_FLAG_CREATE | KF_FLAG_INIT) returned hr=0x%x\nThe KnownFolder was not registered.\n", hr);
                            hr = UnregisterFolder(kfid);
                            if (S_OK != hr)
                            {
                                wprintf(L"IKnownFolderManager::UnregisterFolder returned hr=0x%x.\nThe folder was NOT unregistered.\n", hr);
                            }
                            else
                            {
                                wprintf(L"The KnownFolder was not registered.\n");
                            }
                        }
                        else
                        {
                            CoTaskMemFree(pszPath);
                            DumpKnownFolderDef(kfid, kfd);
                        }
                    }
                }
                break;

            case ACT_ENUM:
                wprintf(L"Enumerating all registered KnownFolders \n");
                if (kfd.pszName)
                {
                    wprintf(L" matching pszName '%s'...\n", kfd.pszName);
                }
                else if (GUID_NULL != kfid)
                {
                    WCHAR szGuid[GUID_SIZE];
                    StringFromGUID2(kfid, szGuid, ARRAYSIZE(szGuid));
                    wprintf(L" matching KNOWNFOLDERID %s...\n", szGuid);
                }

                DWORD dwCKF;
                EnumAndDumpKnownFolders(&dwCKF, kfd.pszName, kfid);
                wprintf(L"Finished enumerating %d registered KnownFolders enumerated.\n", dwCKF);
                break;

            case ACT_UNREGISTER:
                if (GUID_NULL == kfid)
                {
                    DumpUsage();
                }
                else
                {
                    hr = UnregisterFolder(kfid);
                    if (S_OK != hr)
                    {
                        wprintf(L"IKnownFolderManager::UnregisterFolder returned hr=0x%x\n", hr);
                    }
                }
                break;

            case ACT_CLEAN:
                wprintf(L"Unregistering all KnownFolders registered by this tool\n");
                DWORD dw;
                UnregisterAllKFsAddedByThisTool(&dw);
                wprintf(L"Unregistered %d KnownFolders\n", dw);
                break;

            case ACT_FIND_FOR_PATH:
                hr = GetKnownFolderForPath(pszFindForPath, &kfid, &kfd);
                if (SUCCEEDED(hr))
                {
                    DumpKnownFolderDef(kfid, kfd);
                }
                else
                {
                    wprintf(L"Failed to find KnownFolder for path: %s\n", pszFindForPath);
                }
                break;

            case ACT_SHOW_USAGE:
            default:
                DumpUsage();
                break;
            }

            FreeKnownFolderDefinitionFields(&kfd);

            CoTaskMemFree(pszFindForPath);
        }
        else
        {
            DumpUsage();
        }

        CoUninitialize();
    }

    return 0;
}