/******************************************************************************
*
*
* Notepad2
*
* Helpers.c
*   General helper functions
*
* See Readme.txt for more information about this source code.
* Please send me your comments to this work.
*
* Distributed under the terms of the GNU General Public License,
* see License.txt for details.
*
*                                              (c) Florian Balmer 1996-2004
*                                                       textview@bluewin.ch
*                                               http://www.flos-freeware.ch
*
*
******************************************************************************/
#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <commctrl.h>
#include <stdio.h>
#include <string.h>
#include "appreg.h"
#include "helpers.h"
#include "resource.h"



//=============================================================================
//
//  BeginWaitCursor()
//
void BeginWaitCursor()
{

  DestroyCursor(
    SetCursor(
    LoadCursor(NULL,IDC_WAIT)));

}


//=============================================================================
//
//  EndWaitCursor()
//
void EndWaitCursor()
{

  DestroyCursor(
    SetCursor(
    LoadCursor(NULL,IDC_ARROW)));

}


//=============================================================================
//
//  KeepWindowsAlive()
//
/*void KeepWindowsAlive()
{
  MSG msg;
  if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
}*/


//=============================================================================
//
//  IsWindowsNT()
//
BOOL IsWindowsNT()
{
  OSVERSIONINFO osvi;
  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

  GetVersionEx(&osvi);

  return (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT);
}


//=============================================================================
//
//  PrivateIsAppThemed()
//
BOOL PrivateIsAppThemed()
{
  BOOL bIsAppThemed = FALSE;
  HMODULE hDll = LoadLibrary("uxtheme.dll");
  if (hDll)
  {
    FARPROC fp = GetProcAddress(hDll,"IsAppThemed");
    if (fp)
    {
      bIsAppThemed = fp();
    }
    FreeLibrary(hDll);
  }
  return bIsAppThemed;
}


//=============================================================================
//
//  SetWindowTitle()
//
BOOL SetWindowTitle(HWND hwnd,UINT uIDAppName,UINT uIDUntitled,
                    LPCSTR lpszFile,BOOL bShort,BOOL bModified,
                    UINT uIDReadOnly,BOOL bReadOnly)
{

  char szUntitled[128],szAppName[128],szReadOnly[32],szTitle[256];
  static const char *pszSep = " - ";
  static const char *pszMod = "* ";

  if (!GetString(uIDAppName,szAppName,COUNTOF(szAppName)) ||
      !GetString(uIDUntitled,szUntitled,COUNTOF(szUntitled)))
    return FALSE;

  if (bModified)
    lstrcpy(szTitle,pszMod);
  else
    lstrcpy(szTitle,"");

  if (lstrlen(lpszFile))
  {
    if (bShort && !PathIsRoot(lpszFile))
    {
      SHFILEINFO shfi;
      SHGetFileInfo2(lpszFile,0,&shfi,sizeof(SHFILEINFO),SHGFI_DISPLAYNAME);
      lstrcat(szTitle,shfi.szDisplayName);
    }
    else
      lstrcat(szTitle,lpszFile);
  }

  else
    lstrcat(szTitle,szUntitled);

  if (bReadOnly && GetString(uIDReadOnly,szReadOnly,COUNTOF(szReadOnly)))
  {
    lstrcat(szTitle," ");
    lstrcat(szTitle,szReadOnly);
  }

  lstrcat(szTitle,pszSep);
  lstrcat(szTitle,szAppName);

  return SetWindowText(hwnd,szTitle);

}


//=============================================================================
//
//  SetWindowTransparentMode()
//
void SetWindowTransparentMode(HWND hwnd,BOOL bTransparentMode)
{
  FARPROC fp;
  int  iAlphaPercent;
  BYTE bAlpha;

  if (bTransparentMode) {
    if (fp = GetProcAddress(GetModuleHandle("User32"),"SetLayeredWindowAttributes")) {
    SetWindowLong(hwnd,GWL_EXSTYLE,
      GetWindowLong(hwnd,GWL_EXSTYLE) | /*WS_EX_LAYERED*/0x00080000);

    // get opacity level from registry
    iAlphaPercent = RegGetAppIntEx("Settings","OpacityLevel",75);
    if (iAlphaPercent < 0 || iAlphaPercent > 100)
      iAlphaPercent = 75;
    bAlpha = 255 / 100 * iAlphaPercent;

    fp(hwnd,0,bAlpha,/*LWA_ALPHA*/0x00000002); } }

  else
    SetWindowLong(hwnd,GWL_EXSTYLE,
      GetWindowLong(hwnd,GWL_EXSTYLE) & ~/*WS_EX_LAYERED*/0x00080000);
}


