Leaked source code of windows server 2003
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.

1515 lines
54 KiB

  1. /* r
  2. * CSVPick.C
  3. *
  4. * Picker wizard for CSV import/export
  5. *
  6. * Copyright 1997 Microsoft Corporation. All Rights Reserved.
  7. */
  8. #include "_comctl.h"
  9. #include <windows.h>
  10. #include <commctrl.h>
  11. #include <mapix.h>
  12. #include <wab.h>
  13. #include <wabguid.h>
  14. #include <wabdbg.h>
  15. #include <wabmig.h>
  16. #include <emsabtag.h>
  17. #include "wabimp.h"
  18. #include "..\..\wab32res\resrc2.h"
  19. #include "dbgutil.h"
  20. #include <shlwapi.h>
  21. const TCHAR szCSVFilter[] = "*.csv";
  22. const TCHAR szCSVExt[] = "csv";
  23. #define CHECK_BITMAP_WIDTH 16
  24. typedef struct {
  25. LPPROP_NAME rgPropNames;
  26. LPPROP_NAME * lppImportMapping;
  27. LPHANDLE lphFile;
  28. LPULONG lpcFields;
  29. LPTSTR szSep;
  30. } PROPSHEET_DATA, * LPPROPSHEET_DATA;
  31. TCHAR szCSVFileName[MAX_PATH + 1] = "";
  32. INT_PTR CALLBACK ExportPickFieldsPageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  33. INT_PTR CALLBACK ExportFilePageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  34. INT_PTR CALLBACK ImportFilePageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  35. INT_PTR CALLBACK ImportMapFieldsPageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  36. INT_PTR CALLBACK ChangeMappingDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  37. /***************************************************************************
  38. Name : FillInPropertyPage
  39. Purpose : Fills in the given PROPSHEETPAGE structure
  40. Parameters: psp -> property sheet page structure
  41. idDlg = dialog id
  42. pszProc = title for page
  43. pfnDlgProc -> Dialog procedure
  44. lParam = application specified data
  45. Returns : none
  46. Comment : This function fills in a PROPSHEETPAGE structure with the
  47. information the system needs to create the page.
  48. ***************************************************************************/
  49. void FillInPropertyPage(PROPSHEETPAGE* psp, int idDlg, LPSTR pszProc,
  50. DLGPROC pfnDlgProc, LPARAM lParam) {
  51. psp->dwSize = sizeof(PROPSHEETPAGE);
  52. psp->dwFlags = 0;
  53. psp->hInstance = hInst;
  54. psp->pszTemplate = MAKEINTRESOURCE(idDlg);
  55. psp->pszIcon = NULL;
  56. psp->pfnDlgProc = pfnDlgProc;
  57. psp->pszTitle = pszProc;
  58. psp->lParam = lParam;
  59. }
  60. /***************************************************************************
  61. Name : HandleCheckMark
  62. Purpose : Deals with setting the checkmark for a particular item in
  63. the listview.
  64. Parameters: hwndLV = ListView handle
  65. iItem = index of item to set
  66. rgTable = PROP_NAME table
  67. Returns : none
  68. Comment :
  69. ***************************************************************************/
  70. void HandleCheckMark(HWND hWndLV, ULONG iItem, LPPROP_NAME rgTable) {
  71. // Locals
  72. LV_ITEM lvi;
  73. // Clear it
  74. ZeroMemory(&lvi, sizeof(LV_ITEM));
  75. lvi.mask = LVIF_PARAM;
  76. lvi.iItem = iItem;
  77. ListView_GetItem(hWndLV, &lvi);
  78. rgTable[lvi.iItem].fChosen =
  79. ! rgTable[lvi.iItem].fChosen;
  80. ZeroMemory(&lvi, sizeof(LV_ITEM));
  81. lvi.mask = LVIF_STATE;
  82. lvi.iItem = iItem;
  83. lvi.state = rgTable[iItem].fChosen ?
  84. INDEXTOSTATEIMAGEMASK(iiconStateChecked + 1) :
  85. INDEXTOSTATEIMAGEMASK(iiconStateUnchecked + 1);
  86. lvi.stateMask = LVIS_STATEIMAGEMASK;
  87. ListView_SetItem(hWndLV, &lvi);
  88. }
  89. /***************************************************************************
  90. Name : HandleMultipleCheckMarks
  91. Purpose : Deals with setting the checkmark for a bunch of selected
  92. items in the list view - basically sets every selected item
  93. to the toggled state of the first item in the selection
  94. Parameters: hwndLV = ListView handle
  95. rgTable = LPPROP_NAME table
  96. Returns : none
  97. Comment :
  98. ***************************************************************************/
  99. void HandleMultipleCheckMarks(HWND hWndLV, LPPROP_NAME rgTable)
  100. {
  101. // Locals
  102. LV_ITEM lvi;
  103. int nIndex = 0;
  104. BOOL fState = FALSE;
  105. // get the index of the first item
  106. nIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED);
  107. // toggle this item
  108. HandleCheckMark(hWndLV, nIndex, rgTable);
  109. fState = rgTable[nIndex].fChosen;
  110. while((nIndex = ListView_GetNextItem(hWndLV, nIndex, LVNI_SELECTED)) >= 0)
  111. {
  112. // Set all the other selected items to the same state
  113. rgTable[nIndex].fChosen = fState;
  114. ZeroMemory(&lvi, sizeof(LV_ITEM));
  115. lvi.mask = LVIF_STATE;
  116. lvi.iItem = nIndex;
  117. lvi.state = rgTable[nIndex].fChosen ?
  118. INDEXTOSTATEIMAGEMASK(iiconStateChecked + 1) :
  119. INDEXTOSTATEIMAGEMASK(iiconStateUnchecked + 1);
  120. lvi.stateMask = LVIS_STATEIMAGEMASK;
  121. ListView_SetItem(hWndLV, &lvi);
  122. }
  123. return;
  124. }
  125. /***************************************************************************
  126. Name : ExportWizard
  127. Purpose : Present the Export Wizard
  128. Parameters: hwnd = parent window handle
  129. szFileName -> filename buffer (MAX_PATH + 1, please)
  130. rgPropNames -> property name list
  131. Returns : HRESULT
  132. Comment :
  133. ***************************************************************************/
  134. HRESULT ExportWizard(HWND hWnd, LPTSTR szFileName, ULONG cchSize, LPPROP_NAME rgPropNames) {
  135. HRESULT hResult = hrSuccess;
  136. PROPSHEETPAGE psp[NUM_EXPORT_WIZARD_PAGES];
  137. PROPSHEETHEADER psh;
  138. FillInPropertyPage(&psp[0], IDD_CSV_EXPORT_WIZARD_FILE, NULL, ExportFilePageProc, 0);
  139. FillInPropertyPage(&psp[1], IDD_CSV_EXPORT_WIZARD_PICK, NULL, ExportPickFieldsPageProc, 0);
  140. psh.dwSize = sizeof(PROPSHEETHEADER);
  141. psh.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD | PSH_NOAPPLYNOW | PSH_USEICONID;
  142. psh.hwndParent = hWnd;
  143. psh.pszCaption = NULL;
  144. psh.pszIcon = MAKEINTRESOURCE(IDI_WabMig);
  145. psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
  146. psh.ppsp = (LPCPROPSHEETPAGE) &psp;
  147. psh.hIcon = NULL;
  148. psh.hInstance = hInst;
  149. psh.nStartPage = 0;
  150. psh.pStartPage = NULL;
  151. switch (PropertySheet(&psh)) {
  152. case -1:
  153. hResult = ResultFromScode(MAPI_E_CALL_FAILED);
  154. DebugTrace("PropertySheet failed -> %u\n", GetLastError());
  155. Assert(FALSE);
  156. break;
  157. case 0:
  158. hResult = ResultFromScode(MAPI_E_USER_CANCEL);
  159. DebugTrace("PropertySheet cancelled by user\n");
  160. break;
  161. default:
  162. StrCpyN(szFileName, szCSVFileName, cchSize);
  163. break;
  164. }
  165. return(hResult);
  166. }
  167. /***************************************************************************
  168. Name : ImportWizard
  169. Purpose : Present the CSV Import Wizard
  170. Parameters: hwnd = parent window handle
  171. szFileName -> filename buffer (MAX_PATH + 1, please)
  172. rgPropNames -> property name list
  173. szSep -> list separator
  174. lppImportMapping -> returned property mapping table
  175. lpcFields -> returned size of property mapping table
  176. lphFile -> returned file handle to CSV file with header
  177. row already parsed out.
  178. Returns : HRESULT
  179. Comment :
  180. ***************************************************************************/
  181. HRESULT ImportWizard(HWND hWnd, LPTSTR szFileName, ULONG cchSize, LPPROP_NAME rgPropNames,
  182. LPTSTR szSep, LPPROP_NAME * lppImportMapping, LPULONG lpcFields, LPHANDLE lphFile) {
  183. HRESULT hResult = hrSuccess;
  184. PROPSHEETPAGE psp[NUM_IMPORT_WIZARD_PAGES];
  185. PROPSHEETHEADER psh;
  186. PROPSHEET_DATA pd;
  187. pd.rgPropNames = rgPropNames;
  188. pd.lppImportMapping = lppImportMapping;
  189. pd.lphFile = lphFile;
  190. pd.lpcFields = lpcFields;
  191. pd.szSep = szSep;
  192. FillInPropertyPage(&psp[0], IDD_CSV_IMPORT_WIZARD_FILE, NULL, ImportFilePageProc, (LPARAM)&pd);
  193. FillInPropertyPage(&psp[1], IDD_CSV_IMPORT_WIZARD_MAP, NULL, ImportMapFieldsPageProc, (LPARAM)&pd);
  194. psh.dwSize = sizeof(PROPSHEETHEADER);
  195. psh.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD | PSH_NOAPPLYNOW | PSH_USEICONID;
  196. psh.hwndParent = hWnd;
  197. psh.pszCaption = NULL;
  198. psh.pszIcon = MAKEINTRESOURCE(IDI_WabMig);
  199. psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
  200. psh.ppsp = (LPCPROPSHEETPAGE) &psp;
  201. psh.hIcon = NULL;
  202. psh.hInstance = hInst;
  203. psh.nStartPage = 0;
  204. psh.pStartPage = NULL;
  205. switch (PropertySheet(&psh)) {
  206. case -1:
  207. hResult = ResultFromScode(MAPI_E_CALL_FAILED);
  208. DebugTrace("PropertySheet failed -> %u\n", GetLastError());
  209. Assert(FALSE);
  210. break;
  211. case 0:
  212. hResult = ResultFromScode(MAPI_E_USER_CANCEL);
  213. DebugTrace("PropertySheet cancelled by user\n");
  214. break;
  215. default:
  216. StrCpyN(szFileName, szCSVFileName, cchSize);
  217. break;
  218. }
  219. return(hResult);
  220. }
  221. /***************************************************************************
  222. Name : ExportFilePageProc
  223. Purpose : Process messages for "Export Filename" page
  224. Parameters: standard window proc parameters
  225. Returns : standard window proc return
  226. Messages : WM_INITDIALOG - intializes the page
  227. WM_NOTIFY - processes the notifications sent to the page
  228. Comment :
  229. ***************************************************************************/
  230. INT_PTR CALLBACK ExportFilePageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
  231. static TCHAR szTempFileName[MAX_PATH + 1] = "";
  232. switch (message) {
  233. case WM_INITDIALOG:
  234. StrCpyN(szTempFileName, szCSVFileName, ARRAYSIZE(szTempFileName));
  235. break;
  236. case WM_COMMAND:
  237. switch (LOWORD(wParam)) {
  238. case IDC_BROWSE:
  239. SendDlgItemMessage(hDlg, IDE_CSV_EXPORT_NAME, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempFileName);
  240. SaveFileDialog(hDlg,
  241. szTempFileName,
  242. szCSVFilter,
  243. IDS_CSV_FILE_SPEC,
  244. szTextFilter,
  245. IDS_TEXT_FILE_SPEC,
  246. szAllFilter,
  247. IDS_ALL_FILE_SPEC,
  248. szCSVExt,
  249. OFN_HIDEREADONLY | OFN_PATHMUSTEXIST,
  250. hInst,
  251. 0, // idsTitle
  252. 0); // idsSaveButton
  253. PropSheet_SetWizButtons(GetParent(hDlg), szTempFileName[0] ? PSWIZB_NEXT : 0);
  254. SendMessage(GetDlgItem(hDlg, IDE_CSV_EXPORT_NAME), WM_SETTEXT, 0, (LPARAM)szTempFileName);
  255. break;
  256. case IDE_CSV_EXPORT_NAME:
  257. switch (HIWORD(wParam)) { // notification code
  258. case EN_CHANGE:
  259. SendDlgItemMessage(hDlg, IDE_CSV_EXPORT_NAME, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempFileName);
  260. if ((ULONG)LOWORD(wParam) == IDE_CSV_EXPORT_NAME) {
  261. PropSheet_SetWizButtons(GetParent(hDlg), szTempFileName[0] ? PSWIZB_NEXT : 0);
  262. }
  263. break;
  264. }
  265. break;
  266. }
  267. break;
  268. case WM_NOTIFY:
  269. switch (((NMHDR FAR *) lParam)->code) {
  270. case PSN_KILLACTIVE:
  271. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
  272. return(1);
  273. case PSN_RESET:
  274. // reset to the original values
  275. StrCpyN(szTempFileName, szCSVFileName, ARRAYSIZE(szTempFileName));
  276. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
  277. break;
  278. case PSN_SETACTIVE:
  279. PropSheet_SetWizButtons(GetParent(hDlg), szTempFileName[0] ? PSWIZB_NEXT : 0);
  280. SendMessage(GetDlgItem(hDlg, IDE_CSV_EXPORT_NAME), WM_SETTEXT, 0, (LPARAM)szTempFileName);
  281. break;
  282. case PSN_WIZNEXT:
  283. // the Next button was pressed
  284. SendDlgItemMessage(hDlg, IDE_CSV_EXPORT_NAME, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempFileName);
  285. StrCpyN(szCSVFileName, szTempFileName, ARRAYSIZE(szCSVFileName));
  286. break;
  287. default:
  288. return(FALSE);
  289. }
  290. break;
  291. default:
  292. return(FALSE);
  293. }
  294. return(TRUE);
  295. }
  296. /***************************************************************************
  297. Name : ExportPickFieldsPageProc
  298. Purpose : Process messages for "Pick Fields" page
  299. Parameters: standard window proc parameters
  300. Returns : standard window proc return
  301. Messages : WM_INITDIALOG - intializes the page
  302. WM_NOTIFY - processes the notifications sent to the page
  303. Comment :
  304. ***************************************************************************/
  305. INT_PTR CALLBACK ExportPickFieldsPageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
  306. HWND hWndLV;
  307. HIMAGELIST himl;
  308. LV_ITEM lvi;
  309. LV_COLUMN lvm;
  310. LV_HITTESTINFO lvh;
  311. POINT point;
  312. ULONG i, nIndex;
  313. NMHDR * pnmhdr;
  314. RECT rect;
  315. switch (message) {
  316. case WM_INITDIALOG:
  317. // Ensure that the common control DLL is loaded.
  318. InitCommonControls();
  319. // List view hwnd
  320. hWndLV = GetDlgItem(hDlg, IDLV_PICKER);
  321. // Load Image List for list view
  322. if (himl = ImageList_LoadBitmap(hInst,
  323. MAKEINTRESOURCE(IDB_CHECKS),
  324. 16,
  325. 0,
  326. RGB(128, 0, 128))) {
  327. ListView_SetImageList(hWndLV, himl, LVSIL_STATE);
  328. }
  329. // Fill the listview
  330. ZeroMemory(&lvi, sizeof(LV_ITEM));
  331. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
  332. for (i = 0; i < NUM_EXPORT_PROPS; i++) {
  333. lvi.iItem = i;
  334. lvi.pszText = rgPropNames[i].lpszName;
  335. lvi.cchTextMax = lstrlen(lvi.pszText);
  336. lvi.lParam = (LPARAM)&rgPropNames[i];
  337. lvi.state = rgPropNames[i].fChosen ?
  338. INDEXTOSTATEIMAGEMASK(iiconStateChecked + 1) :
  339. INDEXTOSTATEIMAGEMASK(iiconStateUnchecked + 1);
  340. lvi.stateMask = LVIS_STATEIMAGEMASK;
  341. if (ListView_InsertItem(hWndLV, &lvi) == -1) {
  342. DebugTrace("ListView_InsertItem -> %u\n", GetLastError());
  343. Assert(FALSE);
  344. }
  345. }
  346. // Insert a column for the text
  347. // We don't have a header, so we don't need to set the text.
  348. ZeroMemory(&lvm, sizeof(LV_COLUMN));
  349. lvm.mask = LVCF_WIDTH;
  350. // set the column width to the size of our listbox.
  351. GetClientRect(hWndLV, &rect);
  352. lvm.cx = rect.right;
  353. ListView_InsertColumn(hWndLV, 0, &lvm);
  354. // Full row selection on listview
  355. ListView_SetExtendedListViewStyle(hWndLV, LVS_EX_FULLROWSELECT);
  356. // Select the first item in the list
  357. ListView_SetItemState( hWndLV,
  358. 0,
  359. LVIS_FOCUSED | LVIS_SELECTED,
  360. LVIS_FOCUSED | LVIS_SELECTED);
  361. return(1);
  362. case WM_COMMAND:
  363. return(TRUE);
  364. break;
  365. case WM_NOTIFY:
  366. pnmhdr = (LPNMHDR)lParam;
  367. switch (((NMHDR FAR *)lParam)->code) {
  368. case NM_CLICK:
  369. case NM_DBLCLK:
  370. hWndLV = GetDlgItem(hDlg, IDLV_PICKER);
  371. i = GetMessagePos();
  372. point.x = LOWORD(i);
  373. point.y = HIWORD(i);
  374. ScreenToClient(hWndLV, &point);
  375. lvh.pt = point;
  376. nIndex = ListView_HitTest(hWndLV, &lvh);
  377. // if single click on icon or double click anywhere, toggle the checkmark.
  378. if (((NMHDR FAR *)lParam)->code == NM_DBLCLK ||
  379. ( (lvh.flags & LVHT_ONITEMSTATEICON) && !(lvh.flags & LVHT_ONITEMLABEL))) {
  380. HandleCheckMark(hWndLV, nIndex, rgPropNames);
  381. }
  382. break;
  383. case LVN_KEYDOWN:
  384. hWndLV = GetDlgItem(hDlg, IDLV_PICKER);
  385. // toggle checkmark if SPACE key is pressed
  386. if (pnmhdr->hwndFrom == hWndLV) {
  387. LV_KEYDOWN *pnkd = (LV_KEYDOWN *)lParam;
  388. // BUG 25097 allow multiple select
  389. if (pnkd->wVKey == VK_SPACE)
  390. {
  391. nIndex = ListView_GetSelectedCount(hWndLV);
  392. if(nIndex == 1)
  393. {
  394. nIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED | LVNI_ALL);
  395. //if (nIndex >= 0) {
  396. HandleCheckMark(hWndLV, nIndex, rgPropNames);
  397. //}
  398. }
  399. else if(nIndex > 1)
  400. {
  401. //multiple select case ...
  402. // Toggle all the selected items to the same state as the
  403. // first item ...
  404. HandleMultipleCheckMarks(hWndLV, rgPropNames);
  405. }
  406. }
  407. }
  408. break;
  409. case PSN_KILLACTIVE:
  410. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
  411. return(1);
  412. break;
  413. case PSN_RESET:
  414. // rest to the original values
  415. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
  416. break;
  417. case PSN_SETACTIVE:
  418. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_FINISH);
  419. break;
  420. case PSN_WIZBACK:
  421. break;
  422. case PSN_WIZFINISH:
  423. // Here's where we do the export
  424. break;
  425. default:
  426. return(FALSE);
  427. }
  428. break;
  429. default:
  430. return(FALSE);
  431. }
  432. return(TRUE);
  433. }
  434. //$$/////////////////////////////////////////////////////////////////////////////
  435. //
  436. // my_atoi - personal version of atoi function
  437. //
  438. // lpsz - string to parse into numbers - non numeral characters are ignored
  439. //
  440. /////////////////////////////////////////////////////////////////////////////////
  441. int my_atoi(LPTSTR lpsz)
  442. {
  443. int i=0;
  444. int nValue = 0;
  445. if(lpsz)
  446. {
  447. if (lstrlen(lpsz))
  448. {
  449. nValue = 0;
  450. while((lpsz[i]!='\0')&&(i<=lstrlen(lpsz)))
  451. {
  452. int tmp = lpsz[i]-'0';
  453. if(tmp <= 9)
  454. nValue = nValue*10 + tmp;
  455. i++;
  456. }
  457. }
  458. }
  459. return nValue;
  460. }
  461. typedef struct {
  462. LPTSTR lpszName;
  463. ULONG iPropNamesTable; // index in rgProp
  464. } SYNONYM, *LPSYNONYM;
  465. /***************************************************************************
  466. Name : FindPropName
  467. Purpose : Finds a property name in the prop name table
  468. Parameters: lpName = name to find or NULL to free the static synonym table
  469. rgPropNames = property name table
  470. ulcPropNames = size of property name table
  471. Returns : index into table or INDEX_NOT_FOUND
  472. Comment :
  473. ***************************************************************************/
  474. #define INDEX_NOT_FOUND 0xFFFFFFFF
  475. ULONG FindPropName(PUCHAR lpName, LPPROP_NAME rgPropNames, ULONG ulcPropNames) {
  476. ULONG i;
  477. static LPSYNONYM lpSynonymTable = NULL;
  478. static ULONG ulSynonymsSave = 0;
  479. ULONG ulSynonyms = ulSynonymsSave; // Keep local copy for compiler bug
  480. ULONG ulSynonymStrings = 0;
  481. if (lpName == NULL) {
  482. goto clean_table;
  483. }
  484. for (i = 0; i < ulcPropNames; i++) {
  485. if (! rgPropNames[i].fChosen) { // Don't re-use props!
  486. if (! lstrcmpi(lpName, rgPropNames[i].lpszName)) {
  487. return(i);
  488. }
  489. }
  490. }
  491. // If it wasn't found, look it up in the synonym table resource
  492. // First, make sure we have a synonym table loaded
  493. if (! lpSynonymTable) {
  494. TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
  495. LPTSTR lpSynonym, lpName;
  496. ULONG j;
  497. // Load the synonym table
  498. if (LoadString(hInst,
  499. idsSynonymCount,
  500. szBuffer, sizeof(szBuffer))) {
  501. DebugTrace("Loading synonym table, %s synonyms\n", szBuffer);
  502. ulSynonymStrings = my_atoi(szBuffer);
  503. if (ulSynonymStrings) {
  504. // Allocate the synonym table
  505. if (! (lpSynonymTable = LocalAlloc(LPTR, ulSynonymStrings * sizeof(SYNONYM)))) {
  506. DebugTrace("LocalAlloc synonym table -> %u\n", GetLastError());
  507. goto clean_table;
  508. }
  509. for (i = 0; i < ulSynonymStrings; i++) {
  510. if (LoadString(hInst,
  511. idsSynonym001 + i, // ids of synonym string
  512. szBuffer,
  513. sizeof(szBuffer))) {
  514. // Split the string at the '=' character
  515. lpSynonym = lpName = szBuffer;
  516. while (*lpName) {
  517. if (*lpName == '=') {
  518. // found equal sign, break the string here
  519. *(lpName++) = '\0';
  520. break;
  521. }
  522. lpName = CharNext(lpName);
  523. }
  524. // Find the name specified
  525. for (j = 0; j < ulcPropNames; j++) {
  526. if (! lstrcmpi(lpName, rgPropNames[j].lpszName)) {
  527. // Found it
  528. // Allocate a buffer for the synonym string
  529. Assert(ulSynonyms < ulSynonymStrings);
  530. if (! (lpSynonymTable[ulSynonyms].lpszName = LocalAlloc(LPTR, lstrlen(lpSynonym) + 1))) {
  531. DebugTrace("LocalAlloc in synonym table -> %u\n", GetLastError());
  532. goto clean_table;
  533. }
  534. StrCpyN(lpSynonymTable[ulSynonyms].lpszName, lpSynonym, lstrlen(lpSynonym) + 1);
  535. lpSynonymTable[ulSynonyms].iPropNamesTable = j;
  536. ulSynonyms++;
  537. break;
  538. }
  539. }
  540. }
  541. }
  542. }
  543. }
  544. ulSynonymsSave = ulSynonyms;
  545. }
  546. if (lpSynonymTable) {
  547. // Find it
  548. for (i = 0; i < ulSynonyms; i++) {
  549. if (! lstrcmpi(lpName, lpSynonymTable[i].lpszName)) {
  550. // Found the name. Is it already used?
  551. if (rgPropNames[lpSynonymTable[i].iPropNamesTable].fChosen) {
  552. break; // Found, but already used
  553. }
  554. return(lpSynonymTable[i].iPropNamesTable);
  555. }
  556. }
  557. }
  558. exit:
  559. return(INDEX_NOT_FOUND);
  560. clean_table:
  561. if (lpSynonymTable) {
  562. for (i = 0; i < ulSynonyms; i++) {
  563. if (lpSynonymTable[i].lpszName) {
  564. LocalFree(lpSynonymTable[i].lpszName);
  565. }
  566. }
  567. LocalFree(lpSynonymTable);
  568. lpSynonymTable = NULL;
  569. ulSynonymsSave = 0;
  570. }
  571. goto exit;
  572. }
  573. /***************************************************************************
  574. Name : BuildCSVTable
  575. Purpose : Builds the initial CSV mapping table from the file header.
  576. Parameters: lpFileName = filename to test
  577. rgPropnames = property name table
  578. szSep = separator character
  579. lppImportMapping -> returned mapping table
  580. lpcFields -> returned size of import mapping table
  581. lphFile -> returned file handle for CSV file. File pointer
  582. will be set past the header row.
  583. Returns : HRESULT
  584. Comment :
  585. ***************************************************************************/
  586. HRESULT BuildCSVTable(LPTSTR lpFileName, LPPROP_NAME rgPropNames, LPTSTR szSep,
  587. LPPROP_NAME * lppImportMapping, LPULONG lpcFields, LPHANDLE lphFile) {
  588. PUCHAR * rgItems = NULL;
  589. ULONG i, ulcItems = 0;
  590. LPPROP_NAME rgImportMapping = NULL;
  591. HRESULT hResult;
  592. ULONG ulPropIndex;
  593. // Open the file
  594. if ((*lphFile = CreateFile(lpFileName,
  595. GENERIC_READ,
  596. FILE_SHARE_READ | FILE_SHARE_WRITE,
  597. NULL,
  598. OPEN_EXISTING,
  599. FILE_FLAG_SEQUENTIAL_SCAN,
  600. NULL)) == INVALID_HANDLE_VALUE) {
  601. DebugTrace("Couldn't open file %s -> %u\n", lpFileName, GetLastError());
  602. return(ResultFromScode(MAPI_E_NOT_FOUND));
  603. }
  604. // Parse the first row
  605. if (hResult = ReadCSVLine(*lphFile, szSep, &ulcItems, &rgItems)) {
  606. DebugTrace("Couldn't read the CSV header\n");
  607. goto exit;
  608. }
  609. // Allocate the table
  610. if (! (*lppImportMapping = rgImportMapping = LocalAlloc(LPTR, ulcItems * sizeof(PROP_NAME)))) {
  611. DebugTrace("Allocation of import mapping table -> %u\n", GetLastError());
  612. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  613. goto exit;
  614. }
  615. // Reset flags on WAB property table
  616. for (i = 0; i < NUM_EXPORT_PROPS; i++) {
  617. rgPropNames[i].fChosen = FALSE;
  618. }
  619. // Fill in the CSV fields
  620. for (i = 0; i < ulcItems; i++) {
  621. Assert(rgItems[i]);
  622. if (rgItems[i] && *rgItems[i]) {
  623. rgImportMapping[i].lpszCSVName = rgItems[i];
  624. // Look it up in the WAB property names table
  625. if (INDEX_NOT_FOUND != (ulPropIndex = FindPropName(rgItems[i], rgPropNames, NUM_EXPORT_PROPS))) {
  626. // Found a match
  627. rgImportMapping[i].lpszName = rgPropNames[ulPropIndex].lpszName;
  628. rgImportMapping[i].ids = rgPropNames[ulPropIndex].ids;
  629. rgImportMapping[i].fChosen = TRUE;
  630. rgImportMapping[i].ulPropTag = rgPropNames[ulPropIndex].ulPropTag;
  631. rgPropNames[ulPropIndex].fChosen = TRUE;
  632. DebugTrace("Match %u: %s\n", i, rgItems[i]);
  633. } else {
  634. DebugTrace("Unknown %u: %s\n", i, rgItems[i]);
  635. }
  636. } else {
  637. DebugTrace("Empty %u: %s\n", i, rgItems[i]);
  638. }
  639. }
  640. *lpcFields = ulcItems;
  641. exit:
  642. if (hResult) {
  643. if (*lphFile != INVALID_HANDLE_VALUE) {
  644. CloseHandle(*lphFile);
  645. *lphFile = INVALID_HANDLE_VALUE;
  646. }
  647. if (rgItems) {
  648. for (i = 0; i < ulcItems; i++) {
  649. if (rgItems[i]) {
  650. LocalFree(rgItems[i]);
  651. }
  652. }
  653. }
  654. if (rgImportMapping) {
  655. LocalFree(rgImportMapping);
  656. *lppImportMapping = NULL;
  657. }
  658. }
  659. // If no error, leave the item strings since they are part of the mapping table.
  660. if (rgItems) {
  661. LocalFree(rgItems);
  662. }
  663. // Free the static memory for the synonym table.
  664. FindPropName(NULL, rgPropNames, NUM_EXPORT_PROPS);
  665. return(hResult);
  666. }
  667. /***************************************************************************
  668. Name : FileExists
  669. Purpose : Tests for existence of a file
  670. Parameters: lpFileName = filename to test
  671. Returns : TRUE if the file exists
  672. Comment :
  673. ***************************************************************************/
  674. BOOL FileExists(LPTSTR lpFileName) {
  675. DWORD dwRet;
  676. if ((dwRet = GetFileAttributes(lpFileName)) == 0xFFFFFFFF) {
  677. return(FALSE);
  678. } else {
  679. return(! (dwRet & FILE_ATTRIBUTE_DIRECTORY)); // file was found
  680. }
  681. }
  682. /***************************************************************************
  683. Name : ImportFilePageProc
  684. Purpose : Process messages for "Import Filename" page
  685. Parameters: standard window proc parameters
  686. Returns : standard window proc return
  687. Messages : WM_INITDIALOG - intializes the page
  688. WM_NOTIFY - processes the notifications sent to the page
  689. Comment :
  690. ***************************************************************************/
  691. INT_PTR CALLBACK ImportFilePageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
  692. static TCHAR szTempFileName[MAX_PATH + 1] = "";
  693. static LPPROPSHEET_DATA lppd = NULL;
  694. LPPROPSHEETPAGE lppsp;
  695. switch (message) {
  696. case WM_INITDIALOG:
  697. StrCpyN(szTempFileName, szCSVFileName, ARRAYSIZE(szTempFileName));
  698. lppsp = (LPPROPSHEETPAGE)lParam;
  699. lppd = (LPPROPSHEET_DATA)lppsp->lParam;
  700. break;
  701. case WM_COMMAND:
  702. switch (LOWORD(wParam)) {
  703. case IDC_BROWSE:
  704. SendDlgItemMessage(hDlg, IDE_CSV_IMPORT_NAME, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempFileName);
  705. OpenFileDialog(hDlg,
  706. szTempFileName,
  707. szCSVFilter,
  708. IDS_CSV_FILE_SPEC,
  709. szTextFilter,
  710. IDS_TEXT_FILE_SPEC,
  711. szAllFilter,
  712. IDS_ALL_FILE_SPEC,
  713. szCSVExt,
  714. OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
  715. hInst,
  716. 0, //idsTitle
  717. 0); // idsSaveButton
  718. PropSheet_SetWizButtons(GetParent(hDlg), FileExists(szTempFileName) ? PSWIZB_NEXT : 0);
  719. SendMessage(GetDlgItem(hDlg, IDE_CSV_IMPORT_NAME), WM_SETTEXT, 0, (LPARAM)szTempFileName);
  720. break;
  721. case IDE_CSV_IMPORT_NAME:
  722. switch (HIWORD(wParam)) { // notification code
  723. case EN_CHANGE:
  724. SendDlgItemMessage(hDlg, IDE_CSV_IMPORT_NAME, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempFileName);
  725. if ((ULONG)LOWORD(wParam) == IDE_CSV_IMPORT_NAME) {
  726. PropSheet_SetWizButtons(GetParent(hDlg), FileExists(szTempFileName) ? PSWIZB_NEXT : 0);
  727. }
  728. break;
  729. }
  730. break;
  731. }
  732. break;
  733. case WM_NOTIFY:
  734. switch (((NMHDR FAR *) lParam)->code) {
  735. case PSN_KILLACTIVE:
  736. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
  737. return(1);
  738. case PSN_RESET:
  739. // reset to the original values
  740. StrCpyN(szTempFileName, szCSVFileName, ARRAYSIZE(szTempFileName));
  741. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
  742. break;
  743. case PSN_SETACTIVE:
  744. PropSheet_SetWizButtons(GetParent(hDlg), szTempFileName[0] ? PSWIZB_NEXT : 0);
  745. SendMessage(GetDlgItem(hDlg, IDE_CSV_IMPORT_NAME), WM_SETTEXT, 0, (LPARAM)szTempFileName);
  746. break;
  747. case PSN_WIZNEXT:
  748. // the Next button was pressed
  749. SendDlgItemMessage(hDlg, IDE_CSV_IMPORT_NAME, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempFileName);
  750. StrCpyN(szCSVFileName, szTempFileName, ARRAYSIZE(szCSVFileName));
  751. break;
  752. default:
  753. return(FALSE);
  754. }
  755. break;
  756. default:
  757. return(FALSE);
  758. }
  759. return(TRUE);
  760. }
  761. typedef struct {
  762. LPPROP_NAME lpMapping;
  763. LPPROP_NAME rgPropNames;
  764. ULONG ulcPropNames;
  765. ULONG ulColumn;
  766. } CHANGE_MAPPING_INFO, * LPCHANGE_MAPPING_INFO;
  767. void HandleChangeMapping(HWND hDlg, LPPROPSHEET_DATA lppd) {
  768. HWND hWndLV = GetDlgItem(hDlg, IDLV_MAPPER);
  769. ULONG nIndex;
  770. CHANGE_MAPPING_INFO cmi;
  771. LV_ITEM lvi;
  772. ULONG ulPropTagOld, i;
  773. LPPROP_NAME lpMappingTable;
  774. ULONG ulcMapping;
  775. if ((nIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED)) == 0xFFFFFFFF) {
  776. nIndex = 0;
  777. ListView_SetItemState(hWndLV, nIndex, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
  778. }
  779. lpMappingTable = *(lppd->lppImportMapping);
  780. cmi.lpMapping = &(lpMappingTable[nIndex]);
  781. cmi.rgPropNames = lppd->rgPropNames;
  782. cmi.ulcPropNames = NUM_EXPORT_PROPS;
  783. cmi.ulColumn = nIndex;
  784. ulPropTagOld = cmi.lpMapping->ulPropTag;
  785. DialogBoxParam(hInst,
  786. MAKEINTRESOURCE(IDD_CSV_CHANGE_MAPPING),
  787. hDlg,
  788. ChangeMappingDialogProc,
  789. (LPARAM)&cmi);
  790. // Fix the entry in the listbox
  791. ZeroMemory(&lvi, sizeof(LV_ITEM));
  792. // If there is no mapping, ensure that the field is unchosen
  793. if (cmi.lpMapping->ulPropTag == PR_NULL || cmi.lpMapping->ulPropTag == 0 ) {
  794. cmi.lpMapping->fChosen = FALSE;
  795. }
  796. lvi.iItem = nIndex;
  797. lvi.lParam = (LPARAM)NULL;
  798. lvi.mask = LVIF_STATE;
  799. lvi.iSubItem = 0; // Checkbox is in first column
  800. lvi.state = cmi.lpMapping->fChosen ?
  801. INDEXTOSTATEIMAGEMASK(iiconStateChecked + 1) :
  802. INDEXTOSTATEIMAGEMASK(iiconStateUnchecked + 1);
  803. lvi.stateMask = LVIS_STATEIMAGEMASK;
  804. if (ListView_SetItem(hWndLV, &lvi) == -1) {
  805. DebugTrace("ListView_SetItem -> %u\n", GetLastError());
  806. Assert(FALSE);
  807. }
  808. lvi.mask = LVIF_TEXT;
  809. lvi.iSubItem = 1; // WAB Field
  810. lvi.pszText = cmi.lpMapping->lpszName ? cmi.lpMapping->lpszName : (LPTSTR)szEmpty; // new wab field text
  811. if (ListView_SetItem(hWndLV, &lvi) == -1) {
  812. DebugTrace("ListView_SetItem -> %u\n", GetLastError());
  813. Assert(FALSE);
  814. }
  815. // if we changed the mapping, make sure there's not a duplicate proptag mapped.
  816. if (ulPropTagOld != cmi.lpMapping->ulPropTag) {
  817. ulcMapping = *(lppd->lpcFields);
  818. for (i = 0; i < ulcMapping; i++) {
  819. if ((i != nIndex) && cmi.lpMapping->ulPropTag == lpMappingTable[i].ulPropTag) {
  820. // Found a duplicate, nuke it.
  821. lpMappingTable[i].ulPropTag = PR_NULL;
  822. lpMappingTable[i].lpszName = (LPTSTR)szEmpty;
  823. lpMappingTable[i].ids = 0;
  824. lpMappingTable[i].fChosen = FALSE;
  825. // Now, redraw that row in the listview
  826. lvi.iItem = i;
  827. lvi.lParam = (LPARAM)NULL;
  828. // uncheck the box first
  829. lvi.mask = LVIF_STATE;
  830. lvi.iSubItem = 0; // Checkbox is in first column
  831. lvi.state = INDEXTOSTATEIMAGEMASK(iiconStateUnchecked + 1);
  832. lvi.stateMask = LVIS_STATEIMAGEMASK;
  833. if (ListView_SetItem(hWndLV, &lvi) == -1) {
  834. DebugTrace("ListView_SetItem -> %u\n", GetLastError());
  835. Assert(FALSE);
  836. }
  837. // Now, change the name mapping
  838. lvi.mask = LVIF_TEXT;
  839. lvi.iSubItem = 1; // WAB Field
  840. lvi.pszText = (LPTSTR)szEmpty; // new wab field text
  841. if (ListView_SetItem(hWndLV, &lvi) == -1) {
  842. DebugTrace("ListView_SetItem -> %u\n", GetLastError());
  843. Assert(FALSE);
  844. }
  845. }
  846. }
  847. }
  848. }
  849. /***************************************************************************
  850. Name : FieldOrColumnName
  851. Purpose : If the field name is empty, generate one for it.
  852. Parameters: lpField -> Field name pointer (may be null)
  853. index = index of this column
  854. szBuffer = buffer in which to create new string if
  855. needed
  856. cbBuffer = size of szBuffer
  857. Returns : pointer to correct field name
  858. Comment :
  859. ***************************************************************************/
  860. LPTSTR FieldOrColumnName(LPTSTR lpField, ULONG index, LPTSTR szBuffer, ULONG cbBuffer) {
  861. LPTSTR lpReturn = (LPTSTR)szEmpty;
  862. if (lpField && *lpField) {
  863. return(lpField);
  864. } else {
  865. TCHAR szFormat[MAX_RESOURCE_STRING + 1];
  866. TCHAR szNumber[11];
  867. LPTSTR lpszArg[1] = {szNumber};
  868. // Format a "Column 23" type of label
  869. wnsprintf(szNumber, ARRAYSIZE(szNumber), "%u", index);
  870. if (LoadString(hInst,
  871. IDS_CSV_COLUMN,
  872. szFormat,
  873. sizeof(szFormat))) {
  874. if (! FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  875. szFormat,
  876. 0, 0, //ignored
  877. szBuffer,
  878. cbBuffer,
  879. (va_list *)lpszArg)) {
  880. DebugTrace("FormatMessage -> %u\n", GetLastError());
  881. } else {
  882. lpReturn = szBuffer;
  883. }
  884. }
  885. }
  886. return(lpReturn);
  887. }
  888. /***************************************************************************
  889. Name : ImportMapFieldsPageProc
  890. Purpose : Process messages for "Mapi Fields" page
  891. Parameters: standard window proc parameters
  892. Returns : standard window proc return
  893. Messages : WM_INITDIALOG - intializes the page
  894. WM_NOTIFY - processes the notifications sent to the page
  895. Comment :
  896. ***************************************************************************/
  897. INT_PTR CALLBACK ImportMapFieldsPageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
  898. HWND hWndLV;
  899. HIMAGELIST himl;
  900. LV_ITEM lvi;
  901. LV_COLUMN lvm;
  902. LV_HITTESTINFO lvh;
  903. POINT point;
  904. ULONG i, nIndex, nOldIndex;
  905. NMHDR * pnmhdr;
  906. RECT rect;
  907. TCHAR szBuffer[MAX_RESOURCE_STRING + 1 + 10];
  908. ULONG cxTextWidth;
  909. static LPPROPSHEET_DATA lppd = NULL;
  910. LPPROPSHEETPAGE lppsp;
  911. HRESULT hResult;
  912. CHANGE_MAPPING_INFO cmi;
  913. LPPROP_NAME lpImportMapping;
  914. switch (message) {
  915. case WM_INITDIALOG:
  916. lppsp = (LPPROPSHEETPAGE)lParam;
  917. lppd = (LPPROPSHEET_DATA)lppsp->lParam;
  918. // Ensure that the common control DLL is loaded.
  919. InitCommonControls();
  920. // List view hwnd
  921. hWndLV = GetDlgItem(hDlg, IDLV_MAPPER);
  922. // How big should the text columns be?
  923. GetClientRect(hWndLV, &rect);
  924. cxTextWidth = (rect.right - CHECK_BITMAP_WIDTH) / 2;
  925. cxTextWidth -= cxTextWidth % 2;
  926. // Insert a column for the CSV Field Names
  927. ZeroMemory(&lvm, sizeof(LV_COLUMN));
  928. lvm.mask = LVCF_TEXT | LVCF_WIDTH;
  929. lvm.cx = cxTextWidth + 9; // a touch more room for the bitmap
  930. // Get the string for the header
  931. if (LoadString(hInst, IDS_CSV_IMPORT_HEADER_CSV, szBuffer, sizeof(szBuffer))) {
  932. lvm.pszText = szBuffer;
  933. } else {
  934. DebugTrace("Cannot load resource string %u\n", IDS_CSV_IMPORT_HEADER_CSV);
  935. lvm.pszText = NULL;
  936. Assert(FALSE);
  937. }
  938. ListView_InsertColumn(hWndLV, 0, &lvm);
  939. // Insert a column for the WAB Field Names
  940. lvm.mask = LVCF_TEXT | LVCF_WIDTH;
  941. lvm.cx = cxTextWidth - 4; // room for second column text
  942. // Get the string for the header
  943. if (LoadString(hInst, IDS_CSV_IMPORT_HEADER_WAB, szBuffer, sizeof(szBuffer))) {
  944. lvm.pszText = szBuffer;
  945. } else {
  946. DebugTrace("Cannot load resource string %u\n", IDS_CSV_IMPORT_HEADER_WAB);
  947. lvm.pszText = NULL;
  948. Assert(FALSE);
  949. }
  950. ListView_InsertColumn(hWndLV, 1, &lvm);
  951. // Full row selection on listview
  952. ListView_SetExtendedListViewStyle(hWndLV, LVS_EX_FULLROWSELECT);
  953. // Load Image List for list view
  954. if (himl = ImageList_LoadBitmap(hInst,
  955. MAKEINTRESOURCE(IDB_CHECKS),
  956. CHECK_BITMAP_WIDTH,
  957. 0,
  958. RGB(128, 0, 128))) {
  959. ListView_SetImageList(hWndLV, himl, LVSIL_STATE);
  960. }
  961. // Fill the listview
  962. ZeroMemory(&lvi, sizeof(LV_ITEM));
  963. // Open the file and parse out the headers line
  964. if ((! (hResult = BuildCSVTable(szCSVFileName, lppd->rgPropNames,
  965. lppd->szSep, lppd->lppImportMapping, lppd->lpcFields, lppd->lphFile))) && ((*lppd->lpcFields) > 0)) {
  966. for (i = 0; i < *lppd->lpcFields; i++) {
  967. ULONG index;
  968. TCHAR szBuffer[MAX_RESOURCE_STRING + 1 + 10];
  969. lpImportMapping = *lppd->lppImportMapping;
  970. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
  971. lvi.iItem = i;
  972. lvi.iSubItem = 0;
  973. lvi.pszText = FieldOrColumnName(lpImportMapping[i].lpszCSVName,
  974. i,
  975. szBuffer,
  976. sizeof(szBuffer));
  977. lvi.cchTextMax = lstrlen(lvi.pszText);
  978. lvi.lParam = (LPARAM)&lpImportMapping[i];
  979. lvi.state = lpImportMapping[i].fChosen ?
  980. INDEXTOSTATEIMAGEMASK(iiconStateChecked + 1) :
  981. INDEXTOSTATEIMAGEMASK(iiconStateUnchecked + 1);
  982. lvi.stateMask = LVIS_STATEIMAGEMASK;
  983. if (index = ListView_InsertItem(hWndLV, &lvi) == -1) {
  984. DebugTrace("ListView_InsertItem -> %u\n", GetLastError());
  985. Assert(FALSE);
  986. }
  987. lvi.mask = LVIF_TEXT;
  988. // lvi.iItem = index;
  989. lvi.iSubItem = 1; // WAB Field
  990. lvi.pszText = lpImportMapping[i].lpszName ? lpImportMapping[i].lpszName : (LPTSTR)szEmpty; // new wab field text
  991. lvi.lParam = (LPARAM)NULL;
  992. if (ListView_SetItem(hWndLV, &lvi) == -1) {
  993. DebugTrace("ListView_SetItem -> %u\n", GetLastError());
  994. Assert(FALSE);
  995. }
  996. }
  997. }
  998. else
  999. EnableWindow(GetDlgItem(hDlg,IDC_CHANGE_MAPPING),FALSE);
  1000. // Select the first item in the list
  1001. ListView_SetItemState( hWndLV,
  1002. 0,
  1003. LVIS_FOCUSED | LVIS_SELECTED,
  1004. LVIS_FOCUSED | LVIS_SELECTED);
  1005. return(1);
  1006. case WM_NOTIFY:
  1007. pnmhdr = (LPNMHDR)lParam;
  1008. switch (((NMHDR FAR *)lParam)->code) {
  1009. case NM_CLICK:
  1010. hWndLV = GetDlgItem(hDlg, IDLV_MAPPER);
  1011. i = GetMessagePos();
  1012. point.x = LOWORD(i);
  1013. point.y = HIWORD(i);
  1014. ScreenToClient(hWndLV, &point);
  1015. lvh.pt = point;
  1016. nIndex = ListView_HitTest(hWndLV, &lvh);
  1017. // if single click on icon or double click anywhere, toggle the checkmark.
  1018. if (((NMHDR FAR *)lParam)->code == NM_DBLCLK ||
  1019. ( (lvh.flags & LVHT_ONITEMSTATEICON) && !(lvh.flags & LVHT_ONITEMLABEL))) {
  1020. HandleCheckMark(hWndLV, nIndex, *lppd->lppImportMapping);
  1021. // if the box is now clicked, but there is no mapping, bring up the
  1022. // mapping dialog
  1023. if ((*(lppd->lppImportMapping))[nIndex].fChosen &&
  1024. (! (*(lppd->lppImportMapping))[nIndex].lpszName ||
  1025. lstrlen((*(lppd->lppImportMapping))[nIndex].lpszName) == 0)) {
  1026. // Select the row
  1027. ListView_SetItemState(hWndLV, nIndex, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
  1028. HandleChangeMapping(hDlg, lppd);
  1029. }
  1030. }
  1031. break;
  1032. case NM_DBLCLK:
  1033. hWndLV = GetDlgItem(hDlg, IDLV_MAPPER);
  1034. i = GetMessagePos();
  1035. point.x = LOWORD(i);
  1036. point.y = HIWORD(i);
  1037. ScreenToClient(hWndLV, &point);
  1038. lvh.pt = point;
  1039. nIndex = ListView_HitTest(hWndLV, &lvh);
  1040. ListView_SetItemState(hWndLV, nIndex, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
  1041. HandleChangeMapping(hDlg, lppd);
  1042. break;
  1043. case LVN_KEYDOWN:
  1044. hWndLV = GetDlgItem(hDlg, IDLV_MAPPER);
  1045. // toggle checkmark if SPACE key is pressed
  1046. if (pnmhdr->hwndFrom == hWndLV) {
  1047. LV_KEYDOWN *pnkd = (LV_KEYDOWN *)lParam;
  1048. if (pnkd->wVKey == VK_SPACE) {
  1049. nIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED | LVNI_ALL);
  1050. //if (nIndex >= 0)
  1051. {
  1052. HandleCheckMark(hWndLV, nIndex, *lppd->lppImportMapping);
  1053. // if the box is now clicked, but there is no mapping, bring up the
  1054. // mapping dialog
  1055. if ((*(lppd->lppImportMapping))[nIndex].fChosen &&
  1056. (! (*(lppd->lppImportMapping))[nIndex].lpszName ||
  1057. lstrlen((*(lppd->lppImportMapping))[nIndex].lpszName) == 0)) {
  1058. // Select the row
  1059. ListView_SetItemState(hWndLV, nIndex, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
  1060. HandleChangeMapping(hDlg, lppd);
  1061. }
  1062. }
  1063. }
  1064. }
  1065. break;
  1066. case PSN_KILLACTIVE:
  1067. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
  1068. return(1);
  1069. break;
  1070. case PSN_RESET:
  1071. // rest to the original values
  1072. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
  1073. break;
  1074. case PSN_SETACTIVE:
  1075. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_FINISH);
  1076. break;
  1077. case PSN_WIZBACK:
  1078. break;
  1079. case PSN_WIZFINISH:
  1080. // Validate the properties selected to make sure we have
  1081. // name fields of some kind.
  1082. lpImportMapping = *lppd->lppImportMapping;
  1083. for (i = 0; i < *lppd->lpcFields; i++) {
  1084. ULONG ulPropTag = lpImportMapping[i].ulPropTag;
  1085. if (lpImportMapping[i].fChosen && (
  1086. ulPropTag == PR_DISPLAY_NAME ||
  1087. ulPropTag == PR_SURNAME ||
  1088. ulPropTag == PR_GIVEN_NAME ||
  1089. ulPropTag == PR_NICKNAME ||
  1090. ulPropTag == PR_COMPANY_NAME ||
  1091. ulPropTag == PR_EMAIL_ADDRESS ||
  1092. ulPropTag == PR_MIDDLE_NAME)) {
  1093. return(TRUE); // OK to go do the import
  1094. }
  1095. }
  1096. ShowMessageBoxParam(hDlg, IDE_CSV_NO_COLUMNS, 0);
  1097. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
  1098. break;
  1099. default:
  1100. return(FALSE);
  1101. }
  1102. break;
  1103. case WM_COMMAND:
  1104. switch (LOWORD(wParam)) {
  1105. case IDC_CHANGE_MAPPING:
  1106. HandleChangeMapping(hDlg, lppd);
  1107. break;
  1108. }
  1109. break;
  1110. default:
  1111. return(FALSE);
  1112. }
  1113. return(TRUE);
  1114. }
  1115. INT_PTR CALLBACK ChangeMappingDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
  1116. LPCHANGE_MAPPING_INFO lpcmi = (LPCHANGE_MAPPING_INFO)GetWindowLongPtr(hwnd, DWLP_USER);
  1117. static BOOL fChosenSave = FALSE;
  1118. ULONG iItem;
  1119. switch (message) {
  1120. case WM_INITDIALOG:
  1121. {
  1122. TCHAR szFormat[MAX_RESOURCE_STRING + 1];
  1123. TCHAR szBuffer[MAX_RESOURCE_STRING + 1 + 10];
  1124. LPTSTR lpszMessage = NULL;
  1125. ULONG ids, i, iDefault = 0xFFFFFFFF;
  1126. HWND hwndComboBox = GetDlgItem(hwnd, IDC_CSV_MAPPING_COMBO);
  1127. SetWindowLongPtr(hwnd, DWLP_USER, lParam); //Save this for future reference
  1128. lpcmi = (LPCHANGE_MAPPING_INFO)lParam;
  1129. fChosenSave = lpcmi->lpMapping->fChosen;
  1130. if (LoadString(hInst,
  1131. IDS_CSV_CHANGE_MAPPING_TEXT_FIELD,
  1132. szFormat, sizeof(szFormat))) {
  1133. LPTSTR lpszArg[1] = {FieldOrColumnName(lpcmi->lpMapping->lpszCSVName,
  1134. lpcmi->ulColumn,
  1135. szBuffer,
  1136. sizeof(szBuffer))};
  1137. if (! FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1138. szFormat,
  1139. 0, 0, //ignored
  1140. (LPTSTR)&lpszMessage,
  1141. 0,
  1142. (va_list *)lpszArg)) {
  1143. DebugTrace("FormatMessage -> %u\n", GetLastError());
  1144. } else {
  1145. if (! SetDlgItemText(hwnd, IDC_CSV_CHANGE_MAPPING_TEXT_FIELD, lpszMessage)) {
  1146. DebugTrace("SetDlgItemText -> %u\n", GetLastError());
  1147. }
  1148. LocalFree(lpszMessage);
  1149. }
  1150. }
  1151. // Fill in the combo box
  1152. for (i = 0; i < lpcmi->ulcPropNames; i++) {
  1153. SendMessage(hwndComboBox, CB_ADDSTRING, 0, (LPARAM)lpcmi->rgPropNames[i].lpszName);
  1154. if (lpcmi->lpMapping->ids == lpcmi->rgPropNames[i].ids) {
  1155. SendMessage(hwndComboBox, CB_SETCURSEL, (WPARAM)i, 0);
  1156. }
  1157. }
  1158. // Add blank line
  1159. SendMessage(hwndComboBox, CB_ADDSTRING, 0, (LPARAM)szEmpty);
  1160. if (lpcmi->lpMapping->ids == 0) {
  1161. SendMessage(hwndComboBox, CB_SETCURSEL, (WPARAM)(i + 1), 0);
  1162. }
  1163. // Init the checkbox
  1164. CheckDlgButton(hwnd, IDC_CSV_MAPPING_SELECT, fChosenSave ? BST_CHECKED : BST_UNCHECKED);
  1165. return(TRUE);
  1166. }
  1167. case WM_COMMAND :
  1168. switch (LOWORD(wParam)) {
  1169. case IDCANCEL:
  1170. lpcmi->lpMapping->fChosen = fChosenSave;
  1171. SendMessage(hwnd, WM_CLOSE, 0, 0L);
  1172. return(0);
  1173. case IDCLOSE:
  1174. SendMessage(hwnd, WM_CLOSE, 0, 0L);
  1175. return(0);
  1176. case IDOK:
  1177. // Set the state of the parameter
  1178. // Get the mapping
  1179. if ((iItem = (ULONG) SendMessage(GetDlgItem(hwnd, IDC_CSV_MAPPING_COMBO), CB_GETCURSEL, 0, 0)) != CB_ERR) {
  1180. if (iItem >= lpcmi->ulcPropNames) {
  1181. lpcmi->lpMapping->lpszName = (LPTSTR)szEmpty;
  1182. lpcmi->lpMapping->ids = 0;
  1183. lpcmi->lpMapping->ulPropTag = PR_NULL;
  1184. lpcmi->lpMapping->fChosen = FALSE;
  1185. } else {
  1186. lpcmi->lpMapping->lpszName = rgPropNames[iItem].lpszName;
  1187. lpcmi->lpMapping->ids = rgPropNames[iItem].ids;
  1188. lpcmi->lpMapping->ulPropTag = rgPropNames[iItem].ulPropTag;
  1189. }
  1190. }
  1191. SendMessage(hwnd, WM_CLOSE, 0, 0);
  1192. return(0);
  1193. case IDM_EXIT:
  1194. SendMessage(hwnd, WM_DESTROY, 0, 0L);
  1195. return(0);
  1196. case IDC_CSV_MAPPING_SELECT:
  1197. switch (HIWORD(wParam)) {
  1198. case BN_CLICKED:
  1199. if ((int)LOWORD(wParam) == IDC_CSV_MAPPING_SELECT) {
  1200. // toggle the checkbox
  1201. lpcmi->lpMapping->fChosen = ! lpcmi->lpMapping->fChosen;
  1202. CheckDlgButton(hwnd, IDC_CSV_MAPPING_SELECT, lpcmi->lpMapping->fChosen ? BST_CHECKED : BST_UNCHECKED);
  1203. }
  1204. break;
  1205. }
  1206. break;
  1207. }
  1208. break;
  1209. case IDCANCEL:
  1210. SendMessage(hwnd, WM_CLOSE, 0, 0);
  1211. break;
  1212. case WM_CLOSE:
  1213. EndDialog(hwnd, FALSE);
  1214. return(0);
  1215. default:
  1216. return(FALSE);
  1217. }
  1218. return(TRUE);
  1219. }