- establish basic Rust project layout. - move all old code into independent directory.
407 lines
13 KiB
C
407 lines
13 KiB
C
#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(®pathAppPaths, 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(®pathApplicationsRealName, 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(®pathApplicationsProgId, 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))
|
|
);
|
|
} |