//=============================================================================
//
//  CenterDlgInParent()
//
void CenterDlgInParent(HWND hDlg)
{

  RECT rcDlg;
  HWND hParent;
  RECT rcParent;
  RECT rcScreen;

  int xMin, yMin, xMax, yMax, x, y;

  GetWindowRect(hDlg,&rcDlg);

  hParent = GetParent(hDlg);
  GetWindowRect(hParent,&rcParent);

  SystemParametersInfo(SPI_GETWORKAREA,0,&rcScreen,0);

  xMin = 0;
  yMin = 0;

  xMax = (rcScreen.right - rcScreen.left) - (rcDlg.right - rcDlg.left);
  yMax = (rcScreen.bottom - rcScreen.top) - (rcDlg.bottom - rcDlg.top);

  if ((rcParent.right - rcParent.left) - (rcDlg.right - rcDlg.left) > 20)
    x = rcParent.left + (((rcParent.right - rcParent.left) - (rcDlg.right - rcDlg.left)) / 2);
  else
    x = rcParent.left + 70;

  if ((rcParent.bottom - rcParent.top) - (rcDlg.bottom - rcDlg.top) > 20)
    y = rcParent.top  + (((rcParent.bottom - rcParent.top) - (rcDlg.bottom - rcDlg.top)) / 2);
  else
    y = rcParent.top + 60;

  SetWindowPos(hDlg,NULL,max(xMin,min(xMax,x)),max(yMin,min(yMax,y)),0,0,SWP_NOZORDER|SWP_NOSIZE);

}


//=============================================================================
//
//  MakeBitmapButton()
//
void MakeBitmapButton(HWND hwnd,int nCtlId,HINSTANCE hInstance,UINT uBmpId)
{

  HWND hwndCtl = GetDlgItem(hwnd,nCtlId);

  if (PrivateIsAppThemed())
  {
    BITMAP bmp;
    struct { HIMAGELIST himl; RECT margin; UINT uAlign; } bi;
    HBITMAP hBmp = LoadImage(hInstance,MAKEINTRESOURCE(uBmpId),
                             IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);
    GetObject(hBmp,sizeof(BITMAP),&bmp);
    bi.himl = ImageList_Create(bmp.bmWidth,bmp.bmHeight,ILC_COLORDDB|ILC_MASK,1,0);
    ImageList_AddMasked(bi.himl,hBmp,RGB(128,128,128));
    DeleteObject(hBmp);
    SetRect(&bi.margin,0,0,0,0);
    bi.uAlign = 4/*BUTTON_IMAGELIST_ALIGN_CENTER*/;
    SendMessage(hwndCtl,0x1600+0x0002/*BCM_FIRST+BCM_SETIMAGELIST*/,0,(LPARAM)&bi);
  }

  else
  {
    DWORD dwStyle = GetWindowLong(hwndCtl,GWL_STYLE);
    dwStyle |= BS_BITMAP;
    SetWindowLong(hwndCtl,GWL_STYLE,dwStyle);

    SendMessage(hwndCtl,BM_SETIMAGE,IMAGE_BITMAP,
      (LPARAM)LoadImage(hInstance,MAKEINTRESOURCE(uBmpId),
      IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS));
  }

}


//=============================================================================
//
//  StatusSetText()
//
BOOL StatusSetText(HWND hwnd,UINT nPart,LPCSTR lpszText)
{

  UINT uFlags = (nPart == 255) ? nPart|SBT_NOBORDERS : nPart;
  return SendMessage(hwnd,SB_SETTEXT,uFlags,(LPARAM)lpszText);

}


//=============================================================================
//
//  SendWMSize()
//
LRESULT SendWMSize(HWND hwnd)
{
  RECT rc; GetClientRect(hwnd,&rc);
  return(SendMessage(hwnd,WM_SIZE,SIZE_RESTORED,
         MAKELPARAM(rc.right,rc.bottom)));
}


//=============================================================================
//
//  StatusSetTextID()
//
BOOL StatusSetTextID(HWND hwnd,UINT nPart,UINT uID)
{

  char szText[256];
  UINT uFlags = (nPart == 255) ? nPart|SBT_NOBORDERS : nPart;

  if (!uID)
  {
    SendMessage(hwnd,SB_SETTEXT,uFlags,0);
    return TRUE;
  }

  if (!GetString(uID,szText,256))
    return FALSE;

  return SendMessage(hwnd,SB_SETTEXT,uFlags,(LPARAM)szText);

}


//=============================================================================
//
//  StatusCalcPaneWidth()
//
int StatusCalcPaneWidth(HWND hwnd,LPCSTR lpsz)
{
  SIZE  size;
  HDC   hdc   = GetDC(hwnd);
  HFONT hfont = (HFONT)SendMessage(hwnd,WM_GETFONT,0,0);
  HFONT hfold = SelectObject(hdc,hfont);
  int   mmode = SetMapMode(hdc,MM_TEXT);

  GetTextExtentPoint32(hdc,lpsz,lstrlen(lpsz),&size);

  SetMapMode(hdc,mmode);
  SelectObject(hdc,hfold);
  ReleaseDC(hwnd,hdc);

  return(size.cx + 9);
}


