Garmin Fleet Management Controller  2.19.0
CFileConverterDlg.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 *
3 * MODULE NAME:
4 * CFileConverterDlg.cpp
5 *
6 * Copyright 2008-2016 by Garmin Ltd. or its subsidiaries.
7 *---------------------------------------------------------------------
8 * $NoKeywords$
9 *********************************************************************/
10 #include "stdafx.h"
11 #include "Shlwapi.h"
12 
13 #include <fstream>
14 #include <sstream>
15 #include <string>
16 #include <vector>
17 
18 #include "CFileConverterDlg.h"
19 #include "util.h"
20 
21 using namespace std;
22 
23 #if( FMI_SUPPORT_A622 )
24 
25 IMPLEMENT_DYNAMIC( CFileConverterDlg, CDialog )
26 
27 BEGIN_MESSAGE_MAP( CFileConverterDlg, CDialog )
28  ON_EN_CHANGE( IDC_FILE_CONVERT_EDIT_SRC_FILENAME, OnEnChangeFile )
29  ON_EN_CHANGE( IDC_FILE_CONVERT_EDIT_DST_FILENAME, OnEnChangeFile )
30  ON_EN_CHANGE( IDC_FILE_CONVERT_EDIT_DST_FOLDER, OnEnChangeFile )
31  ON_EN_CHANGE( IDC_FILE_CONVERT_EDIT_STOPID, OnEnChangeFile )
32  ON_EN_CHANGE( IDC_FILE_CONVERT_EDIT_ROUTE_NAME, OnEnChangeFile )
33  ON_CBN_SELENDOK( IDC_FILE_CONVERT_CBO_TYPE, OnComboChanged )
34  ON_BN_CLICKED( IDC_FILE_CONVERT_BTN_FIND, OnBnClickedFind )
35  ON_BN_CLICKED( IDC_FILE_CONVERT_BTN_CHOOSE, OnBnClickedChoose )
36  ON_BN_CLICKED( IDOK, OnBnClickedOk )
37 END_MESSAGE_MAP()
38 
41 {
45 };
46 
47 /*--------------------------------------------------------------------
48 LITERAL CONSTANTS
49 --------------------------------------------------------------------*/
50 
53 {
54  { CONV_PSR_TO_CSV, _T( "PSR to CSV" ), NULL, _T(".csv"), _T( "PSR Files (*.*)|*.*|" ) },
55  { CONV_CSV_TO_PSR, _T( "CSV to PSR" ), NULL, _T(".psr"), _T( "CSV Files (*.csv)|*.csv|" ) },
56  { CONV_GPX_TO_PSR, _T( "GPX to PSR" ), NULL, _T(".psr"), _T( "GPX Files (*.gpx)|*.gpx|" ) }
57 };
58 
59 //----------------------------------------------------------------------
63 //----------------------------------------------------------------------
65  (
66  CWnd * aParent,
67  FmiApplicationLayer & aCom
68  )
69  : CDialog( CFileConverterDlg::IDD, aParent )
70  , mCom( aCom )
71  , mConversionType( 0 )
72  , mSrcFilePath( _T("") )
73  , mDstFileName( _T("") )
74  , mDstFolder( _T("") )
75  , mConversionIndex( 0 )
76  , mStopId( _T("") )
77  , mRouteName( _T("") )
78  , mSrcCoords( 0 )
79  , mDstCoords( 0 )
80 {
81 }
82 
83 //----------------------------------------------------------------------
85 //----------------------------------------------------------------------
87 {
88 }
89 
90 //----------------------------------------------------------------------
93 //----------------------------------------------------------------------
95  (
96  CDataExchange * aDataExchange
97  )
98 {
99  CDialog::DoDataExchange( aDataExchange );
100 
101  DDX_Text( aDataExchange, IDC_FILE_CONVERT_EDIT_SRC_FILENAME, mSrcFilePath );
102  DDX_Text( aDataExchange, IDC_FILE_CONVERT_EDIT_DST_FILENAME, mDstFileName );
103  DDX_Text( aDataExchange, IDC_FILE_CONVERT_EDIT_DST_FOLDER, mDstFolder );
104 
105  if( mConversionType == CONV_CSV_TO_PSR )
106  {
107  DDX_Text( aDataExchange, IDC_FILE_CONVERT_EDIT_STOPID, mStopId );
108  DDX_Text( aDataExchange, IDC_FILE_CONVERT_EDIT_ROUTE_NAME, mRouteName );
109  }
110  else if( mConversionType == CONV_GPX_TO_PSR )
111  {
112  DDX_Text( aDataExchange, IDC_FILE_CONVERT_EDIT_STOPID, mStopId );
113  }
114 }
115 
116 //----------------------------------------------------------------------
122 //----------------------------------------------------------------------
124 {
125  CDialog::OnInitDialog();
126 
127  // Populate file type combobox
128  CComboBox * cbo = (CComboBox *)GetDlgItem( IDC_FILE_CONVERT_CBO_TYPE );
129  cbo->ResetContent();
130  for( int i = 0; i < cnt_of_array( conversion_types ); i++ )
131  {
132  cbo->AddString( conversion_types[i].text );
133  }
134  cbo->SetCurSel( 0 );
135  mConversionType = conversion_types[0].index;
136 
137  // Initially set the source file radio button to "Semi-Circles"
139  // Set the destination file radio button to "Degrees"
141  GetDlgItem( IDC_FILE_CONVERT_RADB_1 )->EnableWindow( FALSE );
142  GetDlgItem( IDC_FILE_CONVERT_RADB_2 )->EnableWindow( FALSE );
143 
144  UpdateData( FALSE );
145  return TRUE;
146 } /* OnInitDialog() */
147 
148 //----------------------------------------------------------------------
153 //----------------------------------------------------------------------
155 {
156  UpdateData( TRUE );
157 
158  // Generate the full destination file path
159  CString dstFilePath;
160  BOOL result = FALSE;
161 
162  dstFilePath = mDstFolder;
163  if( !( dstFilePath.Right( 1 ) == _T("\\") ) )
164  {
165  dstFilePath.Append( _T("\\") );
166  }
167  dstFilePath.Append( mDstFileName );
168 
169  // Check if the destination file already exists.
170  // If so, prompt the user to make sure they want to overwrite.
171  CFileStatus status;
172  if( CFile::GetStatus( dstFilePath, status ) != 0 )
173  {
174  if( MessageBox( _T("Destination File already exists. Overwrite File?"), _T("Caution"), MB_YESNO ) == IDNO )
175  {
176  return;
177  }
178  }
179  if( IsDlgButtonChecked( IDC_FILE_CONVERT_RADB_1 ) == BST_CHECKED )
180  {
181  mSrcCoords = 1; // Degrees
182  }
183  else
184  {
185  mSrcCoords = 2; // Semi-circles
186  }
187  if( IsDlgButtonChecked( IDC_FILE_CONVERT_RADB_3 ) == BST_CHECKED )
188  {
189  mDstCoords = 1; // Degrees
190  }
191  else
192  {
193  mDstCoords = 2; // Semi-circles
194  }
195 
196  // Setup Child Process STDOUT Redirection
197  SECURITY_ATTRIBUTES saAttr;
198  saAttr.nLength = sizeof( SECURITY_ATTRIBUTES );
199  saAttr.bInheritHandle = TRUE;
200  saAttr.lpSecurityDescriptor = NULL;
201 
202  // Create a pipe for the child process's STDOUT.
203  if ( ! CreatePipe( &hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &saAttr, 0 ) ) return;
204 
205  // Ensure the read handle to the pipe for STDOUT is not inherited.
206  if ( ! SetHandleInformation( hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0 ) ) return;
207 
208  result = CreateChildProcess( dstFilePath );
209 
210  if( result == TRUE )
211  {
212  CString output;
213  output.Format( _T("Successfully Converted the File.\n\nFile sent to:\n%s"),
214  (LPCTSTR)dstFilePath );
215  MessageBox( output, _T("Conversion Complete") );
216  }
217 }
218 
219 //----------------------------------------------------------------------
222 //----------------------------------------------------------------------
223 CString CFileConverterDlg::FormatArguments( CString dstFilePath )
224 {
225  CString arguments;
226 
227  // Append quotes around the file paths or route name in case of
228  // spaces in the strings.
229  mSrcFilePath.Insert( 0,'\"' );
230  mSrcFilePath.AppendChar( '\"' );
231  dstFilePath.Insert( 0, '\"' );
232  dstFilePath.AppendChar( '\"' );
233  mRouteName.Insert( 0, '\"' );
234  mRouteName.AppendChar( '\"' );
235 
236  // Conversion type is 1-based in FleetFileUtility
237  switch( mConversionType )
238  {
239  case CONV_PSR_TO_CSV:
240  arguments.Format( _T("%i "), CONV_PSR_TO_CSV+1 );
241  arguments.Append( mSrcFilePath );
242  arguments.Append( _T(" "));
243  arguments.Append( dstFilePath );
244  arguments.Append( _T(" -D ") );
245  arguments.AppendFormat( _T("%i"), mDstCoords );
246  break;
247  case CONV_CSV_TO_PSR:
248  arguments.Format( _T("%i "), CONV_CSV_TO_PSR+1 );
249  arguments.Append( mSrcFilePath );
250  arguments.Append( _T(" "));
251  arguments.Append( dstFilePath );
252  arguments.Append( _T(" -R ") );
253  arguments.Append( mRouteName );
254  arguments.Append( _T(" -I ") );
255  arguments.Append( mStopId );
256  arguments.Append( _T(" -S ") );
257  arguments.AppendFormat( _T("%i"), mSrcCoords );
258  break;
259  case CONV_GPX_TO_PSR:
260  arguments.Format( _T("%i "), CONV_GPX_TO_PSR+1 );
261  arguments.Append( mSrcFilePath );
262  arguments.Append( _T(" "));
263  arguments.Append( dstFilePath );
264  arguments.Append( _T(" -I ") );
265  arguments.Append( mStopId );
266  break;
267  default:
268  arguments.Append( _T("-H") );
269  break;
270  }
271  return arguments;
272 }
273 
274 //----------------------------------------------------------------------
278 //----------------------------------------------------------------------
280 {
281  UpdateData();
282 
283  TCHAR workingDirectory[200];
284  // opening a file in another directory changes the current
285  // directory, which will cause problems because the log and data
286  // files are opened relative to the current directory. So, get the
287  // directory now so that it can be restored when the user is done
288  // picking a file.
289  DWORD result = GetCurrentDirectory( 200, workingDirectory );
290  if( result == 0 || result > 200 )
291  {
292  MessageBox( _T("Unable to get current directory"), _T("Severe Error") );
293  OnCancel();
294  return;
295  }
296  CFileDialog dlg
297  (
298  TRUE,
299  conversion_types[ mConversionIndex ].extension,
300  NULL,
301  OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
302  conversion_types[ mConversionIndex ].filter
303  );
304  if( dlg.DoModal() == IDOK )
305  {
306  mSrcFilePath = dlg.GetPathName();
307  mDstFileName = dlg.GetFileTitle();
308  mDstFileName.Append( conversion_types[ mConversionIndex ].newExtension );
309  mDstFolder = dlg.GetFolderPath();
310  UpdateData( FALSE );
311  OnEnChangeFile();
312  }
313  if( !SetCurrentDirectory( workingDirectory ) )
314  {
315  MessageBox( _T("Unable to set current directory"), _T("Severe Error") );
316  OnCancel();
317  return;
318  }
319 }
320 
321 //----------------------------------------------------------------------
325 //----------------------------------------------------------------------
327 {
328  UpdateData();
329 
330  // Archaic implementation. If this project is ever upgraded to VS2010+,
331  // update this code to use CFolderPickerDialog.
332  LPMALLOC pMalloc;
333  BROWSEINFO bi;
334  ZeroMemory( &bi, sizeof( bi ) );
335  TCHAR szDisplayName[MAX_PATH];
336  szDisplayName[0] = NULL;
337  LPITEMIDLIST pidl;
338 
339  bi.hwndOwner = ::GetDesktopWindow();
340  bi.pidlRoot = NULL;
341  bi.pszDisplayName = szDisplayName;
342  bi.lpszTitle = _T( "Please select a folder:" );
343  bi.ulFlags = BIF_USENEWUI|BIF_RETURNONLYFSDIRS;
344  bi.lParam = NULL;
345  bi.iImage = 0;
346  OleInitialize(NULL);
347 
348  if ( ::SHGetMalloc( &pMalloc ) == NOERROR )
349  {
350  if( NULL != ( pidl = SHBrowseForFolder( &bi ) ) )
351  {
352  TCHAR szPathName[MAX_PATH];
353  if( SHGetPathFromIDList( pidl, szPathName ) )
354  {
355  mDstFolder = szPathName;
356  UpdateData( FALSE );
357  OnEnChangeFile();
358  }
359  }
360  pMalloc->Free(pidl);
361  }
362  pMalloc->Release();
363 }
364 
365 //----------------------------------------------------------------------
370 //----------------------------------------------------------------------
372 {
373  CComboBox * cbo = (CComboBox *)GetDlgItem( IDC_FILE_CONVERT_CBO_TYPE );
374  mConversionIndex = cbo->GetCurSel();
375  mConversionType = conversion_types[mConversionIndex].index;
376 
377  // Enable/Disable the stopId/route name edit boxes based on user selection
378  if( mConversionType == CONV_CSV_TO_PSR )
379  {
380  GetDlgItem( IDC_FILE_CONVERT_EDIT_STOPID )->EnableWindow( TRUE );
381  GetDlgItem( IDC_FILE_CONVERT_EDIT_ROUTE_NAME )->EnableWindow( TRUE );
382  GetDlgItem( IDC_FILE_CONVERT_RADB_1 )->EnableWindow( TRUE );
383  GetDlgItem( IDC_FILE_CONVERT_RADB_2 )->EnableWindow( TRUE );
386  GetDlgItem( IDC_FILE_CONVERT_RADB_3 )->EnableWindow( FALSE );
387  GetDlgItem( IDC_FILE_CONVERT_RADB_4 )->EnableWindow( FALSE );
388  }
389  else if( mConversionType == CONV_GPX_TO_PSR )
390  {
391  GetDlgItem( IDC_FILE_CONVERT_EDIT_STOPID )->EnableWindow( TRUE );
392  GetDlgItem( IDC_FILE_CONVERT_EDIT_ROUTE_NAME )->EnableWindow( FALSE );
395  GetDlgItem( IDC_FILE_CONVERT_RADB_1 )->EnableWindow( FALSE );
396  GetDlgItem( IDC_FILE_CONVERT_RADB_2 )->EnableWindow( FALSE );
397  GetDlgItem( IDC_FILE_CONVERT_RADB_3 )->EnableWindow( FALSE );
398  GetDlgItem( IDC_FILE_CONVERT_RADB_4 )->EnableWindow( FALSE );
399  }
400  else
401  {
402  GetDlgItem( IDC_FILE_CONVERT_EDIT_STOPID )->EnableWindow( FALSE );
403  GetDlgItem( IDC_FILE_CONVERT_EDIT_ROUTE_NAME )->EnableWindow( FALSE );
404  GetDlgItem( IDC_FILE_CONVERT_RADB_3 )->EnableWindow( TRUE );
405  GetDlgItem( IDC_FILE_CONVERT_RADB_4 )->EnableWindow( TRUE );
408  GetDlgItem( IDC_FILE_CONVERT_RADB_1 )->EnableWindow( FALSE );
409  GetDlgItem( IDC_FILE_CONVERT_RADB_2 )->EnableWindow( FALSE );
410  }
411 
412  // Item changed, so clear the edit boxes
413  CEdit * ced = (CEdit *)GetDlgItem( IDC_FILE_CONVERT_EDIT_SRC_FILENAME );
414  ced->SetWindowTextW( _T("") );
415  ced = (CEdit *)GetDlgItem( IDC_FILE_CONVERT_EDIT_DST_FILENAME );
416  ced->SetWindowTextW( _T("") );
417  ced = (CEdit *)GetDlgItem( IDC_FILE_CONVERT_EDIT_DST_FOLDER );
418  ced->SetWindowTextW( _T("") );
419  ced = (CEdit *)GetDlgItem( IDC_FILE_CONVERT_EDIT_STOPID );
420  ced->SetWindowTextW( _T("") );
421  ced = (CEdit *)GetDlgItem( IDC_FILE_CONVERT_EDIT_ROUTE_NAME );
422  ced->SetWindowTextW( _T("") );
423 
424  UpdateData(FALSE);
425 }
426 
427 //----------------------------------------------------------------------
431 //----------------------------------------------------------------------
433 {
434  BOOL isValid = TRUE;
435 
436  UpdateData( TRUE );
437 
438  if( mSrcFilePath == "" || mDstFileName == "" || mDstFolder == "" )
439  {
440  isValid = FALSE;
441  }
442  if( mConversionType == CONV_CSV_TO_PSR && ( mStopId == "" || mRouteName == "" ) )
443  {
444  isValid = FALSE;
445  }
446  else if( mConversionType == CONV_GPX_TO_PSR && mStopId == "" )
447  {
448  isValid = FALSE;
449  }
450 
451  if( isValid )
452  {
453  GetDlgItem( IDOK )->EnableWindow( TRUE );
454  }
455  else
456  {
457  GetDlgItem( IDOK )->EnableWindow( FALSE );
458  }
459 }
460 
461 //----------------------------------------------------------------------
466 //----------------------------------------------------------------------
467 BOOL CFileConverterDlg::CreateChildProcess( CString dstFilePath )
468 {
469  PROCESS_INFORMATION piProcInfo;
470  STARTUPINFO siStartInfo;
471  BOOL bSuccess = FALSE;
472 
473 // Set up members of the PROCESS_INFORMATION structure.
474  ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
475 
476 // Set up members of the STARTUPINFO structure.
477 // This structure specifies the STDOUT handles for redirection.
478  ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
479  siStartInfo.cb = sizeof(STARTUPINFO);
480  siStartInfo.hStdError = hChildStd_OUT_Wr;
481  //siStartInfo.hStdOutput = hChildStd_OUT_Wr; // uncomment for additional debug output
482  siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
483  siStartInfo.wShowWindow = SW_HIDE;
484 
485 // Create the command line arguments
486  const int MAX_CMDLINE = 1000;
487  WCHAR modulePath[MAX_PATH];
488  ZeroMemory( &modulePath, MAX_PATH );
489  WCHAR fullPathBuffer[MAX_CMDLINE];
490  WCHAR exe[] = _T("\\FleetFileUtility.exe"); // The exe must be in the same location as FMC!!!
491  GetModuleFileName( NULL, modulePath, MAX_PATH );
492  PathRemoveFileSpec( modulePath );
493  wcscat_s( modulePath, exe );
494  wstring actualPath( modulePath );
495  actualPath.insert(0, L"\""); // Enclose the exe path in quotes in case of spaces in the name
496  actualPath.append(L"\" "); // A trailing space is left to divide the path from the arguments
497  CString parameters = FormatArguments( dstFilePath );
498  actualPath.append( (wstring)parameters );
499  wcscpy_s( fullPathBuffer, actualPath.size()+1, actualPath.c_str() );
500 
501 // Create the child process
502  bSuccess = CreateProcess
503  ( modulePath // Application name
504  , fullPathBuffer // Full Command line
505  , NULL // Process handle not inheritable
506  , NULL // Thread handle not inheritable
507  , TRUE // Handle inheritance true
508  , CREATE_NO_WINDOW // Do not create a window
509  , NULL // Use parent's environment
510  , NULL // Use parent's directory
511  , &siStartInfo // pointer to STARTUPINFO
512  , &piProcInfo // pointer to PROCESS_INFORMATION
513  );
514 
515  if( bSuccess )
516  {
517  GetDlgItem( IDOK )->EnableWindow( FALSE ); // Disable the buttons in case of long conversion
518  GetDlgItem( IDCANCEL )->EnableWindow( FALSE );
519  // Wait for the process to finish running
520  WaitForSingleObject( piProcInfo.hProcess, INFINITE );
521  GetDlgItem( IDOK )->EnableWindow( TRUE ); // Re-enable
522  GetDlgItem( IDCANCEL )->EnableWindow( TRUE );
523 
524  ReadFromPipe();
525  DWORD prcRes;
526  GetExitCodeProcess( piProcInfo.hProcess, &prcRes );
527  bSuccess = (BOOL)prcRes;
528  }
529  else
530  {
531  MessageBox( _T("Unable to locate the Fleet File Utility. Make sure the")
532  _T(" FleetFileUtility.exe is in the same location as the Fleet")
533  _T("ManagementController.exe and try again.")
534  , _T("Severe Error") );
535  }
536  // Close the process handles
537  CloseHandle( piProcInfo.hProcess );
538  CloseHandle( piProcInfo.hThread );
539 
540  return bSuccess;
541 }
542 
543 //----------------------------------------------------------------------
546 //----------------------------------------------------------------------
548 {
549  const int BUFSIZE = 4096;
550  DWORD dwRead;
551  CHAR chBuf[BUFSIZE];
552  ZeroMemory( chBuf, BUFSIZE );
553  BOOL bSuccess = FALSE;
554 
555  CloseHandle( hChildStd_OUT_Wr ); // Reading from the stdout pipe is a blocking
556  // call so we have to close the handle before
557  // reading any output from the child process.
558  bSuccess = ReadFile( hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL );
559  if( dwRead > 0 )
560  {
561  CString output( chBuf );
562  MessageBox( output, _T( "Fleet File Utility" ) );
563  }
564 }
565 #endif
#define IDC_FILE_CONVERT_EDIT_DST_FILENAME
Definition: resource.h:568
#define IDC_FILE_CONVERT_RADB_2
Definition: resource.h:582
#define IDC_FILE_CONVERT_RADB_1
Definition: resource.h:581
BOOL CreateChildProcess(CString dstFilePath)
Create a child process to execute the file conversion.
#define IDC_FILE_CONVERT_EDIT_DST_FOLDER
Definition: resource.h:569
#define IDC_FILE_CONVERT_BTN_CHOOSE
Definition: resource.h:571
#define IDC_FILE_CONVERT_EDIT_SRC_FILENAME
Definition: resource.h:567
STL namespace.
static CFileConverterDlg::conversion_type conversion_types[]
Conversion types that the client accepts.
#define cnt_of_array(_a)
The number of elements in _a.
Definition: util_macros.h:90
#define FALSE
Definition: garmin_types.h:46
virtual ~CFileConverterDlg()
Destructor.
BOOL OnInitDialog()
Initialize the dialog.
#define TRUE
Definition: garmin_types.h:45
#define IDC_FILE_CONVERT_CBO_TYPE
Definition: resource.h:572
afx_msg void OnBnClickedOk()
Click handler for OK button.
#define IDC_FILE_CONVERT_BTN_FIND
Definition: resource.h:570
#define IDC_FILE_CONVERT_RADB_3
Definition: resource.h:583
Serial communication controller for Garmin and FMI packets.
afx_msg void OnBnClickedFind()
Click handler for Find (file to convert) button.
afx_msg void OnBnClickedChoose()
Click handler for Choose (destination folder) button.
afx_msg void OnEnChangeFile()
Edit Change handler for all text boxes.
File conversion tool to support various GPS file formats.
CFileConverterDlg(CWnd *aParent, FmiApplicationLayer &aCom)
Constructor.
conversion_type_type
Valid values for file conversion types.
#define IDC_FILE_CONVERT_EDIT_STOPID
Definition: resource.h:577
afx_msg void OnComboChanged()
Change Handler for the combo box.
virtual void DoDataExchange(CDataExchange *aDataExchange)
Perform dialog data exchange and validation.
CString FormatArguments(CString dstFilePath)
Helper function to format the command line arguments.
#define IDC_FILE_CONVERT_RADB_4
Definition: resource.h:584
#define IDC_FILE_CONVERT_EDIT_ROUTE_NAME
Definition: resource.h:579
void ReadFromPipe(void)
Read output from the child process&#39;s pipe for STDOUT.