1 |
|
---|
2 | /*
|
---|
3 | *@@ ImplCallFileDlg:
|
---|
4 | * this code contacts XFLDR.DLL to show the
|
---|
5 | * XWorkplace file dialog. This does not
|
---|
6 | * return until either an error occurred
|
---|
7 | * or XFLDR.DLL has dismissed the dialog,
|
---|
8 | * either because the user pressed "OK"
|
---|
9 | * or "Cancel".
|
---|
10 | *
|
---|
11 | * In summary, this can almost be called
|
---|
12 | * instead of WinFileDlg.
|
---|
13 | *
|
---|
14 | * If this fails because FILEDLG contains
|
---|
15 | * options that are presently not supported
|
---|
16 | * by XWP's dialog replacement, we set
|
---|
17 | * *pfCallDefault to TRUE and return NULLHANDLE.
|
---|
18 | * As a result, you should check that flag
|
---|
19 | * on return and call WinFileDlg instead
|
---|
20 | * if the flag is TRUE.
|
---|
21 | *
|
---|
22 | *@@added V0.9.19 (2002-04-24) [umoeller]
|
---|
23 | *@@changed V1.0.2 (2003-03-07) [umoeller]: HWND_DESKTOP owner causes focus problems, fixed
|
---|
24 | */
|
---|
25 |
|
---|
26 | HWND APIENTRY ImplCallFileDlg(HWND hwndOwner, // in: owner for dialog
|
---|
27 | PFILEDLG pfd, // in/out: as with WinFileDlg
|
---|
28 | PBOOL pfCallDefault) // out: set to TRUE if replacement failed
|
---|
29 | {
|
---|
30 | HWND hwndReturn = NULLHANDLE;
|
---|
31 |
|
---|
32 | *pfCallDefault = TRUE;
|
---|
33 |
|
---|
34 | // first, some compatibility checks...
|
---|
35 | if ( (pfd)
|
---|
36 | && ( (!(pfd->fl & ( FDS_CUSTOM
|
---|
37 | | FDS_MODELESS // we can't handle non-modal dialogs
|
---|
38 | | FDS_MULTIPLESEL // we can't handle multiple selections for now
|
---|
39 | )
|
---|
40 | )))
|
---|
41 | )
|
---|
42 | {
|
---|
43 | // OK:
|
---|
44 |
|
---|
45 | // check if XWP is running; if so, a block of
|
---|
46 | // named shared memory must exist
|
---|
47 | APIRET arc;
|
---|
48 | PXWPGLOBALSHARED pXwpGlobalShared = 0;
|
---|
49 | if (!(arc = DosGetNamedSharedMem((PVOID*)&pXwpGlobalShared,
|
---|
50 | SHMEM_XWPGLOBAL, // "\\SHAREMEM\\XWORKPLC\\DMNSHARE.DAT",
|
---|
51 | PAG_READ | PAG_WRITE)))
|
---|
52 | {
|
---|
53 | // we can get the shared memory --> XWP running:
|
---|
54 | PID pidWPS = 0;
|
---|
55 | TID tidWPS = 0;
|
---|
56 | CHAR szEmptyTitle[1];
|
---|
57 | HWND hwndNotify;
|
---|
58 | HAB hab;
|
---|
59 |
|
---|
60 | szEmptyTitle[0] = 0;
|
---|
61 |
|
---|
62 | // create temporary object window for notifications from XFLDR.DLL;
|
---|
63 | // this handle is passed to XFLDR.DLL in the shared memory block
|
---|
64 | // so it can post WM_USER back to this window, upon which we
|
---|
65 | // terminate our modal loop here
|
---|
66 | if ( (hwndNotify = WinCreateWindow(HWND_OBJECT,
|
---|
67 | WC_STATIC,
|
---|
68 | szEmptyTitle,
|
---|
69 | 0,
|
---|
70 | 0,0,0,0,
|
---|
71 | 0,
|
---|
72 | HWND_BOTTOM,
|
---|
73 | 0,
|
---|
74 | NULL,
|
---|
75 | NULL))
|
---|
76 | // and we need the anchor block for WinGetMsg:
|
---|
77 | && (hab = WinQueryAnchorBlock(hwndNotify))
|
---|
78 | // is thread-1 object window in XFLDR.DLL running?
|
---|
79 | && (pXwpGlobalShared->hwndThread1Object)
|
---|
80 | && (WinIsWindow(hab,
|
---|
81 | pXwpGlobalShared->hwndThread1Object))
|
---|
82 | // get WPS PID from thread-1 object window
|
---|
83 | && (WinQueryWindowProcess(pXwpGlobalShared->hwndThread1Object,
|
---|
84 | &pidWPS, // on stack
|
---|
85 | &tidWPS)) // on stack
|
---|
86 | )
|
---|
87 | {
|
---|
88 | // yes:
|
---|
89 | PXWPFILEDLG pfdShared = NULL;
|
---|
90 |
|
---|
91 | // sum up how much shared memory we need:
|
---|
92 | // this is the sum of FILEDLG plus buffers for
|
---|
93 | // all the strings the stupid caller gave to WinFileDlg
|
---|
94 | // (we're cross-process here)
|
---|
95 |
|
---|
96 | // 1) at least the size of FILEDLG
|
---|
97 | ULONG cbShared = sizeof(XWPFILEDLG),
|
---|
98 | cTypes = 0; // count of types in papszITypes
|
---|
99 |
|
---|
100 | // 2) add memory for extra fields
|
---|
101 | if (pfd->pszTitle)
|
---|
102 | cbShared += strlen(pfd->pszTitle) + 1;
|
---|
103 | if (pfd->pszOKButton)
|
---|
104 | cbShared += strlen(pfd->pszOKButton) + 1;
|
---|
105 |
|
---|
106 | // 3) type
|
---|
107 | if (pfd->pszIType)
|
---|
108 | cbShared += strlen(pfd->pszIType) + 1;
|
---|
109 | // and types array: this is especially sick...
|
---|
110 | // this is a pointer to an array of PSZ's, so
|
---|
111 | // we need:
|
---|
112 | // a) 4 bytes for each PSZ in the PSZ's array
|
---|
113 | // b) string length + 1 for each string pointed
|
---|
114 | // to from the array
|
---|
115 | // c) another 4 bytes for the NULL array terminator
|
---|
116 | if (pfd->papszITypeList)
|
---|
117 | {
|
---|
118 | PSZ *ppszThis = pfd->papszITypeList[0];
|
---|
119 | while (*ppszThis)
|
---|
120 | {
|
---|
121 | cbShared += sizeof(PSZ) // for the PSZ array item
|
---|
122 | + strlen(*ppszThis) // string length
|
---|
123 | + 1; // null terminator
|
---|
124 | ppszThis++;
|
---|
125 | cTypes++; // count the types so we can align
|
---|
126 | // properly below
|
---|
127 | }
|
---|
128 | cbShared += 4; // array is terminated with a NULL psz,
|
---|
129 | // which we must allocate too
|
---|
130 | }
|
---|
131 |
|
---|
132 | // 4) drives array... ignored for now
|
---|
133 | /* if (pfd->pszIType)
|
---|
134 | cbShared += strlen(pfd->pszIDrive) + 1;
|
---|
135 | if (pfd->papszIDriveList)
|
---|
136 | {
|
---|
137 | PSZ *ppszThis = pfd->papszIDriveList[0];
|
---|
138 | while (*ppszThis)
|
---|
139 | {
|
---|
140 | cbShared += strlen(*ppszThis) + 1;
|
---|
141 | ppszThis++;
|
---|
142 | }
|
---|
143 | } */
|
---|
144 |
|
---|
145 | // OK, now we know how much memory we need...
|
---|
146 | // allocate a block of shared memory with this size
|
---|
147 | if ( (!(arc = DosAllocSharedMem((PVOID*)&pfdShared, // on stack
|
---|
148 | NULL, // unnamed
|
---|
149 | cbShared,
|
---|
150 | PAG_COMMIT | OBJ_GIVEABLE | OBJ_TILE
|
---|
151 | | PAG_READ | PAG_WRITE)))
|
---|
152 | && (pfdShared)
|
---|
153 | )
|
---|
154 | {
|
---|
155 | // OK, we got shared memory:
|
---|
156 | PPIB ppib = NULL;
|
---|
157 | PTIB ptib = NULL;
|
---|
158 | ULONG ulCurDisk = 0;
|
---|
159 | ULONG ulMap = 0;
|
---|
160 | ULONG cbBuf = CCHMAXPATH;
|
---|
161 |
|
---|
162 | ULONG cbThis;
|
---|
163 | PBYTE pb = (PBYTE)pfdShared + sizeof(XWPFILEDLG);
|
---|
164 | // current offset where to copy to
|
---|
165 |
|
---|
166 | // ZERO the structure
|
---|
167 | memset((PBYTE)pfdShared, 0, cbShared);
|
---|
168 |
|
---|
169 | // fix HWND_DESKTOP owner V1.0.2 (2003-03-07) [umoeller]
|
---|
170 | if (hwndOwner == HWND_DESKTOP)
|
---|
171 | hwndOwner = NULLHANDLE;
|
---|
172 |
|
---|
173 | // copy owner window
|
---|
174 | pfdShared->hwndOwner = hwndOwner;
|
---|
175 |
|
---|
176 | // store PID and TID of caller
|
---|
177 | DosGetInfoBlocks(&ptib, &ppib);
|
---|
178 | pfdShared->pidCaller = ppib->pib_ulpid;
|
---|
179 | pfdShared->tidCaller = ptib->tib_ptib2->tib2_ultid;
|
---|
180 |
|
---|
181 | // get the process's current directory so
|
---|
182 | // file dialog can base on that
|
---|
183 | if ( (arc = DosQueryCurrentDisk(&ulCurDisk, &ulMap))
|
---|
184 | || (ulCurDisk == 0)
|
---|
185 | )
|
---|
186 | DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
|
---|
187 | &ulCurDisk,
|
---|
188 | sizeof(ulCurDisk));
|
---|
189 |
|
---|
190 | pfdShared->szCurrentDir[0] = 'A' + ulCurDisk - 1;
|
---|
191 | pfdShared->szCurrentDir[1] = ':';
|
---|
192 | pfdShared->szCurrentDir[2] = '\\';
|
---|
193 | DosQueryCurrentDir(0,
|
---|
194 | &pfdShared->szCurrentDir[3],
|
---|
195 | &cbBuf);
|
---|
196 |
|
---|
197 | // copy FILEDLG
|
---|
198 | memcpy((PBYTE)&pfdShared->fd,
|
---|
199 | (PBYTE)pfd,
|
---|
200 | _min(pfd->cbSize, sizeof(FILEDLG)));
|
---|
201 |
|
---|
202 | // now pack the various fields into the
|
---|
203 | // shared mem AFTER the XWPFILEDLG
|
---|
204 | if (pfd->pszTitle)
|
---|
205 | {
|
---|
206 | cbThis = strlen(pfd->pszTitle) + 1;
|
---|
207 | memcpy(pb, pfd->pszTitle, cbThis);
|
---|
208 | pfdShared->fd.pszTitle = pb;
|
---|
209 | pb += cbThis;
|
---|
210 | }
|
---|
211 | if (pfd->pszOKButton)
|
---|
212 | {
|
---|
213 | cbThis = strlen(pfd->pszOKButton) + 1;
|
---|
214 | memcpy(pb, pfd->pszOKButton, cbThis);
|
---|
215 | pfdShared->fd.pszOKButton = pb;
|
---|
216 | pb += cbThis;
|
---|
217 | }
|
---|
218 |
|
---|
219 | // types array
|
---|
220 | if (pfd->pszIType)
|
---|
221 | {
|
---|
222 | cbThis = strlen(pfd->pszIType) + 1;
|
---|
223 | memcpy(pb, pfd->pszIType, cbThis);
|
---|
224 | pfdShared->fd.pszIType = pb;
|
---|
225 | pb += cbThis;
|
---|
226 | }
|
---|
227 |
|
---|
228 | if (cTypes) // we counted types in the array above:
|
---|
229 | {
|
---|
230 | ULONG ul;
|
---|
231 |
|
---|
232 | // 1) reserve room for the array of PSZ's;
|
---|
233 | // that's (cTypes + 1) * sizeof(PSZ) (null-terminator!)
|
---|
234 |
|
---|
235 | PAPSZ papszTarget = (PAPSZ)pb;
|
---|
236 |
|
---|
237 | PSZ *ppszSourceThis = pfd->papszITypeList[0],
|
---|
238 | *ppszTargetThis = papszTarget[0];
|
---|
239 |
|
---|
240 | pb += ((cTypes + 1) * sizeof(PSZ));
|
---|
241 |
|
---|
242 | // 2) pb points to the room for the first string now...
|
---|
243 | // (after the PSZ's array)
|
---|
244 |
|
---|
245 | for (ul = 0;
|
---|
246 | ul < cTypes;
|
---|
247 | ul++)
|
---|
248 | {
|
---|
249 | // copy this string from buffer to buffer
|
---|
250 | cbThis = strlen(*ppszSourceThis) + 1;
|
---|
251 | memcpy(pb, *ppszSourceThis, cbThis);
|
---|
252 |
|
---|
253 | // set target PSZ array item
|
---|
254 | *ppszTargetThis = pb;
|
---|
255 | // advance pointers
|
---|
256 | pb += cbThis;
|
---|
257 | ppszSourceThis++;
|
---|
258 | ppszTargetThis++;
|
---|
259 | }
|
---|
260 |
|
---|
261 | // set null terminator in target array... christ
|
---|
262 | *ppszTargetThis = 0;
|
---|
263 |
|
---|
264 | pfdShared->fd.papszITypeList = papszTarget;
|
---|
265 | }
|
---|
266 |
|
---|
267 | // drives array
|
---|
268 | /* if (pfd->pszIDrive)
|
---|
269 | {
|
---|
270 | cbThis = strlen(pfd->pszIDrive) + 1;
|
---|
271 | memcpy(pb, pfd->pszIDrive, cbThis);
|
---|
272 | pfdShared->fd.pszIDrive = pb;
|
---|
273 | pb += cbThis;
|
---|
274 | }
|
---|
275 | if (pfd->papszIDriveList)
|
---|
276 | {
|
---|
277 | PSZ *ppszThis = pfd->papszIDriveList[0];
|
---|
278 | PBYTE pbFirst = pb;
|
---|
279 | while (*ppszThis)
|
---|
280 | {
|
---|
281 | cbThis = strlen(*ppszThis) + 1;
|
---|
282 | memcpy(pb, *ppszThis, cbThis);
|
---|
283 | pb += cbThis;
|
---|
284 |
|
---|
285 | ppszThis++;
|
---|
286 | }
|
---|
287 |
|
---|
288 | pfdShared->fd.papszIDriveList = (PVOID)pbFirst;
|
---|
289 | } */
|
---|
290 |
|
---|
291 | // OK, now we got everything in shared memory...
|
---|
292 | // give the WPS access to it
|
---|
293 | if (!(arc = DosGiveSharedMem(pfdShared,
|
---|
294 | pidWPS,
|
---|
295 | PAG_READ | PAG_WRITE)))
|
---|
296 | {
|
---|
297 | // send this block to XFLDR.DLL;
|
---|
298 | // we can't use WinSendMsg because this would
|
---|
299 | // block the msg queue for the calling thread.
|
---|
300 | // So instead we use WinPostMsg and wait for
|
---|
301 | // XFLDR.DLL to post something back to our
|
---|
302 | // temporary object window here...
|
---|
303 |
|
---|
304 | pfdShared->hwndNotify = hwndNotify;
|
---|
305 |
|
---|
306 | if (WinPostMsg(pXwpGlobalShared->hwndAPIObject,
|
---|
307 | APIM_FILEDLG,
|
---|
308 | (MPARAM)pfdShared,
|
---|
309 | 0))
|
---|
310 | {
|
---|
311 | // the file dialog should be showing up now
|
---|
312 | // in the WPS process...
|
---|
313 |
|
---|
314 | QMSG qmsg;
|
---|
315 | BOOL fQuit = FALSE;
|
---|
316 | USHORT fsFrameFlags = 0;
|
---|
317 |
|
---|
318 | // OK, if we got this far:
|
---|
319 |
|
---|
320 | // 1) do not show the default dialog
|
---|
321 | *pfCallDefault = FALSE;
|
---|
322 |
|
---|
323 | // 2) DISABLE the owner window... we need to
|
---|
324 | // simulate a modal dialog here, but this doesn't
|
---|
325 | // really work because the dialog is in the WPS
|
---|
326 | // process, so a couple hacks are needed
|
---|
327 |
|
---|
328 | if (hwndOwner) // WinEnableWindow
|
---|
329 | WinEnableWindow(hwndOwner, FALSE);
|
---|
330 |
|
---|
331 | // keep processing our message queue until
|
---|
332 | // XFLDR.DLL posts back WM_USER to the
|
---|
333 | // object window
|
---|
334 | while (WinGetMsg(hab,
|
---|
335 | &qmsg, // on stack
|
---|
336 | 0,
|
---|
337 | 0,
|
---|
338 | 0))
|
---|
339 | {
|
---|
340 | // current message for our object window?
|
---|
341 | if ( (qmsg.hwnd == hwndNotify)
|
---|
342 | && (qmsg.msg == WM_USER)
|
---|
343 | )
|
---|
344 | // yes: this means the file dlg has been
|
---|
345 | // dismissed, and we can get outta here
|
---|
346 | fQuit = TRUE;
|
---|
347 |
|
---|
348 | WinDispatchMsg(hab,
|
---|
349 | &qmsg); // on stack
|
---|
350 |
|
---|
351 | if (fQuit)
|
---|
352 | break;
|
---|
353 | }
|
---|
354 |
|
---|
355 | // return hwndReturn from XFLDR.DLL;
|
---|
356 | // this is either TRUE or FALSE (stupid cast)
|
---|
357 | hwndReturn = pfdShared->hwndReturn;
|
---|
358 |
|
---|
359 | // copy stuff back from shared block (filled
|
---|
360 | // by WPS code) into caller's FILEDLG
|
---|
361 | pfd->lReturn = pfdShared->fd.lReturn;
|
---|
362 | pfd->lSRC = pfdShared->fd.lSRC;
|
---|
363 | memcpy(pfd->szFullFile,
|
---|
364 | pfdShared->fd.szFullFile,
|
---|
365 | sizeof(pfd->szFullFile));
|
---|
366 |
|
---|
367 | pfd->ulFQFCount = pfdShared->fd.ulFQFCount;
|
---|
368 | pfd->sEAType = pfdShared->fd.sEAType;
|
---|
369 | // @@todo: papszFQFilename for multiple selections
|
---|
370 |
|
---|
371 | // re-enable the owner and bring it back to top
|
---|
372 | if (hwndOwner)
|
---|
373 | {
|
---|
374 | WinEnableWindow(hwndOwner, TRUE);
|
---|
375 | WinSetActiveWindow(HWND_DESKTOP, hwndOwner);
|
---|
376 | }
|
---|
377 | }
|
---|
378 | } // end DosGiveSharedMem(pfdShared,
|
---|
379 |
|
---|
380 | DosFreeMem(pfdShared);
|
---|
381 |
|
---|
382 | } // end DosAllocSharedMem
|
---|
383 |
|
---|
384 | } // end if hwndNotify and stuff
|
---|
385 |
|
---|
386 | if (hwndNotify)
|
---|
387 | WinDestroyWindow(hwndNotify);
|
---|
388 |
|
---|
389 | } // end if !arc = DosGetNamedSharedMem((PVOID*)&pXwpGlobalShared,
|
---|
390 | } // end if if ( (pfd)
|
---|
391 |
|
---|
392 | return hwndReturn;
|
---|
393 | }
|
---|
394 |
|
---|