//=============================================================================
//
//  Toolbar_SetButtonImage()
//
void Toolbar_SetButtonImage(HWND hwnd,int idCommand,int iImage)
{
  TBBUTTONINFO tbbi;

  tbbi.cbSize = sizeof(TBBUTTONINFO);
  tbbi.dwMask = TBIF_IMAGE;
  tbbi.iImage = iImage;

  SendMessage(hwnd,TB_SETBUTTONINFO,(WPARAM)idCommand,(LPARAM)&tbbi);
}


//=============================================================================
//
//  IsCmdEnabled()
//
BOOL IsCmdEnabled(HWND hwnd,UINT uId)
{

  HMENU hmenu;
  UINT ustate;

  hmenu = GetMenu(hwnd);

  SendMessage(hwnd,WM_INITMENU,(WPARAM)hmenu,0);

  ustate = GetMenuState(hmenu,uId,MF_BYCOMMAND);

  if (ustate == 0xFFFFFFFF)
    return TRUE;

  else
    return (!(ustate & (MF_GRAYED|MF_DISABLED)));

}


//=============================================================================
//
//  FormatString()
//
int FormatString(LPSTR lpOutput,int nOutput,UINT uIdFormat,...)
{

  char *p = malloc(nOutput);

  if (GetString(uIdFormat,p,nOutput))
    wvsprintf(lpOutput,p,(LPVOID)(&uIdFormat+1));

  free(p);

  return lstrlen(lpOutput);

}


//=============================================================================
//
//  FormatBytes()
//
void FormatBytes(LPSTR lpOutput,int nOutput,DWORD dwBytes)
{

  char tch[256];
  int i;
  double dBytes = dwBytes;
  static const char *pBytes[] = { "Bytes","KB","MB","GB" };

  if (dwBytes > 1023)
  {
    for (i = 0; i < 4; i++)
    {

      if (dBytes >= 1024.0)
        dBytes /= 1024.0;

      else
        break;
    }
    sprintf(tch,"%.2f",dBytes);
    GetNumberFormat(LOCALE_USER_DEFAULT,0,tch,NULL,lpOutput,nOutput);
    lstrcat(lpOutput," ");
    lstrcat(lpOutput,pBytes[i]);
  }

  else
  {
    sprintf(lpOutput,"%i",dwBytes);
    FormatNumberStr(lpOutput);
    lstrcat(lpOutput," ");
    lstrcat(lpOutput,pBytes[0]);
  }

}


///////////////////////////////////////////////////////////////////////////////
//
//
//  Name: PathIsLnkFile()
//
//  Purpose: Determine wheter pszPath is a Windows Shell Link File by
//           comparing the filename extension with ".lnk"
//
//  Manipulates:
//
BOOL PathIsLnkFile(LPCSTR pszPath)
{

  //char *pszExt;

  char tchResPath[256];

  if (!pszPath || !*pszPath)
    return FALSE;

/*pszExt = strrchr(pszPath,'.');

  if (!pszExt)
    return FALSE;

  if (!lstrcmpi(pszExt,".lnk"))
    return TRUE;

  else
    return FALSE;*/

  //if (!lstrcmpi(PathFindExtension(pszPath),".lnk"))
  //  return TRUE;

  //else
  //  return FALSE;

  if (lstrcmpi(PathFindExtension(pszPath),".lnk"))
    return FALSE;

  else
    return PathGetLnkPath(pszPath,tchResPath,COUNTOF(tchResPath));

}


///////////////////////////////////////////////////////////////////////////////
//
//
//  Name: PathGetLnkPath()
//
//  Purpose: Try to get the path to which a lnk-file is linked
//
//
//  Manipulates: pszResPath
//
BOOL PathGetLnkPath(LPCSTR pszLnkFile,LPSTR pszResPath,int cchResPath)
{

  IShellLink       *psl;
  WIN32_FIND_DATA  fd;
  BOOL             bSucceeded = FALSE;

  if (SUCCEEDED(CoCreateInstance(&CLSID_ShellLink,NULL,
                                 CLSCTX_INPROC_SERVER,
                                 &IID_IShellLink,&psl)))
  {
    IPersistFile *ppf;

    if (SUCCEEDED(psl->lpVtbl->QueryInterface(psl,&IID_IPersistFile,&ppf)))
    {
      WORD wsz[MAX_PATH];

      MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,
                          pszLnkFile,-1,wsz,MAX_PATH);

      if (SUCCEEDED(ppf->lpVtbl->Load(ppf,wsz,STGM_READ)))
      {
        if (NOERROR == psl->lpVtbl->GetPath(psl,pszResPath,cchResPath,&fd,0))
          bSucceeded = TRUE;
      }
      ppf->lpVtbl->Release(ppf);
    }
    psl->lpVtbl->Release(psl);
  }

  // This additional check seems reasonable
  if (!lstrlen(pszResPath))
    bSucceeded = FALSE;

  if (bSucceeded) {
    ExpandEnvironmentStringsEx(pszResPath,cchResPath);
    PathCanonicalizeEx(pszResPath); }

  return(bSucceeded);

}


