upload files which idk when i write
This commit is contained in:
166
wfassoc/utils.c
166
wfassoc/utils.c
@ -1,166 +0,0 @@
|
||||
#include "utils.h"
|
||||
|
||||
#pragma region WFString
|
||||
|
||||
WFERROR WFString_Alloc(WFString** strl, wchar_t* raw_data) {
|
||||
WFERROR ec;
|
||||
if ((ec = WFString_Alloc(strl, 0)) != WFERROR_OK) return ec;
|
||||
if ((ec = WFString_SetData(*strl, raw_data)) != WFERROR_OK) return ec;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_Alloc(WFString** strl, char* raw_data, BOOL is_utf8) {
|
||||
return WFERROR();
|
||||
}
|
||||
|
||||
WFERROR WFString_Alloc(WFString** strl, uint32_t size) {
|
||||
*strl = WFNEW(WFString);
|
||||
if (*strl == NULL) return WFERROR_ALLOC;
|
||||
|
||||
// only init capacity and raw data here, other field will be refreshed in rezise func
|
||||
WFERROR ec;
|
||||
(*strl)->mCapacity = 0;
|
||||
(*strl)->mRawData = NULL;
|
||||
ec = WFString_Resize(*strl, size);
|
||||
|
||||
// return resize result
|
||||
return ec;
|
||||
}
|
||||
|
||||
WFERROR WFString_Free(WFString* strl) {
|
||||
if (strl == NULL) return WFERROR_OK;
|
||||
if (strl->mRawData == NULL) return WFERROR_NULLPTR;
|
||||
free(strl->mRawData);
|
||||
free(strl);
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_Resize(WFString* strl, uint32_t new_size) {
|
||||
// if remain data is not enough, we need alloc new one
|
||||
if (new_size >= strl->mCapacity) {
|
||||
strl->mCapacity = new_size * 2;
|
||||
strl->mRealCapacity = strl->mCapacity + 1;
|
||||
|
||||
// alloc buffer
|
||||
if (strl->mRawData != NULL)
|
||||
strl->mRawData = realloc(strl->mRawData, strl->mRealCapacity * sizeof(wchar_t));
|
||||
else
|
||||
strl->mRawData = malloc(strl->mRealCapacity * sizeof(wchar_t));
|
||||
if (strl->mRawData == NULL) return WFERROR_ALLOC;
|
||||
}
|
||||
|
||||
// set length as new length
|
||||
strl->mLength = new_size;
|
||||
strl->mRealLength = strl->mLength + 1;
|
||||
|
||||
// set the last one is zero
|
||||
strl->mRawData[strl->mRealLength - 1] = 0;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_GetData(WFString* strl, wchar_t** pdata) {
|
||||
if (strl == NULL) return WFERROR_NULLPTR;
|
||||
*pdata = strl->mRawData;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_SetData(WFString* strl, wchar_t* data) {
|
||||
// get length and resize buffer
|
||||
WFERROR ec;
|
||||
uint32_t size = wcslen(data);
|
||||
ec = WFString_Resize(strl, size);
|
||||
if (ec != WFERROR_OK) return ec;
|
||||
|
||||
// copy data
|
||||
if (size != 0)
|
||||
memcpy(strl->mRawData, data, sizeof(wchar_t) * size);
|
||||
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_GetLength(WFString* strl, uint32_t* len) {
|
||||
if (strl == NULL) return WFERROR_NULLPTR;
|
||||
*len = strl->mLength;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_Printf(WFString* strl, wchar_t* format, ...) {
|
||||
return WFERROR();
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region WFLinkedList
|
||||
|
||||
WFERROR WFLinkedList_Alloc(WFLinkedList** list) {
|
||||
*list = WFNEW(WFLinkedList);
|
||||
if (*list == NULL) return WFERROR_ALLOC;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFLinkedList_Free(WFLinkedList* list) {
|
||||
return WFLinkedList_Free_Full(list, NULL);
|
||||
}
|
||||
|
||||
WFERROR WFLinkedList_Free_Full(WFLinkedList* list, WFLinkedListNode_FreeDataFunc free_func) {
|
||||
if (list == NULL) return WFERROR_OK;
|
||||
|
||||
// iterate full list and remove data and node
|
||||
WFLinkedListNode* node = list->mHead, * free_node = NULL;
|
||||
while (node != NULL) {
|
||||
// free raw data
|
||||
if (free_func != NULL) (*free_func)(node->mRawData);
|
||||
// move to next node and free current node
|
||||
free_node = node;
|
||||
node = node->mNext;
|
||||
free(free_node);
|
||||
}
|
||||
|
||||
// free list self
|
||||
free(list);
|
||||
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFLinkedList_Add(WFLinkedList* list, void* data) {
|
||||
if (list == NULL) return WFERROR_NULLPTR;
|
||||
|
||||
WFLinkedListNode* new_item = WFNEW(WFLinkedListNode);
|
||||
if (new_item == NULL) return WFERROR_ALLOC;
|
||||
new_item->mNext = NULL;
|
||||
new_item->mRawData = data;
|
||||
|
||||
if (list->mLength == 0) {
|
||||
list->mHead = list->mTail = new_item;
|
||||
} else {
|
||||
list->mTail->mNext = new_item;
|
||||
list->mTail = new_item;
|
||||
}
|
||||
++list->mLength;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFLinkedList_NodeIterator(WFLinkedList* list, WFLinkedListNode** node_ptr) {
|
||||
if (list == NULL) return WFERROR_NULLPTR;
|
||||
|
||||
if (*node_ptr == NULL) {
|
||||
// if node_ptr is NULL, it mean that wo should iterate this list from head
|
||||
*node_ptr = list->mHead;
|
||||
} else {
|
||||
// otherwise, move to next node
|
||||
*node_ptr = (*node_ptr)->mNext;
|
||||
}
|
||||
|
||||
// if the header is null, return end of tail error to notice caller stop iterate
|
||||
if (*node_ptr == NULL) return WFERROR_END_OF_TAIL;
|
||||
else return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFLinkedListNode_GetData(WFLinkedListNode* node, void** pdata) {
|
||||
if (node == NULL) return WFERROR_NULLPTR;
|
||||
|
||||
*pdata = node->mRawData;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
#pragma endregion
|
@ -1,44 +0,0 @@
|
||||
#if !defined(_YYCDLL_WFASSOC_UTILS_H__IMPORTED_)
|
||||
#define _YYCDLL_WFASSOC_UTILS_H__IMPORTED_
|
||||
|
||||
#include "wfassoc.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef struct _WFString {
|
||||
wchar_t* mRawData;
|
||||
uint32_t mLength;
|
||||
uint32_t mCapacity;
|
||||
|
||||
uint32_t mRealLength;
|
||||
uint32_t mRealCapacity;
|
||||
}WFString;
|
||||
|
||||
WFERROR WFString_Alloc(WFString** strl, wchar_t* raw_data);
|
||||
WFERROR WFString_Alloc(WFString** strl, char* raw_data, BOOL is_utf8);
|
||||
WFERROR WFString_Alloc(WFString** strl, uint32_t size);
|
||||
WFERROR WFString_Free(WFString* strl);
|
||||
WFERROR WFString_Resize(WFString* strl, uint32_t new_size);
|
||||
WFERROR WFString_GetData(WFString* strl, wchar_t** pdata);
|
||||
WFERROR WFString_SetData(WFString* strl, wchar_t* data);
|
||||
WFERROR WFString_GetLength(WFString* strl, uint32_t* len);
|
||||
WFERROR WFString_Printf(WFString* strl, wchar_t* format, ...);
|
||||
|
||||
typedef WFERROR(*WFLinkedListNode_FreeDataFunc)(void* data);
|
||||
typedef struct _WFLinkedListNode {
|
||||
void* mRawData;
|
||||
WFLinkedListNode* mNext;
|
||||
}WFLinkedListNode;
|
||||
typedef struct _WFLinkedList {
|
||||
WFLinkedListNode* mHead;
|
||||
WFLinkedListNode* mTail;
|
||||
uint32_t mLength;
|
||||
}WFLinkedList;
|
||||
|
||||
WFERROR WFLinkedList_Alloc(WFLinkedList** list);
|
||||
WFERROR WFLinkedList_Free(WFLinkedList* list);
|
||||
WFERROR WFLinkedList_Free_Full(WFLinkedList* list, WFLinkedListNode_FreeDataFunc free_func);
|
||||
WFERROR WFLinkedList_Add(WFLinkedList* list, void* data);
|
||||
WFERROR WFLinkedList_NodeIterator(WFLinkedList* list, WFLinkedListNode** node_ptr);
|
||||
WFERROR WFLinkedListNode_GetData(WFLinkedListNode* node, void** pdata);
|
||||
|
||||
#endif
|
@ -1,344 +0,0 @@
|
||||
#include "wfassoc.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>
|
||||
WCHAR* ConvMultiByteToWideChar_AL(CHAR* source);
|
||||
WCHAR* GetAppNameFromAppPath_NAL(WCHAR* path);
|
||||
WCHAR* Strcat_AL(WCHAR* str1, WCHAR* str2);
|
||||
WCHAR* GetPathFromAppPath_AL(WCHAR* path);
|
||||
WCHAR* IterateSupportedTypesString_NAL(WCHAR* typesString, WCHAR* prev);
|
||||
|
||||
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_FORMATA "%s.%s.%d"
|
||||
#define LEGACY_PROGID_FORMATW 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_ERROR;goto skipLabel;}
|
||||
#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 WFInstallApplicationW(WFAPP_PROFILEW* profile) {
|
||||
if (profile->WFVersion != WFVERSION) return WFERROR_INVALID_VERSION;
|
||||
|
||||
WFERROR error = WFERROR_OK;
|
||||
LSTATUS win32_error;
|
||||
WCHAR* itemSupportedTypes = NULL;
|
||||
|
||||
// generate necessary strings
|
||||
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;
|
||||
}
|
||||
|
||||
WCHAR* GetAppNameFromAppPath_NAL(WCHAR* path) {
|
||||
WCHAR* lastSlash = path;
|
||||
while (*path != L'\0') {
|
||||
if (*path == L'\\' || *path == L'/') {
|
||||
lastSlash = path;
|
||||
}
|
||||
path++;
|
||||
}
|
||||
|
||||
return ++lastSlash;
|
||||
}
|
||||
|
||||
WCHAR* GetPathFromAppPath_AL(WCHAR* path) {
|
||||
size_t length = wsclen(path);
|
||||
|
||||
WCHAR* dest = NULL;
|
||||
dest = WFALLOC(WCHAR, length);
|
||||
if (dest == NULL) return NULL;
|
||||
wcscpy(dest, path);
|
||||
|
||||
// get the last slash.
|
||||
// if this path do not contain slash, then lastSlash == dest, the path is not existed, return full path instead.
|
||||
// otherwise, set lastSlash is zero to indicate the end of string
|
||||
WCHAR* lastSlash = GetAppNameFromAppPath(dest);
|
||||
if (lastSlash != dest) {
|
||||
*(lastSlash - 1) = L'\0';
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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))
|
||||
);
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
#if !defined(_YYCDLL_WFASSOC_H__IMPORTED_)
|
||||
#define _YYCDLL_WFASSOC_H__IMPORTED_
|
||||
|
||||
#include <Windows.h>
|
||||
#include <sal.h>
|
||||
|
||||
// quick marco for developer and should not be used in wfassoc self
|
||||
|
||||
#if defined(_UNICODE)
|
||||
#define WFAPP_PROFILE WFAPP_PROFILEW
|
||||
#define WFInstallApplication WFInstallApplicationW
|
||||
#define WFUninstallApplication WFUninstallApplicationW
|
||||
#define WFGenerateProgID WFGenerateProgIDW
|
||||
#elif defined(_MBCS)
|
||||
#define WFAPP_PROFILE WFAPP_PROFILEA
|
||||
#define WFInstallApplication WFInstallApplicationA
|
||||
#define WFUninstallApplication WFUninstallApplicationA
|
||||
#define WFGenerateProgID WFGenerateProgIDA
|
||||
#endif
|
||||
|
||||
// useful macro
|
||||
|
||||
#define WFNEW(type) ((type*)malloc(sizeof(type)))
|
||||
#define WFVERSION 0
|
||||
#define WFSUCCESS(expr) (!expr)
|
||||
#define WFFAILED(expr) expr
|
||||
|
||||
/// <summary>
|
||||
/// wfassoc Error Enum
|
||||
/// </summary>
|
||||
typedef enum _WFERROR {
|
||||
/// <summary>
|
||||
/// All operation done successfully
|
||||
/// </summary>
|
||||
WFERROR_OK = 0,
|
||||
/// <summary>
|
||||
/// The filed `WFVersion` in Profile Struct is not matched. It usually mean that currently used DLL is not matched with the DLL when compiling this application.
|
||||
/// </summary>
|
||||
WFERROR_INVALID_VERSION = 1,
|
||||
/// <summary>
|
||||
/// The buffer in some operations is insufficient, please try expanding buffer.
|
||||
/// </summary>
|
||||
WFERROR_INSUFFICIENT_BUFFER = 2,
|
||||
/// <summary>
|
||||
/// Some essential pointer variable is NULL.
|
||||
/// </summary>
|
||||
WFERROR_NULLPTR = 3,
|
||||
/// <summary>
|
||||
/// The encoding of string has error.
|
||||
/// </summary>
|
||||
WFERROR_ENCODING = 4,
|
||||
WFERROR_WIN32_ERROR = 5,
|
||||
WFERROR_ASSERT_ERROR = 6,
|
||||
WFERROR_ALLOC = 7,
|
||||
WFERROR_END_OF_TAIL = 8
|
||||
}WFERROR;
|
||||
|
||||
/// <summary>
|
||||
/// wfassoc Wide Character Set Profile Struct
|
||||
/// </summary>
|
||||
typedef struct _WFAPP_PROFILEW {
|
||||
/// <summary>
|
||||
/// wfassoc version. Fill it with `WFVERSION` in your application. This field is used for version checking.
|
||||
/// </summary>
|
||||
INT WFVersion;
|
||||
/// <summary>
|
||||
/// The path to locate your application.
|
||||
/// </summary>
|
||||
WCHAR* AppPath;
|
||||
/// <summary>
|
||||
/// The command will be executed when opening files.
|
||||
/// </summary>
|
||||
WCHAR* AppCommand;
|
||||
/// <summary>
|
||||
/// Your application's ProgID.
|
||||
/// For more detail about how to create your ProgID, please browse: https://docs.microsoft.com/en-us/windows/win32/shell/fa-progids
|
||||
/// We also provide a generator for creating legacy ProgID. Use `WFGenerateProgID` to create a legacy ProgID.
|
||||
/// </summary>
|
||||
WCHAR* ProgID;
|
||||
/// <summary>
|
||||
/// Your application supported file extensions.
|
||||
/// The structure of this field is connecting all supported extensions with dot(.) end to end. For example:
|
||||
/// `.jpg\0.png\0.gif\0`
|
||||
/// </summary>
|
||||
WCHAR* SupportedTypes;
|
||||
BOOL RegisterForAllUsers;
|
||||
BOOL SetAsDefault;
|
||||
BOOL ShowInOpenWithMenu;
|
||||
BOOL UseOpenWithList;
|
||||
}WFAPP_PROFILEW;
|
||||
|
||||
/// <summary>
|
||||
/// wfassoc Narrow Character Set Profile Struct
|
||||
/// </summary>
|
||||
typedef struct _WFAPP_PROFILEA {
|
||||
/// <summary>
|
||||
/// wfassoc version. Fill it with `WFVERSION` in your application. This field is used for version checking.
|
||||
/// </summary>
|
||||
INT WFVersion;
|
||||
/// <summary>
|
||||
/// The path to locate your application.
|
||||
/// </summary>
|
||||
CHAR* AppPath;
|
||||
/// <summary>
|
||||
/// The command will be executed when opening files.
|
||||
/// </summary>
|
||||
CHAR* AppCommand;
|
||||
/// <summary>
|
||||
/// Your application's ProgID.
|
||||
/// For more detail about how to create your ProgID, please browse: https://docs.microsoft.com/en-us/windows/win32/shell/fa-progids
|
||||
/// We also provide a generator for creating legacy ProgID. Use `WFGenerateProgID` to create a legacy ProgID.
|
||||
/// </summary>
|
||||
CHAR* ProgID;
|
||||
/// <summary>
|
||||
/// Your application supported file extensions.
|
||||
/// The structure of this field is connecting all supported extensions with dot(.) end to end. For example:
|
||||
/// `.jpg\0.png\0.gif\0`
|
||||
/// </summary>
|
||||
CHAR* SupportedTypes;
|
||||
}WFAPP_PROFILEA;
|
||||
|
||||
/// <summary>
|
||||
/// Install Application via Wide Character
|
||||
/// </summary>
|
||||
/// <param name="profile"></param>
|
||||
/// <returns></returns>
|
||||
WFERROR WFInstallApplicationW(WFAPP_PROFILEW* profile);
|
||||
WFERROR WFInstallApplicationA(WFAPP_PROFILEA* profile);
|
||||
WFERROR WFUninstallApplicationW(WFAPP_PROFILEW* profile);
|
||||
WFERROR WFUninstallApplicationA(WFAPP_PROFILEA* profile);
|
||||
/// <summary>
|
||||
/// Generate Legacy ProgID
|
||||
/// </summary>
|
||||
/// <param name="vendor">Vendor. Such as `Word`, `Excel`, `PowerPoint`.</param>
|
||||
/// <param name="component">Component. Such as `Document`, `Sheet`, `Diagram`.</param>
|
||||
/// <param name="version">Version. Such as `0`, `1`, `114514`.</param>
|
||||
/// <param name="result">Pointer to output ProgID. If this variable is NULL, function will calculate proper length of receiving buffer and return it via `result_length`.</param>
|
||||
/// <param name="result_length">Pointer to a int variable containing buffer's length. If `result` is not NULL, it should be the length of `result`.</param>
|
||||
/// <returns></returns>
|
||||
WFERROR WFGenerateProgIDW(WCHAR* vendor, WCHAR* component, INT version, WCHAR* result, INT* result_length);
|
||||
/// <summary>
|
||||
/// Generate Legacy ProgID
|
||||
/// </summary>
|
||||
/// <param name="vendor">Vendor. Such as `Word`, `Excel`, `PowerPoint`.</param>
|
||||
/// <param name="component">Component. Such as `Document`, `Sheet`, `Diagram`.</param>
|
||||
/// <param name="version">Version. Such as `0`, `1`, `114514`.</param>
|
||||
/// <param name="result">Pointer to output ProgID. If this variable is NULL, function will calculate proper length of receiving buffer and return it via `result_length`.</param>
|
||||
/// <param name="result_length">Pointer to a int variable containing buffer's length. If `result` is not NULL, it should be the length of `result`.</param>
|
||||
/// <returns></returns>
|
||||
WFERROR WFGenerateProgIDA(CHAR* vendor, CHAR* component, INT version, CHAR* result, INT* result_length);
|
||||
|
||||
#endif
|
@ -147,12 +147,14 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="utils.h" />
|
||||
<ClInclude Include="wfassoc.h" />
|
||||
<ClInclude Include="wfassoc_utils.h" />
|
||||
<ClInclude Include="wfassoc_core.h" />
|
||||
<ClInclude Include="wfassoc_private.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="utils.c" />
|
||||
<ClCompile Include="wfassoc.c" />
|
||||
<ClCompile Include="wfassoc_private.c" />
|
||||
<ClCompile Include="wfassoc_utils.c" />
|
||||
<ClCompile Include="wfassoc_core.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="wfassoc.def" />
|
||||
|
@ -15,18 +15,24 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="wfassoc.h">
|
||||
<ClInclude Include="wfassoc_core.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utils.h">
|
||||
<ClInclude Include="wfassoc_utils.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="wfassoc_private.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="wfassoc.c">
|
||||
<ClCompile Include="wfassoc_core.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utils.c">
|
||||
<ClCompile Include="wfassoc_utils.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="wfassoc_private.c">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
|
407
wfassoc/wfassoc_core.c
Normal file
407
wfassoc/wfassoc_core.c
Normal file
@ -0,0 +1,407 @@
|
||||
#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))
|
||||
);
|
||||
}
|
60
wfassoc/wfassoc_core.h
Normal file
60
wfassoc/wfassoc_core.h
Normal file
@ -0,0 +1,60 @@
|
||||
#if !defined(_YYCDLL_WFASSOC_H__IMPORTED_)
|
||||
#define _YYCDLL_WFASSOC_H__IMPORTED_
|
||||
|
||||
#include <Windows.h>
|
||||
#include <sal.h>
|
||||
#include "wfassoc_utils.h"
|
||||
|
||||
// quick marco for developer and should not be used in wfassoc self
|
||||
|
||||
//#if defined(_UNICODE)
|
||||
//#define WFAPP_PROFILE WFAPP_PROFILEW
|
||||
//#define WFInstallApplication WFInstallApplicationW
|
||||
//#define WFUninstallApplication WFUninstallApplicationW
|
||||
//#define WFGenerateProgID WFGenerateProgIDW
|
||||
//#elif defined(_MBCS)
|
||||
//#define WFAPP_PROFILE WFAPP_PROFILEA
|
||||
//#define WFInstallApplication WFInstallApplicationA
|
||||
//#define WFUninstallApplication WFUninstallApplicationA
|
||||
//#define WFGenerateProgID WFGenerateProgIDA
|
||||
//#endif
|
||||
|
||||
/// <summary>
|
||||
/// Install Application via Wide Character
|
||||
/// </summary>
|
||||
/// <param name="profile"></param>
|
||||
/// <returns></returns>
|
||||
WFERROR WFInstallApplication(WFAPP_PROFILE* profile);
|
||||
WFERROR WFUninstallApplication(WFAPP_PROFILE* profile);
|
||||
|
||||
WFERROR WFRegisterAppPath(WFAPP_INTERNAL_PROFILE* internal_profile);
|
||||
WFERROR WFRegisterApplication(WFAPP_INTERNAL_PROFILE* internal_profile);
|
||||
WFERROR WFRegisterExtensions(WFAPP_INTERNAL_PROFILE* internal_profile);
|
||||
|
||||
//WFERROR WFProfile_Alloc(WFAPP_PROFILE** profile);
|
||||
//WFERROR WFProfile_Free(WFAPP_PROFILE* profile);
|
||||
//WFERROR WFProfile_SetProgIDA(WFAPP_PROFILE** profile, char* vendor, char* component, uint32_t version, BOOL is_utf8);
|
||||
//WFERROR WFProfile_SetProgIDW(WFAPP_PROFILE** profile, wchar_t* vendor, wchar_t* component, uint32_t version);
|
||||
|
||||
/// <summary>
|
||||
/// Generate Legacy ProgID
|
||||
/// </summary>
|
||||
/// <param name="vendor">Vendor. Such as `Word`, `Excel`, `PowerPoint`.</param>
|
||||
/// <param name="component">Component. Such as `Document`, `Sheet`, `Diagram`.</param>
|
||||
/// <param name="version">Version. Such as `0`, `1`, `114514`.</param>
|
||||
/// <param name="result">Pointer to output ProgID. If this variable is NULL, function will calculate proper length of receiving buffer and return it via `result_length`.</param>
|
||||
/// <param name="result_length">Pointer to a int variable containing buffer's length. If `result` is not NULL, it should be the length of `result`.</param>
|
||||
/// <returns></returns>
|
||||
//WFERROR WFGenerateProgIDW(WCHAR* vendor, WCHAR* component, INT version, WCHAR* result, INT* result_length);
|
||||
/// <summary>
|
||||
/// Generate Legacy ProgID
|
||||
/// </summary>
|
||||
/// <param name="vendor">Vendor. Such as `Word`, `Excel`, `PowerPoint`.</param>
|
||||
/// <param name="component">Component. Such as `Document`, `Sheet`, `Diagram`.</param>
|
||||
/// <param name="version">Version. Such as `0`, `1`, `114514`.</param>
|
||||
/// <param name="result">Pointer to output ProgID. If this variable is NULL, function will calculate proper length of receiving buffer and return it via `result_length`.</param>
|
||||
/// <param name="result_length">Pointer to a int variable containing buffer's length. If `result` is not NULL, it should be the length of `result`.</param>
|
||||
/// <returns></returns>
|
||||
//WFERROR WFGenerateProgIDA(CHAR* vendor, CHAR* component, INT version, CHAR* result, INT* result_length);
|
||||
|
||||
#endif
|
1
wfassoc/wfassoc_private.c
Normal file
1
wfassoc/wfassoc_private.c
Normal file
@ -0,0 +1 @@
|
||||
#include "wfassoc_private.h"
|
9
wfassoc/wfassoc_private.h
Normal file
9
wfassoc/wfassoc_private.h
Normal file
@ -0,0 +1,9 @@
|
||||
#if !defined(_YYCDLL_WFASSOC_PRIVATE_H__IMPORTED_)
|
||||
#define _YYCDLL_WFASSOC_PRIVATE_H__IMPORTED_
|
||||
|
||||
typedef struct _WFAPP_RAWDATA {
|
||||
uint32_t mVersion;
|
||||
|
||||
}WFAPP_RAWDATA;
|
||||
|
||||
#endif
|
256
wfassoc/wfassoc_utils.c
Normal file
256
wfassoc/wfassoc_utils.c
Normal file
@ -0,0 +1,256 @@
|
||||
#include "wfassoc_utils.h"
|
||||
|
||||
#pragma region WFString
|
||||
|
||||
WFERROR WFString_Alloc_Wchar(WFString** strl, const wchar_t* raw_data) {
|
||||
if (raw_data == NULL) return WFERROR_NULLPTR;
|
||||
|
||||
WFERROR ec;
|
||||
if ((ec = WFString_Alloc(strl)) != WFERROR_OK) return ec;
|
||||
if ((ec = WFString_SetData(*strl, raw_data)) != WFERROR_OK) return ec;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_Alloc_Char(WFString** strl, const char* raw_data, BOOL is_utf8) {
|
||||
if (raw_data == NULL) return WFERROR_NULLPTR;
|
||||
|
||||
// init string
|
||||
WFERROR ec;
|
||||
if ((ec = WFString_Alloc(strl)) != WFERROR_OK) return ec;
|
||||
|
||||
// compute expected string length
|
||||
uint32_t sourceLength = strlen(raw_data);
|
||||
int destLength = MultiByteToWideChar(is_utf8 ? CP_UTF8 : CP_ACP, 0, raw_data, sourceLength, NULL, 0);
|
||||
if (destLength <= 0) return WFERROR_CRT;
|
||||
--destLength; // remove terminal char
|
||||
|
||||
// resize string
|
||||
if ((ec = WFString_Resize(*strl, destLength)) != WFERROR_OK) return ec;
|
||||
|
||||
// clear buffer and write data
|
||||
wchar_t* buffer;
|
||||
if ((ec = WFString_GetData(*strl, &buffer)) != WFERROR_OK) return ec;
|
||||
memset(buffer, 0, sizeof(WCHAR) * destLength);
|
||||
int crt_error = MultiByteToWideChar(is_utf8 ? CP_UTF8 : CP_ACP, 0, raw_data, sourceLength, buffer, destLength);
|
||||
if (crt_error <= 0) return WFERROR_CRT;
|
||||
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_Alloc_Capacity(WFString** strl, uint32_t size) {
|
||||
*strl = WFNEW(WFString);
|
||||
if (*strl == NULL) return WFERROR_ALLOC;
|
||||
|
||||
// init struct data
|
||||
(*strl)->mCapacity = size;
|
||||
(*strl)->mRealCapacity = size + 1;
|
||||
(*strl)->mLength = 0;
|
||||
(*strl)->mRealLength = 1;
|
||||
|
||||
(*strl)->mRawData = malloc((*strl)->mRealCapacity * sizeof(wchar_t));
|
||||
if ((*strl)->mRawData == NULL) return WFERROR_ALLOC;
|
||||
|
||||
(*strl)->mRawData[(*strl)->mRealLength - 1] = 0;
|
||||
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_Alloc(WFString** strl) {
|
||||
return WFString_Alloc_Capacity(strl, 256);
|
||||
}
|
||||
|
||||
WFERROR WFString_Free(WFString* strl) {
|
||||
if (strl == NULL) return WFERROR_OK;
|
||||
if (strl->mRawData == NULL) return WFERROR_NULLPTR;
|
||||
free(strl->mRawData);
|
||||
free(strl);
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_Resize(WFString* strl, uint32_t new_size) {
|
||||
// if remain data is not enough, we need alloc new one
|
||||
if (new_size >= strl->mCapacity) {
|
||||
strl->mCapacity = new_size * 2;
|
||||
strl->mRealCapacity = strl->mCapacity + 1;
|
||||
|
||||
// alloc buffer
|
||||
if (strl->mRawData != NULL)
|
||||
strl->mRawData = realloc(strl->mRawData, strl->mRealCapacity * sizeof(wchar_t));
|
||||
else
|
||||
strl->mRawData = malloc(strl->mRealCapacity * sizeof(wchar_t));
|
||||
if (strl->mRawData == NULL) return WFERROR_ALLOC;
|
||||
}
|
||||
|
||||
// set length as new length
|
||||
strl->mLength = new_size;
|
||||
strl->mRealLength = strl->mLength + 1;
|
||||
|
||||
// set the last one is zero
|
||||
strl->mRawData[strl->mRealLength - 1] = 0;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_GetData(WFString* strl, wchar_t** pdata) {
|
||||
if (strl == NULL) return WFERROR_NULLPTR;
|
||||
*pdata = strl->mRawData;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_SetData(WFString* strl, const wchar_t* data) {
|
||||
if (strl == NULL || data == NULL) return WFERROR_NULLPTR;
|
||||
|
||||
// get length and resize buffer
|
||||
WFERROR ec;
|
||||
uint32_t size = wcslen(data);
|
||||
ec = WFString_Resize(strl, size);
|
||||
if (ec != WFERROR_OK) return ec;
|
||||
|
||||
// copy data
|
||||
if (size != 0)
|
||||
memcpy(strl->mRawData, data, sizeof(wchar_t) * size);
|
||||
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_GetLength(WFString* strl, uint32_t* len) {
|
||||
if (strl == NULL) return WFERROR_NULLPTR;
|
||||
*len = strl->mLength;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_Printf(WFString* strl, const wchar_t* format, ...) {
|
||||
if (strl == NULL) return WFERROR_NULLPTR;
|
||||
|
||||
// get expected size
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
uint32_t count = _vsnwprintf(NULL, 0, format, argptr);
|
||||
//count++;
|
||||
va_end(argptr);
|
||||
|
||||
// resize string and get buffer ptr
|
||||
WFERROR ec;
|
||||
wchar_t* buffer;
|
||||
if ((ec = WFString_Resize(strl, count)) != WFERROR_OK) return ec;
|
||||
if ((ec = WFString_GetData(strl, &buffer)) != WFERROR_OK) return ec;
|
||||
|
||||
// write data to buffer
|
||||
buffer[count - 1] = L'\0';
|
||||
va_start(argptr, format);
|
||||
int write_result = _vsnwprintf(buffer, count, format, argptr);
|
||||
va_end(argptr);
|
||||
if (write_result < 0 || write_result >= count) return WFERROR_CRT;
|
||||
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFString_Concat_Wchar(WFString* strl, const wchar_t* extra) {
|
||||
if (strl == NULL) return WFERROR_NULLPTR;
|
||||
if (extra == NULL) return WFERROR_OK;
|
||||
|
||||
uint32_t count = wcslen(extra);
|
||||
uint32_t oldlen = strl->mLength;
|
||||
|
||||
// if extra strl count is 0, do not copy any data.
|
||||
if (count == 0) return WFERROR_OK;
|
||||
|
||||
WFERROR ec;
|
||||
if ((ec = WFString_Resize(strl, oldlen + count)) != WFERROR_OK) return ec;
|
||||
memcpy(strl->mRawData + oldlen, extra, sizeof(wchar_t) * count);
|
||||
return WFERROR_OK;
|
||||
}
|
||||
WFERROR WFString_Concat_String(WFString* strl, WFString* extra) {
|
||||
if (strl == NULL) return WFERROR_NULLPTR;
|
||||
if (extra == NULL) return WFERROR_OK;
|
||||
|
||||
return WFString_Concat_Wchar(strl, extra->mRawData);
|
||||
}
|
||||
|
||||
WFERROR WFString_SubString(WFString* strl, WFString* substring, uint32_t start_index, uint32_t length) {
|
||||
if (strl == NULL) return WFERROR_NULLPTR;
|
||||
if (start_index >= strl->mLength || length > strl->mLength - start_index) return WFERROR_INVALID_ARGUMENTS;
|
||||
|
||||
WFERROR ec;
|
||||
if ((ec = WFString_Resize(substring, length)) != WFERROR_OK) return ec;
|
||||
if (length != 0) {
|
||||
memcpy(substring->mRawData, strl->mRawData + start_index, sizeof(wchar_t) * length);
|
||||
}
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region WFLinkedList
|
||||
|
||||
WFERROR WFLinkedList_Alloc(WFLinkedList** list) {
|
||||
*list = WFNEW(WFLinkedList);
|
||||
if (*list == NULL) return WFERROR_ALLOC;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFLinkedList_Free(WFLinkedList* list) {
|
||||
return WFLinkedList_Free_Full(list, NULL);
|
||||
}
|
||||
|
||||
WFERROR WFLinkedList_Free_Full(WFLinkedList* list, WFLinkedListNode_FreeDataFunc free_func) {
|
||||
if (list == NULL) return WFERROR_OK;
|
||||
|
||||
// iterate full list and remove data and node
|
||||
WFLinkedListNode* node = list->mHead, * free_node = NULL;
|
||||
while (node != NULL) {
|
||||
// free raw data
|
||||
if (free_func != NULL) (*free_func)(node->mRawData);
|
||||
// move to next node and free current node
|
||||
free_node = node;
|
||||
node = node->mNext;
|
||||
free(free_node);
|
||||
}
|
||||
|
||||
// free list self
|
||||
free(list);
|
||||
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFLinkedList_Add(WFLinkedList* list, void* data) {
|
||||
if (list == NULL) return WFERROR_NULLPTR;
|
||||
|
||||
WFLinkedListNode* new_item = WFNEW(WFLinkedListNode);
|
||||
if (new_item == NULL) return WFERROR_ALLOC;
|
||||
new_item->mNext = NULL;
|
||||
new_item->mRawData = data;
|
||||
|
||||
if (list->mLength == 0) {
|
||||
list->mHead = list->mTail = new_item;
|
||||
} else {
|
||||
list->mTail->mNext = new_item;
|
||||
list->mTail = new_item;
|
||||
}
|
||||
++list->mLength;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFLinkedList_NodeIterator(WFLinkedList* list, WFLinkedListNode** node_ptr) {
|
||||
if (list == NULL) return WFERROR_NULLPTR;
|
||||
|
||||
if (*node_ptr == NULL) {
|
||||
// if node_ptr is NULL, it mean that wo should iterate this list from head
|
||||
*node_ptr = list->mHead;
|
||||
} else {
|
||||
// otherwise, move to next node
|
||||
*node_ptr = (*node_ptr)->mNext;
|
||||
}
|
||||
|
||||
// if the header is null, return end of tail error to notice caller stop iterate
|
||||
if (*node_ptr == NULL) return WFERROR_END_OF_TAIL;
|
||||
else return WFERROR_OK;
|
||||
}
|
||||
|
||||
WFERROR WFLinkedListNode_GetData(WFLinkedListNode* node, void** pdata) {
|
||||
if (node == NULL) return WFERROR_NULLPTR;
|
||||
|
||||
*pdata = node->mRawData;
|
||||
return WFERROR_OK;
|
||||
}
|
||||
|
||||
#pragma endregion
|
136
wfassoc/wfassoc_utils.h
Normal file
136
wfassoc/wfassoc_utils.h
Normal file
@ -0,0 +1,136 @@
|
||||
#if !defined(_YYCDLL_WFASSOC_UTILS_H__IMPORTED_)
|
||||
#define _YYCDLL_WFASSOC_UTILS_H__IMPORTED_
|
||||
|
||||
#include <Windows.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// useful macro
|
||||
|
||||
#define WFNEW(type) ((type*)malloc(sizeof(type)))
|
||||
#define WFNEW_ARRAY(type) ((type*)malloc(sizeof(type)*count);)
|
||||
#define WFVERSION 0
|
||||
#define WFSUCCESS(expr) (!expr)
|
||||
#define WFFAILED(expr) expr
|
||||
|
||||
/// <summary>
|
||||
/// wfassoc Error Enum
|
||||
/// </summary>
|
||||
typedef enum _WFERROR {
|
||||
/// <summary>
|
||||
/// All operation done successfully
|
||||
/// </summary>
|
||||
WFERROR_OK = 0,
|
||||
/// <summary>
|
||||
/// The filed `WFVersion` in Profile Struct is not matched. It usually mean that currently used DLL is not matched with the DLL when compiling this application.
|
||||
/// </summary>
|
||||
WFERROR_INVALID_VERSION = 1,
|
||||
/// <summary>
|
||||
/// The buffer in some operations is insufficient, please try expanding buffer.
|
||||
/// </summary>
|
||||
WFERROR_INSUFFICIENT_BUFFER = 2,
|
||||
/// <summary>
|
||||
/// Some essential pointer variable is NULL.
|
||||
/// </summary>
|
||||
WFERROR_NULLPTR = 3,
|
||||
WFERROR_WIN32 = 5,
|
||||
WFERROR_ALLOC = 6,
|
||||
WFERROR_END_OF_TAIL = 7,
|
||||
WFERROR_CRT = 8,
|
||||
WFERROR_INVALID_ARGUMENTS = 9
|
||||
}WFERROR;
|
||||
|
||||
/// <summary>
|
||||
/// wfassoc Profile Struct
|
||||
/// </summary>
|
||||
typedef struct _WFAPP_PROFILE {
|
||||
/// <summary>
|
||||
/// wfassoc version. Fill it with `WFVERSION` in your application. This field is used for version checking.
|
||||
/// </summary>
|
||||
uint32_t WFVersion;
|
||||
/// <summary>
|
||||
/// The path to locate your application.
|
||||
/// </summary>
|
||||
wchar_t* AppPath;
|
||||
/// <summary>
|
||||
/// The command will be executed when opening files.
|
||||
/// </summary>
|
||||
wchar_t* AppCommand;
|
||||
/// <summary>
|
||||
/// Your application's ProgID.
|
||||
/// For more detail about how to create your ProgID, please browse: https://docs.microsoft.com/en-us/windows/win32/shell/fa-progids
|
||||
/// We also provide a generator for creating legacy ProgID. Use `WFGenerateProgID` to create a legacy ProgID.
|
||||
/// </summary>
|
||||
wchar_t* ProgID_Vendor;
|
||||
wchar_t* ProgID_Component;
|
||||
uint32_t ProgID_Version;
|
||||
/// <summary>
|
||||
/// Your application supported file extensions.
|
||||
/// The structure of this field is connecting all supported extensions with dot(.) end to end. For example:
|
||||
/// `.jpg\0.png\0.gif\0`
|
||||
/// </summary>
|
||||
wchar_t* SupportedTypes;
|
||||
BOOL RegisterForAllUsers;
|
||||
BOOL SetAsDefault;
|
||||
BOOL ShowInOpenWithMenu;
|
||||
BOOL UseOpenWithList;
|
||||
}WFAPP_PROFILE;
|
||||
|
||||
typedef struct _WFAPP_INTERNAL_PROFILE {
|
||||
WFString* AppPath;
|
||||
WFString* AppBasePath;
|
||||
WFString* AppFileName;
|
||||
|
||||
WFString* ProgID;
|
||||
|
||||
WFString* AppCommand;
|
||||
|
||||
WFLinkedList* SupportedTypes;
|
||||
|
||||
BOOL RegisterForAllUsers;
|
||||
BOOL SetAsDefault;
|
||||
BOOL ShowInOpenWithMenu;
|
||||
BOOL UseOpenWithList;
|
||||
}WFAPP_INTERNAL_PROFILE;
|
||||
|
||||
typedef struct _WFString {
|
||||
wchar_t* mRawData;
|
||||
uint32_t mLength;
|
||||
uint32_t mCapacity;
|
||||
|
||||
uint32_t mRealLength;
|
||||
uint32_t mRealCapacity;
|
||||
}WFString;
|
||||
|
||||
WFERROR WFString_Alloc_Wchar(WFString** strl, const wchar_t* raw_data);
|
||||
WFERROR WFString_Alloc_Char(WFString** strl, const char* raw_data, BOOL is_utf8);
|
||||
WFERROR WFString_Alloc_Capacity(WFString** strl, uint32_t size);
|
||||
WFERROR WFString_Alloc(WFString** strl);
|
||||
WFERROR WFString_Free(WFString* strl);
|
||||
WFERROR WFString_Resize(WFString* strl, uint32_t new_size);
|
||||
WFERROR WFString_GetData(WFString* strl, wchar_t** pdata);
|
||||
WFERROR WFString_SetData(WFString* strl, const wchar_t* data);
|
||||
WFERROR WFString_GetLength(WFString* strl, uint32_t* len);
|
||||
WFERROR WFString_Printf(WFString* strl, const wchar_t* format, ...);
|
||||
WFERROR WFString_Concat_Wchar(WFString* strl, const wchar_t* extra);
|
||||
WFERROR WFString_Concat_String(WFString* strl, WFString* extra);
|
||||
WFERROR WFString_SubString(WFString* strl, WFString* substring, uint32_t start_index, uint32_t length);
|
||||
|
||||
typedef WFERROR(*WFLinkedListNode_FreeDataFunc)(void* data);
|
||||
typedef struct _WFLinkedListNode {
|
||||
void* mRawData;
|
||||
WFLinkedListNode* mNext;
|
||||
}WFLinkedListNode;
|
||||
typedef struct _WFLinkedList {
|
||||
WFLinkedListNode* mHead;
|
||||
WFLinkedListNode* mTail;
|
||||
uint32_t mLength;
|
||||
}WFLinkedList;
|
||||
|
||||
WFERROR WFLinkedList_Alloc(WFLinkedList** list);
|
||||
WFERROR WFLinkedList_Free(WFLinkedList* list);
|
||||
WFERROR WFLinkedList_Free_Full(WFLinkedList* list, WFLinkedListNode_FreeDataFunc free_func);
|
||||
WFERROR WFLinkedList_Add(WFLinkedList* list, void* data);
|
||||
WFERROR WFLinkedList_NodeIterator(WFLinkedList* list, WFLinkedListNode** node_ptr);
|
||||
WFERROR WFLinkedListNode_GetData(WFLinkedListNode* node, void** pdata);
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user