RetroZilla/modules/plugin/tools/spy/windows/dirpick.cpp
2015-10-20 23:03:22 -04:00

604 lines
17 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <windows.h>
#include <windowsx.h>
#include <direct.h>
#include <stdio.h>
#include "resource.h"
extern HINSTANCE hInst;
#define ITEM_BITMAPWIDTH 16
#define ITEM_BITMAPHEIGHT 16
#define ITEM_LEFTMARGIN 4
#define ITEM_GAP 4
static HWND hWndDirPicker;
static HICON hIconDrives[5];
static HICON hIconFolders[3];
static LPSTR lpszStringToReturn;
static char szUNCRoot[256] = "";
UINT DriveType(UINT iType);
static void fillComboBox(HWND hWnd)
{
HWND hWndCB = GetDlgItem(hWnd, ID_COMBO_DIR);
HWND hWndTempLB = GetDlgItem(hWnd, ID_LISTTEMP_DIR);
if(hWndCB == NULL)
return;
ComboBox_ResetContent(hWndCB);
ListBox_ResetContent(hWndTempLB);
ListBox_Dir(hWndTempLB, DDL_DRIVES|DDL_EXCLUSIVE, (LPSTR)"*");
int iDriveCount = ListBox_GetCount(hWndTempLB);
int iCurDrive=_getdrive() - 1;
char szDrive[16];
char szItem[80];
for (int i = 0; i < iDriveCount; i++)
{
ListBox_GetText(hWndTempLB, i, szDrive);
CharLower(szDrive);
int iDrive = szDrive[2] - 'a';
char szRoot[16];
sprintf(szRoot, "%c:\\", szDrive[2]);
int iType = DriveType(iDrive);
if(iType < 2)
continue;
//Start the item string with the drive letter, colon, and two spaces
sprintf(szItem, "%c%s", szDrive[2], ": ");
if((iType == DRIVE_FIXED) || (iType == DRIVE_RAMDISK))
{ // get volume ID
char szVolumeID[80];
DWORD dwMaxLength;
DWORD dwSysFlags;
GetVolumeInformation(szRoot, // address of root directory of the file system
szVolumeID, // address of name of the volume
sizeof(szVolumeID), // length of lpVolumeNameBuffer
NULL, // address of volume serial number
&dwMaxLength, // address of system's maximum filename length
&dwSysFlags, // address of file system flags
NULL, // address of name of file system
NULL); // length of lpFileSystemNameBuffer
CharLower(szVolumeID);
lstrcat(szItem, szVolumeID);
}
//For network drives, go grab the \\server\share for it.
if(DRIVE_REMOTE == iType)
{
char szNet[64];
szNet[0] = '\0';
DWORD dwSizeOfszNet = sizeof(szNet);
sprintf(szDrive, "%c:", szDrive[2]);
CharUpper(szDrive);
WNetGetConnection(szDrive, szNet, &dwSizeOfszNet);
CharLower(szNet);
lstrcat(szItem, szNet);
}
int index = ComboBox_AddString(hWndCB, szItem);
ComboBox_SetItemData(hWndCB, index, MAKELONG(iDrive, iType));
if(iDrive == iCurDrive)
ComboBox_SetCurSel(hWndCB, index);
if(szUNCRoot[0] != '\0')
ComboBox_SetCurSel(hWndCB, -1);
}
}
static void fillTempLBWithDirs(HWND hWndTempLB, LPSTR lpszDir)
{
BOOL bDone = FALSE;
WIN32_FIND_DATA ffdataStruct;
char szPath[_MAX_PATH];
char szFileName[_MAX_PATH];
lstrcpy(szPath, lpszDir);
if(szPath[lstrlen(szPath) - 1] == '\\')
szPath[lstrlen(szPath) - 1] = '\0';
lstrcpy(szFileName, szPath);
lstrcat(szFileName, "\\*");
HANDLE handle = FindFirstFile(szFileName, &ffdataStruct);
if(handle == INVALID_HANDLE_VALUE)
{
FindClose(handle);
return;
}
while(!bDone)
{
lstrcpy(szFileName, szPath);
lstrcat(szFileName, "\\");
lstrcat(szFileName, ffdataStruct.cFileName);
if(ffdataStruct. dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
char szStringToAdd[_MAX_PATH + 2];
lstrcpy(szStringToAdd, "[");
lstrcat(szStringToAdd, ffdataStruct.cFileName);
lstrcat(szStringToAdd, "]");
CharLower(szStringToAdd);
ListBox_AddString(hWndTempLB, szStringToAdd);
}
bDone = !FindNextFile(handle, &ffdataStruct);
}
FindClose(handle);
}
static void fillListBox(HWND hWnd, LPSTR lpszDir)
{
HWND hWndLB = GetDlgItem(hWnd, ID_LIST_DIR);
HWND hWndTempLB = GetDlgItem(hWnd, ID_LISTTEMP_DIR);
HWND hWndEdit = GetDlgItem(hWnd, ID_EDIT_DIR);
if((hWndLB == NULL) || (lpszDir == NULL))
return;
int iLastChar = lstrlen(lpszDir);
if(lpszDir[iLastChar - 1] == '\\')
lpszDir[iLastChar - 1] = '\0';
SetWindowRedraw(hWndLB, FALSE);
ListBox_ResetContent(hWndLB);
ListBox_ResetContent(hWndTempLB);
LPSTR lpszLast;
lpszLast = CharLower(lpszDir);
SetWindowText(hWndLB, lpszDir);
char szDir[_MAX_DIR];
char szFullDir[_MAX_DIR];
sprintf(szFullDir, "%s", lpszDir);
sprintf(szDir, "%s\\*.*", lpszDir);
BOOL bFirst = TRUE;
char ch;
int index;
while (TRUE)
{
LPSTR lpsz;
if((lpszDir[0] == '\\') && (lpszDir[1] == '\\') && bFirst)
lpsz = strchr(lpszLast + lstrlen(szUNCRoot), '\\');
else
lpsz = strchr(lpszLast, '\\');
if(lpsz != NULL) {
if (bFirst)
ch = *(++lpsz);
else
ch = *lpsz;
*lpsz = 0;
}
else
{
//If we're looking at a drive only, then append a backslash
if (lpszLast == lpszDir && bFirst)
lstrcat(lpszLast, "\\");
}
//Add the drive string--includes the last one where lpsz == NULL
index = ListBox_AddString(hWndLB, lpszLast);
UINT i = (NULL != lpsz) ? ID_ICON_FOLDEROPEN : ID_ICON_OPENSELECT;
ListBox_SetItemData(hWndLB, index, MAKELONG(index, i));
if(NULL == lpsz)
break;
//Restore last character.
*lpsz = ch;
lpsz += (bFirst) ? 0 : 1;
bFirst=FALSE;
lpszLast = lpsz;
}
int indent = index + 1;
//Get available directories
fillTempLBWithDirs(hWndTempLB, lpszDir);
int itemCount = ListBox_GetCount(hWndTempLB);
for (int i = 0; i < itemCount; i++) {
index = ListBox_GetText(hWndTempLB, i, lpszDir);
//Skip directories beginning with . (skipping . and ..)
if(lpszDir[1] == '.')
continue;
//Remove the ending ']'
iLastChar = lstrlen(lpszDir);
lpszDir[iLastChar - 1] = '\0';
//Add the string to the real directory list.
index = ListBox_AddString(hWndLB, lpszDir + 1);
ListBox_SetItemData(hWndLB, index, MAKELONG(indent, ID_ICON_FOLDERCLOSED));
}
//Force a listbox repaint.
SetWindowRedraw(hWndLB, TRUE);
InvalidateRect(hWndLB, NULL, TRUE);
if(szFullDir[lstrlen(szFullDir) - 1] == ':')
lstrcat(szFullDir, "\\");
Edit_SetText(hWndEdit, szFullDir);
GetScrollRange(hWndLB, SB_VERT, (LPINT)&i, (LPINT)&index);
if(!(i == 0 && index == 0))
ListBox_SetTopIndex(hWndLB, max((int)(index - 2), 0));
ListBox_SetCurSel(hWndLB, indent - 1);
}
static void onDrawItem(LPDRAWITEMSTRUCT lpdis, BOOL bDrive)
{
if((int)lpdis->itemID < 0)
return;
char szItem[_MAX_DIR];
DWORD dwItemData;
if(bDrive)
{
dwItemData = ComboBox_GetItemData(lpdis->hwndItem, lpdis->itemID);
ComboBox_GetLBText(lpdis->hwndItem, lpdis->itemID, szItem);
}
else
{
dwItemData = ListBox_GetItemData(lpdis->hwndItem, lpdis->itemID);
ListBox_GetText(lpdis->hwndItem, lpdis->itemID, szItem);
}
if(lpdis->itemAction & (ODA_DRAWENTIRE | ODA_SELECT))
{
COLORREF colorText;
COLORREF colorBack;
if(lpdis->itemState & ODS_SELECTED)
{
colorText = SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
colorBack = SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
}
HICON hIcon;
int indent = 0;
if(bDrive)
{
int iType=(int)HIWORD(dwItemData);
switch (iType)
{
case DRIVE_REMOVABLE:
hIcon = hIconDrives[0];
break;
case DRIVE_FIXED:
hIcon = hIconDrives[1];
break;
case DRIVE_REMOTE:
hIcon = hIconDrives[2];
break;
case DRIVE_CDROM:
hIcon = hIconDrives[3];
break;
case DRIVE_RAMDISK:
hIcon = hIconDrives[4];
break;
}
}
else
{
int iconID = (int)HIWORD(lpdis->itemData);
switch (iconID)
{
case ID_ICON_FOLDERCLOSED:
hIcon = hIconFolders[0];
break;
case ID_ICON_FOLDEROPEN:
hIcon = hIconFolders[1];
break;
case ID_ICON_OPENSELECT:
hIcon = hIconFolders[2];
break;
}
indent = 4 * (1 + LOWORD(lpdis->itemData));
}
ExtTextOut(lpdis->hDC,
lpdis->rcItem.left + ITEM_LEFTMARGIN + ITEM_BITMAPWIDTH + ITEM_GAP + indent,
lpdis->rcItem.top,
ETO_OPAQUE | ETO_CLIPPED,
&lpdis->rcItem,
szItem,
lstrlen(szItem),
NULL);
BOOL res = DrawIcon(lpdis->hDC,
lpdis->rcItem.left + ITEM_LEFTMARGIN + indent,
lpdis->rcItem.top,
hIcon);
if(lpdis->itemState & ODS_SELECTED)
{
SetTextColor(lpdis->hDC, colorText);
SetBkColor(lpdis->hDC, colorBack);
}
}
if((lpdis->itemAction & ODA_FOCUS) || (lpdis->itemState & ODS_FOCUS))
DrawFocusRect(lpdis->hDC, &lpdis->rcItem);
}
static void fillUNCRootArray(LPSTR lpsz)
{
char szCurDir[_MAX_PATH];
_getcwd(szCurDir, sizeof(szCurDir));
lstrcpy(szUNCRoot, lpsz);
if(szUNCRoot[lstrlen(szUNCRoot) - 1] == '\\')
szUNCRoot[lstrlen(szUNCRoot) - 1] = '\0';
for(;;)
{
LPSTR lptemp = strrchr(szUNCRoot, '\\');
if(lptemp == NULL)
break;
*lptemp = '\0';
if(_chdir(szUNCRoot) == -1)
{
*lptemp = '\\';
break;
}
}
_chdir(szCurDir);
}
static void onInitDialog(HWND hWnd, LPSTR lpsz)
{
hWndDirPicker = hWnd;
lpszStringToReturn = lpsz;
hIconDrives[0] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_DRIVEFLOPPY));
hIconDrives[1] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_DRIVEHARD));
hIconDrives[2] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_DRIVENETWORK));
hIconDrives[3] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_DRIVECDROM));
hIconDrives[4] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_DRIVERAM));
hIconFolders[0] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_FOLDERCLOSED));
hIconFolders[1] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_FOLDEROPEN));
hIconFolders[2] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_OPENSELECT));
if(lpsz[0] == '\0')
_getcwd(lpsz, _MAX_PATH);
else if(lpsz[lstrlen(lpsz) - 1] == ':')
lstrcat(lpsz, "\\");
int ret = _chdir(lpsz);
if(ret == -1)
{
char szText[_MAX_PATH + 80];
sprintf(szText, "The specified directory %s\ncannot be found", lpsz);
MessageBox(GetParent(hWnd), szText, "Choose Directory", MB_ICONEXCLAMATION|MB_OK);
_getcwd(lpsz, _MAX_PATH);
}
if((lpsz[0] == '\\') && (lpsz[1] == '\\'))
fillUNCRootArray(lpsz);
fillListBox(hWnd, lpsz);
fillComboBox(hWnd);
}
static void shutDialog(HWND hWnd)
{
szUNCRoot[0] = '\0';
}
static void onCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify)
{
char szCurDir[_MAX_PATH];
switch(id)
{
case ID_LIST_DIR:
if(codeNotify == LBN_DBLCLK)
{
int index = ListBox_GetCurSel(hWndCtl);
DWORD dwItemData = ListBox_GetItemData(hWndCtl, index);
if(HIWORD(dwItemData) == ID_ICON_OPENSELECT)
{
shutDialog(hWnd);
char szString[_MAX_PATH];
Edit_GetText(GetDlgItem(hWndDirPicker, ID_EDIT_DIR), szString, sizeof(szString));
lstrcpy(lpszStringToReturn, szString);
EndDialog(hWnd, IDOK);
break;
}
ListBox_GetText(hWndCtl, index, szCurDir);
char szDir[_MAX_DIR];
LPSTR lpsz;
if((HIWORD(dwItemData) == ID_ICON_FOLDEROPEN) && (index != 0))
{
GetWindowText(hWndCtl, szDir, sizeof(szDir));
lpsz=_fstrstr(szDir, szCurDir);
*(lpsz + lstrlen(szCurDir)) = '\0';
lstrcpy(szCurDir, szDir);
}
if (_chdir(szCurDir) == 0)
{
_getcwd(szCurDir, _MAX_PATH);
fillListBox(hWndDirPicker, szCurDir);
}
}
break;
case ID_COMBO_DIR:
if(codeNotify == CBN_SELCHANGE)
{
char szDrive[80];
int index = ComboBox_GetCurSel(hWndCtl);
if(index == CB_ERR)
break;
ComboBox_GetLBText(hWndCtl, index, szDrive);
int iCurDrive = _getdrive();
Retry:
HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
SetCapture(hWndDirPicker);
if((0 == _chdrive((int)(szDrive[0] - 'a' + 1))) && (NULL != _getcwd(szCurDir, _MAX_PATH)))
{
fillListBox(hWndDirPicker, szCurDir);
ListBox_SetTopIndex(GetDlgItem(hWndDirPicker, ID_LIST_DIR), 0);
SetCursor(hCursorOld);
ReleaseCapture();
break;
}
SetCursor(hCursorOld);
ReleaseCapture();
char szText[80];
sprintf(szText, "Cannot read drive %c:", szDrive[0]);
if(IDRETRY == MessageBox(hWndDirPicker, szText, "Choose Directory", MB_ICONEXCLAMATION|MB_RETRYCANCEL))
goto Retry;
//Changing drives failed so restore drive and selection
_chdrive(iCurDrive);
sprintf(szDrive, "%c:", (char)(iCurDrive + 'a' - 1));
index = ComboBox_SelectString(hWndCtl, -1, szDrive);
}
break;
case IDOK:
shutDialog(hWnd);
char szString[_MAX_PATH];
Edit_GetText(GetDlgItem(hWndDirPicker, ID_EDIT_DIR), szString, sizeof(szString));
lstrcpy(lpszStringToReturn, szString);
EndDialog(hWnd, IDOK);
break;
case IDCANCEL:
shutDialog(hWnd);
lpszStringToReturn[0] = '\0';
EndDialog(hWnd, IDCANCEL);
break;
default:
break;
}
}
static BOOL CALLBACK DirPickDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg) {
case WM_INITDIALOG:
onInitDialog(hWnd, (LPSTR)lParam);
break;
case WM_COMMAND:
HANDLE_WM_COMMAND(hWnd, wParam, lParam, onCommand);
break;
case WM_MEASUREITEM:
{
static int cyItem = -1; //Height of a listbox item
LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam;
if(cyItem == -1)
{
HFONT hFont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0L);
if(hFont == NULL)
hFont = GetStockFont(SYSTEM_FONT);
HDC hDC = GetDC(hWnd);
HFONT hFontOld = SelectFont(hDC, hFont);
TEXTMETRIC tm;
GetTextMetrics(hDC, &tm);
cyItem = max(ITEM_BITMAPHEIGHT, tm.tmHeight);
SelectFont(hDC, hFontOld);
ReleaseDC(hWnd, hDC);
}
lpmis->itemHeight = cyItem;
}
break;
case WM_DRAWITEM:
onDrawItem((LPDRAWITEMSTRUCT)lParam, ((UINT)wParam == ID_COMBO_DIR));
return TRUE; // to prevent default action in listbox (drawing focus)
default:
return FALSE;
}
return TRUE;
}
/*
* DriveType
*
* Purpose:
* Augments the Windows API GetDriveType with a call to the CD-ROM
* extensions to determine if a drive is a floppy, hard disk, CD-ROM,
* RAM-drive, or networked drive.
*
* Parameters:
* iDrive UINT containing the zero-based drive index
*
* Return Value:
* UINT One of the following values describing the drive:
* DRIVE_FLOPPY, DRIVE_HARD, DRIVE_CDROM, DRIVE_RAMDISK,
* DRIVE_NETWORK.
*
* Copyright (c)1992 Kraig Brockschmidt, All Right Reserved
* Compuserve: 70750,2344
* Internet : kraigb@microsoft.com
*
*/
UINT DriveType(UINT iDrive)
{
//Validate possible drive indices
if((0 > iDrive) || (25 < iDrive))
return (UINT)-1;
static char path[] = "d:\\";
path[0] = 'a' + iDrive;
int iType = GetDriveType(path);
/*
* Under Windows NT, GetDriveType returns complete information
* not provided under Windows 3.x which we now get through other
* means.
*/
return iType;
}
BOOL PickupDirectory(HWND hWndOwner, LPSTR lpszString)
{
if(hWndOwner == NULL)
hWndOwner = GetDesktopWindow();
int ret = DialogBoxParam(hInst, MAKEINTRESOURCE(ID_DIALOG_CHOOSEDIR), hWndOwner, DirPickDlgProc, (LPARAM)lpszString);
return (ret == IDOK);
}