///////////////////////////////////////////////////////////////////////////////
//
//
//  Name: PathIsLnkToDirectory()
//
//  Purpose: Determine wheter pszPath is a Windows Shell Link File which
//           refers to a directory
//
//  Manipulates: pszResPath
//
PathIsLnkToDirectory(LPCSTR pszPath,LPSTR pszResPath,int cchResPath)
{

  char tchResPath[MAX_PATH];

  if (PathIsLnkFile(pszPath)) {

    if (PathGetLnkPath(pszPath,tchResPath,sizeof(char)*COUNTOF(tchResPath))) {

      if (PathIsDirectory(tchResPath)) {

        lstrcpyn(pszResPath,tchResPath,cchResPath);
        return (TRUE); }

      else
        return FALSE; }

    else
      return FALSE; }

  else
    return FALSE;

}


///////////////////////////////////////////////////////////////////////////////
//
//
//  Name: PathCreateDeskLnk()
//
//  Purpose: Modified to create a desktop link to Notepad2
//
//  Manipulates:
//
BOOL PathCreateDeskLnk(LPCSTR pszDocument)
{

  char tchExeFile[MAX_PATH];
  char tchDocTemp[MAX_PATH];
  char tchArguments[MAX_PATH+16];
  char tchLinkDir[MAX_PATH];
  char tchDescription[64];

  char tchLnkFileName[MAX_PATH];

  IShellLink *psl;
  BOOL bSucceeded = FALSE;
  BOOL fMustCopy;

  if (!pszDocument || lstrlen(pszDocument) == 0)
    return TRUE;

  // init strings
  GetModuleFileName(NULL,tchExeFile,COUNTOF(tchExeFile));

  lstrcpy(tchDocTemp,pszDocument);
  PathQuoteSpaces(tchDocTemp);

  lstrcpy(tchArguments,"-n ");
  lstrcat(tchArguments,tchDocTemp);

  GetDefaultOpenWithDir(tchLinkDir,COUNTOF(tchLinkDir));

  GetString(IDS_LINKDESCRIPTION,tchDescription,COUNTOF(tchDescription));

  // Try to construct a valid filename...
  if (!SHGetNewLinkInfo(pszDocument,tchLinkDir,tchLnkFileName,&fMustCopy,SHGNLI_PREFIXNAME))
    return(FALSE);

  if (SUCCEEDED(CoCreateInstance(&CLSID_ShellLink,NULL,
                                 CLSCTX_INPROC_SERVER,
                                 &IID_IShellLink,&psl)))
  {
    IPersistFile *ppf;

    if (SUCCEEDED(psl->lpVtbl->QueryInterface(psl,&IID_IPersistFile,&ppf)))
    {
      WORD wsz[MAX_PATH];

      MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,
                          tchLnkFileName,-1,wsz,MAX_PATH);

      psl->lpVtbl->SetPath(psl,tchExeFile);
      psl->lpVtbl->SetArguments(psl,tchArguments);
      psl->lpVtbl->SetDescription(psl,tchDescription);

      if (SUCCEEDED(ppf->lpVtbl->Save(ppf,wsz,TRUE)))
        bSucceeded = TRUE;

      ppf->lpVtbl->Release(ppf);
    }
    psl->lpVtbl->Release(psl);
  }

  return(bSucceeded);

}


///////////////////////////////////////////////////////////////////////////////
//
//
//  Name: PathCreateFavLnk()
//
//  Purpose: Modified to create a Notepad2 favorites link
//
//  Manipulates:
//
BOOL PathCreateFavLnk(LPCSTR pszName,LPCSTR pszTarget,LPCSTR pszDir)
{

  char tchLnkFileName[MAX_PATH];

  IShellLink *psl;
  BOOL bSucceeded = FALSE;

  if (!pszName || lstrlen(pszName) == 0)
    return TRUE;

  lstrcpy(tchLnkFileName,pszDir);
  PathAppend(tchLnkFileName,pszName);
  lstrcat(tchLnkFileName,".lnk");

  if (PathFileExists(tchLnkFileName))
    return FALSE;

  if (SUCCEEDED(CoCreateInstance(&CLSID_ShellLink,NULL,
                                 CLSCTX_INPROC_SERVER,
                                 &IID_IShellLink,&psl)))
  {
    IPersistFile *ppf;

    if (SUCCEEDED(psl->lpVtbl->QueryInterface(psl,&IID_IPersistFile,&ppf)))
    {
      WORD wsz[MAX_PATH];

      MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,
                          tchLnkFileName,-1,wsz,MAX_PATH);

      psl->lpVtbl->SetPath(psl,pszTarget);

      if (SUCCEEDED(ppf->lpVtbl->Save(ppf,wsz,TRUE)))
        bSucceeded = TRUE;

      ppf->lpVtbl->Release(ppf);
    }
    psl->lpVtbl->Release(psl);
  }

  return(bSucceeded);

}


