-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathProjectNotification.cs
More file actions
286 lines (265 loc) · 11.5 KB
/
Copy pathProjectNotification.cs
File metadata and controls
286 lines (265 loc) · 11.5 KB
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
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace BinaryNinja
{
/// <summary>Receives lifecycle and content change events from a project.</summary>
public class ProjectNotification
{
private enum ItemKind
{
FileCreated,
FileUpdated,
FileDeleted,
FolderCreated,
FolderUpdated,
FolderDeleted
}
private readonly List<Delegate> callbackRoots = new List<Delegate>();
private GCHandle callbacksHandle;
public ProjectNotification()
{
BNProjectNotification callbacks = new BNProjectNotification();
callbacks.context = IntPtr.Zero;
callbacks.beforeOpenProject = this.RootCallback(
new NativeDelegates.BNProjectNotificationBeforeProject(this.InvokeBeforeOpenProject)
);
callbacks.afterOpenProject = this.RootCallback(
new NativeDelegates.BNProjectNotificationAfterProject(this.InvokeAfterOpenProject)
);
callbacks.beforeCloseProject = this.RootCallback(
new NativeDelegates.BNProjectNotificationBeforeProject(this.InvokeBeforeCloseProject)
);
callbacks.afterCloseProject = this.RootCallback(
new NativeDelegates.BNProjectNotificationAfterProject(this.InvokeAfterCloseProject)
);
callbacks.beforeProjectMetadataWritten = this.RootCallback(
new NativeDelegates.BNProjectNotificationBeforeMetadata(this.InvokeBeforeMetadataWritten)
);
callbacks.afterProjectMetadataWritten = this.RootCallback(
new NativeDelegates.BNProjectNotificationAfterMetadata(this.InvokeAfterMetadataWritten)
);
callbacks.beforeProjectFileCreated = this.RootCallback(
new NativeDelegates.BNProjectNotificationBeforeItem(this.InvokeBeforeFileCreated)
);
callbacks.afterProjectFileCreated = this.RootCallback(
new NativeDelegates.BNProjectNotificationAfterItem(this.InvokeAfterFileCreated)
);
callbacks.beforeProjectFileUpdated = this.RootCallback(
new NativeDelegates.BNProjectNotificationBeforeItem(this.InvokeBeforeFileUpdated)
);
callbacks.afterProjectFileUpdated = this.RootCallback(
new NativeDelegates.BNProjectNotificationAfterItem(this.InvokeAfterFileUpdated)
);
callbacks.beforeProjectFileDeleted = this.RootCallback(
new NativeDelegates.BNProjectNotificationBeforeItem(this.InvokeBeforeFileDeleted)
);
callbacks.afterProjectFileDeleted = this.RootCallback(
new NativeDelegates.BNProjectNotificationAfterItem(this.InvokeAfterFileDeleted)
);
callbacks.beforeProjectFolderCreated = this.RootCallback(
new NativeDelegates.BNProjectNotificationBeforeItem(this.InvokeBeforeFolderCreated)
);
callbacks.afterProjectFolderCreated = this.RootCallback(
new NativeDelegates.BNProjectNotificationAfterItem(this.InvokeAfterFolderCreated)
);
callbacks.beforeProjectFolderUpdated = this.RootCallback(
new NativeDelegates.BNProjectNotificationBeforeItem(this.InvokeBeforeFolderUpdated)
);
callbacks.afterProjectFolderUpdated = this.RootCallback(
new NativeDelegates.BNProjectNotificationAfterItem(this.InvokeAfterFolderUpdated)
);
callbacks.beforeProjectFolderDeleted = this.RootCallback(
new NativeDelegates.BNProjectNotificationBeforeItem(this.InvokeBeforeFolderDeleted)
);
callbacks.afterProjectFolderDeleted = this.RootCallback(
new NativeDelegates.BNProjectNotificationAfterItem(this.InvokeAfterFolderDeleted)
);
this.callbacksHandle = GCHandle.Alloc(callbacks, GCHandleType.Pinned);
}
~ProjectNotification()
{
if (this.callbacksHandle.IsAllocated)
{
this.callbacksHandle.Free();
}
}
internal IntPtr CallbacksPointer
{
get { return this.callbacksHandle.AddrOfPinnedObject(); }
}
public virtual bool OnBeforeOpenProject(Project project) { return true; }
public virtual void OnAfterOpenProject(Project project) { }
public virtual bool OnBeforeCloseProject(Project project) { return true; }
public virtual void OnAfterCloseProject(Project project) { }
public virtual bool OnBeforeProjectMetadataWritten(Project project, string key, Metadata value) { return true; }
public virtual void OnAfterProjectMetadataWritten(Project project, string key, Metadata value) { }
public virtual bool OnBeforeProjectFileCreated(Project project, ProjectFile file) { return true; }
public virtual void OnAfterProjectFileCreated(Project project, ProjectFile file) { }
public virtual bool OnBeforeProjectFileUpdated(Project project, ProjectFile file) { return true; }
public virtual void OnAfterProjectFileUpdated(Project project, ProjectFile file) { }
public virtual bool OnBeforeProjectFileDeleted(Project project, ProjectFile file) { return true; }
public virtual void OnAfterProjectFileDeleted(Project project, ProjectFile file) { }
public virtual bool OnBeforeProjectFolderCreated(Project project, ProjectFolder folder) { return true; }
public virtual void OnAfterProjectFolderCreated(Project project, ProjectFolder folder) { }
public virtual bool OnBeforeProjectFolderUpdated(Project project, ProjectFolder folder) { return true; }
public virtual void OnAfterProjectFolderUpdated(Project project, ProjectFolder folder) { }
public virtual bool OnBeforeProjectFolderDeleted(Project project, ProjectFolder folder) { return true; }
public virtual void OnAfterProjectFolderDeleted(Project project, ProjectFolder folder) { }
private IntPtr RootCallback<TDelegate>(TDelegate callback)
where TDelegate : Delegate
{
this.callbackRoots.Add(callback);
return Marshal.GetFunctionPointerForDelegate<TDelegate>(callback);
}
private bool InvokeBeforeOpenProject(IntPtr context, IntPtr project)
{
return this.InvokeBeforeProject(project, true);
}
private bool InvokeBeforeCloseProject(IntPtr context, IntPtr project)
{
return this.InvokeBeforeProject(project, false);
}
private bool InvokeBeforeProject(IntPtr projectHandle, bool open)
{
try
{
using (Project project = Project.MustNewFromHandle(projectHandle))
{
return open ? this.OnBeforeOpenProject(project) : this.OnBeforeCloseProject(project);
}
}
catch (Exception exception)
{
Core.LogError("Unhandled exception in project notification: {0}", exception);
return false;
}
}
private void InvokeAfterOpenProject(IntPtr context, IntPtr project)
{
this.InvokeAfterProject(project, true);
}
private void InvokeAfterCloseProject(IntPtr context, IntPtr project)
{
this.InvokeAfterProject(project, false);
}
private void InvokeAfterProject(IntPtr projectHandle, bool open)
{
try
{
using (Project project = Project.MustNewFromHandle(projectHandle))
{
if (open) { this.OnAfterOpenProject(project); }
else { this.OnAfterCloseProject(project); }
}
}
catch (Exception exception)
{
Core.LogError("Unhandled exception in project notification: {0}", exception);
}
}
private bool InvokeBeforeMetadataWritten(IntPtr context, IntPtr projectHandle, IntPtr key, IntPtr value)
{
string managedKey = UnsafeUtils.TakeUtf8String(key);
try
{
using (Project project = Project.MustNewFromHandle(projectHandle))
using (Metadata metadata = Metadata.MustNewFromHandle(value))
{
return this.OnBeforeProjectMetadataWritten(project, managedKey, metadata);
}
}
catch (Exception exception)
{
Core.LogError("Unhandled exception in project metadata notification: {0}", exception);
return false;
}
}
private void InvokeAfterMetadataWritten(IntPtr context, IntPtr projectHandle, IntPtr key, IntPtr value)
{
string managedKey = UnsafeUtils.TakeUtf8String(key);
try
{
using (Project project = Project.MustNewFromHandle(projectHandle))
using (Metadata metadata = Metadata.MustNewFromHandle(value))
{
this.OnAfterProjectMetadataWritten(project, managedKey, metadata);
}
}
catch (Exception exception)
{
Core.LogError("Unhandled exception in project metadata notification: {0}", exception);
}
}
private bool InvokeBeforeFileCreated(IntPtr c, IntPtr p, IntPtr i) { return this.InvokeBeforeItem(p, i, ItemKind.FileCreated); }
private bool InvokeBeforeFileUpdated(IntPtr c, IntPtr p, IntPtr i) { return this.InvokeBeforeItem(p, i, ItemKind.FileUpdated); }
private bool InvokeBeforeFileDeleted(IntPtr c, IntPtr p, IntPtr i) { return this.InvokeBeforeItem(p, i, ItemKind.FileDeleted); }
private bool InvokeBeforeFolderCreated(IntPtr c, IntPtr p, IntPtr i) { return this.InvokeBeforeItem(p, i, ItemKind.FolderCreated); }
private bool InvokeBeforeFolderUpdated(IntPtr c, IntPtr p, IntPtr i) { return this.InvokeBeforeItem(p, i, ItemKind.FolderUpdated); }
private bool InvokeBeforeFolderDeleted(IntPtr c, IntPtr p, IntPtr i) { return this.InvokeBeforeItem(p, i, ItemKind.FolderDeleted); }
private void InvokeAfterFileCreated(IntPtr c, IntPtr p, IntPtr i) { this.InvokeAfterItem(p, i, ItemKind.FileCreated); }
private void InvokeAfterFileUpdated(IntPtr c, IntPtr p, IntPtr i) { this.InvokeAfterItem(p, i, ItemKind.FileUpdated); }
private void InvokeAfterFileDeleted(IntPtr c, IntPtr p, IntPtr i) { this.InvokeAfterItem(p, i, ItemKind.FileDeleted); }
private void InvokeAfterFolderCreated(IntPtr c, IntPtr p, IntPtr i) { this.InvokeAfterItem(p, i, ItemKind.FolderCreated); }
private void InvokeAfterFolderUpdated(IntPtr c, IntPtr p, IntPtr i) { this.InvokeAfterItem(p, i, ItemKind.FolderUpdated); }
private void InvokeAfterFolderDeleted(IntPtr c, IntPtr p, IntPtr i) { this.InvokeAfterItem(p, i, ItemKind.FolderDeleted); }
private bool InvokeBeforeItem(IntPtr projectHandle, IntPtr itemHandle, ItemKind kind)
{
try
{
using (Project project = Project.MustNewFromHandle(projectHandle))
{
if (ItemKind.FileCreated == kind || ItemKind.FileUpdated == kind || ItemKind.FileDeleted == kind)
{
using (ProjectFile file = ProjectFile.MustNewFromHandle(itemHandle))
{
if (ItemKind.FileCreated == kind) { return this.OnBeforeProjectFileCreated(project, file); }
if (ItemKind.FileUpdated == kind) { return this.OnBeforeProjectFileUpdated(project, file); }
return this.OnBeforeProjectFileDeleted(project, file);
}
}
using (ProjectFolder folder = ProjectFolder.MustNewFromHandle(itemHandle))
{
if (ItemKind.FolderCreated == kind) { return this.OnBeforeProjectFolderCreated(project, folder); }
if (ItemKind.FolderUpdated == kind) { return this.OnBeforeProjectFolderUpdated(project, folder); }
return this.OnBeforeProjectFolderDeleted(project, folder);
}
}
}
catch (Exception exception)
{
Core.LogError("Unhandled exception in project item notification: {0}", exception);
return false;
}
}
private void InvokeAfterItem(IntPtr projectHandle, IntPtr itemHandle, ItemKind kind)
{
try
{
using (Project project = Project.MustNewFromHandle(projectHandle))
{
if (ItemKind.FileCreated == kind || ItemKind.FileUpdated == kind || ItemKind.FileDeleted == kind)
{
using (ProjectFile file = ProjectFile.MustNewFromHandle(itemHandle))
{
if (ItemKind.FileCreated == kind) { this.OnAfterProjectFileCreated(project, file); }
else if (ItemKind.FileUpdated == kind) { this.OnAfterProjectFileUpdated(project, file); }
else { this.OnAfterProjectFileDeleted(project, file); }
return;
}
}
using (ProjectFolder folder = ProjectFolder.MustNewFromHandle(itemHandle))
{
if (ItemKind.FolderCreated == kind) { this.OnAfterProjectFolderCreated(project, folder); }
else if (ItemKind.FolderUpdated == kind) { this.OnAfterProjectFolderUpdated(project, folder); }
else { this.OnAfterProjectFolderDeleted(project, folder); }
}
}
}
catch (Exception exception)
{
Core.LogError("Unhandled exception in project item notification: {0}", exception);
}
}
}
}