1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright © 2009 Red Hat, Inc.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person obtaining a
5*4882a593Smuzhiyun * copy of this software and associated documentation files (the "Software"),
6*4882a593Smuzhiyun * to deal in the Software without restriction, including without limitation
7*4882a593Smuzhiyun * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*4882a593Smuzhiyun * and/or sell copies of the Software, and to permit persons to whom the
9*4882a593Smuzhiyun * Software is furnished to do so, subject to the following conditions:
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * The above copyright notice and this permission notice (including the next
12*4882a593Smuzhiyun * paragraph) shall be included in all copies or substantial portions of the
13*4882a593Smuzhiyun * Software.
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*4882a593Smuzhiyun * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*4882a593Smuzhiyun * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*4882a593Smuzhiyun * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*4882a593Smuzhiyun * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21*4882a593Smuzhiyun * DEALINGS IN THE SOFTWARE.
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * Author: Peter Hutterer
24*4882a593Smuzhiyun */
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /***********************************************************************
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun * Request to grab or ungrab input device.
29*4882a593Smuzhiyun *
30*4882a593Smuzhiyun */
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
33*4882a593Smuzhiyun #include <dix-config.h>
34*4882a593Smuzhiyun #endif
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #include "inputstr.h" /* DeviceIntPtr */
37*4882a593Smuzhiyun #include "windowstr.h" /* window structure */
38*4882a593Smuzhiyun #include <X11/extensions/XI2.h>
39*4882a593Smuzhiyun #include <X11/extensions/XI2proto.h>
40*4882a593Smuzhiyun #include "swaprep.h"
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #include "exglobals.h" /* BadDevice */
43*4882a593Smuzhiyun #include "exevents.h"
44*4882a593Smuzhiyun #include "xipassivegrab.h"
45*4882a593Smuzhiyun #include "dixgrabs.h"
46*4882a593Smuzhiyun #include "misc.h"
47*4882a593Smuzhiyun #include "inpututils.h"
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun int _X_COLD
SProcXIPassiveGrabDevice(ClientPtr client)50*4882a593Smuzhiyun SProcXIPassiveGrabDevice(ClientPtr client)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun int i;
53*4882a593Smuzhiyun uint32_t *mods;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun REQUEST(xXIPassiveGrabDeviceReq);
56*4882a593Smuzhiyun REQUEST_AT_LEAST_SIZE(xXIPassiveGrabDeviceReq);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun swaps(&stuff->length);
59*4882a593Smuzhiyun swaps(&stuff->deviceid);
60*4882a593Smuzhiyun swapl(&stuff->grab_window);
61*4882a593Smuzhiyun swapl(&stuff->cursor);
62*4882a593Smuzhiyun swapl(&stuff->time);
63*4882a593Smuzhiyun swapl(&stuff->detail);
64*4882a593Smuzhiyun swaps(&stuff->mask_len);
65*4882a593Smuzhiyun swaps(&stuff->num_modifiers);
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun REQUEST_FIXED_SIZE(xXIPassiveGrabDeviceReq,
68*4882a593Smuzhiyun ((uint32_t) stuff->mask_len + stuff->num_modifiers) *4);
69*4882a593Smuzhiyun mods = (uint32_t *) &stuff[1] + stuff->mask_len;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun for (i = 0; i < stuff->num_modifiers; i++, mods++) {
72*4882a593Smuzhiyun swapl(mods);
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun return ProcXIPassiveGrabDevice(client);
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun int
ProcXIPassiveGrabDevice(ClientPtr client)79*4882a593Smuzhiyun ProcXIPassiveGrabDevice(ClientPtr client)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun DeviceIntPtr dev, mod_dev;
82*4882a593Smuzhiyun xXIPassiveGrabDeviceReply rep = {
83*4882a593Smuzhiyun .repType = X_Reply,
84*4882a593Smuzhiyun .RepType = X_XIPassiveGrabDevice,
85*4882a593Smuzhiyun .sequenceNumber = client->sequence,
86*4882a593Smuzhiyun .length = 0,
87*4882a593Smuzhiyun .num_modifiers = 0
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun int i, ret = Success;
90*4882a593Smuzhiyun uint32_t *modifiers;
91*4882a593Smuzhiyun xXIGrabModifierInfo *modifiers_failed = NULL;
92*4882a593Smuzhiyun GrabMask mask = { 0 };
93*4882a593Smuzhiyun GrabParameters param;
94*4882a593Smuzhiyun void *tmp;
95*4882a593Smuzhiyun int mask_len;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun REQUEST(xXIPassiveGrabDeviceReq);
98*4882a593Smuzhiyun REQUEST_FIXED_SIZE(xXIPassiveGrabDeviceReq,
99*4882a593Smuzhiyun ((uint32_t) stuff->mask_len + stuff->num_modifiers) * 4);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun if (stuff->deviceid == XIAllDevices)
102*4882a593Smuzhiyun dev = inputInfo.all_devices;
103*4882a593Smuzhiyun else if (stuff->deviceid == XIAllMasterDevices)
104*4882a593Smuzhiyun dev = inputInfo.all_master_devices;
105*4882a593Smuzhiyun else {
106*4882a593Smuzhiyun ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGrabAccess);
107*4882a593Smuzhiyun if (ret != Success) {
108*4882a593Smuzhiyun client->errorValue = stuff->deviceid;
109*4882a593Smuzhiyun return ret;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun if (stuff->grab_type != XIGrabtypeButton &&
114*4882a593Smuzhiyun stuff->grab_type != XIGrabtypeKeycode &&
115*4882a593Smuzhiyun stuff->grab_type != XIGrabtypeEnter &&
116*4882a593Smuzhiyun stuff->grab_type != XIGrabtypeFocusIn &&
117*4882a593Smuzhiyun stuff->grab_type != XIGrabtypeTouchBegin) {
118*4882a593Smuzhiyun client->errorValue = stuff->grab_type;
119*4882a593Smuzhiyun return BadValue;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun if ((stuff->grab_type == XIGrabtypeEnter ||
123*4882a593Smuzhiyun stuff->grab_type == XIGrabtypeFocusIn ||
124*4882a593Smuzhiyun stuff->grab_type == XIGrabtypeTouchBegin) && stuff->detail != 0) {
125*4882a593Smuzhiyun client->errorValue = stuff->detail;
126*4882a593Smuzhiyun return BadValue;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun if (stuff->grab_type == XIGrabtypeTouchBegin &&
130*4882a593Smuzhiyun (stuff->grab_mode != XIGrabModeTouch ||
131*4882a593Smuzhiyun stuff->paired_device_mode != GrabModeAsync)) {
132*4882a593Smuzhiyun client->errorValue = stuff->grab_mode;
133*4882a593Smuzhiyun return BadValue;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun if (XICheckInvalidMaskBits(client, (unsigned char *) &stuff[1],
137*4882a593Smuzhiyun stuff->mask_len * 4) != Success)
138*4882a593Smuzhiyun return BadValue;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun mask.xi2mask = xi2mask_new();
141*4882a593Smuzhiyun if (!mask.xi2mask)
142*4882a593Smuzhiyun return BadAlloc;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun mask_len = min(xi2mask_mask_size(mask.xi2mask), stuff->mask_len * 4);
145*4882a593Smuzhiyun xi2mask_set_one_mask(mask.xi2mask, stuff->deviceid,
146*4882a593Smuzhiyun (unsigned char *) &stuff[1], mask_len * 4);
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun memset(¶m, 0, sizeof(param));
149*4882a593Smuzhiyun param.grabtype = XI2;
150*4882a593Smuzhiyun param.ownerEvents = stuff->owner_events;
151*4882a593Smuzhiyun param.grabWindow = stuff->grab_window;
152*4882a593Smuzhiyun param.cursor = stuff->cursor;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun if (IsKeyboardDevice(dev)) {
155*4882a593Smuzhiyun param.this_device_mode = stuff->grab_mode;
156*4882a593Smuzhiyun param.other_devices_mode = stuff->paired_device_mode;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun else {
159*4882a593Smuzhiyun param.this_device_mode = stuff->paired_device_mode;
160*4882a593Smuzhiyun param.other_devices_mode = stuff->grab_mode;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun if (stuff->cursor != None) {
164*4882a593Smuzhiyun ret = dixLookupResourceByType(&tmp, stuff->cursor,
165*4882a593Smuzhiyun RT_CURSOR, client, DixUseAccess);
166*4882a593Smuzhiyun if (ret != Success) {
167*4882a593Smuzhiyun client->errorValue = stuff->cursor;
168*4882a593Smuzhiyun goto out;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun ret =
173*4882a593Smuzhiyun dixLookupWindow((WindowPtr *) &tmp, stuff->grab_window, client,
174*4882a593Smuzhiyun DixSetAttrAccess);
175*4882a593Smuzhiyun if (ret != Success)
176*4882a593Smuzhiyun goto out;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun ret = CheckGrabValues(client, ¶m);
179*4882a593Smuzhiyun if (ret != Success)
180*4882a593Smuzhiyun goto out;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun modifiers = (uint32_t *) &stuff[1] + stuff->mask_len;
183*4882a593Smuzhiyun modifiers_failed =
184*4882a593Smuzhiyun calloc(stuff->num_modifiers, sizeof(xXIGrabModifierInfo));
185*4882a593Smuzhiyun if (!modifiers_failed) {
186*4882a593Smuzhiyun ret = BadAlloc;
187*4882a593Smuzhiyun goto out;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun mod_dev = (IsFloating(dev)) ? dev : GetMaster(dev, MASTER_KEYBOARD);
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun for (i = 0; i < stuff->num_modifiers; i++, modifiers++) {
193*4882a593Smuzhiyun uint8_t status = Success;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun param.modifiers = *modifiers;
196*4882a593Smuzhiyun ret = CheckGrabValues(client, ¶m);
197*4882a593Smuzhiyun if (ret != Success)
198*4882a593Smuzhiyun goto out;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun switch (stuff->grab_type) {
201*4882a593Smuzhiyun case XIGrabtypeButton:
202*4882a593Smuzhiyun status = GrabButton(client, dev, mod_dev, stuff->detail,
203*4882a593Smuzhiyun ¶m, XI2, &mask);
204*4882a593Smuzhiyun break;
205*4882a593Smuzhiyun case XIGrabtypeKeycode:
206*4882a593Smuzhiyun /* XI2 allows 32-bit keycodes but thanks to XKB we can never
207*4882a593Smuzhiyun * implement this. Just return an error for all keycodes that
208*4882a593Smuzhiyun * cannot work anyway */
209*4882a593Smuzhiyun if (stuff->detail > 255)
210*4882a593Smuzhiyun status = XIAlreadyGrabbed;
211*4882a593Smuzhiyun else
212*4882a593Smuzhiyun status = GrabKey(client, dev, mod_dev, stuff->detail,
213*4882a593Smuzhiyun ¶m, XI2, &mask);
214*4882a593Smuzhiyun break;
215*4882a593Smuzhiyun case XIGrabtypeEnter:
216*4882a593Smuzhiyun case XIGrabtypeFocusIn:
217*4882a593Smuzhiyun status = GrabWindow(client, dev, stuff->grab_type, ¶m, &mask);
218*4882a593Smuzhiyun break;
219*4882a593Smuzhiyun case XIGrabtypeTouchBegin:
220*4882a593Smuzhiyun status = GrabTouch(client, dev, mod_dev, ¶m, &mask);
221*4882a593Smuzhiyun break;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (status != GrabSuccess) {
225*4882a593Smuzhiyun xXIGrabModifierInfo *info = modifiers_failed + rep.num_modifiers;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun info->status = status;
228*4882a593Smuzhiyun info->modifiers = *modifiers;
229*4882a593Smuzhiyun if (client->swapped)
230*4882a593Smuzhiyun swapl(&info->modifiers);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun rep.num_modifiers++;
233*4882a593Smuzhiyun rep.length += bytes_to_int32(sizeof(xXIGrabModifierInfo));
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun WriteReplyToClient(client, sizeof(rep), &rep);
238*4882a593Smuzhiyun if (rep.num_modifiers)
239*4882a593Smuzhiyun WriteToClient(client, rep.length * 4, modifiers_failed);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun out:
242*4882a593Smuzhiyun free(modifiers_failed);
243*4882a593Smuzhiyun xi2mask_free(&mask.xi2mask);
244*4882a593Smuzhiyun return ret;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun void _X_COLD
SRepXIPassiveGrabDevice(ClientPtr client,int size,xXIPassiveGrabDeviceReply * rep)248*4882a593Smuzhiyun SRepXIPassiveGrabDevice(ClientPtr client, int size,
249*4882a593Smuzhiyun xXIPassiveGrabDeviceReply * rep)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun swaps(&rep->sequenceNumber);
252*4882a593Smuzhiyun swapl(&rep->length);
253*4882a593Smuzhiyun swaps(&rep->num_modifiers);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun WriteToClient(client, size, rep);
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun int _X_COLD
SProcXIPassiveUngrabDevice(ClientPtr client)259*4882a593Smuzhiyun SProcXIPassiveUngrabDevice(ClientPtr client)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun int i;
262*4882a593Smuzhiyun uint32_t *modifiers;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun REQUEST(xXIPassiveUngrabDeviceReq);
265*4882a593Smuzhiyun REQUEST_AT_LEAST_SIZE(xXIPassiveUngrabDeviceReq);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun swaps(&stuff->length);
268*4882a593Smuzhiyun swapl(&stuff->grab_window);
269*4882a593Smuzhiyun swaps(&stuff->deviceid);
270*4882a593Smuzhiyun swapl(&stuff->detail);
271*4882a593Smuzhiyun swaps(&stuff->num_modifiers);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun REQUEST_FIXED_SIZE(xXIPassiveUngrabDeviceReq,
274*4882a593Smuzhiyun ((uint32_t) stuff->num_modifiers) << 2);
275*4882a593Smuzhiyun modifiers = (uint32_t *) &stuff[1];
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun for (i = 0; i < stuff->num_modifiers; i++, modifiers++)
278*4882a593Smuzhiyun swapl(modifiers);
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun return ProcXIPassiveUngrabDevice(client);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun int
ProcXIPassiveUngrabDevice(ClientPtr client)284*4882a593Smuzhiyun ProcXIPassiveUngrabDevice(ClientPtr client)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun DeviceIntPtr dev, mod_dev;
287*4882a593Smuzhiyun WindowPtr win;
288*4882a593Smuzhiyun GrabPtr tempGrab;
289*4882a593Smuzhiyun uint32_t *modifiers;
290*4882a593Smuzhiyun int i, rc;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun REQUEST(xXIPassiveUngrabDeviceReq);
293*4882a593Smuzhiyun REQUEST_FIXED_SIZE(xXIPassiveUngrabDeviceReq,
294*4882a593Smuzhiyun ((uint32_t) stuff->num_modifiers) << 2);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun if (stuff->deviceid == XIAllDevices)
297*4882a593Smuzhiyun dev = inputInfo.all_devices;
298*4882a593Smuzhiyun else if (stuff->deviceid == XIAllMasterDevices)
299*4882a593Smuzhiyun dev = inputInfo.all_master_devices;
300*4882a593Smuzhiyun else {
301*4882a593Smuzhiyun rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGrabAccess);
302*4882a593Smuzhiyun if (rc != Success)
303*4882a593Smuzhiyun return rc;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun if (stuff->grab_type != XIGrabtypeButton &&
307*4882a593Smuzhiyun stuff->grab_type != XIGrabtypeKeycode &&
308*4882a593Smuzhiyun stuff->grab_type != XIGrabtypeEnter &&
309*4882a593Smuzhiyun stuff->grab_type != XIGrabtypeFocusIn &&
310*4882a593Smuzhiyun stuff->grab_type != XIGrabtypeTouchBegin) {
311*4882a593Smuzhiyun client->errorValue = stuff->grab_type;
312*4882a593Smuzhiyun return BadValue;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun if ((stuff->grab_type == XIGrabtypeEnter ||
316*4882a593Smuzhiyun stuff->grab_type == XIGrabtypeFocusIn ||
317*4882a593Smuzhiyun stuff->grab_type == XIGrabtypeTouchBegin) && stuff->detail != 0) {
318*4882a593Smuzhiyun client->errorValue = stuff->detail;
319*4882a593Smuzhiyun return BadValue;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun rc = dixLookupWindow(&win, stuff->grab_window, client, DixSetAttrAccess);
323*4882a593Smuzhiyun if (rc != Success)
324*4882a593Smuzhiyun return rc;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun mod_dev = (IsFloating(dev)) ? dev : GetMaster(dev, MASTER_KEYBOARD);
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun tempGrab = AllocGrab(NULL);
329*4882a593Smuzhiyun if (!tempGrab)
330*4882a593Smuzhiyun return BadAlloc;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun tempGrab->resource = client->clientAsMask;
333*4882a593Smuzhiyun tempGrab->device = dev;
334*4882a593Smuzhiyun tempGrab->window = win;
335*4882a593Smuzhiyun switch (stuff->grab_type) {
336*4882a593Smuzhiyun case XIGrabtypeButton:
337*4882a593Smuzhiyun tempGrab->type = XI_ButtonPress;
338*4882a593Smuzhiyun break;
339*4882a593Smuzhiyun case XIGrabtypeKeycode:
340*4882a593Smuzhiyun tempGrab->type = XI_KeyPress;
341*4882a593Smuzhiyun break;
342*4882a593Smuzhiyun case XIGrabtypeEnter:
343*4882a593Smuzhiyun tempGrab->type = XI_Enter;
344*4882a593Smuzhiyun break;
345*4882a593Smuzhiyun case XIGrabtypeFocusIn:
346*4882a593Smuzhiyun tempGrab->type = XI_FocusIn;
347*4882a593Smuzhiyun break;
348*4882a593Smuzhiyun case XIGrabtypeTouchBegin:
349*4882a593Smuzhiyun tempGrab->type = XI_TouchBegin;
350*4882a593Smuzhiyun break;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun tempGrab->grabtype = XI2;
353*4882a593Smuzhiyun tempGrab->modifierDevice = mod_dev;
354*4882a593Smuzhiyun tempGrab->modifiersDetail.pMask = NULL;
355*4882a593Smuzhiyun tempGrab->detail.exact = stuff->detail;
356*4882a593Smuzhiyun tempGrab->detail.pMask = NULL;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun modifiers = (uint32_t *) &stuff[1];
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun for (i = 0; i < stuff->num_modifiers; i++, modifiers++) {
361*4882a593Smuzhiyun tempGrab->modifiersDetail.exact = *modifiers;
362*4882a593Smuzhiyun DeletePassiveGrabFromList(tempGrab);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun FreeGrab(tempGrab);
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun return Success;
368*4882a593Smuzhiyun }
369