//=============================================================================
//
//  TrimString()
//
BOOL TrimString(LPSTR lpString)
{

  LPSTR psz;


  if (!lpString || !*lpString)
    return FALSE;

  // Trim left
  psz = lpString;

  while (*psz == ' ')
    psz = CharNext(psz);

  MoveMemory(lpString,psz,lstrlen(psz) + 1);

  // Trim right
  psz = StrEnd(lpString);

  while (*(psz = CharPrev(lpString,psz)) == ' ')
    *psz = '\0';

  return TRUE;

}


//=============================================================================
//
//  ExtractFirstArgument()
//
BOOL ExtractFirstArgument(LPCSTR lpArgs,LPSTR lpArg1,LPSTR lpArg2)
{

  LPSTR psz;
  BOOL bQuoted = FALSE;

  lstrcpy(lpArg1,lpArgs);
  if (lpArg2)
    *lpArg2 = '\0';

  if (!TrimString(lpArg1))
    return FALSE;

  if (*lpArg1 == '\"')
  {
    *lpArg1 = ' ';
    TrimString(lpArg1);
    bQuoted = TRUE;
  }

  if (bQuoted)
    psz = strchr(lpArg1,'\"');
  else
    psz = strchr(lpArg1,' ');;

  if (psz)
  {
    *psz = '\0';
    if (lpArg2)
      lstrcpy(lpArg2,psz + 1);
  }

  TrimString(lpArg1);

  if (lpArg2)
    TrimString(lpArg2);

  return TRUE;

}


//=============================================================================
//
//  PrepareFilterStr()
//
void PrepareFilterStr(LPSTR lpFilter)
{
  LPSTR psz = StrEnd(lpFilter);
  while (psz != lpFilter)
  {
    if (*(psz = CharPrev(lpFilter,psz)) == '\n')
      *psz = '\0';
  }
}


//=============================================================================
//
//  StrTab2Space() - in place conversion
//
void StrTab2Space(LPSTR lpsz)
{
  char *c;
  while (c = strchr(lpsz,'\t'))
    *c = ' ';
}


//=============================================================================
//
//  ExpandEnvironmentStringsEx()
//
//  Adjusted for Windows 95
//
void ExpandEnvironmentStringsEx(LPSTR lpSrc,DWORD dwSrc)
{
  char szBuf[312];

  if (ExpandEnvironmentStrings(lpSrc,szBuf,COUNTOF(szBuf)))
    lstrcpyn(lpSrc,szBuf,dwSrc);
}


//=============================================================================
//
//  PathCanonicalizeEx()
//
//
void PathCanonicalizeEx(LPSTR lpSrc)
{
  char szDst[MAX_PATH];

  if (PathCanonicalize(szDst,lpSrc))
    lstrcpy(lpSrc,szDst);
}


//=============================================================================
//
//  GetLongPathNameEx()
//
//  Works fine with Windows 95!
//
extern LPMALLOC g_lpMalloc;

DWORD GetLongPathNameEx(LPCSTR lpszShortPath,LPSTR lpszLongPath,DWORD cchBuffer)
{
  WCHAR wszShortPath[MAX_PATH];
  LPSHELLFOLDER lpsfDesktop;
  ULONG chParsed = 0;
  ULONG dwAttributes = 0;
  LPITEMIDLIST  pidl = NULL;
  BOOL fSucceeded = FALSE;

  //MessageBox(GetFocus(),lpszShortPath,"GetLongPathNameEx(): lpszShortPath",0);

  // Convert lpszShortPath to a UNICODE string
  MultiByteToWideChar(
    CP_ACP,MB_PRECOMPOSED,lpszShortPath,-1,wszShortPath,MAX_PATH);

  // Get Desktop Folder
  if (NOERROR == SHGetDesktopFolder(&lpsfDesktop))
  {
    // Convert wszShortPath to a pidl
    if (NOERROR == lpsfDesktop->lpVtbl->ParseDisplayName(
                     lpsfDesktop,NULL,NULL,wszShortPath,&chParsed,&pidl,&dwAttributes))
    {
      if (SHGetPathFromIDList(pidl,lpszLongPath))
        fSucceeded = FALSE;
      g_lpMalloc->lpVtbl->Free(g_lpMalloc,pidl);
    }
  }

  //MessageBox(GetFocus(),lpszLongPath,"GetLongPathNameEx(): lpszLongPath",0);

  if (fSucceeded)
    return(lstrlen(lpszLongPath));
  else {
    if (lpszShortPath != lpszLongPath)
      lstrcpy(lpszLongPath,lpszShortPath);
    return(0); }

  cchBuffer;
}


