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
|
#define REPLY_FAIL 0x88888888
#define REPLY_OK 0x00000000
#define REQUEST_ICONS 1
#define REQUEST_GROUPS (REQUEST_ICONS << 1)
#define REQUEST_CONTACTS (REQUEST_GROUPS << 1)
#define REQUEST_XFRFILES (REQUEST_CONTACTS << 1)
#define REQUEST_NEWICONS (REQUEST_XFRFILES << 1)
#define REQUEST_CLEARMRU (REQUEST_NEWICONS << 1)
#define ICONS_NOTIMPL 0x00000008
#define GROUPS_NOTIMPL 0x00000080
#define CONTACTS_NOTIMPL 0x00000800
#define STATUS_PROFILENAME 2
#define ICMF_NORMAL 0x00000000
#define ICMF_DEFAULTONLY 0x00000001
#define ICMF_VERBSONLY 0x00000002
#define ICMF_EXPLORE 0x00000004
#define ICMF_NOVERBS 0x00000008
#define ICMF_CANRENAME 0x00000010
#define ICMF_NODEFAULT 0x00000020
#define ICMF_INCLUDESTATIC 0x00000040
#define ICMF_RESERVED 0xFFFF0000
// IContextMenu*:GetCommandString() uType flags
#define IGCS_VERBA 0x00000000 // canonical verb
#define IGCS_HELPTEXTA 0x00000001 // help text (for status bar)
#define IGCS_VALIDATEA 0x00000002 // validate command exists
#define IGCS_VERBW 0x00000004 // canonical verb (unicode)
#define IGC_HELPTEXTW 0x00000005 // help text (unicode version)
#define IGCS_VALIDATEW 0x00000006 // validate command exists (unicode)
#define IGCS_UNICODE 0x00000004 // for bit testing - Unicode string
#define IGCS_VERB GCS_VERBA
#define IGCS_HELPTEXT GCS_HELPTEXTA
#define IGCS_VALIDATE GCS_VALIDATEA
#define HIPC_NOICONS 1
#define IPC_PACKET_SIZE (0x1000 * 32)
#define IPC_PACKET_NAME "m.mi.miranda.ipc.server"
/////////////////////////////////////////////////////////////////////////////////////////
struct TGroupNode
{
TGroupNode *Left, *Right, *_prev, *_next;
int Depth;
UINT Hash; // hash of the group name alone
char *szGroup;
int cchGroup;
HMENU hMenu;
int hMenuGroupID;
DWORD dwItems;
};
struct TGroupNodeList
{
TGroupNode *First, *Last;
};
struct TStrTokRec
{
char *szStr, *szSet;
// need a delimiter after the token too?, e.g. FOO^BAR^ if FOO^BAR
// is the string then only FOO^ is returned, could cause infinite loops
// if the condition isn't accounted for thou.
bool bSetTerminator;
};
/////////////////////////////////////////////////////////////////////////////////////////
struct TSlotProtoIcons
{
UINT pid; // pid of Miranda this protocol was on
UINT hProto; // hash of the protocol
HICON hIcons[10]; // each status in order of ID_STATUS_*
HBITMAP hBitmaps[10]; // each status "icon" as a bitmap
};
struct TSlotIPC
{
BYTE cbSize;
int fType; // a REQUEST_* type
TSlotIPC *Next;
HANDLE hContact;
UINT hProto; // hash of the protocol the user is on
UINT hGroup; // hash of the entire path (not defined for REQUEST_GROUPS slots)
WORD Status;
// only used for contacts -- can be STATUS_PROFILENAME -- but that is because returning the profile name is optional
BYTE MRU; // if set, contact has been recently used
int cbStrSection;
};
struct THeaderIPC
{
int cbSize;
DWORD dwVersion;
void *pServerBaseAddress, *pClientBaseAddress;
int fRequests;
DWORD dwFlags;
int Slots;
HANDLE Param;
char SignalEventName[64];
char MirandaName[64];
char MRUMenuName[64];
char ClearEntries[64];
TSlotIPC *IconsBegin, *ContactsBegin, *GroupsBegin, *NewIconsBegin;
// start of an flat memory stack, which is referenced as a linked list
int DataSize;
TSlotIPC *DataPtr, *DataPtrEnd;
void *DataFramePtr;
};
/////////////////////////////////////////////////////////////////////////////////////////
struct TShellExt : public IShellExtInit, public IContextMenu3, public MZeroedObject
{
TShellExt();
ULONG RefCount;
// this is owned by the shell after items are added 'n' is used to
// grab menu information directly via id rather than array indexin'
HMENU hRootMenu;
int idCmdFirst;
// most of the memory allocated is on this heap object so HeapDestroy()
// can do most of the cleanup, extremely lazy I know.
HANDLE hDllHeap;
// This is a submenu that recently used contacts are inserted into
// the contact is inserted twice, once in its normal list (or group) and here
// Note: These variables are global data, but refered to locally by each instance
// Do not rely on these variables outside the process enumeration.
HMENU hRecentMenu;
UINT RecentCount; // number of added items
// array of all the protocol icons, for every running instance!
TSlotProtoIcons *ProtoIcons;
UINT ProtoIconsCount;
// maybe null, taken from IShellExtInit_Initalise() and AddRef()'d
// only used if a Miranda instance is actually running and a user
// is selected
IDataObject *pDataObject;
// DC is used for font metrics and saves on creating and destroying lots of DC handles
// during WM_MEASUREITEM
HDC hMemDC;
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
ULONG STDMETHODCALLTYPE AddRef(void);
ULONG STDMETHODCALLTYPE Release(void);
HRESULT STDMETHODCALLTYPE Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID);
HRESULT STDMETHODCALLTYPE QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
HRESULT STDMETHODCALLTYPE InvokeCommand(CMINVOKECOMMANDINFO *pici);
HRESULT STDMETHODCALLTYPE GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pReserved, LPSTR pszName, UINT cchMax);
HRESULT STDMETHODCALLTYPE HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
HRESULT STDMETHODCALLTYPE HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult);
};
struct TEnumData
{
TShellExt *Self;
// autodetected, don't hard code since shells that don't support it
// won't send WM_MEASUREITETM/WM_DRAWITEM at all.
BOOL bOwnerDrawSupported;
// as per user setting (maybe of multiple Mirandas)
BOOL bShouldOwnerDraw;
int idCmdFirst;
THeaderIPC *ipch;
// OpenEvent()'d handle to give each IPC server an object to set signalled
HANDLE hWaitFor;
DWORD pid; // sub-unique value used to make work object name
};
struct TClassFactoryRec : public IClassFactory
{
TClassFactoryRec();
LONG RefCount;
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
ULONG STDMETHODCALLTYPE AddRef(void);
ULONG STDMETHODCALLTYPE Release(void);
HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock);
};
/////////////////////////////////////////////////////////////////////////////////////////
enum TSlotDrawType {dtEntry = 0x01, dtGroup = 0x02, dtContact = 0x04, dtCommand = 0x08 };
typedef int TSlotDrawTypes;
typedef int (__stdcall TMenuCommandCallback)(
THeaderIPC *pipch, // IPC header info, already mapped
HANDLE hWorkThreadEvent, // event object being waited on on miranda thread
HANDLE hAckEvent, // ack event object that has been created
struct TMenuDrawInfo *psd); // command/draw info
struct TMenuDrawInfo
{
char *szText, *szProfile;
int cch;
int wID; // should be the same as the menu item's ID
TSlotDrawTypes fTypes;
HANDLE hContact;
HICON hStatusIcon; // HICON from Self->ProtoIcons[index].hIcons[status]; Do not DestroyIcon()
HBITMAP hStatusBitmap; // HBITMAP, don't free.
int pid;
TMenuCommandCallback *MenuCommandCallback; // dtCommand must be set also.
};
/////////////////////////////////////////////////////////////////////////////////////////
void ipcPrepareRequests(int ipcPacketSize, THeaderIPC *pipch, DWORD fRequests);
DWORD ipcSendRequest(HANDLE hSignal, HANDLE hWaitFor, THeaderIPC *pipch, DWORD dwTimeoutMsecs);
TSlotIPC* ipcAlloc(THeaderIPC *pipch, int nSize);
void ipcFixupAddresses(BOOL FromServer, THeaderIPC *pipch);
TGroupNode* AllocGroupNode(TGroupNodeList *list, TGroupNode *Root, int Depth);
TGroupNode* FindGroupNode(TGroupNode* p, const DWORD Hash, int Depth);
char* CreateProcessUID(int pid, char *buf, size_t bufLen);
|