Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1485 lines
38 KiB

  1. /*++
  2. *
  3. * WOW v1.0
  4. *
  5. * Copyright (c) 1991, Microsoft Corporation
  6. *
  7. * WSHELL.C
  8. * WOW32 16-bit SHELL API support
  9. *
  10. * History:
  11. * 14-April-1992 Chandan Chauhan (ChandanC)
  12. * Created.
  13. *
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include <winreg.h>
  18. #include "wowshlp.h"
  19. MODNAME(wshell.c);
  20. LONG
  21. WOWRegDeleteKey(
  22. IN HKEY hKey,
  23. IN LPCTSTR lpszSubKey
  24. );
  25. #ifndef WIN16_HKEY_CLASSES_ROOT
  26. #define WIN16_HKEY_CLASSES_ROOT 1
  27. #endif
  28. #ifndef WIN16_ERROR_SUCCESS
  29. #define WIN16_ERROR_SUCCESS 0L
  30. #define WIN16_ERROR_BADDB 1L
  31. #define WIN16_ERROR_BADKEY 2L
  32. #define WIN16_ERROR_CANTOPEN 3L
  33. #define WIN16_ERROR_CANTREAD 4L
  34. #define WIN16_ERROR_CANTWRITE 5L
  35. #define WIN16_ERROR_OUTOFMEMORY 6L
  36. #define WIN16_ERROR_INVALID_PARAMETER 7L
  37. #define WIN16_ERROR_ACCESS_DENIED 8L
  38. #endif
  39. //
  40. // Flags for DROPALIAS's dwFlags member
  41. //
  42. #define ALLOC_H32 0x0001L
  43. #define ALLOC_H16 0x0002L
  44. ULONG FASTCALL WS32DoEnvironmentSubst(PVDMFRAME pFrame)
  45. {
  46. //
  47. // This is an undocumented shell.dll API used by ProgMan
  48. // and Norton AntiVirus for Windows (part of Norton
  49. // Desktop for Windows), probably among others.
  50. // Since it's not in the Win32 shellapi.h, we have a
  51. // copy of the prototype here, copied from
  52. // \nt\private\windows\shell\library\expenv.c.
  53. //
  54. ULONG ul;
  55. register PDOENVIRONMENTSUBST16 parg16;
  56. PSZ psz;
  57. WORD cch;
  58. PSZ pszExpanded;
  59. DWORD cchExpanded;
  60. GETARGPTR(pFrame, sizeof(DOENVIRONMENTSUBST16), parg16);
  61. GETPSZPTR(parg16->vpsz, psz);
  62. cch = FETCHWORD(parg16->cch);
  63. LOGDEBUG(0,("WS32DoEnvironmentSubst input: '%s'\n", psz));
  64. //
  65. // DoEnvironmentSubst makes its substitution in an allocated
  66. // buffer of cch characters. If the substution is too long
  67. // to fit, the original string is left untouched and the
  68. // low word of the return is FALSE, the high word is the
  69. // value of cch. If it fits, the string is overlaid and
  70. // the low word of the return is TRUE, and the high word
  71. // is the length (strlen()-style) of the expanded string.
  72. //
  73. if (!(pszExpanded = malloc_w(cch * sizeof(*psz)))) {
  74. goto Fail;
  75. }
  76. cchExpanded = ExpandEnvironmentStrings(
  77. psz, // source
  78. pszExpanded, // dest.
  79. cch // dest. size
  80. );
  81. if (cchExpanded <= (DWORD)cch) {
  82. //
  83. // Succeeded, copy expanded string to caller's buffer.
  84. // cchExpanded includes null terminator, our return
  85. // code doesn't.
  86. //
  87. RtlCopyMemory(psz, pszExpanded, cchExpanded);
  88. LOGDEBUG(0,("WS32DoEnvironmentSubst output: '%s'\n", psz));
  89. WOW32ASSERT((cchExpanded - 1) == strlen(psz));
  90. FLUSHVDMPTR(parg16->vpsz, (USHORT)cchExpanded, psz);
  91. ul = MAKELONG((WORD)(cchExpanded - 1), TRUE);
  92. } else {
  93. Fail:
  94. ul = MAKELONG((WORD)cch, FALSE);
  95. LOGDEBUG(0,("WS32DoEnvironmentSubst failing!!!\n"));
  96. }
  97. if (pszExpanded) {
  98. free_w(pszExpanded);
  99. }
  100. FREEPSZPTR(psz);
  101. FREEARGPTR(parg16);
  102. RETURN(ul);
  103. }
  104. ULONG FASTCALL WS32RegOpenKey(PVDMFRAME pFrame)
  105. {
  106. ULONG ul;
  107. register PREGOPENKEY16 parg16;
  108. HKEY hkResult = 0;
  109. HKEY hkey;
  110. PSZ psz;
  111. PSZ psz1 = NULL;
  112. PHKEY lp;
  113. GETARGPTR(pFrame, sizeof(REGOPENKEY16), parg16);
  114. GETPSZPTR(parg16->f2, psz);
  115. GETOPTPTR(parg16->f3, 0, lp);
  116. hkey = (HKEY)FETCHDWORD(parg16->f1);
  117. if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
  118. hkey = (HKEY)HKEY_CLASSES_ROOT;
  119. }
  120. if (!hkey) {
  121. if (psz) {
  122. psz1 = Remove_Classes (psz);
  123. }
  124. ul = RegOpenKey (
  125. HKEY_CLASSES_ROOT,
  126. psz1,
  127. &hkResult
  128. );
  129. if ((psz1) && (psz1 != psz)) {
  130. free_w (psz1);
  131. }
  132. }
  133. else {
  134. ul = RegOpenKey (
  135. hkey,
  136. psz,
  137. &hkResult
  138. );
  139. }
  140. STOREDWORD(*lp, hkResult);
  141. FLUSHVDMPTR(parg16->f3, 4, lp);
  142. ul = ConvertToWin31Error(ul);
  143. FREEOPTPTR(lp);
  144. FREEPSZPTR(psz);
  145. FREEARGPTR(parg16);
  146. RETURN(ul);
  147. }
  148. ULONG FASTCALL WS32RegCreateKey(PVDMFRAME pFrame)
  149. {
  150. ULONG ul;
  151. register PREGCREATEKEY16 parg16;
  152. PSZ psz;
  153. PSZ psz1 = NULL;
  154. HKEY hkResult = 0;
  155. HKEY hkey;
  156. PHKEY lp;
  157. GETARGPTR(pFrame, sizeof(REGCREATEKEY16), parg16);
  158. GETPSZPTR(parg16->f2, psz);
  159. GETOPTPTR(parg16->f3, 0, lp);
  160. hkey = (HKEY)FETCHDWORD(parg16->f1);
  161. if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
  162. hkey = (HKEY)HKEY_CLASSES_ROOT;
  163. }
  164. if (!hkey) {
  165. if (psz) {
  166. psz1 = Remove_Classes (psz);
  167. }
  168. ul = RegCreateKey (
  169. HKEY_CLASSES_ROOT,
  170. psz1,
  171. &hkResult
  172. );
  173. if ((psz1) && (psz1 != psz)) {
  174. free_w (psz1);
  175. }
  176. }
  177. else {
  178. ul = RegCreateKey (
  179. hkey,
  180. psz,
  181. &hkResult
  182. );
  183. }
  184. STOREDWORD(*lp, hkResult);
  185. FLUSHVDMPTR(parg16->f3, 4, lp);
  186. ul = ConvertToWin31Error(ul);
  187. FREEOPTPTR(lp);
  188. FREEPSZPTR(psz);
  189. FREEARGPTR(parg16);
  190. RETURN(ul);
  191. }
  192. ULONG FASTCALL WS32RegCloseKey(PVDMFRAME pFrame)
  193. {
  194. ULONG ul;
  195. register PREGCLOSEKEY16 parg16;
  196. HKEY hkey;
  197. GETARGPTR(pFrame, sizeof(REGCLOSEKEY16), parg16);
  198. hkey = (HKEY)FETCHDWORD(parg16->f1);
  199. if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
  200. hkey = (HKEY)HKEY_CLASSES_ROOT;
  201. }
  202. ul = RegCloseKey (
  203. hkey
  204. );
  205. ul = ConvertToWin31Error(ul);
  206. FREEARGPTR(parg16);
  207. RETURN(ul);
  208. }
  209. ULONG FASTCALL WS32RegDeleteKey(PVDMFRAME pFrame)
  210. {
  211. ULONG ul;
  212. register PREGDELETEKEY16 parg16;
  213. HKEY hkey;
  214. PSZ psz;
  215. PSZ psz1 = NULL;
  216. GETARGPTR(pFrame, sizeof(REGDELETEKEY16), parg16);
  217. GETPSZPTR(parg16->f2, psz);
  218. hkey = (HKEY)FETCHDWORD(parg16->f1);
  219. if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
  220. hkey = (HKEY)HKEY_CLASSES_ROOT;
  221. }
  222. //
  223. // Fail any attempt to RegDeleteKey(something, NULL),
  224. // with ERROR_BADKEY as Win3.1 does.
  225. //
  226. if ((!psz) || (*psz == '\0')) {
  227. ul = ERROR_BADKEY;
  228. } else {
  229. if (!hkey) {
  230. psz1 = Remove_Classes (psz);
  231. ul = WOWRegDeleteKey (
  232. HKEY_CLASSES_ROOT,
  233. psz1
  234. );
  235. if ((psz1) && (psz1 != psz)) {
  236. free_w (psz1);
  237. }
  238. } else {
  239. ul = WOWRegDeleteKey (
  240. hkey,
  241. psz
  242. );
  243. }
  244. }
  245. ul = ConvertToWin31Error(ul);
  246. FREEPSZPTR(psz);
  247. FREEARGPTR(parg16);
  248. RETURN(ul);
  249. }
  250. LONG
  251. APIENTRY
  252. WOWRegDeleteKey(
  253. HKEY hKey,
  254. LPCSTR lpszSubKey
  255. )
  256. /*++
  257. Routine Description:
  258. There is a significant difference between the Win3.1 and Win32
  259. behavior of RegDeleteKey when the key in question has subkeys.
  260. The Win32 API does not allow you to delete a key with subkeys,
  261. while the Win3.1 API deletes a key and all its subkeys.
  262. This routine is a recursive worker that enumerates the subkeys
  263. of a given key, applies itself to each one, then deletes itself.
  264. It specifically does not attempt to deal rationally with the
  265. case where the caller may not have access to some of the subkeys
  266. of the key to be deleted. In this case, all the subkeys which
  267. the caller can delete will be deleted, but the api will still
  268. return ERROR_ACCESS_DENIED.
  269. Arguments:
  270. hKey - Supplies a handle to an open registry key.
  271. lpszSubKey - Supplies the name of a subkey which is to be deleted
  272. along with all of its subkeys.
  273. Return Value:
  274. ERROR_SUCCESS - entire subtree successfully deleted.
  275. ERROR_ACCESS_DENIED - given subkey could not be deleted.
  276. --*/
  277. {
  278. DWORD i;
  279. HKEY Key;
  280. LONG Status;
  281. DWORD ClassLength=0;
  282. DWORD SubKeys;
  283. DWORD MaxSubKey;
  284. DWORD MaxClass;
  285. DWORD Values;
  286. DWORD MaxValueName;
  287. DWORD MaxValueData;
  288. DWORD SecurityLength;
  289. FILETIME LastWriteTime;
  290. LPTSTR NameBuffer;
  291. //
  292. // First open the given key so we can enumerate its subkeys
  293. //
  294. Status = RegOpenKeyEx(hKey,
  295. lpszSubKey,
  296. 0,
  297. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
  298. &Key);
  299. if (Status != ERROR_SUCCESS) {
  300. //
  301. // possibly we have delete access, but not enumerate/query.
  302. // So go ahead and try the delete call, but don't worry about
  303. // any subkeys. If we have any, the delete will fail anyway.
  304. //
  305. return(RegDeleteKey(hKey,lpszSubKey));
  306. }
  307. //
  308. // Use RegQueryInfoKey to determine how big to allocate the buffer
  309. // for the subkey names.
  310. //
  311. Status = RegQueryInfoKey(Key,
  312. NULL,
  313. &ClassLength,
  314. 0,
  315. &SubKeys,
  316. &MaxSubKey,
  317. &MaxClass,
  318. &Values,
  319. &MaxValueName,
  320. &MaxValueData,
  321. &SecurityLength,
  322. &LastWriteTime);
  323. if ((Status != ERROR_SUCCESS) &&
  324. (Status != ERROR_MORE_DATA) &&
  325. (Status != ERROR_INSUFFICIENT_BUFFER)) {
  326. RegCloseKey(Key);
  327. return(Status);
  328. }
  329. NameBuffer = malloc_w(MaxSubKey + 1);
  330. if (NameBuffer == NULL) {
  331. RegCloseKey(Key);
  332. return(ERROR_NOT_ENOUGH_MEMORY);
  333. }
  334. //
  335. // Enumerate subkeys and apply ourselves to each one.
  336. //
  337. i=0;
  338. do {
  339. Status = RegEnumKey(Key,
  340. i,
  341. NameBuffer,
  342. MaxSubKey+1);
  343. if (Status == ERROR_SUCCESS) {
  344. Status = WOWRegDeleteKey(Key,NameBuffer);
  345. }
  346. if (Status != ERROR_SUCCESS) {
  347. //
  348. // Failed to delete the key at the specified index. Increment
  349. // the index and keep going. We could probably bail out here,
  350. // since the api is going to fail, but we might as well keep
  351. // going and delete everything we can.
  352. //
  353. ++i;
  354. }
  355. } while ( (Status != ERROR_NO_MORE_ITEMS) &&
  356. (i < SubKeys) );
  357. free_w(NameBuffer);
  358. RegCloseKey(Key);
  359. return(RegDeleteKey(hKey,lpszSubKey));
  360. }
  361. ULONG FASTCALL WS32RegSetValue(PVDMFRAME pFrame)
  362. {
  363. register PREGSETVALUE16 parg16;
  364. ULONG ul;
  365. CHAR szZero[] = { '0', '\0' };
  366. HKEY hkey;
  367. PSZ psz2;
  368. PSZ psz1 = NULL;
  369. LPBYTE lpszData;
  370. GETARGPTR(pFrame, sizeof(REGSETVALUE16), parg16);
  371. // Do what Win 3.1 does
  372. if(parg16->f3 != REG_SZ) {
  373. FREEARGPTR(parg16);
  374. return(WIN16_ERROR_INVALID_PARAMETER);
  375. }
  376. GETOPTPTR(parg16->f2, 0, psz2);
  377. // Windows 3.1 API reference says that cb (f5) is ignored.
  378. // Ergo, remove it from this call and use 1 in its place
  379. // (1 being the smallest size of a sz string)
  380. if(parg16->f4) {
  381. GETOPTPTR(parg16->f4, 1, lpszData);
  382. }
  383. // Quattro Pro 6.0 Install passes lpszData == NULL
  384. // In Win3.1, if(!lpszData || *lpszData == '\0') the value is set to 0
  385. else {
  386. lpszData = szZero;
  387. }
  388. hkey = (HKEY)FETCHDWORD(parg16->f1);
  389. if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
  390. hkey = (HKEY)HKEY_CLASSES_ROOT;
  391. }
  392. if (!hkey) {
  393. if (psz2) {
  394. psz1 = Remove_Classes (psz2);
  395. }
  396. ul = RegSetValue (HKEY_CLASSES_ROOT,
  397. psz1,
  398. REG_SZ,
  399. lpszData,
  400. lstrlen(lpszData));
  401. if ((psz1) && (psz1 != psz2)) {
  402. free_w (psz1);
  403. }
  404. }
  405. else {
  406. ul = RegSetValue (hkey,
  407. psz2,
  408. REG_SZ,
  409. lpszData,
  410. lstrlen(lpszData));
  411. }
  412. ul = ConvertToWin31Error(ul);
  413. FREEOPTPTR(psz2);
  414. FREEOPTPTR(lpszData);
  415. FREEARGPTR(parg16);
  416. RETURN(ul);
  417. }
  418. ULONG FASTCALL WS32RegQueryValue(PVDMFRAME pFrame)
  419. {
  420. ULONG ul;
  421. register PREGQUERYVALUE16 parg16;
  422. HKEY hkey;
  423. PSZ psz1 = NULL;
  424. PSZ psz2;
  425. LPBYTE lpszData;
  426. LPDWORD lpcbValue;
  427. DWORD cbValue;
  428. #define QUERYBUFFERSIZE 128
  429. DWORD cbOriginalValue;
  430. BYTE cbBuffer[QUERYBUFFERSIZE];
  431. LPBYTE lpByte = NULL;
  432. BOOL fAllocated = FALSE;
  433. GETARGPTR(pFrame, sizeof(REGQUERYVALUE16), parg16);
  434. GETOPTPTR(parg16->f2, 0, psz2);
  435. GETOPTPTR(parg16->f3, 0, lpszData);
  436. GETOPTPTR(parg16->f4, 0, lpcbValue);
  437. if ( lpcbValue == NULL ) { // Prevent us from dying just in case!
  438. FREEOPTPTR(psz2);
  439. FREEOPTPTR(lpszData);
  440. FREEOPTPTR(lpcbValue);
  441. FREEARGPTR(parg16);
  442. return( WIN16_ERROR_INVALID_PARAMETER );
  443. }
  444. cbOriginalValue = cbValue = FETCHDWORD(*lpcbValue);
  445. #ifdef FE_SB // for Lotus 123 by v-kenich 94.Aug.27
  446. // Lotus doesn't set value to *lpcb in one case
  447. // in other case set 80
  448. // so when not set, assume 80 and set 80 in this field
  449. if (CURRENTPTD()->dwWOWCompatFlagsFE & WOWCF_FE_FORCEREGQRYLEN) {
  450. if (cbValue > 80) {
  451. cbOriginalValue = cbValue = 80;
  452. }
  453. }
  454. #endif // FE_SB
  455. // Fix MSTOOLBR.DLL unintialized cbValue by forcing it to be less than 64K
  456. // Win 3.1 Registry values are always less than 64K.
  457. cbOriginalValue &= 0x0000FFFF;
  458. if ( lpszData == NULL ) {
  459. lpByte = NULL;
  460. } else {
  461. lpByte = cbBuffer;
  462. if ( cbOriginalValue > QUERYBUFFERSIZE ) {
  463. lpByte = malloc_w(cbOriginalValue);
  464. if ( lpByte == NULL ) {
  465. FREEOPTPTR(psz2);
  466. FREEOPTPTR(lpszData);
  467. FREEOPTPTR(lpcbValue);
  468. FREEARGPTR(parg16);
  469. RETURN( WIN16_ERROR_OUTOFMEMORY );
  470. }
  471. fAllocated = TRUE;
  472. }
  473. }
  474. hkey = (HKEY)FETCHDWORD(parg16->f1);
  475. if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
  476. hkey = (HKEY)HKEY_CLASSES_ROOT;
  477. }
  478. if (!hkey) {
  479. if (psz2) {
  480. psz1 = Remove_Classes (psz2);
  481. }
  482. hkey = HKEY_CLASSES_ROOT;
  483. } else {
  484. psz1 = psz2;
  485. }
  486. ul = RegQueryValue (
  487. hkey,
  488. psz1,
  489. lpByte,
  490. &cbValue
  491. );
  492. if (ul == ERROR_SUCCESS) {
  493. if ( lpszData ) {
  494. memcpy( lpszData, lpByte, cbValue );
  495. }
  496. } else {
  497. if ( ul == ERROR_MORE_DATA ) {
  498. //
  499. // We need to allocate more
  500. //
  501. if ( fAllocated ) {
  502. free_w( lpByte );
  503. }
  504. lpByte = malloc_w( cbValue );
  505. if ( lpByte == NULL ) {
  506. if ((psz1) && (psz1 != psz2)) {
  507. // If we did some key name copying, then free that buffer
  508. free_w (psz1);
  509. }
  510. FREEOPTPTR(psz2);
  511. FREEOPTPTR(lpszData);
  512. FREEOPTPTR(lpcbValue);
  513. FREEARGPTR(parg16);
  514. RETURN(WIN16_ERROR_OUTOFMEMORY);
  515. }
  516. fAllocated = TRUE;
  517. ul = RegQueryValue( hkey,
  518. psz1,
  519. lpByte,
  520. &cbValue );
  521. cbValue = cbOriginalValue;
  522. if ( lpszData ) {
  523. memcpy( lpszData, lpByte, cbValue );
  524. }
  525. }
  526. }
  527. if ((psz1) && (psz1 != psz2)) {
  528. // If we did some key name copying, then free that buffer
  529. free_w (psz1);
  530. }
  531. if ( fAllocated ) {
  532. // If we've allocated memory for the output buffer, then free it
  533. free_w (lpByte);
  534. }
  535. STOREDWORD(*lpcbValue, cbValue);
  536. FLUSHVDMPTR(parg16->f4, 4, lpcbValue);
  537. if ( lpszData != NULL ) {
  538. FLUSHVDMPTR(parg16->f3, (USHORT)cbValue, lpszData);
  539. }
  540. ul = ConvertToWin31Error(ul);
  541. FREEOPTPTR(psz2);
  542. FREEOPTPTR(lpszData);
  543. FREEOPTPTR(lpcbValue);
  544. FREEARGPTR(parg16);
  545. RETURN(ul);
  546. }
  547. ULONG FASTCALL WS32RegEnumKey(PVDMFRAME pFrame)
  548. {
  549. ULONG ul;
  550. register PREGENUMKEY16 parg16;
  551. HKEY hkey;
  552. LPBYTE lpszName;
  553. GETARGPTR(pFrame, sizeof(REGENUMKEY16), parg16);
  554. GETOPTPTR(parg16->f3, parg16->f4, lpszName);
  555. hkey = (HKEY)FETCHDWORD(parg16->f1);
  556. if ((DWORD)hkey == WIN16_HKEY_CLASSES_ROOT) {
  557. hkey = (HKEY)HKEY_CLASSES_ROOT;
  558. }
  559. ul = RegEnumKey (
  560. hkey,
  561. parg16->f2,
  562. lpszName,
  563. parg16->f4
  564. );
  565. FLUSHVDMPTR(parg16->f3, (USHORT)parg16->f4, lpszName);
  566. ul = ConvertToWin31Error(ul);
  567. FREEOPTPTR(lpszName);
  568. FREEARGPTR(parg16);
  569. RETURN(ul);
  570. }
  571. ULONG FASTCALL WS32DragAcceptFiles(PVDMFRAME pFrame)
  572. {
  573. ULONG ul=0;
  574. register PDRAGACCEPTFILES16 parg16;
  575. GETARGPTR(pFrame, sizeof(DRAGACCEPTFILES16), parg16);
  576. DragAcceptFiles(HWND32(parg16->f1),(BOOL)parg16->f2);
  577. FREEARGPTR(parg16);
  578. RETURN(ul);
  579. }
  580. ULONG FASTCALL WS32DragQueryFile(PVDMFRAME pFrame)
  581. {
  582. ULONG ul = 0l;
  583. register PDRAGQUERYFILE16 parg16;
  584. LPSTR lpFile;
  585. HANDLE hdfs32;
  586. GETARGPTR(pFrame, sizeof(DRAGQUERYFILE16), parg16);
  587. if (hdfs32 = HDROP32(parg16->f1)) {
  588. GETOPTPTR(parg16->f3, parg16->f4, lpFile);
  589. ul = DragQueryFileAorW (hdfs32, INT32(parg16->f2),
  590. lpFile, parg16->f4, TRUE,TRUE);
  591. if ((lpFile != NULL) && (parg16->f2 != -1)) {
  592. FLUSHVDMPTR(parg16->f3, parg16->f4, lpFile);
  593. }
  594. FREEOPTPTR(lpFile);
  595. }
  596. FREEARGPTR(parg16);
  597. RETURN(ul);
  598. }
  599. ULONG FASTCALL WS32DragFinish(PVDMFRAME pFrame)
  600. {
  601. register PDRAGFINISH16 parg16;
  602. HDROP h32;
  603. GETARGPTR(pFrame, sizeof(PDRAGFINISH16), parg16);
  604. //
  605. // freehdrop16, frees the alias and returns the corresponding h32
  606. //
  607. if (h32 = FREEHDROP16(parg16->f1)) {
  608. DragFinish(h32);
  609. }
  610. FREEARGPTR(parg16);
  611. return 0;
  612. }
  613. ULONG FASTCALL WS32ShellAbout (PVDMFRAME pFrame)
  614. {
  615. ULONG ul;
  616. register PSHELLABOUT16 parg16;
  617. PSZ psz2;
  618. PSZ psz3;
  619. GETARGPTR(pFrame, sizeof(SHELLABOUT16), parg16);
  620. GETPSZPTR(parg16->f2, psz2);
  621. GETPSZPTR(parg16->f3, psz3);
  622. ul = GETINT16(ShellAbout (
  623. HWND32(parg16->f1),
  624. psz2,
  625. psz3,
  626. HICON32(parg16->f4)
  627. ));
  628. FREEPSZPTR(psz2);
  629. FREEPSZPTR(psz3);
  630. FREEARGPTR(parg16);
  631. RETURN(ul);
  632. }
  633. // NOTE : The return value can be instance handle or the handle of a
  634. // DDE server. So, take this information into account while debugging
  635. // the effect of the return value from this API. ChandanC 4/24/92.
  636. // You would notice that I am treating the return value as HINSTANCE.
  637. //
  638. ULONG FASTCALL WS32ShellExecute (PVDMFRAME pFrame)
  639. {
  640. ULONG ul;
  641. register PSHELLEXECUTE16 parg16;
  642. PSZ psz2;
  643. PSZ psz3;
  644. PSZ psz4;
  645. PSZ psz5;
  646. GETARGPTR(pFrame, sizeof(SHELLEXECUTE16), parg16);
  647. GETPSZPTR(parg16->f2, psz2);
  648. GETPSZPTR(parg16->f3, psz3);
  649. GETPSZPTR(parg16->f4, psz4);
  650. GETPSZPTR(parg16->f5, psz5);
  651. UpdateDosCurrentDirectory( DIR_DOS_TO_NT);
  652. ul = GETHINST16(WOWShellExecute (
  653. HWND32(parg16->f1),
  654. psz2,
  655. psz3,
  656. psz4,
  657. psz5,
  658. parg16->f6,
  659. (LPVOID) W32ShellExecuteCallBack
  660. ));
  661. FREEPSZPTR(psz2);
  662. FREEPSZPTR(psz3);
  663. FREEPSZPTR(psz4);
  664. FREEPSZPTR(psz5);
  665. FREEARGPTR(parg16);
  666. RETURN(ul);
  667. }
  668. /*
  669. * This is an equivalent of a nasty win'95 style hack that prevents us from
  670. * launching things from winexec that are lfn-based
  671. * Unfortunate as it is -- this alone can't save us in all the cases -- it
  672. * just allows for a fix to ole-based method (another method should be
  673. * employed to fix winexec)
  674. *
  675. * The code was stolen from base/client/process.c
  676. * with win95's method being to try CreateProcess instead of SearchPath within
  677. * the inner loop.
  678. *
  679. * Parameters:
  680. * lpstrParsed -- destination string which upon successful return will contain
  681. * 1. Short path for an exe file
  682. * 2. The rest of the cmdline in an appropriate order
  683. * lpszCmdLine -- command line for an app with parameters
  684. * cchParsed -- character count for the lpstrParsed string
  685. *
  686. * fConvert -- if TRUE, path is going to be converted to its short
  687. * form, if FALSE -- it is going to be quoted for winexec
  688. * not to stumble upon it.
  689. *
  690. */
  691. ULONG WS32ParseCmdLine(
  692. PBYTE lpstrParsed,
  693. LPSZ lpszCmdLine,
  694. ULONG cchstrParsed,
  695. BOOL fConvert)
  696. {
  697. BOOL fQuote = FALSE; // was there a quote ?
  698. PCHAR psz = lpszCmdLine; // original ptr to the command line
  699. CHAR szFileName[MAX_PATH];// exe filename in its final form (from szCmd)
  700. CHAR szCmd[MAX_PATH]; // command that is being built from lpszCmdLine
  701. PCHAR pszCmd = szCmd;
  702. CHAR c;
  703. DWORD dwLength, dwLengthFileName, dwLengthCmdTail;
  704. DWORD dwError = ERROR_SUCCESS;
  705. WOW32ASSERTMSGF(lstrlen(lpszCmdLine) < sizeof(szCmd)/sizeof(szCmd[0]),
  706. ("WOW::WS32ParseCmdLine -- cmd line too long\n"));
  707. c = *psz;
  708. while(TRUE) {
  709. if ('\"' == c) {
  710. fQuote = !fQuote; // state variable -- flip quoting
  711. }
  712. else {
  713. // now check for space chars
  714. // the condition here is: if it is outside of a quote -- then
  715. // space is a delimiter. Another condition is an end of a string
  716. if (((' ' == c || '\t' == c) && !fQuote) || ('\0' == c)) {
  717. // delimiter -- now try for a file search
  718. *pszCmd = '\0';
  719. dwLengthFileName = SearchPath(NULL,
  720. szCmd,
  721. ".exe",
  722. sizeof(szFileName)/sizeof(szFileName[0]),
  723. szFileName,
  724. NULL);
  725. // return value is length in chars
  726. if (!dwLengthFileName || dwLengthFileName > sizeof(szFileName)/sizeof(szFileName[0])) {
  727. // oops -- we have found none
  728. // so remember the error
  729. dwError = ERROR_FILE_NOT_FOUND;
  730. if ('\0' == c) {
  731. break; // end of the string
  732. }
  733. }
  734. else {
  735. // szFileName is what we need
  736. dwError = ERROR_SUCCESS;
  737. break;
  738. }
  739. }
  740. *pszCmd++ = c; // copy the character over and continue
  741. // Hack alert! szCmd is MAX_PATH -- we don't check
  742. // for overrun since shell's CmdLine buffer is also
  743. // MAX_PATH long. This may change in the future,
  744. // watch out!
  745. }
  746. // now move to the next char
  747. c = *++psz;
  748. }
  749. if (ERROR_SUCCESS != dwError) {
  750. return(dwError);
  751. }
  752. dwLengthCmdTail = strlen(psz);
  753. // now
  754. // psz points to a delimiter char that we have terminated our search on.
  755. // the part before this char -- is exe filename
  756. // the part after this char -- cmdline tail
  757. if (fConvert) {
  758. // now we go converting first
  759. dwLength = GetShortPathName(szFileName, lpstrParsed, cchstrParsed);
  760. if (!dwLength || dwLength > cchstrParsed-1) {
  761. LOGDEBUG(0, ("WS32ParseCmdLine: Can't convert to the short name\n"));
  762. WOW32ASSERT(FALSE);
  763. return(GetLastError());
  764. }
  765. if (dwLength + dwLengthCmdTail > cchstrParsed - 1) {
  766. LOGDEBUG(0, ("WS32ParseCmdLine: Buffer too short for cmdline tail\n"));
  767. WOW32ASSERT(FALSE);
  768. return(ERROR_INSUFFICIENT_BUFFER);
  769. }
  770. }
  771. else {
  772. // now here we just insert quotes around the filename -- unless there
  773. // already were some quotes surrounding it
  774. if (dwLengthFileName + 2 > cchstrParsed - 1) {
  775. LOGDEBUG(0, ("WS32ParseCmdLine: Buffer too short for quoted filename\n"));
  776. WOW32ASSERT(FALSE);
  777. return(ERROR_INSUFFICIENT_BUFFER);
  778. }
  779. *lpstrParsed++ = '\"';
  780. lstrcpyn(lpstrParsed, szFileName, dwLengthFileName+1);
  781. lstrcat(lpstrParsed, "\"");
  782. }
  783. lstrcat(lpstrParsed, psz);
  784. return(ERROR_SUCCESS);
  785. }
  786. extern DWORD demSetCurrentDirectoryGetDrive(LPSTR lpDirectoryName, PUINT pDriveNum);
  787. extern DWORD demLFNGetCurrentDirectory(UINT DriveNum, LPSTR lpDirectoryName);
  788. WORD W32ShellExecuteCallBack (LPSZ lpszCmdLine, WORD fuCmdShow, LPSZ lpszNewDir)
  789. {
  790. PBYTE lpstr16;
  791. PARM16 Parm16;
  792. ULONG ul = 0;
  793. VPVOID vpstr16;
  794. CHAR szCurrentDirectory[MAX_PATH];
  795. UINT Drive;
  796. DWORD dwStatus;
  797. BOOL fRestoreDir;
  798. // what +5 is doing here ? The reasoning is like this :
  799. // generated short path could never be longer than the original (long path)
  800. //
  801. ULONG cchstr16 = lstrlen(lpszCmdLine) + 5;
  802. UpdateDosCurrentDirectory(DIR_NT_TO_DOS);
  803. // we're given a current directory here --
  804. // so we see if this matches our current directory
  805. // demSetCurrentDirectoryLong(
  806. dwStatus = demLFNGetCurrentDirectory(0, szCurrentDirectory);
  807. fRestoreDir = NT_SUCCESS(dwStatus);
  808. dwStatus = demSetCurrentDirectoryGetDrive(lpszNewDir, &Drive);
  809. if (NT_SUCCESS(dwStatus)) {
  810. DosWowSetDefaultDrive((UCHAR)Drive);
  811. }
  812. if (vpstr16 = malloc16 (cchstr16)) { // .exe, remember ?
  813. GETMISCPTR (vpstr16, lpstr16);
  814. if (lpstr16) {
  815. // we cannot simply copy the command line here -- although memory
  816. // that was allocated is going to be sufficient.
  817. // Problem is that winexec will choke when the program name
  818. // is denoted as Long File Name -- which is the case with new Office
  819. // applications. The rule should be -- whatever comes into land16
  820. // should be in a form of a short file name.
  821. // mind you that vpstr16 is big enough for both the long and
  822. // short name -- so this code requires no memory realloc
  823. // now we need to have
  824. ul = WS32ParseCmdLine(lpstr16, lpszCmdLine, cchstr16, TRUE);
  825. if (ERROR_SUCCESS != ul) {
  826. WOW32ASSERTMSGF(FALSE, ("WS32ParseCmdLine failed: 0x%lx\n", ul));
  827. lstrcpy (lpstr16, lpszCmdLine);
  828. }
  829. Parm16.WndProc.wParam = fuCmdShow;
  830. Parm16.WndProc.lParam = vpstr16;
  831. CallBack16(RET_WINEXEC, &Parm16, 0, &ul);
  832. FREEMISCPTR (lpstr16);
  833. }
  834. free16(vpstr16);
  835. }
  836. if (fRestoreDir) {
  837. dwStatus = demSetCurrentDirectoryGetDrive(szCurrentDirectory, &Drive);
  838. if (NT_SUCCESS(dwStatus)) {
  839. DosWowSetDefaultDrive((UCHAR)Drive);
  840. }
  841. }
  842. return (LOWORD(ul));
  843. }
  844. ULONG FASTCALL WS32FindExecutable (PVDMFRAME pFrame)
  845. {
  846. ULONG ul;
  847. register PFINDEXECUTABLE16 parg16;
  848. PSZ psz1;
  849. PSZ psz2;
  850. PSZ psz3;
  851. GETARGPTR(pFrame, sizeof(FINDEXECUTABLE16), parg16);
  852. GETPSZPTR(parg16->f1, psz1);
  853. GETPSZPTR(parg16->f2, psz2);
  854. GETPSZPTRNOLOG(parg16->f3, psz3);
  855. ul = (ULONG) FindExecutable (
  856. psz1,
  857. psz2,
  858. psz3
  859. );
  860. LOGDEBUG(11,(" returns @%08lx: \"%.80s\"\n", FETCHDWORD(parg16->f3), psz3));
  861. FLUSHVDMPTR(parg16->f3, strlen(psz3)+1, psz3);
  862. // This is for success condition.
  863. if (ul > 32) {
  864. ul = GETHINST16 (ul);
  865. }
  866. FREEPSZPTR(psz1);
  867. FREEPSZPTR(psz2);
  868. FREEPSZPTR(psz3);
  869. FREEARGPTR(parg16);
  870. RETURN(ul);
  871. }
  872. ULONG FASTCALL WS32ExtractIcon (PVDMFRAME pFrame)
  873. {
  874. ULONG ul;
  875. register PEXTRACTICON16 parg16;
  876. PSZ psz;
  877. UINT Id;
  878. GETARGPTR(pFrame, sizeof(EXTRACTICON16), parg16);
  879. GETPSZPTR(parg16->f2, psz);
  880. Id = (parg16->f3 == (WORD)0xffff) ? (UINT)(SHORT)parg16->f3 :
  881. (UINT)parg16->f3;
  882. ul = (ULONG) ExtractIcon (HMODINST32(parg16->f1), psz, Id);
  883. // This is for success condition.
  884. if ((Id != (UINT)(-1)) && ul > 1) {
  885. ul = GETHICON16(ul);
  886. }
  887. FREEPSZPTR(psz);
  888. FREEARGPTR(parg16);
  889. RETURN(ul);
  890. }
  891. //
  892. // This routine convert the Win 32 registry error codes to Win 31
  893. // error codes.
  894. //
  895. ULONG ConvertToWin31Error(ULONG ul)
  896. {
  897. LOGDEBUG(3, ("WOW::ConvertToWin31Error: Ret value from NT = %08lx\n", ul));
  898. switch (ul) {
  899. case ERROR_SUCCESS: return(WIN16_ERROR_SUCCESS);
  900. case ERROR_BADDB: return(WIN16_ERROR_BADDB);
  901. case ERROR_BADKEY: return(WIN16_ERROR_BADKEY);
  902. case ERROR_CANTOPEN: return(WIN16_ERROR_CANTOPEN);
  903. case ERROR_CANTREAD: return(WIN16_ERROR_CANTREAD);
  904. case ERROR_CANTWRITE: return(WIN16_ERROR_CANTWRITE);
  905. case ERROR_OUTOFMEMORY: return(WIN16_ERROR_OUTOFMEMORY);
  906. case ERROR_INVALID_PARAMETER: return(WIN16_ERROR_INVALID_PARAMETER);
  907. case ERROR_EA_ACCESS_DENIED: return(WIN16_ERROR_ACCESS_DENIED);
  908. case ERROR_MORE_DATA: return(WIN16_ERROR_INVALID_PARAMETER);
  909. case ERROR_FILE_NOT_FOUND: return(WIN16_ERROR_BADKEY);
  910. case ERROR_NO_MORE_ITEMS: return(WIN16_ERROR_BADKEY);
  911. default:
  912. LOGDEBUG(3, ("WOW::Registry Error Code unknown =%08lx : returning 8 (WIN16_ERROR_ACCESS_DENIED)\n", ul));
  913. return (WIN16_ERROR_ACCESS_DENIED);
  914. }
  915. }
  916. LPSZ Remove_Classes (LPSZ psz)
  917. {
  918. LPSZ lpsz;
  919. LPSZ lpsz1;
  920. if (!WOW32_stricmp (".classes", psz)) {
  921. if (lpsz = malloc_w (1)) {
  922. *lpsz = '\0';
  923. return (lpsz);
  924. }
  925. }
  926. else {
  927. if (*psz) {
  928. lpsz = WOW32_strchr (psz, '\\');
  929. if (lpsz) {
  930. *lpsz = '\0';
  931. if (!WOW32_stricmp (".classes", lpsz)) {
  932. *lpsz = '\\';
  933. if (lpsz1 = malloc_w (strlen(lpsz+1)+1)) {
  934. strcpy (lpsz1, (lpsz+1));
  935. return (lpsz1);
  936. }
  937. else {
  938. return (0);
  939. }
  940. }
  941. *lpsz = '\\';
  942. return (psz);
  943. }
  944. else {
  945. return (psz);
  946. }
  947. }
  948. else {
  949. return (psz);
  950. }
  951. }
  952. return (psz);
  953. }
  954. //****************************************************************************
  955. // DropFilesHandler -
  956. // takes either h16 or h32 as input. flInput identifies the type of the
  957. // handle and other operations to perform. return value varies but in most
  958. // cases it is the opposite to the 'input type'- ie returns h16 if h32 was
  959. // input and viceversa.
  960. // - nanduri
  961. //****************************************************************************
  962. LPDROPALIAS glpDropAlias = NULL;
  963. LPDROPALIAS DropFilesFind(DWORD h, UINT fInput, LPDROPALIAS* ppPrev)
  964. {
  965. LPDROPALIAS lpT = glpDropAlias;
  966. LPDROPALIAS lpTPrev = NULL;
  967. WOW32ASSERT(h);
  968. WOW32ASSERT((!!(fInput & HDROP_H16)) ^ (!!(fInput & HDROP_H32)));
  969. while (NULL != lpT) {
  970. if (fInput & HDROP_H16) {
  971. if ((lpT->h16 & ~1) == (((HAND16)h) & ~1)) {
  972. break;
  973. }
  974. }
  975. else if (fInput & HDROP_H32) {
  976. if (lpT->h32 == (HANDLE)h) {
  977. break;
  978. }
  979. }
  980. lpTPrev = lpT;
  981. lpT = lpT->lpNext;
  982. }
  983. if (ppPrev) {
  984. *ppPrev = lpTPrev;
  985. }
  986. return(lpT);
  987. }
  988. DWORD DropFilesHandler(HAND16 h16, HANDLE h32, UINT flInput)
  989. {
  990. LPDROPALIAS lpT;
  991. LPDROPALIAS lpTprev;
  992. DWORD dwRet = 0;
  993. // assert if specified both or neither handle or flag
  994. WOW32ASSERT((h16) || (h32));
  995. WOW32ASSERT((!!(flInput & HDROP_H32)) ^ (!!(flInput & HDROP_H16)));
  996. // find handle
  997. lpT = DropFilesFind(flInput & HDROP_H16 ? (DWORD)h16 : (DWORD)h32,
  998. flInput,
  999. &lpTprev);
  1000. //
  1001. // if not found, create the alias if requested
  1002. //
  1003. if (lpT == (LPDROPALIAS)NULL && (flInput & HDROP_ALLOCALIAS)) {
  1004. if (lpT = malloc_w(sizeof(DROPALIAS))) {
  1005. lpT->h16 = h16;
  1006. lpT->h32 = h32;
  1007. lpT->lpNext = glpDropAlias;
  1008. lpT->dwFlags = 0;
  1009. glpDropAlias = lpT;
  1010. flInput |= HDROP_COPYDATA;
  1011. }
  1012. }
  1013. //
  1014. // if found - do the necessary operation. all (other) HDROP_* flags
  1015. // have priority over HDROP_H16 and HDROP_H32 flags.
  1016. //
  1017. if (lpT) {
  1018. if (flInput & HDROP_COPYDATA) {
  1019. if (h32) {
  1020. dwRet = (DWORD) (lpT->h16 = CopyDropFilesFrom32(h32));
  1021. lpT->dwFlags |= ALLOC_H16;
  1022. } else {
  1023. dwRet = (DWORD) (lpT->h32 = CopyDropFilesFrom16(h16));
  1024. lpT->dwFlags |= ALLOC_H32;
  1025. }
  1026. }
  1027. else if (flInput & HDROP_FREEALIAS) {
  1028. dwRet = (DWORD)lpT->h32;
  1029. if (lpTprev) {
  1030. lpTprev->lpNext = lpT->lpNext;
  1031. }
  1032. else {
  1033. glpDropAlias = lpT->lpNext;
  1034. }
  1035. free_w(lpT);
  1036. }
  1037. else if (flInput & HDROP_H16) {
  1038. dwRet = (DWORD)lpT->h32;
  1039. }
  1040. else if (flInput & HDROP_H32) {
  1041. dwRet = (DWORD)lpT->h16;
  1042. }
  1043. }
  1044. return (dwRet);
  1045. }
  1046. //
  1047. // FindAndReleaseHDrop16
  1048. // Called from the 16-bit GlobalFree to see if we need to free alias
  1049. // associated with this handle
  1050. // The actual call is made through the wowddeglobalfree
  1051. // Function frees 32-bit handle (or disposes of it using DragFinish
  1052. // for consistency) but 16-bit handle is freed elsewere
  1053. //
  1054. BOOL FindAndReleaseHDrop16 (HAND16 h16)
  1055. {
  1056. LPDROPALIAS lpT;
  1057. LPDROPALIAS lpTPrev;
  1058. if (NULL != (lpT = DropFilesFind(h16, HDROP_H16, &lpTPrev))) {
  1059. // found, now free 32-bit handle, but not 16-bit one
  1060. // this assert will fire if we had not allocated 32-bit handle but
  1061. // app tried to free the 16-bit equivalent instead
  1062. LOGDEBUG(LOG_ALWAYS, ("HDrop16: removing handle 16:%lx 32:%lx\n",
  1063. (DWORD)h16,
  1064. (DWORD)lpT->h32));
  1065. if (lpT->dwFlags & ALLOC_H32) {
  1066. LOGDEBUG(LOG_ALWAYS, ("HDROP16: h32 allocated through OLE\n"));
  1067. WOWGLOBALFREE((HANDLE)lpT->h32);
  1068. }
  1069. else { // this handle was not allocated - but rather retrieved via old
  1070. // style dropfiles mechanism
  1071. LOGDEBUG(LOG_ALWAYS, ("HDrop16: h32 retrieved from shell\n"));
  1072. DragFinish((HDROP)lpT->h32);
  1073. }
  1074. // now unlink
  1075. if (NULL != lpTPrev) {
  1076. lpTPrev->lpNext = lpT->lpNext;
  1077. }
  1078. else {
  1079. glpDropAlias = lpT->lpNext;
  1080. }
  1081. // unmark 16-bit memory as being dde...
  1082. W32UnMarkDDEHandle(h16);
  1083. // free the list item
  1084. free_w(lpT);
  1085. }
  1086. return(NULL != lpT);
  1087. }
  1088. //****************************************************************************
  1089. // CopyDropFilesStruct -
  1090. //
  1091. // returns h16.
  1092. //****************************************************************************
  1093. HAND16 CopyDropFilesFrom32(HANDLE h32)
  1094. {
  1095. UINT cbSize;
  1096. HAND16 hRet = 0;
  1097. HAND16 hMem;
  1098. VPVOID vp;
  1099. //
  1100. // the allocated 16bit handle and the corresponding 32bit handle
  1101. // are freed in the shell api 'DragFinish' (if it is called by the app)
  1102. //
  1103. cbSize = GlobalSize((HANDLE)h32);
  1104. if (vp = GlobalAllocLock16(GMEM_DDESHARE, cbSize, &hMem)) {
  1105. LPDROPFILESTRUCT lpdfs32;
  1106. PDROPFILESTRUCT16 lpdfs16;
  1107. ULONG uIgnore;
  1108. GETMISCPTR(vp, lpdfs16);
  1109. if (lpdfs32 = (LPDROPFILESTRUCT)GlobalLock((HANDLE)h32)) {
  1110. //
  1111. // pFiles is a byte count to the beginning of the file.
  1112. //
  1113. lpdfs16->pFiles = sizeof(DROPFILESTRUCT16);
  1114. lpdfs16->x = (SHORT) lpdfs32->pt.x;
  1115. lpdfs16->y = (SHORT) lpdfs32->pt.y;
  1116. lpdfs16->fNC = (SHORT) lpdfs32->fNC;
  1117. if (lpdfs32->fWide) {
  1118. RtlUnicodeToMultiByteN(((PCHAR)lpdfs16)+lpdfs16->pFiles,
  1119. cbSize-lpdfs16->pFiles,
  1120. &uIgnore,
  1121. (PWSTR)(((PCHAR)lpdfs32)+lpdfs32->pFiles),
  1122. cbSize-lpdfs32->pFiles);
  1123. }
  1124. else {
  1125. //
  1126. // Copy the files after each structure.
  1127. // The offset from the beginning of the structure changes
  1128. // (since the structures are differenly sized), but we
  1129. // compensate by changes pFiles above.
  1130. //
  1131. RtlCopyMemory(lpdfs16+1, lpdfs32+1,
  1132. GlobalSize((HANDLE)h32) - sizeof(DROPFILESTRUCT));
  1133. }
  1134. GlobalUnlock((HANDLE)h32);
  1135. hRet = hMem;
  1136. // and before we return - mark this memory as being suspect for
  1137. // stray mapping release
  1138. // This function in wdde.c marks arena with GAH_PHANTOM flag
  1139. // we will destroy the alias when the globalfree is called either
  1140. // from 16-bit shell api DragFinish or from 16-bit ReleaseStgMedium
  1141. W32MarkDDEHandle(hMem);
  1142. }
  1143. else {
  1144. GlobalUnlockFree16(vp);
  1145. }
  1146. FREEMISCPTR(lpdfs16);
  1147. }
  1148. return (hRet);
  1149. }
  1150. /*--------------------------------------------------------------------------*/
  1151. /* */
  1152. /* CopyDropFilesFrom16() */
  1153. /* */
  1154. /*--------------------------------------------------------------------------*/
  1155. HANDLE CopyDropFilesFrom16(HAND16 h16)
  1156. {
  1157. HANDLE h32 = 0;
  1158. ULONG cbSize16;
  1159. UINT cbSize32;
  1160. VPVOID vp;
  1161. if (vp = GlobalLock16(h16, &cbSize16)) {
  1162. LPDROPFILESTRUCT lpdfs32;
  1163. PDROPFILESTRUCT16 lpdfs16;
  1164. GETMISCPTR(vp, lpdfs16);
  1165. cbSize32 = 2*sizeof(TCHAR) + sizeof(DROPFILESTRUCT) +
  1166. (cbSize16 - sizeof(DROPFILESTRUCT16));
  1167. if (h32 = WOWGLOBALALLOC(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,
  1168. cbSize32)){
  1169. lpdfs32 = (LPDROPFILESTRUCT)GlobalLock(h32);
  1170. lpdfs32->pFiles = sizeof(DROPFILESTRUCT);
  1171. lpdfs32->pt.x = (LONG) lpdfs16->x;
  1172. lpdfs32->pt.y = (LONG) lpdfs16->y;
  1173. lpdfs32->fNC = lpdfs16->fNC;
  1174. lpdfs32->fWide = FALSE;
  1175. RtlCopyMemory(lpdfs32+1, lpdfs16+1,
  1176. cbSize16 - sizeof(DROPFILESTRUCT16));
  1177. GlobalUnlock(h32);
  1178. }
  1179. FREEMISCPTR(lpdfs16);
  1180. GlobalUnlock16(h16);
  1181. }
  1182. return(h32);
  1183. }