1
0
Files
wfassoc/legacy/wfassoc/wfassoc_core.c

407 lines
13 KiB
C
Raw Normal View History

2025-09-13 15:48:51 +08:00
#include "wfassoc_core.h"
#include <strsafe.h>
#include <ShlObj.h>
// private function and variable declearions.
// the function with _AL tail mean that the value returned by function is allocated from heap and should be free manually.
// otherwise, the tail of _NAL mean this function will not allocate any new memeory.
/// <summary>
/// Convert multi byte string to wide char string
/// Notice: this function will allocate memory for returns and it should be released safely.
/// </summary>
/// <param name="source">The string will be converted</param>
/// <param name="error">The error happend during converting</param>
/// <returns>The string has been converted. If return NULL, it mean that the converting failed.</returns>
//WFERROR ConvMultiByteToWideChar(CHAR* source);
WFERROR WFSplitAppPath(WFString* app_path, WFString* app_name, WFString* base_path);
//WFERROR Strcat(WCHAR* str1, WCHAR* str2);
//WFERROR WFGetBasePathFromAppPath(WFString* app_path, WFString* base_path);
WFERROR WFSplitSupportedTypesString(wchar_t* typesString, WFLinkedList* list);
void WFPrintflnInDebug();
// some effective reg function
LSTATUS WFRegOpenKeyWithCreation(HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult);
LSTATUS WFRegSetStringValue(HKEY hkey, LPCWSTR lpValueName, const WCHAR* data);
#define LEGACY_PROGID_FORMAT L"%s.%s.%d"
#define WFALLOC(type,count) (type*)malloc(sizeof(type)*count);
#define SAFE_EXEC_WIN32(wfError, recvError, skipLabel, function) recvError=function; if(recvError!=ERROR_SUCCESS) {wfError = WFERROR_WIN32;goto skipLabel;}
#define SAFE_EXEC_WF_LABEL(wfError, skipLabel, function) if((wfError=function)!=WFERROR_OK) {goto skipLabel;}
#define SAFE_EXEC_WF_RETURN(wfError, function) if((wfError=function)!=WFERROR_OK) {return wfError;}
#define SAFE_EXEC_STRALLOC(wfError, skipLabel, vStr, function) vStr=function; if(vStr==NULL) {wfError = WFERROR_ALLOC;goto skipLabel;}
#define SAFE_FREE_PTR(obj) if(obj!=NULL){free(obj);obj=NULL;}
#define SAFE_FREE_HKEY(hkey) if(hkey!=NULL&&hkey!=INVALID_HANDLE_VALUE){RegCloseKey(hkey);hkey=NULL;}
// public function implements.
WFERROR WFInstallApplication(WFAPP_PROFILE* profile) {
if (profile->WFVersion != WFVERSION) return WFERROR_INVALID_VERSION;
WFERROR wf_error = WFERROR_OK;
LSTATUS win32_error = ERROR_SUCCESS;
//WCHAR* itemSupportedTypes = NULL;
// ==================================
// generate necessary data
// init string
WFString* strProgID = NULL,
* strAppPath = NULL,
* strAppBasePath = NULL,
* strAppFileName = NULL;
SAFE_EXEC_WF_LABEL(wf_error, final_process,
WFString_Alloc(&strProgID)
);
SAFE_EXEC_WF_LABEL(wf_error, final_process,
WFString_Alloc_Wchar(&strAppPath, profile->AppPath)
);
SAFE_EXEC_WF_LABEL(wf_error, final_process,
WFString_Alloc(&strAppBasePath)
);
SAFE_EXEC_WF_LABEL(wf_error, final_process,
WFString_Alloc(&strAppFileName)
);
// write string
SAFE_EXEC_WF_LABEL(wf_error, final_process,
WFString_Printf(strProgID, LEGACY_PROGID_FORMAT, profile->ProgID_Vendor, profile->ProgID_Component, profile->ProgID_Version)
);
SAFE_EXEC_WF_LABEL(wf_error, final_process,
WFSplitAppPath(strAppPath, strAppFileName, strAppBasePath)
);
WFString* regpathAppPaths = NULL,
* regpathApplicationsRealName = NULL,
* regpathApplicationsProgId = NULL;
SAFE_EXEC_WF_LABEL(wf_error, final_process,
WFString_Alloc_Wchar(&regpathAppPaths, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\")
);
SAFE_EXEC_WF_LABEL(wf_error, final_process,
WFString_Concat_String(regpathAppPaths, strAppFileName)
);
SAFE_EXEC_WF_LABEL(wf_error, final_process,
WFString_Alloc_Wchar(&regpathApplicationsRealName, L"SOFTWARE\\Classes\\Applications\\")
);
SAFE_EXEC_WF_LABEL(wf_error, final_process,
WFString_Concat_String(regpathApplicationsRealName, strAppFileName)
);
SAFE_EXEC_WF_LABEL(wf_error, final_process,
WFString_Alloc_Wchar(&regpathApplicationsProgId, L"SOFTWARE\\Classes\\Applications\\")
);
SAFE_EXEC_WF_LABEL(wf_error, final_process,
WFString_Concat_String(regpathApplicationsProgId, strProgID)
);
//WCHAR* strAppPath = NULL,
// * strPath = NULL,
// * strApplications = NULL,
// * strProgID = NULL,
// * strOpenWithList = NULL;
//SAFE_EXEC_STRALLOC(error, final_process,
// strPath, GetPathFromAppPath_AL(profile->AppPath)
//);
//SAFE_EXEC_STRALLOC(error, final_process,
// strAppPath, Strcat_AL(
// L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\",
// GetAppNameFromAppPath_NAL(profile->AppPath)
//)
//);
//SAFE_EXEC_STRALLOC(error, final_process,
// strProgID, Strcat_AL(
// L"SOFTWARE\\Classes\\Applications\\",
// profile->ProgID
//)
//);
//SAFE_EXEC_STRALLOC(error, final_process,
// strApplications, Strcat_AL(
// L"SOFTWARE\\Classes\\Applications\\",
// GetAppNameFromAppPath_NAL(profile->AppPath)
//)
//);
// generate necessary HKEY
HKEY nodeAppPath = NULL,
nodeApplications = NULL,
nodeApplications_Verb = NULL,
nodeApplications_SupportedTypes = NULL,
nodeProgID = NULL,
nodeProgID_Verb = NULL,
nodeClasses = NULL,
nodeExt = NULL,
nodeExt_OpenWithProgIds = NULL,
nodeExt_OpenWithList = NULL;
// register in `App Paths`
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegOpenKeyWithCreation(profile->RegisterForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, strAppPath, &nodeAppPath)
);
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegOpenKeyWithCreation(profile->RegisterForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, strApplications, &nodeApplications)
);
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegOpenKeyWithCreation(nodeApplications, L"shell\\open\\command", &nodeApplications_Verb)
);
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegOpenKeyWithCreation(nodeApplications, L"SupportedTypes", &nodeApplications_SupportedTypes)
);
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegOpenKeyWithCreation(profile->RegisterForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, strProgID, &nodeProgID)
);
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegOpenKeyWithCreation(nodeProgID, L"shell\\open\\command", &nodeProgID_Verb)
);
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegOpenKeyWithCreation(profile->RegisterForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, L"SOFTWARE\\Classes", &nodeClasses)
);
// operate HKEY
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegSetStringValue(nodeAppPath, NULL, profile->AppPath) // visit Default key
);
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegSetStringValue(nodeAppPath, L"Path", strPath)
);
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegSetStringValue(nodeApplications_Verb, NULL, profile->AppCommand) // visit Default key
);
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegSetStringValue(nodeProgID_Verb, NULL, profile->AppCommand) // visit Default key
);
while ((itemSupportedTypes = IterateSupportedTypesString_NAL(profile->SupportedTypes, itemSupportedTypes)) != NULL) {
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegSetStringValue(nodeApplications_SupportedTypes, itemSupportedTypes, NULL) // register supported type with blank item
);
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegOpenKeyWithCreation(nodeClasses, itemSupportedTypes, &nodeExt)
);
if (profile->SetAsDefault) {
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegSetStringValue(nodeExt, NULL, profile->ProgID) // visit Default key
);
}
if (profile->ShowInOpenWithMenu) {
if (profile->UseOpenWithList) {
// use Windows XP node
SAFE_EXEC_STRALLOC(error, final_process,
strOpenWithList, Strcat_AL(
L"OpenWithList\\",
GetAppNameFromAppPath_NAL(profile->AppPath)
)
);
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegOpenKeyWithCreation(nodeExt, itemSupportedTypes, &nodeExt_OpenWithList);
);
SAFE_FREE_PTR(strOpenWithList);
SAFE_FREE_HKEY(nodeExt_OpenWithList);
} else {
// use Windows Vista node
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegOpenKeyWithCreation(nodeExt, itemSupportedTypes, &nodeExt_OpenWithProgIds);
);
SAFE_EXEC_WIN32(error, win32_error, final_process,
WFRegSetStringValue(nodeExt_OpenWithProgIds, profile->ProgID, NULL)
);
SAFE_FREE_HKEY(nodeExt_OpenWithProgIds);
}
}
SAFE_FREE_HKEY(nodeExt);
}
final_process:
// free HKEY and strings
SAFE_FREE_HKEY(nodeAppPath);
SAFE_FREE_HKEY(nodeApplications);
SAFE_FREE_HKEY(nodeApplications_Verb);
SAFE_FREE_HKEY(nodeApplications_SupportedTypes);
SAFE_FREE_HKEY(nodeProgID);
SAFE_FREE_HKEY(nodeProgID_Verb);
SAFE_FREE_HKEY(nodeClasses);
SAFE_FREE_HKEY(nodeExt);
SAFE_FREE_HKEY(nodeExt_OpenWithProgIds);
SAFE_FREE_HKEY(nodeExt_OpenWithList);
SAFE_FREE_PTR(strAppPath);
SAFE_FREE_PTR(strPath);
SAFE_FREE_PTR(strApplications);
SAFE_FREE_PTR(strProgID);
// order uninstall to wipe out all written data
// if function failed
if (error != WFERROR_OK)
WFUninstallApplicationW(profile);
// active changes
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
// return error
return error;
}
//WFERROR WFInstallApplicationA(WFAPP_PROFILEA* profile) {
// return WFERROR_OK;
//}
//
//WFERROR WFUninstallApplicationW(WFAPP_PROFILEW* profile) {
// if (profile->WFVersion != WFVERSION) return WFERROR_INVALID_VERSION;
//
// return WFERROR_OK;
//}
//
//WFERROR WFUninstallApplicationA(WFAPP_PROFILEA* profile) {
// return WFERROR_OK;
//}
//
//WFERROR WFGenerateProgIDW(WCHAR* vendor, WCHAR* component, INT version, WCHAR* result, INT* result_length) {
// if (result_length == NULL) return WFERROR_NULLPTR;
// if (result == NULL) {
// *result_length = _snwprintf(NULL, 0, LEGACY_PROGID_FORMATW, vendor, component, version) + 1;
// } else {
// int write_result = _snwprintf(result, *result_length, LEGACY_PROGID_FORMATW, vendor, component, version);
// if (write_result < 0 || write_result >= *result_length) return WFERROR_INSUFFICIENT_BUFFER;
// }
// return WFERROR_OK;
//}
//
//WFERROR WFGenerateProgIDA(CHAR* vendor, CHAR* component, INT version, CHAR* result, INT* result_length) {
// if (result_length == NULL) return WFERROR_NULLPTR;
// if (result == NULL) {
// *result_length = _snprintf(NULL, 0, LEGACY_PROGID_FORMATA, vendor, component, version) + 1;
// } else {
// int write_result = _snprintf(result, *result_length, LEGACY_PROGID_FORMATA, vendor, component, version);
// if (write_result < 0 || write_result >= *result_length) return WFERROR_INSUFFICIENT_BUFFER;
// }
// return WFERROR_OK;
//}
// private function and variable implements.
//WCHAR* ConvMultiByteToWideChar_AL(CHAR* source) {
// WCHAR* dest = NULL;
// size_t sourceLength = strlen(source);
//
// int destLength = MultiByteToWideChar(CP_ACP, 0, source, sourceLength, NULL, 0);
// if (destLength <= 0) return NULL;
// destLength += 10;
//
// dest = WFALLOC(WCHAR, destLength);
// if (dest == NULL) return NULL;
//
// memset(dest, 0, sizeof(WCHAR) * destLength);
// int error = MultiByteToWideChar(CP_ACP, 0, source, sourceLength, dest, destLength);
// if (error <= 0) {
// free(dest);
// return NULL;
// }
//
// return dest;
//}
WFERROR WFSplitAppPath(WFString* app_path, WFString* app_name, WFString* base_path) {
WFERROR ec;
wchar_t* lastSlash, *src, *ptr;
SAFE_EXEC_WF_RETURN(ec, WFString_GetData(app_path, &ptr));
src = lastSlash = ptr;
while (*ptr != L'\0') {
if (*ptr == L'\\' || *ptr == L'/') {
lastSlash = ptr;
}
ptr++;
}
SAFE_EXEC_WF_RETURN(ec, WFString_SubString(app_path, base_path, 0, lastSlash - src));
SAFE_EXEC_WF_RETURN(ec, WFString_SetData(app_name, ++lastSlash));
return WFERROR_OK;
}
//WCHAR* Strcat_AL(WCHAR* str1, WCHAR* str2) {
// size_t length = wcslen(str1) + wcslen(str2) + 10;
//
// WCHAR* dest = NULL;
// dest = WFALLOC(WCHAR, length);
// if (dest == NULL) return NULL;
//
// wcscpy(dest, str1);
// wcscat(dest, str2);
// return dest;
//}
WFERROR WFSplitSupportedTypesString(wchar_t* typesString, WFLinkedList* list) {
WFERROR ec;
wchar_t* ptr;
WFString* strl;
uint32_t len_str;
ptr = typesString;
while (*ptr != L'\0') {
// add into list
SAFE_EXEC_WF_RETURN(ec, WFString_Alloc(&strl, ptr));
SAFE_EXEC_WF_RETURN(ec, WFLinkedList_Add(list, strl));
// shift to next string
SAFE_EXEC_WF_RETURN(ec, WFString_GetLength(strl, &len_str));
ptr += len_str + 1;
}
return WFERROR_OK;
}
//WCHAR* IterateSupportedTypesString_NAL(WCHAR* typesString, WCHAR* prev) {
// if (typesString == NULL || *typesString == L'\0') return NULL;
// if (prev == NULL) return typesString;
//
// // skip prev string
// while (*prev != L'\0') {
// prev++;
// }
//
// // if the next string is start with zero, it mean that the full string is over and return NULL to terminate analyse.
// // otherwise return next string
// prev++;
// if (*prev == L'\0') return NULL;
// else return prev;
//}
void WFPrintflnInDebug() {
}
LSTATUS WFRegOpenKeyWithCreation(HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult) {
return RegCreateKeyExW(
hkey,
lpSubKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
phkResult,
NULL
);
}
LSTATUS WFRegSetStringValue(HKEY hkey, LPCWSTR lpValueName, const WCHAR* data) {
return RegSetValueExW(
hkey,
lpValueName,
0,
REG_SZ,
data,
data == NULL ? 0 : ((wcslen(data) + 1) * sizeof(WCHAR))
);
}