SOL9 Sample: Progman

SOL9 2.0 Samples

1 Screenshot


2 Source code

/*
 * Progman.cpp 
 * Copyright (c) 2015 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 */



// SOL++2000 
// 2000.03.20
// 2009/11/06 Modified to stop the Program Scanner Thread
// 2012/07/26 Updated

#define COMMONCONTROLS_V6

#include <sol\ApplicationView.h>
#include <sol\Thread.h>
#include <sol\PopupView.h>
#include <sol\ListView.h>

#include <sol\ImageList.h>
#include <sol\Stdio.h>
#include <sol/EventObject.h>
#include <sol/SystemMetrics.h>
#include "Resource.h"

#define WM_LISTUP  (WM_USER+2000)

//  class ProgramScanner 

namespace SOL {

class ProgramScanner :public Thread {
private:
  ImageList&  imageList;
  ListView&  listView;
  bool  cancel;
  View*  application;
  String  startingDir;

  //EventObject eventObj;
  HANDLE  hEvent;

//private:
//  static const UINT WM_SOL_THREAD_CANCEL = (WM_USER+2009);

public:
  ProgramScanner(View* parent, ListView& listv, ImageList& image, 
    const TCHAR* scanDirectory=NULL)
    :application(parent),
    listView(listv),
    imageList(image),
    hEvent(NULL)
  {

    if (scanDirectory) {
            
      startingDir = scanDirectory;
      startingDir.removeBackSlash();
      
    
    } else {
      TCHAR windir[MAX_PATH];

      GetWindowsDirectory(windir, CountOf(windir));
      windir[3] = '\0';
      //strcat(windir, _T("Program Files"));
      _stprintf_s(&windir[3], CountOf(windir)-3, _T("%s"), _T("Program Files"));
      startingDir = windir;
    }
  }

public:
  void run()
  {
    cancel = false;
    
    find((TCHAR*)startingDir);
  }

private:
  void dispatchMessage()
  {
    if (hEvent) {
            
      while (true)  { 
        if (MsgWaitForMultipleObjects(1, &hEvent, FALSE,   
          INFINITE, QS_ALLINPUT|QS_ALLEVENTS) == WAIT_OBJECT_0+1 ) {

          MSG msg;
          PeekMessage (&msg,NULL,0,0,PM_REMOVE);
        
          SleepEx(10, TRUE);

          TranslateMessage(&msg);
          DispatchMessage(&msg);
      
        }else {
          break;   
        }
      }

      CloseHandle(hEvent);
      hEvent = NULL;

    } else {
  
      MSG msg;
      while(PeekMessage (&msg,NULL,0,0,PM_REMOVE)) {
        SleepEx(10, TRUE);

        if (msg.message == WM_SOL_THREAD_CANCEL) {
          this->cancel = true;
          break;
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
    }
  }


private:
  void find(TCHAR* dir)
  {
    String xdir = &dir[1];
    if (xdir.startsWithIgnoreCase(_T(":\\$Recycle.Bin"))) {
      //2009/11/06 Skip Recyle.Bin folder
      return;  
    }
    dispatchMessage();

    if (isCancelled()) {
      return;
    }

    WIN32_FIND_DATA data;

    TCHAR* buffer = new TCHAR[_MAX_PATH*2];
    _stprintf_s(buffer, _MAX_PATH*2, _T("%s\\*"), dir);
    HANDLE fFile= ::FindFirstFile(buffer, &data);
    application->setText(buffer);

    if(fFile != INVALID_HANDLE_VALUE) {
      do {
        dispatchMessage();

        if (isCancelled()) {
          break;
        }

        if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
          if (strcmp(_T("."), data.cFileName) != 0 && 
            strcmp(_T(".."), data.cFileName) != 0) {
            dispatchMessage();
            if (isCancelled()) {
              break;
            }

            TCHAR* subDir = new TCHAR[_MAX_PATH*2];

            _stprintf_s(subDir, _MAX_PATH*2, _T("%s\\%s"), dir, data.cFileName);

            find(subDir);
            delete [] subDir;
          }
        } else {
          CharLower(data.cFileName);
          //Listup only *.exe files.
          const TCHAR* p = strstr(data.cFileName, _T(".exe"));
          if (p) {
            addToListView(dir, data.cFileName);
          }
        }
      } while(::FindNextFile(fFile, &data)); 
      ::FindClose(fFile);
    }
    delete [] buffer;
  }

public:
  virtual void doresume()
  {
    cancel = false;
    if (hEvent) {
      SetEvent(hEvent);
    }
  }

public:
  virtual void dosuspend()
  {
    if (hEvent) {
      CloseHandle(hEvent);
    }
    hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  }

public:
  void stop()
  {
    cancel = true;  
    post(WM_SOL_THREAD_CANCEL, 0, 0);
  }

public:
  bool isCancelled()
  {
    return this->cancel;
  }

private:
  void addToListView(TCHAR* dir, TCHAR* fileName)
  {
    // Extract an icon.
    TCHAR fullpath[_MAX_PATH];
    _stprintf_s(fullpath, CountOf(fullpath), _T("%s\\%s"), dir, fileName);

    HINSTANCE hInst = GetModuleHandle(NULL);//Application::getInstance();

    //Listup only the first icon  
    HICON hicon = ExtractIcon(hInst, fullpath, 0);

    if(hicon) {
      LV_ITEM item;
      memset(&item, 0, sizeof(LV_ITEM));

        // If it has an icon, add it ot the imageList.
      item.mask = LVIF_TEXT|LVIF_IMAGE;

      int id = imageList.addIcon(hicon);
      item.iImage  = id;
    
      item.pszText    = fullpath;  //fileName;
      item.cchTextMax = _MAX_PATH;
      listView.insertItem(&item);  
    }
  }
};



//   ProgramManager

class ProgramManager :public ApplicationView {
  
private:
  //<InnerClass> 2012/07/26
  class ProgramListView :public ListView {
  public:
    void reshape(int x, int y, int w, int h, Boolean redraw=True)
    {
      ListView::reshape(x, y, w, h, redraw);
      SystemMetrics metrics;
      setColumnWidth(0, w-metrics.vScrollWidth());
    }
  };
  //</InnerClass>

private:

