forked from mintty/mintty
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jumplist.c
250 lines (204 loc) · 6.84 KB
/
jumplist.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
#if CYGWIN_VERSION_API_MINOR >= 74
#include "std.h"
//#undef NTDDI_VERSION
//#define NTDDI_VERSION NTDDI_WIN7
#ifndef ___PROCESSOR_NUMBER_DEFINED
#define ___PROCESSOR_NUMBER_DEFINED
typedef struct _PROCESSOR_NUMBER {
WORD Group;
BYTE Number;
BYTE Reserved;
} PROCESSOR_NUMBER, *PPROCESSOR_NUMBER;
#endif
#undef WINVER
#define WINVER 0x0601
// kill mysterious compilation bug since gcc 14
#define TpSetCallbackPriority(cbe, prio)
#include <shlobj.h>
#include <propkey.h> // PKEY_Title
#include "jumplist.h"
#include "charset.h"
#include "config.h"
static inline wchar *
last_error()
{
int err = GetLastError();
if (err) {
static wchar winmsg[1024]; // constant and < 1273 or 1705 => issue #530
FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK,
0, err, 0, winmsg, lengthof(winmsg), 0
);
return winmsg;
}
else
return W("");
}
static HRESULT
clear_jumplist(void)
{
HRESULT hr = S_OK;
ICustomDestinationList *pCustomDestinationList;
hr = CoCreateInstance(&CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER, &IID_ICustomDestinationList, (void **)&pCustomDestinationList);
if (FAILED(hr)) {
return hr;
}
hr = pCustomDestinationList->lpVtbl->DeleteList((void *)pCustomDestinationList, NULL);
pCustomDestinationList->lpVtbl->Release((void *)pCustomDestinationList);
return hr;
}
static HRESULT
InitPropVariantFromString(PCWSTR psz, PROPVARIANT *ppropvar)
{
HRESULT hres = 0;
//hres = SHStrDupW(psz, &ppropvar->pwszVal);
ppropvar->pwszVal = wcsdup(psz);
if(SUCCEEDED(hres))
ppropvar->vt = VT_LPWSTR;
else
PropVariantInit(ppropvar);
return hres;
}
static HRESULT
register_task(IObjectCollection *pobjs, wstring title, wstring cmd, wstring icon, int ii)
{
HRESULT hr = S_OK;
IShellLinkW *pShellLink;
if (!cmd || !*cmd)
return S_OK;
wstring show_title = (!title || !*title) ? cmd : title;
wchar exe_path[MAX_PATH + 1];
if (GetModuleFileNameW(NULL, exe_path, MAX_PATH) == 0)
return S_FALSE;
//printf("register_task <%ls>: <%ls> <%ls>\n", title, exe_path, cmd);
hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (void **)&pShellLink);
if (SUCCEEDED(hr)) {
do {
// set title
IPropertyStore *pPropertyStore;
hr = pShellLink->lpVtbl->QueryInterface((void *)pShellLink, &IID_IPropertyStore, (void **)&pPropertyStore);
if (SUCCEEDED(hr)) {
PROPVARIANT propVariant;
hr = InitPropVariantFromString(show_title, &propVariant);
if (SUCCEEDED(hr)) {
hr = pPropertyStore->lpVtbl->SetValue((void *)pPropertyStore, &PKEY_Title, &propVariant);
if (SUCCEEDED(hr)) {
pPropertyStore->lpVtbl->Commit((void *)pPropertyStore);
}
}
}
if (FAILED(hr))
break;
// set icon path and index
if (icon)
hr = pShellLink->lpVtbl->SetIconLocation((void *)pShellLink, icon, ii);
else
hr = pShellLink->lpVtbl->SetIconLocation((void *)pShellLink, exe_path, 0);
if (FAILED(hr))
break;
// set full path of mintty.exe
hr = pShellLink->lpVtbl->SetPath((void *)pShellLink, exe_path);
if (FAILED(hr))
break;
// set arguments
hr = pShellLink->lpVtbl->SetArguments((void *)pShellLink, cmd);
if (FAILED(hr))
break;
// finally, register this column into the jump list
hr = pobjs->lpVtbl->AddObject((void *)pobjs, (IUnknown *)pShellLink);
} while (0);
pShellLink->lpVtbl->Release((void *)pShellLink);
}
return hr;
}
void *
init_jumplist()
{
IObjectCollection * pobjs;
HRESULT hr = CoCreateInstance(&CLSID_EnumerableObjectCollection,
NULL, CLSCTX_INPROC_SERVER,
&IID_IObjectCollection, (void **)&pobjs);
//printf("create_jumplist CoCreateInstance %ld\n", (long)hr);
if (SUCCEEDED(hr))
return pobjs;
else
return 0;
}
static HRESULT
create_jumplist(wstring appid, IObjectCollection *pobjs)
{
HRESULT hr = S_OK;
ICustomDestinationList *pCustomDestinationList;
hr = CoCreateInstance(&CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER, &IID_ICustomDestinationList, (void **)&pCustomDestinationList);
//printf("create_jumplist CoCreateInstance %ld\n", (long)hr);
if (SUCCEEDED(hr)) {
// register all custom tasks
hr = pCustomDestinationList->lpVtbl->SetAppID((void *)pCustomDestinationList, appid);
//printf("create_jumplist SetAppID(%ls) %ld (%ld %ls)\n", appid, (long)hr, (long)GetLastError(), last_error());
hr = S_OK; // ignore failure of SetAppID
if (SUCCEEDED(hr)) {
UINT nSlots;
IObjectArray *pRemovedList;
hr = pCustomDestinationList->lpVtbl->BeginList((void *)pCustomDestinationList, &nSlots, &IID_IObjectArray, (void **)&pRemovedList);
//printf("create_jumplist BeginList %ld\n", (long)hr);
if (SUCCEEDED(hr)) {
IObjectArray *pObjectArray;
hr = pobjs->lpVtbl->QueryInterface((void *)pobjs, &IID_IObjectArray, (void **)&pObjectArray);
if (SUCCEEDED(hr)) {
hr = pCustomDestinationList->lpVtbl->AddUserTasks((void *)pCustomDestinationList, pObjectArray);
//printf("create_jumplist AddUserTasks %ld\n", (long)hr);
pObjectArray->lpVtbl->Release((void *)pObjectArray);
}
// should we commit only within previous SUCCEEDED?
pCustomDestinationList->lpVtbl->CommitList((void *)pCustomDestinationList);
//printf("create_jumplist CommitList %ld\n", (long)hr);
pRemovedList->lpVtbl->Release((void *)pRemovedList);
}
}
pCustomDestinationList->lpVtbl->Release((void *)pCustomDestinationList);
}
return hr;
}
HRESULT
setup_jumplist(wstring appid, int n, wstring titles[], wstring cmds[], wstring icons[], int ii[])
{
OSVERSIONINFO ver;
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&ver);
//printf("setup_jumplist\n");
// if running under the machine older than Windows 7, silently return.
if (!((ver.dwMajorVersion == 6 && ver.dwMinorVersion >= 1) || ver.dwMajorVersion >= 7)) {
return S_OK;
}
HRESULT hr = S_OK;
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr))
return hr;
hr = clear_jumplist();
hr = S_OK;
if (SUCCEEDED(hr)) {
IObjectCollection * pobjs = init_jumplist();
//printf("setup_jumplist items %p\n", pobjs);
if (pobjs) {
for (int i = 0; i < n; ++i) {
hr = register_task(pobjs, titles[i], cmds[i], icons[i], ii[i]);
if (FAILED(hr)) {
break;
}
}
if (SUCCEEDED(hr))
hr = create_jumplist(appid, pobjs);
pobjs->lpVtbl->Release((void *)pobjs);
}
}
CoUninitialize();
return hr;
}
#else
HRESULT
setup_jumplist(wstring appid, int n, wstring titles[], wstring cmds[], wstring icons[], int ii[])
{
(void)appid; (void)n; (void)titles; (void)cmds; (void)icons; (void)ii;
return 0;
}
#endif