//=============================================================================
//
//  SHGetFileInfo2() - return a default name when the file has been removed
//
DWORD_PTR SHGetFileInfo2(LPCTSTR pszPath,DWORD dwFileAttributes,
                         SHFILEINFO *psfi,UINT cbFileInfo,UINT uFlags)
{

  if (PathFileExists(pszPath))
    return SHGetFileInfo(pszPath,dwFileAttributes,psfi,cbFileInfo,uFlags);

  else
    return SHGetFileInfo(pszPath,FILE_ATTRIBUTE_NORMAL,
                         psfi,cbFileInfo,uFlags|SHGFI_USEFILEATTRIBUTES);

}


//=============================================================================
//
//  FormatNumberStr()
//
int FormatNumberStr(LPSTR lpNumberStr)
{
  char *c;
  char szSep[8];
  int  i = 0;

  if (!lstrlen(lpNumberStr))
    return(0);

  if (!GetLocaleInfo(LOCALE_USER_DEFAULT,
                     LOCALE_STHOUSAND,
                     szSep,
                     COUNTOF(szSep)))
    szSep[0] = '\'';

  c = StrEnd(lpNumberStr);

  while ((c = CharPrev(lpNumberStr,c)) != lpNumberStr)
  {
    if (++i == 3)
    {
      i = 0;
      MoveMemory(c+1,c,lstrlen(c)+1);
      *c = szSep[0];
    }
  }

  return(lstrlen(lpNumberStr));
}


//=============================================================================
//
//  SetDlgItemIntEx()
//
BOOL SetDlgItemIntEx(HWND hwnd,int nIdItem,UINT uValue)
{
  char szBuf[64];

  wsprintf(szBuf,"%u",uValue);
  FormatNumberStr(szBuf);

  return(SetDlgItemText(hwnd,nIdItem,szBuf));
}


//=============================================================================
//
//  A2W: Convert Dialog Item Text form Unicode to UTF-8 and vice versa
//
UINT GetDlgItemTextA2W(UINT uCP,HWND hDlg,int nIDDlgItem,LPSTR lpString,int nMaxCount)
{
  WCHAR wsz[256];
  UINT uRet = GetDlgItemTextW(hDlg,nIDDlgItem,wsz,256);
  WCharToMBCS(uCP,wsz,lpString,nMaxCount);
  return uRet;
}

UINT SetDlgItemTextA2W(UINT uCP,HWND hDlg,int nIDDlgItem,LPSTR lpString)
{
  WCHAR wsz[256];
  MBCSToWChar(uCP,lpString,wsz,256 / sizeof(WCHAR));
  return SetDlgItemTextW(hDlg,nIDDlgItem,wsz);
}

LRESULT ComboBox_AddStringA2W(UINT uCP,HWND hwnd,LPCSTR lpString)
{
  WCHAR wsz[256];
  MBCSToWChar(uCP,lpString,wsz,256 / sizeof(WCHAR));
  return SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)wsz);
}


//=============================================================================
//
//  CodePageFromCharSet()
//
UINT CodePageFromCharSet(UINT uCharSet)
{
  CHARSETINFO ci;
  if (TranslateCharsetInfo((DWORD*)uCharSet,&ci,TCI_SRCCHARSET))
    return(ci.ciACP);
  else
    return(GetACP());
}


//=============================================================================
//
//  GetDefaultFavoritesDir()
//
void GetDefaultFavoritesDir(LPSTR lpFavDir,int cchFavDir)
{

  LPITEMIDLIST pidl;
  LPMALLOC     lpMalloc;

  if (NOERROR == SHGetSpecialFolderLocation(
                   NULL,CSIDL_PERSONAL,&pidl))
  {
    SHGetPathFromIDList(pidl,lpFavDir);

    if (NOERROR == SHGetMalloc(&lpMalloc))
    {
      lpMalloc->lpVtbl->Free(lpMalloc,pidl);
      lpMalloc->lpVtbl->Release(lpMalloc);
    }

  }

  else
    GetWindowsDirectory(lpFavDir,cchFavDir);

}


