mirror of https://github.com/lianthony/NT4.0
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.
639 lines
19 KiB
639 lines
19 KiB
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef WINNT
|
|
#define CXIMAGEGAP 0 // NT doesn't align menu items no more
|
|
#else
|
|
#define CXIMAGEGAP 6
|
|
#endif
|
|
|
|
#define MAXEXTSIZE (PATH_CCH_EXT + 2) // Max length of file extension.
|
|
|
|
#define SRCSTENCIL 0x00B8074AL
|
|
|
|
typedef struct {
|
|
TCHAR szMenuText[CCH_KEYMAX];
|
|
TCHAR szExt[MAXEXTSIZE];
|
|
TCHAR szClass[CCH_KEYMAX];
|
|
DWORD dwFlags;
|
|
int iImage;
|
|
} NEWOBJECTINFO, * LPNEWOBJECTINFO;
|
|
LPNEWOBJECTINFO g_lpnoiLast = NULL;
|
|
|
|
#define NEWTYPE_DATA 1
|
|
#define NEWTYPE_FILE 2
|
|
#define NEWTYPE_NULL 3
|
|
#define NEWTYPE_COMMAND 4
|
|
|
|
typedef struct {
|
|
int type;
|
|
LPVOID lpData;
|
|
DWORD cbData;
|
|
HKEY hkeyNew;
|
|
} NEWFILEINFO, *LPNEWFILEINFO;
|
|
|
|
// this is basically the same as filemenu_getitemdata
|
|
LPNEWOBJECTINFO WINAPI NewObjMenu_GetItemData(HMENU hmenu, UINT iItem)
|
|
{
|
|
MENUITEMINFO mii;
|
|
|
|
mii.cbSize = SIZEOF(MENUITEMINFO);
|
|
mii.fMask = MIIM_DATA | MIIM_STATE;
|
|
mii.cch = 0; // just in case...
|
|
|
|
if (GetMenuItemInfo(hmenu, iItem, TRUE, &mii))
|
|
return (LPNEWOBJECTINFO)mii.dwItemData;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
extern TCHAR const c_szFileName[];
|
|
extern TCHAR const c_szCommand[];
|
|
extern TCHAR const c_szConfig[];
|
|
TCHAR const c_szShellNew[] = TEXT("ShellNew");
|
|
TCHAR const c_szData[] = TEXT("Data");
|
|
TCHAR const c_szNullFile[] = TEXT("NullFile");
|
|
TCHAR const c_szNoExt[] = TEXT("NoExtension");
|
|
|
|
// ShellNew config flags
|
|
#define SNCF_DEFAULT 0x0000
|
|
#define SNCF_NOEXT 0x0001
|
|
|
|
|
|
void GetConfigFlags(HKEY hkey, DWORD * pdwFlags)
|
|
{
|
|
DWORD cbData;
|
|
TCHAR szTemp[MAX_PATH];
|
|
|
|
*pdwFlags = SNCF_DEFAULT;
|
|
|
|
if (cbData = ARRAYSIZE(szTemp), (RegQueryValueEx(hkey, (LPTSTR)c_szNoExt, 0, NULL, (LPBYTE)szTemp, &cbData) == ERROR_SUCCESS)) {
|
|
*pdwFlags |= SNCF_NOEXT;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL GetNewFileInfoForKey(HKEY hkeyExt, LPNEWFILEINFO lpnfi, DWORD * pdwFlags)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
HKEY hKey; // this gets the \\.ext\progid key
|
|
HKEY hkeyNew;
|
|
TCHAR szProgID[80];
|
|
LONG lSize = SIZEOF(szProgID);
|
|
|
|
// open the Newcommand
|
|
if (RegQueryValue(hkeyExt, NULL, szProgID, &lSize) != ERROR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (RegOpenKey(hkeyExt, szProgID, &hKey) != ERROR_SUCCESS) {
|
|
hKey = hkeyExt;
|
|
}
|
|
|
|
if (RegOpenKey(hKey, c_szShellNew, &hkeyNew) == ERROR_SUCCESS) {
|
|
DWORD dwType;
|
|
DWORD cbData;
|
|
TCHAR szTemp[MAX_PATH];
|
|
HKEY hkeyConfig;
|
|
|
|
// Are there any config flags?
|
|
if (pdwFlags) {
|
|
|
|
if (RegOpenKey(hkeyNew, c_szConfig, &hkeyConfig) == ERROR_SUCCESS) {
|
|
GetConfigFlags(hkeyConfig, pdwFlags);
|
|
RegCloseKey(hkeyConfig);
|
|
} else
|
|
*pdwFlags = 0;
|
|
}
|
|
|
|
if (cbData = SIZEOF(szTemp), (RegQueryValueEx(hkeyNew, (LPTSTR)c_szNullFile, 0, &dwType, (LPBYTE)szTemp, &cbData) == ERROR_SUCCESS)) {
|
|
|
|
fRet = TRUE;
|
|
if (lpnfi)
|
|
lpnfi->type = NEWTYPE_NULL;
|
|
|
|
|
|
} else if (cbData = SIZEOF(szTemp), (RegQueryValueEx(hkeyNew, (LPTSTR)c_szFileName, 0, &dwType, (LPBYTE)szTemp, &cbData) == ERROR_SUCCESS) && (dwType == REG_SZ)) {
|
|
|
|
fRet = TRUE;
|
|
if (lpnfi) {
|
|
lpnfi->type = NEWTYPE_FILE;
|
|
lpnfi->hkeyNew = hkeyNew; // store this away so we can find out which one held the file easily
|
|
Assert((LPTSTR*)lpnfi->lpData == NULL);
|
|
lpnfi->lpData = (void*)LocalAlloc(LPTR, (lstrlen(szTemp) + 1) * SIZEOF(TCHAR));
|
|
lstrcpy((LPTSTR)lpnfi->lpData, szTemp);
|
|
|
|
hkeyNew = NULL;
|
|
}
|
|
} else if (cbData = SIZEOF(szTemp), (RegQueryValueEx(hkeyNew, (LPTSTR)c_szCommand, 0, &dwType, (LPBYTE)szTemp, &cbData) == ERROR_SUCCESS) && (dwType == REG_SZ)) {
|
|
|
|
fRet = TRUE;
|
|
if (lpnfi) {
|
|
lpnfi->type = NEWTYPE_COMMAND;
|
|
lpnfi->hkeyNew = hkeyNew; // store this away so we can find out which one held the command easily
|
|
Assert((LPTSTR*)lpnfi->lpData == NULL);
|
|
lpnfi->lpData = (void*)LocalAlloc(LPTR, (lstrlen(szTemp) + 1) * SIZEOF(TCHAR));
|
|
lstrcpy((LPTSTR)lpnfi->lpData, szTemp);
|
|
|
|
hkeyNew = NULL;
|
|
}
|
|
} else if ((RegQueryValueEx(hkeyNew, (LPTSTR)c_szData, 0, &dwType, NULL, &cbData) == ERROR_SUCCESS) && cbData) {
|
|
|
|
// yes! the data for a new file is stored in the registry
|
|
fRet = TRUE;
|
|
// do they want the data?
|
|
if (lpnfi)
|
|
{
|
|
lpnfi->type = NEWTYPE_DATA;
|
|
lpnfi->cbData = cbData;
|
|
lpnfi->lpData = (void*)LocalAlloc(LPTR, cbData);
|
|
#ifdef UNICODE
|
|
if (lpnfi->lpData)
|
|
{
|
|
if (dwType == REG_SZ)
|
|
{
|
|
LPWSTR pszTemp;
|
|
|
|
//
|
|
// Get the Unicode data from the registry.
|
|
//
|
|
pszTemp = (LPWSTR)LocalAlloc(LPTR, cbData);
|
|
if (pszTemp)
|
|
{
|
|
RegQueryValueEx(hkeyNew, (LPTSTR)c_szData, 0, &dwType, (LPBYTE)pszTemp, &cbData);
|
|
|
|
lpnfi->cbData =
|
|
WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
pszTemp,
|
|
-1,
|
|
lpnfi->lpData,
|
|
cbData,
|
|
NULL,
|
|
NULL );
|
|
if (lpnfi->cbData == 0)
|
|
{
|
|
LocalFree(lpnfi->lpData);
|
|
lpnfi->lpData = NULL;
|
|
}
|
|
|
|
LocalFree(pszTemp);
|
|
}
|
|
else
|
|
{
|
|
LocalFree(lpnfi->lpData);
|
|
lpnfi->lpData = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RegQueryValueEx(hkeyNew, (LPTSTR)c_szData, 0, &dwType, lpnfi->lpData, &cbData);
|
|
}
|
|
}
|
|
#else
|
|
if (lpnfi->lpData)
|
|
{
|
|
RegQueryValueEx(hkeyNew, (LPTSTR)c_szData, 0, &dwType, lpnfi->lpData, &cbData);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
if (hkeyNew)
|
|
RegCloseKey(hkeyNew);
|
|
}
|
|
|
|
if (hKey != hkeyExt) {
|
|
RegCloseKey(hKey);
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
BOOL GetNewFileInfoForExtension(LPTSTR lpszExt, LPTSTR lpszClass, LPNEWFILEINFO lpnfi, DWORD * pdwFlags)
|
|
{
|
|
TCHAR szSubKey[128];
|
|
TCHAR szValue[80];
|
|
|
|
LONG lSize = SIZEOF(szValue);
|
|
HKEY hkeyNew;
|
|
BOOL fRet = FALSE;;
|
|
|
|
// check the new keys under the class id (if any)
|
|
wsprintf(szSubKey, c_szSSlashS, lpszClass, c_szCLSID);
|
|
lSize = SIZEOF(szValue);
|
|
if (RegQueryValue(HKEY_CLASSES_ROOT, szSubKey, szValue, &lSize) == ERROR_SUCCESS) {
|
|
|
|
wsprintf(szSubKey, c_szSSlashS, c_szCLSID, szValue);
|
|
lSize = SIZEOF(szValue);
|
|
if (RegOpenKey(HKEY_CLASSES_ROOT, szSubKey, &hkeyNew) == ERROR_SUCCESS) {
|
|
|
|
fRet = GetNewFileInfoForKey(hkeyNew, lpnfi, pdwFlags);
|
|
RegCloseKey(hkeyNew);
|
|
}
|
|
}
|
|
|
|
// otherwise check under the type extension... do the extension, not the type
|
|
// so that multi-ext to 1 type will work right
|
|
if (!fRet && (RegOpenKey(HKEY_CLASSES_ROOT, lpszExt, &hkeyNew) == ERROR_SUCCESS)) {
|
|
fRet = GetNewFileInfoForKey(hkeyNew, lpnfi, pdwFlags);
|
|
RegCloseKey(hkeyNew);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
void NewObjMenu_Fill(HMENU hmenu, UINT id, int iStart)
|
|
{
|
|
TCHAR szExt[MAXEXTSIZE];
|
|
TCHAR szClass[CCH_KEYMAX];
|
|
TCHAR szDisplayName[CCH_KEYMAX];
|
|
int i;
|
|
DWORD dwFlags;
|
|
|
|
for (i = 0; RegEnumKey(HKEY_CLASSES_ROOT, i, szExt, ARRAYSIZE(szExt)) == ERROR_SUCCESS; i++)
|
|
{
|
|
LONG lSize = SIZEOF(szClass);
|
|
// find .ext that have proper class descriptions with them.
|
|
if ((szExt[0] == TEXT('.')) &&
|
|
RegQueryValue(HKEY_CLASSES_ROOT, szExt, szClass, &lSize) == ERROR_SUCCESS && (lSize > 0) &&
|
|
GetNewFileInfoForExtension(szExt, szClass, NULL, &dwFlags) &&
|
|
GetClassDescription(HKEY_CLASSES_ROOT, szClass, szDisplayName, ARRAYSIZE(szDisplayName),
|
|
GCD_MUSTHAVEOPENCMD))
|
|
{
|
|
LPNEWOBJECTINFO lpnoi = Alloc(SIZEOF(NEWOBJECTINFO));
|
|
if (lpnoi)
|
|
{
|
|
lpnoi->dwFlags = dwFlags;
|
|
|
|
lstrcpy(lpnoi->szExt, szExt);
|
|
lstrcpy(lpnoi->szClass, szClass);
|
|
lstrcpy(lpnoi->szMenuText, szDisplayName);
|
|
|
|
//BUGBUG, fix this later
|
|
lpnoi->iImage = -1; //FS_ExtensionSystemImageIndex(szExt);
|
|
// BUGBUG: if this fails we have a leak
|
|
AppendMenu(hmenu, MF_OWNERDRAW, id, (LPTSTR)lpnoi);
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugMsg(DM_TRACE, TEXT("sh TR - NewObj_Fill: filed (%x, %d)"),
|
|
hmenu, GetMenuItemCount(hmenu));
|
|
|
|
// remove dups.
|
|
// need to call GetMenuItemCount each time because
|
|
// we're removing things...
|
|
for (i = iStart; i < GetMenuItemCount(hmenu); i++) {
|
|
int j;
|
|
LPNEWOBJECTINFO lpnoi = NewObjMenu_GetItemData(hmenu, i);
|
|
for (j = GetMenuItemCount(hmenu) - 1; j > i; j--) {
|
|
LPNEWOBJECTINFO lpnoi2 = NewObjMenu_GetItemData(hmenu, j);
|
|
if ( !lstrcmpi(lpnoi->szMenuText, lpnoi2->szMenuText)) {
|
|
DeleteMenu(hmenu, j, MF_BYPOSITION);
|
|
Free(lpnoi2);
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugMsg(DM_TRACE, TEXT("sh TR - NewObj_Fill: dup removed (%x, %d)"),
|
|
hmenu, GetMenuItemCount(hmenu));
|
|
}
|
|
|
|
|
|
void WINAPI NewObjMenu_DrawItem(DRAWITEMSTRUCT *lpdi)
|
|
{
|
|
if ((lpdi->itemAction & ODA_SELECT) || (lpdi->itemAction & ODA_DRAWENTIRE))
|
|
{
|
|
DWORD dwRop;
|
|
int x, y;
|
|
SIZE sz;
|
|
LPNEWOBJECTINFO lpnoi = (LPNEWOBJECTINFO)lpdi->itemData;
|
|
|
|
// Draw the image (if there is one).
|
|
if (lpnoi->iImage != -1)
|
|
{
|
|
extern HIMAGELIST himlIconsSmall;
|
|
|
|
x = lpdi->rcItem.left+CXIMAGEGAP;
|
|
y = (lpdi->rcItem.bottom+lpdi->rcItem.top-g_cySmIcon)/2;
|
|
ImageList_Draw(himlIconsSmall, lpnoi->iImage, lpdi->hDC, x, y, ILD_TRANSPARENT);
|
|
x += g_cxSmIcon;
|
|
} else {
|
|
BITMAP bm;
|
|
HBITMAP hbmCheck;
|
|
hbmCheck = LoadBitmap(NULL, MAKEINTRESOURCE(OBM_CHECK));
|
|
GetObject(hbmCheck, SIZEOF(bm), &bm);
|
|
x = lpdi->rcItem.left + bm.bmWidth + CXIMAGEGAP;
|
|
DeleteObject(hbmCheck);
|
|
}
|
|
|
|
GetTextExtentPoint(lpdi->hDC, lpnoi->szMenuText, lstrlen(lpnoi->szMenuText), &sz);
|
|
|
|
if (lpdi->itemState & ODS_SELECTED)
|
|
{
|
|
SetBkColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHT));
|
|
SetTextColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
|
|
// REVIEW HACK - keep track of the last selected item.
|
|
g_lpnoiLast = lpnoi;
|
|
dwRop = SRCSTENCIL;
|
|
}
|
|
else
|
|
{
|
|
dwRop = SRCAND;
|
|
}
|
|
|
|
// Draw the text.
|
|
y = (lpdi->rcItem.bottom+lpdi->rcItem.top-sz.cy)/2;
|
|
|
|
ExtTextOut(lpdi->hDC, x, y, ETO_OPAQUE, &lpdi->rcItem, lpnoi->szMenuText,
|
|
lstrlen(lpnoi->szMenuText), NULL);
|
|
|
|
}
|
|
}
|
|
|
|
BOOL WINAPI NewObjMenu_InitMenuPopup(HMENU hmenu, int iStart)
|
|
{
|
|
UINT id;
|
|
LPNEWOBJECTINFO lpnoi;
|
|
|
|
lpnoi = NewObjMenu_GetItemData(hmenu, iStart);
|
|
if (lpnoi) // already initialized.
|
|
return FALSE;
|
|
|
|
id = GetMenuItemID(hmenu , iStart);
|
|
DeleteMenu(hmenu, iStart, MF_BYPOSITION);
|
|
NewObjMenu_Fill(hmenu, id, iStart);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LRESULT WINAPI NewObjMenu_MeasureItem(MEASUREITEMSTRUCT *lpmi)
|
|
{
|
|
HDC hdc;
|
|
HFONT hfont, hfontOld;
|
|
NONCLIENTMETRICS ncm;
|
|
LRESULT lres = FALSE;
|
|
LPNEWOBJECTINFO lpnoi;
|
|
|
|
lpnoi = (LPNEWOBJECTINFO)lpmi->itemData;
|
|
if (lpnoi)
|
|
{
|
|
// Get the rough height of an item so we can work out when to break the
|
|
// menu. User should really do this for us but that would be useful.
|
|
hdc = GetDC(NULL);
|
|
if (hdc)
|
|
{
|
|
// REVIEW cache out the menu font?
|
|
ncm.cbSize = SIZEOF(NONCLIENTMETRICS);
|
|
if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, SIZEOF(ncm), &ncm, FALSE))
|
|
{
|
|
hfont = CreateFontIndirect(&ncm.lfMenuFont);
|
|
if (hfont)
|
|
{
|
|
SIZE sz;
|
|
hfontOld = SelectObject(hdc, hfont);
|
|
GetTextExtentPoint(hdc, lpnoi->szMenuText, lstrlen(lpnoi->szMenuText), &sz);
|
|
lpmi->itemHeight = max (g_cySmIcon, sz.cy);
|
|
// lpmi->itemWidth = g_cxSmIcon + 2*CXIMAGEGAP + sz.cx;
|
|
lpmi->itemWidth = 2*CXIMAGEGAP + sz.cx;
|
|
SelectObject(hdc, hfontOld);
|
|
DeleteObject(hfont);
|
|
lres = TRUE;
|
|
}
|
|
}
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_ERROR, TEXT("fm_mi: Filemenu is invalid."));
|
|
}
|
|
|
|
return lres;
|
|
}
|
|
|
|
void WINAPI NewObjMenu_Destroy(HMENU hmenu, int iStart)
|
|
{
|
|
int i;
|
|
LPNEWOBJECTINFO lpnoi;
|
|
|
|
DebugMsg(DM_TRACE, TEXT("sh TR - NewObj_Destroy: called (%x, %d, %d)"),
|
|
hmenu, iStart, GetMenuItemCount(hmenu));
|
|
|
|
for (i = GetMenuItemCount(hmenu) - 1; i >= iStart; i--) {
|
|
lpnoi = NewObjMenu_GetItemData(hmenu, i);
|
|
if (lpnoi)
|
|
Free(lpnoi);
|
|
|
|
//
|
|
// We need to remove them in case for File->New
|
|
//
|
|
DeleteMenu(hmenu, i, MF_BYPOSITION);
|
|
}
|
|
}
|
|
|
|
BOOL CreateWriteCloseFile(HWND hwnd, LPTSTR szFileName, LPVOID lpData, DWORD cbData)
|
|
{
|
|
HFILE hfile = Win32_lcreat(szFileName, 0);
|
|
if (hfile != HFILE_ERROR) {
|
|
if (cbData) {
|
|
_lwrite(hfile, lpData, cbData);
|
|
}
|
|
_lclose(hfile);
|
|
return TRUE;
|
|
} else {
|
|
PathRemoveExtension(szFileName);
|
|
SHSysErrorMessageBox(hwnd, NULL, IDS_CANNOTCREATEFILE,
|
|
GetLastError(), PathFindFileName(szFileName),
|
|
MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT NewObjMenu_RunCommand(HWND hwnd, LPTSTR pszPath, LPTSTR pszRun)
|
|
{
|
|
HRESULT hres;
|
|
SHELLEXECUTEINFO ei;
|
|
TCHAR szCommand[MAX_PATH];
|
|
LPTSTR pszArgs;
|
|
|
|
lstrcpy(szCommand, pszRun);
|
|
PathRemoveArgs(szCommand);
|
|
|
|
// Attempt to include the hwnd and path in the command line
|
|
|
|
pszArgs = ShellConstructMessageString(HINST_THISDLL, PathGetArgs(pszRun), (DWORD)hwnd, (LPTSTR)pszPath);
|
|
|
|
if (pszArgs) {
|
|
FillExecInfo(ei, hwnd, NULL, szCommand, pszArgs, NULL, SW_SHOWNORMAL);
|
|
if (ShellExecuteEx(&ei)) {
|
|
// Return S_FALSE because ShellExecuteEx is not atomic
|
|
hres = S_FALSE;
|
|
}
|
|
else
|
|
hres = E_FAIL;
|
|
|
|
SHFree(pszArgs);
|
|
} else
|
|
hres = E_OUTOFMEMORY;
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
//
|
|
// This function create a new file by copying a template file.
|
|
//
|
|
// Parameters:
|
|
// hwnd -- Specifies the parent/owner window
|
|
// szPath -- Specifies the name of new file to be created.
|
|
// lpnfi -- Specifies the new file info
|
|
//
|
|
// Returns:
|
|
// Returns:
|
|
// S_OK, if succeeded.
|
|
// HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), if failed because the template file does not exist.
|
|
// E_FAIL, if failed for other reason.
|
|
//
|
|
HRESULT NewObjMenu_CopyTemplate(HWND hwnd, LPTSTR szPath, LPNEWFILEINFO lpnfi)
|
|
{
|
|
TCHAR szSrc[MAX_PATH + 1];
|
|
TCHAR szFileName[MAX_PATH +1];
|
|
// now do the actual restore.
|
|
SHFILEOPSTRUCT sFileOp =
|
|
{
|
|
hwnd,
|
|
FO_COPY,
|
|
szSrc,
|
|
szPath,
|
|
FOF_NOCONFIRMATION | FOF_MULTIDESTFILES | FOF_SILENT,
|
|
} ;
|
|
|
|
lstrcpy(szFileName, (LPTSTR)lpnfi->lpData);
|
|
if (PathIsFileSpec(szFileName)) {
|
|
if (!SHGetSpecialFolderPath(NULL, szSrc, CSIDL_TEMPLATES, FALSE))
|
|
return FALSE;
|
|
|
|
PathAppend(szSrc, szFileName);
|
|
} else {
|
|
lstrcpy(szSrc, szFileName);
|
|
}
|
|
|
|
if (!PathFileExists(szSrc)) {
|
|
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
}
|
|
|
|
szSrc[lstrlen(szSrc) + 1] = TEXT('\0'); // double null terminate;
|
|
return ((SHFileOperation(&sFileOp) == 0) && !sFileOp.fAnyOperationsAborted) ?
|
|
S_OK : E_FAIL;
|
|
}
|
|
|
|
//
|
|
// This function creates a new file.
|
|
//
|
|
// HACK: Some parameters (extension, class, ...) are passed via global
|
|
// variable (g_lpnoLast).
|
|
//
|
|
// Parameters:
|
|
// hwnd -- Specifies the parent/owner window
|
|
// pidlParent -- Specifies the parent folder
|
|
// ppidl -- Specifies the pointer to output pidl
|
|
//
|
|
// Return:
|
|
// S_OK, if succeeded.
|
|
//
|
|
HRESULT WINAPI NewObjMenu_DoItToMe(HWND hwnd, LPCITEMIDLIST pidlParent, LPITEMIDLIST *ppidl)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
TCHAR szFileSpec[MAX_PATH+80]; // Add some slop incase we overflow
|
|
NEWFILEINFO nfi;
|
|
DWORD dwError;
|
|
HRESULT hres = NOERROR;
|
|
|
|
nfi.lpData = NULL;
|
|
nfi.hkeyNew = NULL;
|
|
if (g_lpnoiLast == NULL)
|
|
return ResultFromScode(E_FAIL);
|
|
|
|
SHGetPathFromIDList(pidlParent,szPath);
|
|
if (IsLFNDrive(szPath)) {
|
|
|
|
LoadString(HINST_THISDLL, IDS_NEW, szFileSpec, ARRAYSIZE(szFileSpec));
|
|
lstrcat(szFileSpec, g_lpnoiLast->szMenuText);
|
|
|
|
if ( !(g_lpnoiLast->dwFlags & SNCF_NOEXT) )
|
|
lstrcat(szFileSpec, g_lpnoiLast->szExt);
|
|
|
|
} else {
|
|
lstrcpy(szFileSpec, g_lpnoiLast->szMenuText);
|
|
|
|
if ( !(g_lpnoiLast->dwFlags & SNCF_NOEXT) )
|
|
lstrcat(szFileSpec, g_lpnoiLast->szExt);
|
|
|
|
PathCleanupSpec(szPath, szFileSpec);
|
|
}
|
|
|
|
if (!PathYetAnotherMakeUniqueName(szPath, szPath, szFileSpec, szFileSpec))
|
|
{
|
|
dwError = ERROR_FILENAME_EXCED_RANGE;
|
|
goto Error;
|
|
}
|
|
|
|
if (!GetNewFileInfoForExtension(g_lpnoiLast->szExt, g_lpnoiLast->szClass, &nfi, NULL))
|
|
{
|
|
dwError = ERROR_BADKEY;
|
|
goto Error;
|
|
}
|
|
|
|
switch (nfi.type) {
|
|
case NEWTYPE_NULL:
|
|
if (!NewObjMenu_TryNullFileHack(hwnd, szPath)) {
|
|
// do some sort of error
|
|
hres = ResultFromScode(E_FAIL);
|
|
}
|
|
break;
|
|
|
|
case NEWTYPE_DATA:
|
|
if (!CreateWriteCloseFile(hwnd, szPath, nfi.lpData, nfi.cbData)) {
|
|
hres = ResultFromScode(E_FAIL);
|
|
}
|
|
break;
|
|
|
|
case NEWTYPE_FILE:
|
|
hres = NewObjMenu_CopyTemplate(hwnd, szPath, &nfi);
|
|
if (hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
|
{
|
|
dwError = ERROR_FILE_NOT_FOUND;
|
|
goto Error;
|
|
}
|
|
break;
|
|
|
|
case NEWTYPE_COMMAND:
|
|
hres = NewObjMenu_RunCommand(hwnd, szPath, (LPTSTR)nfi.lpData);
|
|
break;
|
|
}
|
|
|
|
if (ppidl) {
|
|
if (hres == S_OK) {
|
|
*ppidl = SHSimpleIDListFromPath(szPath);
|
|
SHChangeNotify(SHCNE_FREESPACE, SHCNF_PATH, szPath, NULL);
|
|
} else
|
|
*ppidl = NULL;
|
|
}
|
|
|
|
if (nfi.lpData)
|
|
LocalFree((HLOCAL)nfi.lpData);
|
|
|
|
if (nfi.hkeyNew)
|
|
RegCloseKey(nfi.hkeyNew);
|
|
return hres;
|
|
|
|
Error:
|
|
|
|
SHSysErrorMessageBox(hwnd, NULL, IDS_CANNOTCREATEFILE,
|
|
dwError, szFileSpec,
|
|
MB_OK | MB_ICONEXCLAMATION);
|
|
return ResultFromScode(E_FAIL);
|
|
|
|
}
|