summaryrefslogtreecommitdiff
path: root/plugins/ShellExt/src/shlcom.h
blob: 4e78587f61b728d9d400ce39d96d5e98c66fef60 (plain)
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

#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;
	HCONTACT 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();
	~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;
   HCONTACT 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);