//=============================================================================
//
//  GetDefaultOpenWithDir()
//
void GetDefaultOpenWithDir(LPSTR lpOpenWithDir,int cchOpenWithDir)
{

  LPITEMIDLIST pidl;
  LPMALLOC     lpMalloc;

  if (NOERROR == SHGetSpecialFolderLocation(
                   NULL,CSIDL_DESKTOP,&pidl))
  {
    SHGetPathFromIDList(pidl,lpOpenWithDir);

    if (NOERROR == SHGetMalloc(&lpMalloc))
    {
      lpMalloc->lpVtbl->Free(lpMalloc,pidl);
      lpMalloc->lpVtbl->Release(lpMalloc);
    }

  }

  else
    GetWindowsDirectory(lpOpenWithDir,cchOpenWithDir);

}


//=============================================================================
//
//  LoadXPM() - Load XPM Resource, must be freed by LocalFree()
//
LPSTR LoadXPM(HINSTANCE hInstRes,UINT uidRes)
{
  HRSRC hResInfo;
  HGLOBAL hResData;
  LPVOID lpvResData;
  DWORD dwResSize;

  LPSTR lpszXPM = NULL;

  if (!(hResInfo = FindResource(hInstRes,MAKEINTRESOURCE(uidRes),"xpm")))
    return NULL;

  if (hResData = LoadResource(hInstRes,hResInfo))
  {
    dwResSize = SizeofResource(hInstRes,hResInfo);
    if (lpvResData = LockResource(hResData))
    {
      lpszXPM = LocalAlloc(LPTR,dwResSize + 16);
      CopyMemory(lpszXPM ,lpvResData,dwResSize);
    }
  }
  return lpszXPM;
}


/*

  MinimizeToTray - Copyright 2000 Matthew Ellis <m.t.ellis@bigfoot.com>

  Changes made by flo:
   - Commented out: #include "stdafx.h"
   - Moved variable declaration: APPBARDATA appBarData;

*/

// MinimizeToTray
//
// A couple of routines to show how to make it produce a custom caption
// animation to make it look like we are minimizing to and maximizing
// from the system tray
//
// These routines are public domain, but it would be nice if you dropped
// me a line if you use them!
//
// 1.0 29.06.2000 Initial version
// 1.1 01.07.2000 The window retains it's place in the Z-order of windows
//     when minimized/hidden. This means that when restored/shown, it doen't
//     always appear as the foreground window unless we call SetForegroundWindow
//
// Copyright 2000 Matthew Ellis <m.t.ellis@bigfoot.com>
/*#include "stdafx.h"*/

// Odd. VC++6 winuser.h has IDANI_CAPTION defined (as well as IDANI_OPEN and
// IDANI_CLOSE), but the Platform SDK only has IDANI_OPEN...

// I don't know what IDANI_OPEN or IDANI_CLOSE do. Trying them in this code
// produces nothing. Perhaps they were intended for window opening and closing
// like the MAC provides...
#ifndef IDANI_OPEN
#define IDANI_OPEN 1
#endif
#ifndef IDANI_CLOSE
#define IDANI_CLOSE 2
#endif
#ifndef IDANI_CAPTION
#define IDANI_CAPTION 3
#endif

#define DEFAULT_RECT_WIDTH 150
#define DEFAULT_RECT_HEIGHT 30

