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
1515 lines
54 KiB
/* r
|
|
* CSVPick.C
|
|
*
|
|
* Picker wizard for CSV import/export
|
|
*
|
|
* Copyright 1997 Microsoft Corporation. All Rights Reserved.
|
|
*/
|
|
|
|
#include "_comctl.h"
|
|
#include <windows.h>
|
|
#include <commctrl.h>
|
|
#include <mapix.h>
|
|
#include <wab.h>
|
|
#include <wabguid.h>
|
|
#include <wabdbg.h>
|
|
#include <wabmig.h>
|
|
#include <emsabtag.h>
|
|
#include "wabimp.h"
|
|
#include "..\..\wab32res\resrc2.h"
|
|
#include "dbgutil.h"
|
|
#include <shlwapi.h>
|
|
|
|
const TCHAR szCSVFilter[] = "*.csv";
|
|
const TCHAR szCSVExt[] = "csv";
|
|
|
|
#define CHECK_BITMAP_WIDTH 16
|
|
typedef struct {
|
|
LPPROP_NAME rgPropNames;
|
|
LPPROP_NAME * lppImportMapping;
|
|
LPHANDLE lphFile;
|
|
LPULONG lpcFields;
|
|
LPTSTR szSep;
|
|
} PROPSHEET_DATA, * LPPROPSHEET_DATA;
|
|
|
|
|
|
TCHAR szCSVFileName[MAX_PATH + 1] = "";
|
|
|
|
|
|
INT_PTR CALLBACK ExportPickFieldsPageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
|
INT_PTR CALLBACK ExportFilePageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
|
INT_PTR CALLBACK ImportFilePageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
|
INT_PTR CALLBACK ImportMapFieldsPageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
|
INT_PTR CALLBACK ChangeMappingDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : FillInPropertyPage
|
|
|
|
Purpose : Fills in the given PROPSHEETPAGE structure
|
|
|
|
Parameters: psp -> property sheet page structure
|
|
idDlg = dialog id
|
|
pszProc = title for page
|
|
pfnDlgProc -> Dialog procedure
|
|
lParam = application specified data
|
|
|
|
Returns : none
|
|
|
|
Comment : This function fills in a PROPSHEETPAGE structure with the
|
|
information the system needs to create the page.
|
|
|
|
***************************************************************************/
|
|
void FillInPropertyPage(PROPSHEETPAGE* psp, int idDlg, LPSTR pszProc,
|
|
DLGPROC pfnDlgProc, LPARAM lParam) {
|
|
psp->dwSize = sizeof(PROPSHEETPAGE);
|
|
psp->dwFlags = 0;
|
|
psp->hInstance = hInst;
|
|
psp->pszTemplate = MAKEINTRESOURCE(idDlg);
|
|
psp->pszIcon = NULL;
|
|
psp->pfnDlgProc = pfnDlgProc;
|
|
psp->pszTitle = pszProc;
|
|
psp->lParam = lParam;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : HandleCheckMark
|
|
|
|
Purpose : Deals with setting the checkmark for a particular item in
|
|
the listview.
|
|
|
|
Parameters: hwndLV = ListView handle
|
|
iItem = index of item to set
|
|
rgTable = PROP_NAME table
|
|
|
|
Returns : none
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
void HandleCheckMark(HWND hWndLV, ULONG iItem, LPPROP_NAME rgTable) {
|
|
// Locals
|
|
LV_ITEM lvi;
|
|
|
|
// Clear it
|
|
ZeroMemory(&lvi, sizeof(LV_ITEM));
|
|
lvi.mask = LVIF_PARAM;
|
|
lvi.iItem = iItem;
|
|
ListView_GetItem(hWndLV, &lvi);
|
|
rgTable[lvi.iItem].fChosen =
|
|
! rgTable[lvi.iItem].fChosen;
|
|
|
|
ZeroMemory(&lvi, sizeof(LV_ITEM));
|
|
lvi.mask = LVIF_STATE;
|
|
lvi.iItem = iItem;
|
|
lvi.state = rgTable[iItem].fChosen ?
|
|
INDEXTOSTATEIMAGEMASK(iiconStateChecked + 1) :
|
|
INDEXTOSTATEIMAGEMASK(iiconStateUnchecked + 1);
|
|
|
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
|
ListView_SetItem(hWndLV, &lvi);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : HandleMultipleCheckMarks
|
|
|
|
Purpose : Deals with setting the checkmark for a bunch of selected
|
|
items in the list view - basically sets every selected item
|
|
to the toggled state of the first item in the selection
|
|
|
|
Parameters: hwndLV = ListView handle
|
|
rgTable = LPPROP_NAME table
|
|
|
|
Returns : none
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
void HandleMultipleCheckMarks(HWND hWndLV, LPPROP_NAME rgTable)
|
|
{
|
|
// Locals
|
|
LV_ITEM lvi;
|
|
int nIndex = 0;
|
|
BOOL fState = FALSE;
|
|
|
|
// get the index of the first item
|
|
nIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED);
|
|
|
|
// toggle this item
|
|
HandleCheckMark(hWndLV, nIndex, rgTable);
|
|
|
|
fState = rgTable[nIndex].fChosen;
|
|
|
|
while((nIndex = ListView_GetNextItem(hWndLV, nIndex, LVNI_SELECTED)) >= 0)
|
|
{
|
|
// Set all the other selected items to the same state
|
|
|
|
rgTable[nIndex].fChosen = fState;
|
|
|
|
ZeroMemory(&lvi, sizeof(LV_ITEM));
|
|
lvi.mask = LVIF_STATE;
|
|
lvi.iItem = nIndex;
|
|
lvi.state = rgTable[nIndex].fChosen ?
|
|
INDEXTOSTATEIMAGEMASK(iiconStateChecked + 1) :
|
|
INDEXTOSTATEIMAGEMASK(iiconStateUnchecked + 1);
|
|
|
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
|
ListView_SetItem(hWndLV, &lvi);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : ExportWizard
|
|
|
|
Purpose : Present the Export Wizard
|
|
|
|
Parameters: hwnd = parent window handle
|
|
szFileName -> filename buffer (MAX_PATH + 1, please)
|
|
rgPropNames -> property name list
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
HRESULT ExportWizard(HWND hWnd, LPTSTR szFileName, ULONG cchSize, LPPROP_NAME rgPropNames) {
|
|
HRESULT hResult = hrSuccess;
|
|
PROPSHEETPAGE psp[NUM_EXPORT_WIZARD_PAGES];
|
|
PROPSHEETHEADER psh;
|
|
|
|
FillInPropertyPage(&psp[0], IDD_CSV_EXPORT_WIZARD_FILE, NULL, ExportFilePageProc, 0);
|
|
FillInPropertyPage(&psp[1], IDD_CSV_EXPORT_WIZARD_PICK, NULL, ExportPickFieldsPageProc, 0);
|
|
|
|
psh.dwSize = sizeof(PROPSHEETHEADER);
|
|
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD | PSH_NOAPPLYNOW | PSH_USEICONID;
|
|
psh.hwndParent = hWnd;
|
|
psh.pszCaption = NULL;
|
|
psh.pszIcon = MAKEINTRESOURCE(IDI_WabMig);
|
|
psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
|
|
psh.ppsp = (LPCPROPSHEETPAGE) &psp;
|
|
|
|
psh.hIcon = NULL;
|
|
psh.hInstance = hInst;
|
|
psh.nStartPage = 0;
|
|
psh.pStartPage = NULL;
|
|
|
|
|
|
switch (PropertySheet(&psh)) {
|
|
case -1:
|
|
hResult = ResultFromScode(MAPI_E_CALL_FAILED);
|
|
DebugTrace("PropertySheet failed -> %u\n", GetLastError());
|
|
Assert(FALSE);
|
|
break;
|
|
case 0:
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
DebugTrace("PropertySheet cancelled by user\n");
|
|
break;
|
|
default:
|
|
StrCpyN(szFileName, szCSVFileName, cchSize);
|
|
break;
|
|
}
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : ImportWizard
|
|
|
|
Purpose : Present the CSV Import Wizard
|
|
|
|
Parameters: hwnd = parent window handle
|
|
szFileName -> filename buffer (MAX_PATH + 1, please)
|
|
rgPropNames -> property name list
|
|
szSep -> list separator
|
|
lppImportMapping -> returned property mapping table
|
|
lpcFields -> returned size of property mapping table
|
|
lphFile -> returned file handle to CSV file with header
|
|
row already parsed out.
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
HRESULT ImportWizard(HWND hWnd, LPTSTR szFileName, ULONG cchSize, LPPROP_NAME rgPropNames,
|
|
LPTSTR szSep, LPPROP_NAME * lppImportMapping, LPULONG lpcFields, LPHANDLE lphFile) {
|
|
HRESULT hResult = hrSuccess;
|
|
PROPSHEETPAGE psp[NUM_IMPORT_WIZARD_PAGES];
|
|
PROPSHEETHEADER psh;
|
|
PROPSHEET_DATA pd;
|
|
|
|
pd.rgPropNames = rgPropNames;
|
|
pd.lppImportMapping = lppImportMapping;
|
|
pd.lphFile = lphFile;
|
|
pd.lpcFields = lpcFields;
|
|
pd.szSep = szSep;
|
|
|
|
FillInPropertyPage(&psp[0], IDD_CSV_IMPORT_WIZARD_FILE, NULL, ImportFilePageProc, (LPARAM)&pd);
|
|
FillInPropertyPage(&psp[1], IDD_CSV_IMPORT_WIZARD_MAP, NULL, ImportMapFieldsPageProc, (LPARAM)&pd);
|
|
|
|
psh.dwSize = sizeof(PROPSHEETHEADER);
|
|
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD | PSH_NOAPPLYNOW | PSH_USEICONID;
|
|
psh.hwndParent = hWnd;
|
|
psh.pszCaption = NULL;
|
|
psh.pszIcon = MAKEINTRESOURCE(IDI_WabMig);
|
|
psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
|
|
psh.ppsp = (LPCPROPSHEETPAGE) &psp;
|
|
|
|
psh.hIcon = NULL;
|
|
psh.hInstance = hInst;
|
|
psh.nStartPage = 0;
|
|
psh.pStartPage = NULL;
|
|
|
|
switch (PropertySheet(&psh)) {
|
|
case -1:
|
|
hResult = ResultFromScode(MAPI_E_CALL_FAILED);
|
|
DebugTrace("PropertySheet failed -> %u\n", GetLastError());
|
|
Assert(FALSE);
|
|
break;
|
|
case 0:
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
DebugTrace("PropertySheet cancelled by user\n");
|
|
break;
|
|
default:
|
|
StrCpyN(szFileName, szCSVFileName, cchSize);
|
|
break;
|
|
}
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : ExportFilePageProc
|
|
|
|
Purpose : Process messages for "Export Filename" page
|
|
|
|
Parameters: standard window proc parameters
|
|
|
|
Returns : standard window proc return
|
|
|
|
Messages : WM_INITDIALOG - intializes the page
|
|
WM_NOTIFY - processes the notifications sent to the page
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
INT_PTR CALLBACK ExportFilePageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
static TCHAR szTempFileName[MAX_PATH + 1] = "";
|
|
|
|
switch (message) {
|
|
case WM_INITDIALOG:
|
|
StrCpyN(szTempFileName, szCSVFileName, ARRAYSIZE(szTempFileName));
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam)) {
|
|
case IDC_BROWSE:
|
|
SendDlgItemMessage(hDlg, IDE_CSV_EXPORT_NAME, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempFileName);
|
|
SaveFileDialog(hDlg,
|
|
szTempFileName,
|
|
szCSVFilter,
|
|
IDS_CSV_FILE_SPEC,
|
|
szTextFilter,
|
|
IDS_TEXT_FILE_SPEC,
|
|
szAllFilter,
|
|
IDS_ALL_FILE_SPEC,
|
|
szCSVExt,
|
|
OFN_HIDEREADONLY | OFN_PATHMUSTEXIST,
|
|
hInst,
|
|
0, // idsTitle
|
|
0); // idsSaveButton
|
|
PropSheet_SetWizButtons(GetParent(hDlg), szTempFileName[0] ? PSWIZB_NEXT : 0);
|
|
SendMessage(GetDlgItem(hDlg, IDE_CSV_EXPORT_NAME), WM_SETTEXT, 0, (LPARAM)szTempFileName);
|
|
break;
|
|
|
|
case IDE_CSV_EXPORT_NAME:
|
|
switch (HIWORD(wParam)) { // notification code
|
|
case EN_CHANGE:
|
|
SendDlgItemMessage(hDlg, IDE_CSV_EXPORT_NAME, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempFileName);
|
|
if ((ULONG)LOWORD(wParam) == IDE_CSV_EXPORT_NAME) {
|
|
PropSheet_SetWizButtons(GetParent(hDlg), szTempFileName[0] ? PSWIZB_NEXT : 0);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR FAR *) lParam)->code) {
|
|
case PSN_KILLACTIVE:
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
|
|
return(1);
|
|
|
|
case PSN_RESET:
|
|
// reset to the original values
|
|
StrCpyN(szTempFileName, szCSVFileName, ARRAYSIZE(szTempFileName));
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
|
|
break;
|
|
|
|
case PSN_SETACTIVE:
|
|
PropSheet_SetWizButtons(GetParent(hDlg), szTempFileName[0] ? PSWIZB_NEXT : 0);
|
|
SendMessage(GetDlgItem(hDlg, IDE_CSV_EXPORT_NAME), WM_SETTEXT, 0, (LPARAM)szTempFileName);
|
|
break;
|
|
|
|
case PSN_WIZNEXT:
|
|
// the Next button was pressed
|
|
SendDlgItemMessage(hDlg, IDE_CSV_EXPORT_NAME, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempFileName);
|
|
StrCpyN(szCSVFileName, szTempFileName, ARRAYSIZE(szCSVFileName));
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : ExportPickFieldsPageProc
|
|
|
|
Purpose : Process messages for "Pick Fields" page
|
|
|
|
Parameters: standard window proc parameters
|
|
|
|
Returns : standard window proc return
|
|
|
|
Messages : WM_INITDIALOG - intializes the page
|
|
WM_NOTIFY - processes the notifications sent to the page
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
INT_PTR CALLBACK ExportPickFieldsPageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
HWND hWndLV;
|
|
HIMAGELIST himl;
|
|
LV_ITEM lvi;
|
|
LV_COLUMN lvm;
|
|
LV_HITTESTINFO lvh;
|
|
POINT point;
|
|
ULONG i, nIndex;
|
|
NMHDR * pnmhdr;
|
|
RECT rect;
|
|
|
|
switch (message) {
|
|
case WM_INITDIALOG:
|
|
// Ensure that the common control DLL is loaded.
|
|
InitCommonControls();
|
|
|
|
// List view hwnd
|
|
hWndLV = GetDlgItem(hDlg, IDLV_PICKER);
|
|
|
|
// Load Image List for list view
|
|
if (himl = ImageList_LoadBitmap(hInst,
|
|
MAKEINTRESOURCE(IDB_CHECKS),
|
|
16,
|
|
0,
|
|
RGB(128, 0, 128))) {
|
|
ListView_SetImageList(hWndLV, himl, LVSIL_STATE);
|
|
}
|
|
|
|
// Fill the listview
|
|
ZeroMemory(&lvi, sizeof(LV_ITEM));
|
|
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
|
|
|
|
for (i = 0; i < NUM_EXPORT_PROPS; i++) {
|
|
lvi.iItem = i;
|
|
lvi.pszText = rgPropNames[i].lpszName;
|
|
lvi.cchTextMax = lstrlen(lvi.pszText);
|
|
lvi.lParam = (LPARAM)&rgPropNames[i];
|
|
lvi.state = rgPropNames[i].fChosen ?
|
|
INDEXTOSTATEIMAGEMASK(iiconStateChecked + 1) :
|
|
INDEXTOSTATEIMAGEMASK(iiconStateUnchecked + 1);
|
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
|
|
|
if (ListView_InsertItem(hWndLV, &lvi) == -1) {
|
|
DebugTrace("ListView_InsertItem -> %u\n", GetLastError());
|
|
Assert(FALSE);
|
|
}
|
|
}
|
|
|
|
// Insert a column for the text
|
|
// We don't have a header, so we don't need to set the text.
|
|
ZeroMemory(&lvm, sizeof(LV_COLUMN));
|
|
lvm.mask = LVCF_WIDTH;
|
|
// set the column width to the size of our listbox.
|
|
GetClientRect(hWndLV, &rect);
|
|
lvm.cx = rect.right;
|
|
ListView_InsertColumn(hWndLV, 0, &lvm);
|
|
|
|
// Full row selection on listview
|
|
ListView_SetExtendedListViewStyle(hWndLV, LVS_EX_FULLROWSELECT);
|
|
|
|
// Select the first item in the list
|
|
ListView_SetItemState( hWndLV,
|
|
0,
|
|
LVIS_FOCUSED | LVIS_SELECTED,
|
|
LVIS_FOCUSED | LVIS_SELECTED);
|
|
|
|
return(1);
|
|
|
|
case WM_COMMAND:
|
|
return(TRUE);
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
pnmhdr = (LPNMHDR)lParam;
|
|
|
|
switch (((NMHDR FAR *)lParam)->code) {
|
|
case NM_CLICK:
|
|
case NM_DBLCLK:
|
|
hWndLV = GetDlgItem(hDlg, IDLV_PICKER);
|
|
|
|
i = GetMessagePos();
|
|
point.x = LOWORD(i);
|
|
point.y = HIWORD(i);
|
|
ScreenToClient(hWndLV, &point);
|
|
lvh.pt = point;
|
|
nIndex = ListView_HitTest(hWndLV, &lvh);
|
|
// if single click on icon or double click anywhere, toggle the checkmark.
|
|
if (((NMHDR FAR *)lParam)->code == NM_DBLCLK ||
|
|
( (lvh.flags & LVHT_ONITEMSTATEICON) && !(lvh.flags & LVHT_ONITEMLABEL))) {
|
|
HandleCheckMark(hWndLV, nIndex, rgPropNames);
|
|
}
|
|
break;
|
|
|
|
case LVN_KEYDOWN:
|
|
hWndLV = GetDlgItem(hDlg, IDLV_PICKER);
|
|
|
|
// toggle checkmark if SPACE key is pressed
|
|
if (pnmhdr->hwndFrom == hWndLV) {
|
|
LV_KEYDOWN *pnkd = (LV_KEYDOWN *)lParam;
|
|
// BUG 25097 allow multiple select
|
|
if (pnkd->wVKey == VK_SPACE)
|
|
{
|
|
nIndex = ListView_GetSelectedCount(hWndLV);
|
|
if(nIndex == 1)
|
|
{
|
|
nIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED | LVNI_ALL);
|
|
//if (nIndex >= 0) {
|
|
HandleCheckMark(hWndLV, nIndex, rgPropNames);
|
|
//}
|
|
}
|
|
else if(nIndex > 1)
|
|
{
|
|
//multiple select case ...
|
|
// Toggle all the selected items to the same state as the
|
|
// first item ...
|
|
HandleMultipleCheckMarks(hWndLV, rgPropNames);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PSN_KILLACTIVE:
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
|
|
return(1);
|
|
break;
|
|
|
|
case PSN_RESET:
|
|
// rest to the original values
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
|
|
break;
|
|
|
|
case PSN_SETACTIVE:
|
|
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_FINISH);
|
|
break;
|
|
|
|
case PSN_WIZBACK:
|
|
break;
|
|
|
|
case PSN_WIZFINISH:
|
|
// Here's where we do the export
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
//$$/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// my_atoi - personal version of atoi function
|
|
//
|
|
// lpsz - string to parse into numbers - non numeral characters are ignored
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
int my_atoi(LPTSTR lpsz)
|
|
{
|
|
int i=0;
|
|
int nValue = 0;
|
|
|
|
if(lpsz)
|
|
{
|
|
if (lstrlen(lpsz))
|
|
{
|
|
nValue = 0;
|
|
while((lpsz[i]!='\0')&&(i<=lstrlen(lpsz)))
|
|
{
|
|
int tmp = lpsz[i]-'0';
|
|
if(tmp <= 9)
|
|
nValue = nValue*10 + tmp;
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nValue;
|
|
}
|
|
|
|
|
|
typedef struct {
|
|
LPTSTR lpszName;
|
|
ULONG iPropNamesTable; // index in rgProp
|
|
} SYNONYM, *LPSYNONYM;
|
|
|
|
/***************************************************************************
|
|
|
|
Name : FindPropName
|
|
|
|
Purpose : Finds a property name in the prop name table
|
|
|
|
Parameters: lpName = name to find or NULL to free the static synonym table
|
|
rgPropNames = property name table
|
|
ulcPropNames = size of property name table
|
|
|
|
Returns : index into table or INDEX_NOT_FOUND
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
#define INDEX_NOT_FOUND 0xFFFFFFFF
|
|
ULONG FindPropName(PUCHAR lpName, LPPROP_NAME rgPropNames, ULONG ulcPropNames) {
|
|
ULONG i;
|
|
static LPSYNONYM lpSynonymTable = NULL;
|
|
static ULONG ulSynonymsSave = 0;
|
|
ULONG ulSynonyms = ulSynonymsSave; // Keep local copy for compiler bug
|
|
ULONG ulSynonymStrings = 0;
|
|
|
|
if (lpName == NULL) {
|
|
goto clean_table;
|
|
}
|
|
|
|
for (i = 0; i < ulcPropNames; i++) {
|
|
if (! rgPropNames[i].fChosen) { // Don't re-use props!
|
|
if (! lstrcmpi(lpName, rgPropNames[i].lpszName)) {
|
|
return(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// If it wasn't found, look it up in the synonym table resource
|
|
// First, make sure we have a synonym table loaded
|
|
if (! lpSynonymTable) {
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
LPTSTR lpSynonym, lpName;
|
|
ULONG j;
|
|
|
|
// Load the synonym table
|
|
if (LoadString(hInst,
|
|
idsSynonymCount,
|
|
szBuffer, sizeof(szBuffer))) {
|
|
DebugTrace("Loading synonym table, %s synonyms\n", szBuffer);
|
|
ulSynonymStrings = my_atoi(szBuffer);
|
|
|
|
if (ulSynonymStrings) {
|
|
// Allocate the synonym table
|
|
if (! (lpSynonymTable = LocalAlloc(LPTR, ulSynonymStrings * sizeof(SYNONYM)))) {
|
|
DebugTrace("LocalAlloc synonym table -> %u\n", GetLastError());
|
|
goto clean_table;
|
|
}
|
|
|
|
for (i = 0; i < ulSynonymStrings; i++) {
|
|
if (LoadString(hInst,
|
|
idsSynonym001 + i, // ids of synonym string
|
|
szBuffer,
|
|
sizeof(szBuffer))) {
|
|
// Split the string at the '=' character
|
|
lpSynonym = lpName = szBuffer;
|
|
while (*lpName) {
|
|
if (*lpName == '=') {
|
|
// found equal sign, break the string here
|
|
*(lpName++) = '\0';
|
|
break;
|
|
}
|
|
lpName = CharNext(lpName);
|
|
}
|
|
|
|
// Find the name specified
|
|
for (j = 0; j < ulcPropNames; j++) {
|
|
if (! lstrcmpi(lpName, rgPropNames[j].lpszName)) {
|
|
// Found it
|
|
// Allocate a buffer for the synonym string
|
|
Assert(ulSynonyms < ulSynonymStrings);
|
|
if (! (lpSynonymTable[ulSynonyms].lpszName = LocalAlloc(LPTR, lstrlen(lpSynonym) + 1))) {
|
|
DebugTrace("LocalAlloc in synonym table -> %u\n", GetLastError());
|
|
goto clean_table;
|
|
}
|
|
StrCpyN(lpSynonymTable[ulSynonyms].lpszName, lpSynonym, lstrlen(lpSynonym) + 1);
|
|
lpSynonymTable[ulSynonyms].iPropNamesTable = j;
|
|
ulSynonyms++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ulSynonymsSave = ulSynonyms;
|
|
}
|
|
|
|
if (lpSynonymTable) {
|
|
// Find it
|
|
for (i = 0; i < ulSynonyms; i++) {
|
|
if (! lstrcmpi(lpName, lpSynonymTable[i].lpszName)) {
|
|
// Found the name. Is it already used?
|
|
if (rgPropNames[lpSynonymTable[i].iPropNamesTable].fChosen) {
|
|
break; // Found, but already used
|
|
}
|
|
|
|
return(lpSynonymTable[i].iPropNamesTable);
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return(INDEX_NOT_FOUND);
|
|
|
|
clean_table:
|
|
if (lpSynonymTable) {
|
|
for (i = 0; i < ulSynonyms; i++) {
|
|
if (lpSynonymTable[i].lpszName) {
|
|
LocalFree(lpSynonymTable[i].lpszName);
|
|
}
|
|
}
|
|
LocalFree(lpSynonymTable);
|
|
lpSynonymTable = NULL;
|
|
ulSynonymsSave = 0;
|
|
}
|
|
goto exit;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : BuildCSVTable
|
|
|
|
Purpose : Builds the initial CSV mapping table from the file header.
|
|
|
|
Parameters: lpFileName = filename to test
|
|
rgPropnames = property name table
|
|
szSep = separator character
|
|
lppImportMapping -> returned mapping table
|
|
lpcFields -> returned size of import mapping table
|
|
lphFile -> returned file handle for CSV file. File pointer
|
|
will be set past the header row.
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
HRESULT BuildCSVTable(LPTSTR lpFileName, LPPROP_NAME rgPropNames, LPTSTR szSep,
|
|
LPPROP_NAME * lppImportMapping, LPULONG lpcFields, LPHANDLE lphFile) {
|
|
PUCHAR * rgItems = NULL;
|
|
ULONG i, ulcItems = 0;
|
|
LPPROP_NAME rgImportMapping = NULL;
|
|
HRESULT hResult;
|
|
ULONG ulPropIndex;
|
|
|
|
|
|
// Open the file
|
|
if ((*lphFile = CreateFile(lpFileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL)) == INVALID_HANDLE_VALUE) {
|
|
DebugTrace("Couldn't open file %s -> %u\n", lpFileName, GetLastError());
|
|
return(ResultFromScode(MAPI_E_NOT_FOUND));
|
|
}
|
|
|
|
// Parse the first row
|
|
if (hResult = ReadCSVLine(*lphFile, szSep, &ulcItems, &rgItems)) {
|
|
DebugTrace("Couldn't read the CSV header\n");
|
|
goto exit;
|
|
}
|
|
|
|
// Allocate the table
|
|
if (! (*lppImportMapping = rgImportMapping = LocalAlloc(LPTR, ulcItems * sizeof(PROP_NAME)))) {
|
|
DebugTrace("Allocation of import mapping table -> %u\n", GetLastError());
|
|
hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
// Reset flags on WAB property table
|
|
for (i = 0; i < NUM_EXPORT_PROPS; i++) {
|
|
rgPropNames[i].fChosen = FALSE;
|
|
}
|
|
|
|
// Fill in the CSV fields
|
|
for (i = 0; i < ulcItems; i++) {
|
|
Assert(rgItems[i]);
|
|
|
|
if (rgItems[i] && *rgItems[i]) {
|
|
rgImportMapping[i].lpszCSVName = rgItems[i];
|
|
|
|
// Look it up in the WAB property names table
|
|
if (INDEX_NOT_FOUND != (ulPropIndex = FindPropName(rgItems[i], rgPropNames, NUM_EXPORT_PROPS))) {
|
|
// Found a match
|
|
rgImportMapping[i].lpszName = rgPropNames[ulPropIndex].lpszName;
|
|
rgImportMapping[i].ids = rgPropNames[ulPropIndex].ids;
|
|
rgImportMapping[i].fChosen = TRUE;
|
|
rgImportMapping[i].ulPropTag = rgPropNames[ulPropIndex].ulPropTag;
|
|
rgPropNames[ulPropIndex].fChosen = TRUE;
|
|
DebugTrace("Match %u: %s\n", i, rgItems[i]);
|
|
} else {
|
|
DebugTrace("Unknown %u: %s\n", i, rgItems[i]);
|
|
}
|
|
} else {
|
|
DebugTrace("Empty %u: %s\n", i, rgItems[i]);
|
|
}
|
|
}
|
|
|
|
*lpcFields = ulcItems;
|
|
|
|
exit:
|
|
if (hResult) {
|
|
if (*lphFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(*lphFile);
|
|
*lphFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (rgItems) {
|
|
for (i = 0; i < ulcItems; i++) {
|
|
if (rgItems[i]) {
|
|
LocalFree(rgItems[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rgImportMapping) {
|
|
LocalFree(rgImportMapping);
|
|
*lppImportMapping = NULL;
|
|
}
|
|
}
|
|
|
|
// If no error, leave the item strings since they are part of the mapping table.
|
|
if (rgItems) {
|
|
LocalFree(rgItems);
|
|
}
|
|
|
|
// Free the static memory for the synonym table.
|
|
FindPropName(NULL, rgPropNames, NUM_EXPORT_PROPS);
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : FileExists
|
|
|
|
Purpose : Tests for existence of a file
|
|
|
|
Parameters: lpFileName = filename to test
|
|
|
|
Returns : TRUE if the file exists
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
BOOL FileExists(LPTSTR lpFileName) {
|
|
DWORD dwRet;
|
|
|
|
if ((dwRet = GetFileAttributes(lpFileName)) == 0xFFFFFFFF) {
|
|
return(FALSE);
|
|
} else {
|
|
return(! (dwRet & FILE_ATTRIBUTE_DIRECTORY)); // file was found
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : ImportFilePageProc
|
|
|
|
Purpose : Process messages for "Import Filename" page
|
|
|
|
Parameters: standard window proc parameters
|
|
|
|
Returns : standard window proc return
|
|
|
|
Messages : WM_INITDIALOG - intializes the page
|
|
WM_NOTIFY - processes the notifications sent to the page
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
INT_PTR CALLBACK ImportFilePageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
static TCHAR szTempFileName[MAX_PATH + 1] = "";
|
|
static LPPROPSHEET_DATA lppd = NULL;
|
|
LPPROPSHEETPAGE lppsp;
|
|
|
|
switch (message) {
|
|
case WM_INITDIALOG:
|
|
StrCpyN(szTempFileName, szCSVFileName, ARRAYSIZE(szTempFileName));
|
|
lppsp = (LPPROPSHEETPAGE)lParam;
|
|
lppd = (LPPROPSHEET_DATA)lppsp->lParam;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam)) {
|
|
case IDC_BROWSE:
|
|
SendDlgItemMessage(hDlg, IDE_CSV_IMPORT_NAME, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempFileName);
|
|
OpenFileDialog(hDlg,
|
|
szTempFileName,
|
|
szCSVFilter,
|
|
IDS_CSV_FILE_SPEC,
|
|
szTextFilter,
|
|
IDS_TEXT_FILE_SPEC,
|
|
szAllFilter,
|
|
IDS_ALL_FILE_SPEC,
|
|
szCSVExt,
|
|
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
|
|
hInst,
|
|
0, //idsTitle
|
|
0); // idsSaveButton
|
|
PropSheet_SetWizButtons(GetParent(hDlg), FileExists(szTempFileName) ? PSWIZB_NEXT : 0);
|
|
SendMessage(GetDlgItem(hDlg, IDE_CSV_IMPORT_NAME), WM_SETTEXT, 0, (LPARAM)szTempFileName);
|
|
break;
|
|
|
|
case IDE_CSV_IMPORT_NAME:
|
|
switch (HIWORD(wParam)) { // notification code
|
|
case EN_CHANGE:
|
|
SendDlgItemMessage(hDlg, IDE_CSV_IMPORT_NAME, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempFileName);
|
|
if ((ULONG)LOWORD(wParam) == IDE_CSV_IMPORT_NAME) {
|
|
PropSheet_SetWizButtons(GetParent(hDlg), FileExists(szTempFileName) ? PSWIZB_NEXT : 0);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR FAR *) lParam)->code) {
|
|
case PSN_KILLACTIVE:
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
|
|
return(1);
|
|
|
|
case PSN_RESET:
|
|
// reset to the original values
|
|
StrCpyN(szTempFileName, szCSVFileName, ARRAYSIZE(szTempFileName));
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
|
|
break;
|
|
|
|
case PSN_SETACTIVE:
|
|
PropSheet_SetWizButtons(GetParent(hDlg), szTempFileName[0] ? PSWIZB_NEXT : 0);
|
|
SendMessage(GetDlgItem(hDlg, IDE_CSV_IMPORT_NAME), WM_SETTEXT, 0, (LPARAM)szTempFileName);
|
|
break;
|
|
|
|
case PSN_WIZNEXT:
|
|
// the Next button was pressed
|
|
SendDlgItemMessage(hDlg, IDE_CSV_IMPORT_NAME, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempFileName);
|
|
StrCpyN(szCSVFileName, szTempFileName, ARRAYSIZE(szCSVFileName));
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
typedef struct {
|
|
LPPROP_NAME lpMapping;
|
|
LPPROP_NAME rgPropNames;
|
|
ULONG ulcPropNames;
|
|
ULONG ulColumn;
|
|
} CHANGE_MAPPING_INFO, * LPCHANGE_MAPPING_INFO;
|
|
|
|
|
|
void HandleChangeMapping(HWND hDlg, LPPROPSHEET_DATA lppd) {
|
|
HWND hWndLV = GetDlgItem(hDlg, IDLV_MAPPER);
|
|
ULONG nIndex;
|
|
CHANGE_MAPPING_INFO cmi;
|
|
LV_ITEM lvi;
|
|
ULONG ulPropTagOld, i;
|
|
LPPROP_NAME lpMappingTable;
|
|
ULONG ulcMapping;
|
|
|
|
if ((nIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED)) == 0xFFFFFFFF) {
|
|
nIndex = 0;
|
|
ListView_SetItemState(hWndLV, nIndex, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
|
|
}
|
|
|
|
lpMappingTable = *(lppd->lppImportMapping);
|
|
|
|
cmi.lpMapping = &(lpMappingTable[nIndex]);
|
|
cmi.rgPropNames = lppd->rgPropNames;
|
|
cmi.ulcPropNames = NUM_EXPORT_PROPS;
|
|
cmi.ulColumn = nIndex;
|
|
|
|
ulPropTagOld = cmi.lpMapping->ulPropTag;
|
|
|
|
DialogBoxParam(hInst,
|
|
MAKEINTRESOURCE(IDD_CSV_CHANGE_MAPPING),
|
|
hDlg,
|
|
ChangeMappingDialogProc,
|
|
(LPARAM)&cmi);
|
|
|
|
// Fix the entry in the listbox
|
|
ZeroMemory(&lvi, sizeof(LV_ITEM));
|
|
|
|
// If there is no mapping, ensure that the field is unchosen
|
|
if (cmi.lpMapping->ulPropTag == PR_NULL || cmi.lpMapping->ulPropTag == 0 ) {
|
|
cmi.lpMapping->fChosen = FALSE;
|
|
}
|
|
|
|
lvi.iItem = nIndex;
|
|
lvi.lParam = (LPARAM)NULL;
|
|
|
|
lvi.mask = LVIF_STATE;
|
|
lvi.iSubItem = 0; // Checkbox is in first column
|
|
lvi.state = cmi.lpMapping->fChosen ?
|
|
INDEXTOSTATEIMAGEMASK(iiconStateChecked + 1) :
|
|
INDEXTOSTATEIMAGEMASK(iiconStateUnchecked + 1);
|
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
|
if (ListView_SetItem(hWndLV, &lvi) == -1) {
|
|
DebugTrace("ListView_SetItem -> %u\n", GetLastError());
|
|
Assert(FALSE);
|
|
}
|
|
|
|
lvi.mask = LVIF_TEXT;
|
|
lvi.iSubItem = 1; // WAB Field
|
|
lvi.pszText = cmi.lpMapping->lpszName ? cmi.lpMapping->lpszName : (LPTSTR)szEmpty; // new wab field text
|
|
if (ListView_SetItem(hWndLV, &lvi) == -1) {
|
|
DebugTrace("ListView_SetItem -> %u\n", GetLastError());
|
|
Assert(FALSE);
|
|
}
|
|
|
|
// if we changed the mapping, make sure there's not a duplicate proptag mapped.
|
|
if (ulPropTagOld != cmi.lpMapping->ulPropTag) {
|
|
ulcMapping = *(lppd->lpcFields);
|
|
|
|
for (i = 0; i < ulcMapping; i++) {
|
|
if ((i != nIndex) && cmi.lpMapping->ulPropTag == lpMappingTable[i].ulPropTag) {
|
|
// Found a duplicate, nuke it.
|
|
lpMappingTable[i].ulPropTag = PR_NULL;
|
|
lpMappingTable[i].lpszName = (LPTSTR)szEmpty;
|
|
lpMappingTable[i].ids = 0;
|
|
lpMappingTable[i].fChosen = FALSE;
|
|
|
|
// Now, redraw that row in the listview
|
|
lvi.iItem = i;
|
|
lvi.lParam = (LPARAM)NULL;
|
|
|
|
// uncheck the box first
|
|
lvi.mask = LVIF_STATE;
|
|
lvi.iSubItem = 0; // Checkbox is in first column
|
|
lvi.state = INDEXTOSTATEIMAGEMASK(iiconStateUnchecked + 1);
|
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
|
if (ListView_SetItem(hWndLV, &lvi) == -1) {
|
|
DebugTrace("ListView_SetItem -> %u\n", GetLastError());
|
|
Assert(FALSE);
|
|
}
|
|
|
|
// Now, change the name mapping
|
|
lvi.mask = LVIF_TEXT;
|
|
lvi.iSubItem = 1; // WAB Field
|
|
lvi.pszText = (LPTSTR)szEmpty; // new wab field text
|
|
if (ListView_SetItem(hWndLV, &lvi) == -1) {
|
|
DebugTrace("ListView_SetItem -> %u\n", GetLastError());
|
|
Assert(FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : FieldOrColumnName
|
|
|
|
Purpose : If the field name is empty, generate one for it.
|
|
|
|
Parameters: lpField -> Field name pointer (may be null)
|
|
index = index of this column
|
|
szBuffer = buffer in which to create new string if
|
|
needed
|
|
cbBuffer = size of szBuffer
|
|
|
|
Returns : pointer to correct field name
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
LPTSTR FieldOrColumnName(LPTSTR lpField, ULONG index, LPTSTR szBuffer, ULONG cbBuffer) {
|
|
LPTSTR lpReturn = (LPTSTR)szEmpty;
|
|
|
|
if (lpField && *lpField) {
|
|
return(lpField);
|
|
} else {
|
|
TCHAR szFormat[MAX_RESOURCE_STRING + 1];
|
|
TCHAR szNumber[11];
|
|
LPTSTR lpszArg[1] = {szNumber};
|
|
|
|
// Format a "Column 23" type of label
|
|
wnsprintf(szNumber, ARRAYSIZE(szNumber), "%u", index);
|
|
|
|
if (LoadString(hInst,
|
|
IDS_CSV_COLUMN,
|
|
szFormat,
|
|
sizeof(szFormat))) {
|
|
|
|
if (! FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
szFormat,
|
|
0, 0, //ignored
|
|
szBuffer,
|
|
cbBuffer,
|
|
(va_list *)lpszArg)) {
|
|
DebugTrace("FormatMessage -> %u\n", GetLastError());
|
|
} else {
|
|
lpReturn = szBuffer;
|
|
}
|
|
}
|
|
}
|
|
return(lpReturn);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : ImportMapFieldsPageProc
|
|
|
|
Purpose : Process messages for "Mapi Fields" page
|
|
|
|
Parameters: standard window proc parameters
|
|
|
|
Returns : standard window proc return
|
|
|
|
Messages : WM_INITDIALOG - intializes the page
|
|
WM_NOTIFY - processes the notifications sent to the page
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
INT_PTR CALLBACK ImportMapFieldsPageProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
HWND hWndLV;
|
|
HIMAGELIST himl;
|
|
LV_ITEM lvi;
|
|
LV_COLUMN lvm;
|
|
LV_HITTESTINFO lvh;
|
|
POINT point;
|
|
ULONG i, nIndex, nOldIndex;
|
|
NMHDR * pnmhdr;
|
|
RECT rect;
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1 + 10];
|
|
ULONG cxTextWidth;
|
|
static LPPROPSHEET_DATA lppd = NULL;
|
|
LPPROPSHEETPAGE lppsp;
|
|
HRESULT hResult;
|
|
CHANGE_MAPPING_INFO cmi;
|
|
LPPROP_NAME lpImportMapping;
|
|
|
|
|
|
switch (message) {
|
|
case WM_INITDIALOG:
|
|
lppsp = (LPPROPSHEETPAGE)lParam;
|
|
lppd = (LPPROPSHEET_DATA)lppsp->lParam;
|
|
|
|
// Ensure that the common control DLL is loaded.
|
|
InitCommonControls();
|
|
|
|
// List view hwnd
|
|
hWndLV = GetDlgItem(hDlg, IDLV_MAPPER);
|
|
|
|
// How big should the text columns be?
|
|
GetClientRect(hWndLV, &rect);
|
|
cxTextWidth = (rect.right - CHECK_BITMAP_WIDTH) / 2;
|
|
cxTextWidth -= cxTextWidth % 2;
|
|
|
|
// Insert a column for the CSV Field Names
|
|
ZeroMemory(&lvm, sizeof(LV_COLUMN));
|
|
lvm.mask = LVCF_TEXT | LVCF_WIDTH;
|
|
lvm.cx = cxTextWidth + 9; // a touch more room for the bitmap
|
|
|
|
// Get the string for the header
|
|
if (LoadString(hInst, IDS_CSV_IMPORT_HEADER_CSV, szBuffer, sizeof(szBuffer))) {
|
|
lvm.pszText = szBuffer;
|
|
} else {
|
|
DebugTrace("Cannot load resource string %u\n", IDS_CSV_IMPORT_HEADER_CSV);
|
|
lvm.pszText = NULL;
|
|
Assert(FALSE);
|
|
}
|
|
|
|
ListView_InsertColumn(hWndLV, 0, &lvm);
|
|
|
|
// Insert a column for the WAB Field Names
|
|
lvm.mask = LVCF_TEXT | LVCF_WIDTH;
|
|
lvm.cx = cxTextWidth - 4; // room for second column text
|
|
|
|
// Get the string for the header
|
|
if (LoadString(hInst, IDS_CSV_IMPORT_HEADER_WAB, szBuffer, sizeof(szBuffer))) {
|
|
lvm.pszText = szBuffer;
|
|
} else {
|
|
DebugTrace("Cannot load resource string %u\n", IDS_CSV_IMPORT_HEADER_WAB);
|
|
lvm.pszText = NULL;
|
|
Assert(FALSE);
|
|
}
|
|
|
|
ListView_InsertColumn(hWndLV, 1, &lvm);
|
|
|
|
// Full row selection on listview
|
|
ListView_SetExtendedListViewStyle(hWndLV, LVS_EX_FULLROWSELECT);
|
|
|
|
// Load Image List for list view
|
|
if (himl = ImageList_LoadBitmap(hInst,
|
|
MAKEINTRESOURCE(IDB_CHECKS),
|
|
CHECK_BITMAP_WIDTH,
|
|
0,
|
|
RGB(128, 0, 128))) {
|
|
ListView_SetImageList(hWndLV, himl, LVSIL_STATE);
|
|
}
|
|
|
|
// Fill the listview
|
|
ZeroMemory(&lvi, sizeof(LV_ITEM));
|
|
|
|
// Open the file and parse out the headers line
|
|
if ((! (hResult = BuildCSVTable(szCSVFileName, lppd->rgPropNames,
|
|
lppd->szSep, lppd->lppImportMapping, lppd->lpcFields, lppd->lphFile))) && ((*lppd->lpcFields) > 0)) {
|
|
for (i = 0; i < *lppd->lpcFields; i++) {
|
|
ULONG index;
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1 + 10];
|
|
|
|
lpImportMapping = *lppd->lppImportMapping;
|
|
|
|
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
|
|
lvi.iItem = i;
|
|
lvi.iSubItem = 0;
|
|
lvi.pszText = FieldOrColumnName(lpImportMapping[i].lpszCSVName,
|
|
i,
|
|
szBuffer,
|
|
sizeof(szBuffer));
|
|
lvi.cchTextMax = lstrlen(lvi.pszText);
|
|
lvi.lParam = (LPARAM)&lpImportMapping[i];
|
|
lvi.state = lpImportMapping[i].fChosen ?
|
|
INDEXTOSTATEIMAGEMASK(iiconStateChecked + 1) :
|
|
INDEXTOSTATEIMAGEMASK(iiconStateUnchecked + 1);
|
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
|
|
|
if (index = ListView_InsertItem(hWndLV, &lvi) == -1) {
|
|
DebugTrace("ListView_InsertItem -> %u\n", GetLastError());
|
|
Assert(FALSE);
|
|
}
|
|
|
|
|
|
lvi.mask = LVIF_TEXT;
|
|
// lvi.iItem = index;
|
|
lvi.iSubItem = 1; // WAB Field
|
|
lvi.pszText = lpImportMapping[i].lpszName ? lpImportMapping[i].lpszName : (LPTSTR)szEmpty; // new wab field text
|
|
lvi.lParam = (LPARAM)NULL;
|
|
|
|
if (ListView_SetItem(hWndLV, &lvi) == -1) {
|
|
DebugTrace("ListView_SetItem -> %u\n", GetLastError());
|
|
Assert(FALSE);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
EnableWindow(GetDlgItem(hDlg,IDC_CHANGE_MAPPING),FALSE);
|
|
|
|
// Select the first item in the list
|
|
ListView_SetItemState( hWndLV,
|
|
0,
|
|
LVIS_FOCUSED | LVIS_SELECTED,
|
|
LVIS_FOCUSED | LVIS_SELECTED);
|
|
return(1);
|
|
|
|
case WM_NOTIFY:
|
|
pnmhdr = (LPNMHDR)lParam;
|
|
|
|
switch (((NMHDR FAR *)lParam)->code) {
|
|
case NM_CLICK:
|
|
hWndLV = GetDlgItem(hDlg, IDLV_MAPPER);
|
|
|
|
i = GetMessagePos();
|
|
point.x = LOWORD(i);
|
|
point.y = HIWORD(i);
|
|
ScreenToClient(hWndLV, &point);
|
|
lvh.pt = point;
|
|
nIndex = ListView_HitTest(hWndLV, &lvh);
|
|
// if single click on icon or double click anywhere, toggle the checkmark.
|
|
if (((NMHDR FAR *)lParam)->code == NM_DBLCLK ||
|
|
( (lvh.flags & LVHT_ONITEMSTATEICON) && !(lvh.flags & LVHT_ONITEMLABEL))) {
|
|
HandleCheckMark(hWndLV, nIndex, *lppd->lppImportMapping);
|
|
|
|
// if the box is now clicked, but there is no mapping, bring up the
|
|
// mapping dialog
|
|
if ((*(lppd->lppImportMapping))[nIndex].fChosen &&
|
|
(! (*(lppd->lppImportMapping))[nIndex].lpszName ||
|
|
lstrlen((*(lppd->lppImportMapping))[nIndex].lpszName) == 0)) {
|
|
// Select the row
|
|
ListView_SetItemState(hWndLV, nIndex, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
|
|
HandleChangeMapping(hDlg, lppd);
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case NM_DBLCLK:
|
|
hWndLV = GetDlgItem(hDlg, IDLV_MAPPER);
|
|
i = GetMessagePos();
|
|
point.x = LOWORD(i);
|
|
point.y = HIWORD(i);
|
|
ScreenToClient(hWndLV, &point);
|
|
lvh.pt = point;
|
|
nIndex = ListView_HitTest(hWndLV, &lvh);
|
|
ListView_SetItemState(hWndLV, nIndex, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
|
|
HandleChangeMapping(hDlg, lppd);
|
|
break;
|
|
|
|
case LVN_KEYDOWN:
|
|
hWndLV = GetDlgItem(hDlg, IDLV_MAPPER);
|
|
|
|
// toggle checkmark if SPACE key is pressed
|
|
if (pnmhdr->hwndFrom == hWndLV) {
|
|
LV_KEYDOWN *pnkd = (LV_KEYDOWN *)lParam;
|
|
if (pnkd->wVKey == VK_SPACE) {
|
|
nIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED | LVNI_ALL);
|
|
//if (nIndex >= 0)
|
|
{
|
|
HandleCheckMark(hWndLV, nIndex, *lppd->lppImportMapping);
|
|
|
|
// if the box is now clicked, but there is no mapping, bring up the
|
|
// mapping dialog
|
|
if ((*(lppd->lppImportMapping))[nIndex].fChosen &&
|
|
(! (*(lppd->lppImportMapping))[nIndex].lpszName ||
|
|
lstrlen((*(lppd->lppImportMapping))[nIndex].lpszName) == 0)) {
|
|
// Select the row
|
|
ListView_SetItemState(hWndLV, nIndex, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
|
|
HandleChangeMapping(hDlg, lppd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PSN_KILLACTIVE:
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
|
|
return(1);
|
|
break;
|
|
|
|
case PSN_RESET:
|
|
// rest to the original values
|
|
|
|
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
|
|
break;
|
|
|
|
case PSN_SETACTIVE:
|
|
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_FINISH);
|
|
break;
|
|
|
|
case PSN_WIZBACK:
|
|
break;
|
|
|
|
case PSN_WIZFINISH:
|
|
// Validate the properties selected to make sure we have
|
|
// name fields of some kind.
|
|
lpImportMapping = *lppd->lppImportMapping;
|
|
|
|
for (i = 0; i < *lppd->lpcFields; i++) {
|
|
ULONG ulPropTag = lpImportMapping[i].ulPropTag;
|
|
if (lpImportMapping[i].fChosen && (
|
|
ulPropTag == PR_DISPLAY_NAME ||
|
|
ulPropTag == PR_SURNAME ||
|
|
ulPropTag == PR_GIVEN_NAME ||
|
|
ulPropTag == PR_NICKNAME ||
|
|
ulPropTag == PR_COMPANY_NAME ||
|
|
ulPropTag == PR_EMAIL_ADDRESS ||
|
|
ulPropTag == PR_MIDDLE_NAME)) {
|
|
return(TRUE); // OK to go do the import
|
|
}
|
|
}
|
|
|
|
ShowMessageBoxParam(hDlg, IDE_CSV_NO_COLUMNS, 0);
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam)) {
|
|
case IDC_CHANGE_MAPPING:
|
|
HandleChangeMapping(hDlg, lppd);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
INT_PTR CALLBACK ChangeMappingDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
LPCHANGE_MAPPING_INFO lpcmi = (LPCHANGE_MAPPING_INFO)GetWindowLongPtr(hwnd, DWLP_USER);
|
|
static BOOL fChosenSave = FALSE;
|
|
ULONG iItem;
|
|
|
|
|
|
switch (message) {
|
|
case WM_INITDIALOG:
|
|
{
|
|
TCHAR szFormat[MAX_RESOURCE_STRING + 1];
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1 + 10];
|
|
LPTSTR lpszMessage = NULL;
|
|
ULONG ids, i, iDefault = 0xFFFFFFFF;
|
|
HWND hwndComboBox = GetDlgItem(hwnd, IDC_CSV_MAPPING_COMBO);
|
|
|
|
SetWindowLongPtr(hwnd, DWLP_USER, lParam); //Save this for future reference
|
|
lpcmi = (LPCHANGE_MAPPING_INFO)lParam;
|
|
|
|
fChosenSave = lpcmi->lpMapping->fChosen;
|
|
|
|
if (LoadString(hInst,
|
|
IDS_CSV_CHANGE_MAPPING_TEXT_FIELD,
|
|
szFormat, sizeof(szFormat))) {
|
|
LPTSTR lpszArg[1] = {FieldOrColumnName(lpcmi->lpMapping->lpszCSVName,
|
|
lpcmi->ulColumn,
|
|
szBuffer,
|
|
sizeof(szBuffer))};
|
|
|
|
if (! FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
|
szFormat,
|
|
0, 0, //ignored
|
|
(LPTSTR)&lpszMessage,
|
|
0,
|
|
(va_list *)lpszArg)) {
|
|
DebugTrace("FormatMessage -> %u\n", GetLastError());
|
|
} else {
|
|
if (! SetDlgItemText(hwnd, IDC_CSV_CHANGE_MAPPING_TEXT_FIELD, lpszMessage)) {
|
|
DebugTrace("SetDlgItemText -> %u\n", GetLastError());
|
|
}
|
|
LocalFree(lpszMessage);
|
|
}
|
|
}
|
|
|
|
// Fill in the combo box
|
|
for (i = 0; i < lpcmi->ulcPropNames; i++) {
|
|
SendMessage(hwndComboBox, CB_ADDSTRING, 0, (LPARAM)lpcmi->rgPropNames[i].lpszName);
|
|
if (lpcmi->lpMapping->ids == lpcmi->rgPropNames[i].ids) {
|
|
SendMessage(hwndComboBox, CB_SETCURSEL, (WPARAM)i, 0);
|
|
}
|
|
}
|
|
|
|
// Add blank line
|
|
SendMessage(hwndComboBox, CB_ADDSTRING, 0, (LPARAM)szEmpty);
|
|
if (lpcmi->lpMapping->ids == 0) {
|
|
SendMessage(hwndComboBox, CB_SETCURSEL, (WPARAM)(i + 1), 0);
|
|
}
|
|
|
|
// Init the checkbox
|
|
CheckDlgButton(hwnd, IDC_CSV_MAPPING_SELECT, fChosenSave ? BST_CHECKED : BST_UNCHECKED);
|
|
return(TRUE);
|
|
}
|
|
|
|
case WM_COMMAND :
|
|
switch (LOWORD(wParam)) {
|
|
case IDCANCEL:
|
|
lpcmi->lpMapping->fChosen = fChosenSave;
|
|
SendMessage(hwnd, WM_CLOSE, 0, 0L);
|
|
return(0);
|
|
|
|
case IDCLOSE:
|
|
SendMessage(hwnd, WM_CLOSE, 0, 0L);
|
|
return(0);
|
|
|
|
case IDOK:
|
|
// Set the state of the parameter
|
|
// Get the mapping
|
|
if ((iItem = (ULONG) SendMessage(GetDlgItem(hwnd, IDC_CSV_MAPPING_COMBO), CB_GETCURSEL, 0, 0)) != CB_ERR) {
|
|
if (iItem >= lpcmi->ulcPropNames) {
|
|
lpcmi->lpMapping->lpszName = (LPTSTR)szEmpty;
|
|
lpcmi->lpMapping->ids = 0;
|
|
lpcmi->lpMapping->ulPropTag = PR_NULL;
|
|
lpcmi->lpMapping->fChosen = FALSE;
|
|
} else {
|
|
lpcmi->lpMapping->lpszName = rgPropNames[iItem].lpszName;
|
|
lpcmi->lpMapping->ids = rgPropNames[iItem].ids;
|
|
lpcmi->lpMapping->ulPropTag = rgPropNames[iItem].ulPropTag;
|
|
}
|
|
}
|
|
SendMessage(hwnd, WM_CLOSE, 0, 0);
|
|
return(0);
|
|
|
|
case IDM_EXIT:
|
|
SendMessage(hwnd, WM_DESTROY, 0, 0L);
|
|
return(0);
|
|
|
|
case IDC_CSV_MAPPING_SELECT:
|
|
switch (HIWORD(wParam)) {
|
|
case BN_CLICKED:
|
|
if ((int)LOWORD(wParam) == IDC_CSV_MAPPING_SELECT) {
|
|
// toggle the checkbox
|
|
lpcmi->lpMapping->fChosen = ! lpcmi->lpMapping->fChosen;
|
|
CheckDlgButton(hwnd, IDC_CSV_MAPPING_SELECT, lpcmi->lpMapping->fChosen ? BST_CHECKED : BST_UNCHECKED);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case IDCANCEL:
|
|
SendMessage(hwnd, WM_CLOSE, 0, 0);
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
EndDialog(hwnd, FALSE);
|
|
return(0);
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|