  ProgramScanner* scanner;
  ImageList   imageList;
  ProgramListView  listView;
  int      lastChangedItem;

public:
  /**
   * Constructor
   */
  ProgramManager(Application& applet, const TCHAR* name, Args& args)
  :ApplicationView(applet, name, args),
  imageList(32, 32, ILC_COLOR24|ILC_MASK, 0, 5)
  {
    Args ar;
    //ar.set(XmNstyle, (ulong)WS_CHILD|WS_VISIBLE|WS_BORDER|LVS_ICON);
    ar.set(XmNstyle, (ulong)WS_CHILD|WS_VISIBLE|WS_BORDER|LVS_SORTASCENDING|LVS_REPORT);
  
    listView.create(this, NULL, ar);
    listView.setImageList(&imageList, LVSIL_SMALL);
    listView.setImageList(&imageList, LVSIL_NORMAL);

    ListViewColumn item[1] = {
      {_T("Filename"), 0, 600}
    }  ;
    listView.setColumn(item, 1);

    // Add the listView to the default LayoutManager.
    add(listView);

    listView.addCallback(XmNdoubleClickCallback, this,
      (Callback)&ProgramManager::launch, NULL);

    listView.addCallback(XmNitemChangedCallback, this,
      (Callback)&ProgramManager::itemChanged, NULL);
    ar.reset();
    ar.set(XmNwidth, 300);
    ar.set(XmNheight, 50);

    lastChangedItem = -1;

    // Add a menucallback.
    addCallback(XmNmenuCallback, IDM_RESUME, this, 
      (Callback)&ProgramManager::resume, NULL);

    // Add a menucallback.
    addCallback(XmNmenuCallback, IDM_SUSPEND, this, 
      (Callback)&ProgramManager::suspend, NULL);

    // Add a menucallback.
    addCallback(XmNmenuCallback, IDM_EXIT, this, 
      (Callback)&ProgramManager::exit, NULL);

    addEventHandler(WM_LISTUP, this, 
      (Handler)&ProgramManager::listup, NULL);

    restorePlacement();

    scanner = NULL;

    post(WM_LISTUP, 0, 0);

  }

public:
  void exit(Action& action)
  {
    int rc = MessageBox(NULL, _T("Are you sure you want terminate this program?"), _T("Progman"), MB_ICONQUESTION|MB_OKCANCEL);
    if (rc == IDOK) {
      stopScanner();
      ApplicationView::exit(action);
    }
  }

public:
  ~ProgramManager()
  {
    stopScanner();
    if (scanner) {
      scanner->kill();
      delete scanner;
    }
  }


public:
  void suspend(Action& action)
  {
    if (scanner) {
      scanner->dosuspend();
    }
  }

private:
  void stopScanner()
  {  
    if (scanner) {
    
      scanner->doresume();
      scanner->stop();
      scanner->kill();
      waitForThread(scanner->getHandle());
    }
  }

public:
  void resume(Action& action)
  {
    if (scanner) {
      //Don't call resume mehtod in Thread to avoid a deadlock
      //scanner->resume();  
      scanner->doresume();
    }
  }

private:
  long close(Event& event)
  {
    stopScanner();

    savePlacement();
    return defaultProc(event);
  }

private:
  long listup(Event& event)
  {
    listView.deleteAllItems();

    scanner = new ProgramScanner(this, listView, imageList, _T("C:\\"));
    scanner ->start();
    return 0L;
  }

private:
  void launch(Action& action)
  {
    if(lastChangedItem >= 0) {  
      TCHAR text[_MAX_PATH];
      listView.getItemText(lastChangedItem, 
              0, text, CountOf(text));
      ShellExecute(NULL, _T("open"), text, NULL, NULL, SW_SHOW);
    }
  }

private:
  void itemChanged(Action& action)
  {
    Event& event = action.getEvent();

    NM_LISTVIEW* nmlistv = (NM_LISTVIEW*)event.getLParam();
    lastChangedItem = nmlistv->iItem;
    if(lastChangedItem >= 0) {  
      TCHAR text[_MAX_PATH];
      listView.getItemText(lastChangedItem, 
              0, text, CountOf(text));
      TCHAR title[_MAX_PATH];
      _stprintf_s(title, CountOf(title), _T("ProgramManager - %s "), text);
      setText(title);
    }
  }
};

}

// ProgramManager Main
void  Main(int argc, TCHAR** argv)
{
  ModuleFileName module(argv[0]);
  const TCHAR* name = module.getFileName();
  try {
    Application applet(name, argc, argv);

    Args args;
    ProgramManager programManager(applet, name, args);
    programManager.realize();

    applet.run();

  } catch (Exception& ex) {
    caught(ex);
  } catch (...) {
    caught(UnknownException());
  }
}

Last modified: 1 Feb 2017

Copyright (c) 2017 Antillia.com ALL RIGHTS RESERVED.