// Returns the rect of where we think the system tray is. This will work for
// all current versions of the shell. If explorer isn't running, we try our
// best to work with a 3rd party shell. If we still can't find anything, we
// return a rect in the lower right hand corner of the screen
static VOID GetTrayWndRect(LPRECT lpTrayRect)
{
  APPBARDATA appBarData;
  // First, we'll use a quick hack method. We know that the taskbar is a window
  // of class Shell_TrayWnd, and the status tray is a child of this of class
  // TrayNotifyWnd. This provides us a window rect to minimize to. Note, however,
  // that this is not guaranteed to work on future versions of the shell. If we
  // use this method, make sure we have a backup!
  HWND hShellTrayWnd=FindWindowEx(NULL,NULL,TEXT("Shell_TrayWnd"),NULL);
  if(hShellTrayWnd)
  {
    HWND hTrayNotifyWnd=FindWindowEx(hShellTrayWnd,NULL,TEXT("TrayNotifyWnd"),NULL);
    if(hTrayNotifyWnd)
    {
      GetWindowRect(hTrayNotifyWnd,lpTrayRect);
      return;
    }
  }

  // OK, we failed to get the rect from the quick hack. Either explorer isn't
  // running or it's a new version of the shell with the window class names
  // changed (how dare Microsoft change these undocumented class names!) So, we
  // try to find out what side of the screen the taskbar is connected to. We
  // know that the system tray is either on the right or the bottom of the
  // taskbar, so we can make a good guess at where to minimize to
  /*APPBARDATA appBarData;*/
  appBarData.cbSize=sizeof(appBarData);
  if(SHAppBarMessage(ABM_GETTASKBARPOS,&appBarData))
  {
    // We know the edge the taskbar is connected to, so guess the rect of the
    // system tray. Use various fudge factor to make it look good
    switch(appBarData.uEdge)
    {
      case ABE_LEFT:
      case ABE_RIGHT:
  // We want to minimize to the bottom of the taskbar
  lpTrayRect->top=appBarData.rc.bottom-100;
  lpTrayRect->bottom=appBarData.rc.bottom-16;
  lpTrayRect->left=appBarData.rc.left;
  lpTrayRect->right=appBarData.rc.right;
  break;

      case ABE_TOP:
      case ABE_BOTTOM:
  // We want to minimize to the right of the taskbar
  lpTrayRect->top=appBarData.rc.top;
  lpTrayRect->bottom=appBarData.rc.bottom;
  lpTrayRect->left=appBarData.rc.right-100;
  lpTrayRect->right=appBarData.rc.right-16;
  break;
    }

    return;
  }

  // Blimey, we really aren't in luck. It's possible that a third party shell
  // is running instead of explorer. This shell might provide support for the
  // system tray, by providing a Shell_TrayWnd window (which receives the
  // messages for the icons) So, look for a Shell_TrayWnd window and work out
  // the rect from that. Remember that explorer's taskbar is the Shell_TrayWnd,
  // and stretches either the width or the height of the screen. We can't rely
  // on the 3rd party shell's Shell_TrayWnd doing the same, in fact, we can't
  // rely on it being any size. The best we can do is just blindly use the
  // window rect, perhaps limiting the width and height to, say 150 square.
  // Note that if the 3rd party shell supports the same configuraion as
  // explorer (the icons hosted in NotifyTrayWnd, which is a child window of
  // Shell_TrayWnd), we would already have caught it above
  hShellTrayWnd=FindWindowEx(NULL,NULL,TEXT("Shell_TrayWnd"),NULL);
  if(hShellTrayWnd)
  {
    GetWindowRect(hShellTrayWnd,lpTrayRect);
    if(lpTrayRect->right-lpTrayRect->left>DEFAULT_RECT_WIDTH)
      lpTrayRect->left=lpTrayRect->right-DEFAULT_RECT_WIDTH;
    if(lpTrayRect->bottom-lpTrayRect->top>DEFAULT_RECT_HEIGHT)
      lpTrayRect->top=lpTrayRect->bottom-DEFAULT_RECT_HEIGHT;

    return;
  }

  // OK. Haven't found a thing. Provide a default rect based on the current work
  // area
  SystemParametersInfo(SPI_GETWORKAREA,0,lpTrayRect,0);
  lpTrayRect->left=lpTrayRect->right-DEFAULT_RECT_WIDTH;
  lpTrayRect->top=lpTrayRect->bottom-DEFAULT_RECT_HEIGHT;
}

// Check to see if the animation has been disabled
static BOOL GetDoAnimateMinimize(VOID)
{
  ANIMATIONINFO ai;

  ai.cbSize=sizeof(ai);
  SystemParametersInfo(SPI_GETANIMATION,sizeof(ai),&ai,0);

  return ai.iMinAnimate?TRUE:FALSE;
}

VOID MinimizeWndToTray(HWND hWnd)
{
  if(GetDoAnimateMinimize())
  {
    RECT rcFrom,rcTo;

    // Get the rect of the window. It is safe to use the rect of the whole
    // window - DrawAnimatedRects will only draw the caption
    GetWindowRect(hWnd,&rcFrom);
    GetTrayWndRect(&rcTo);

    // Get the system to draw our animation for us
    DrawAnimatedRects(hWnd,IDANI_CAPTION,&rcFrom,&rcTo);
  }

  // Add the tray icon. If we add it before the call to DrawAnimatedRects,
  // the taskbar gets erased, but doesn't get redrawn until DAR finishes.
  // This looks untidy, so call the functions in this order

  // Hide the window
  ShowWindow(hWnd,SW_HIDE);
}

VOID RestoreWndFromTray(HWND hWnd)
{
  if(GetDoAnimateMinimize())
  {
    // Get the rect of the tray and the window. Note that the window rect
    // is still valid even though the window is hidden
    RECT rcFrom,rcTo;
    GetTrayWndRect(&rcFrom);
    GetWindowRect(hWnd,&rcTo);

    // Get the system to draw our animation for us
    DrawAnimatedRects(hWnd,IDANI_CAPTION,&rcFrom,&rcTo);
  }

  // Show the window, and make sure we're the foreground window
  ShowWindow(hWnd,SW_SHOW);
  SetActiveWindow(hWnd);
  SetForegroundWindow(hWnd);

  // Remove the tray icon. As described above, remove the icon after the
  // call to DrawAnimatedRects, or the taskbar will not refresh itself
  // properly until DAR finished
}



///   End of Helpers.c   \\\
