// apl_gui.cpp : Defines the initialization routines for the DLL.
//

#include "stdafx.h"
#include <afxdllx.h>
#include <locale.h>

#include "apl_gui.h"
#include "resource.h"
#include "ProgressDlgThread.h"
#include "BigMsgDlg.h"
#include "aplMultilineStringDlg.h"
#include "aplLangSelectDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif



HINSTANCE module_inst=0;
extern HHOOK CaplFindInTableDlg_HookProc_hk;

static AFX_EXTENSION_MODULE Apl_guiDLL = { NULL, NULL };

CImageList g_icons_32;
CImageList g_icons_24;
CImageList g_icons_16;
CImageList g_icons_16_tc;

CImageList g_icons_table;
CImageList g_icons_table_tc;

CImageList g_check_icons_16;
CImageList g_check_icons_256;

CImageList g_wait_dlg_img_lst;

int iLastGetBitPerPixel=-1;

CBitmap *g_logo_bmp=0;
COLORREF g_logo_сolor_background=RGB(0,0,0);
int g_std_bmp_num=0;

extern CRITICAL_SECTION list_threads_protect;


extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
	// Remove this if you use lpReserved
	UNREFERENCED_PARAMETER(lpReserved);

	if (dwReason == DLL_PROCESS_ATTACH)
	{
		TRACE0("APL_GUI.DLL Initializing!\n");
		
		// Extension DLL one-time initialization
		if (!AfxInitExtensionModule(Apl_guiDLL, hInstance))
			return 0;

		module_inst=hInstance;

		setlocale(LC_CTYPE, "Russian");
		setlocale(LC_COLLATE, "Russian");
		
		// Insert this DLL into the resource chain
		// NOTE: If this Extension DLL is being implicitly linked to by
		//  an MFC Regular DLL (such as an ActiveX Control)
		//  instead of an MFC application, then you will want to
		//  remove this line from DllMain and put it in a separate
		//  function exported from this Extension DLL.  The Regular DLL
		//  that uses this Extension DLL should then explicitly call that
		//  function to initialize this Extension DLL.  Otherwise,
		//  the CDynLinkLibrary object will not be attached to the
		//  Regular DLL's resource chain, and serious problems will
		//  result.

		//HINSTANCE hres=AfxGetResourceHandle( );
		AfxSetResourceHandle(hInstance);

		CaplDefWindowParam::Load();

		g_icons_32.Create(IDR_ICO_32,32,APLSTDICO_COUNT,RGB(192,192,192));
		g_icons_24.Create(IDR_ICO_24,24,APLSTDICO_COUNT,RGB(192,192,192));
		g_icons_16.Create(IDR_ICO_16,16,APLSTDICO_COUNT,RGB(192,192,192));
		g_icons_table.Create(IDR_TABLE_ICO,16,6,RGB(192,192,192));
		g_check_icons_16.Create(IDR_CHECK_TB,20,20,RGB(192,192,192));

		//CBitmap testbmp;
		//testbmp.LoadBitmap(IDB_APL_LOGO_ENG);
		//aplSetLogoBmp(&testbmp,RGB(0,0,0));

#if _MSC_VER < 1400
		CaplMenu::m_menu_check_il.Create(IDB_CHECK,8,1,RGB(192,192,192));
#endif

		CBitmap bmp0;
		bmp0.LoadBitmap(IDB_CHECK_ICO);
		g_check_icons_256.Create(20,20,ILC_COLOR8|ILC_MASK,0,100);
		g_check_icons_256.Add(&bmp0,RGB(192,192,192));
		
		if(g_icons_16_tc.GetSafeHandle()==0)
		{
			CBitmap bm;
            bm.LoadBitmap(IDB_TC_ICO_16);
			g_icons_16_tc.Create(16, 16, ILC_COLOR24|ILC_MASK, 0, 100);
			g_icons_16_tc.Add(&bm, RGB(192,192,192));
			bm.DeleteObject();
		}

		if(g_icons_table_tc.GetSafeHandle()==0)
		{
			CBitmap bm;
            bm.LoadBitmap(IDB_TC_TABLE_ICO);
			g_icons_table_tc.Create(16, 15, ILC_COLOR24|ILC_MASK, 0, 100);
			g_icons_table_tc.Add(&bm, RGB(192,192,192));
			bm.DeleteObject();
		}

		CBitmap bmp;
		bmp.LoadBitmap(IDB_WAIT_BMP/*IDB_WAIT_EX*/);
		COLORREF mask=RGB(192,192,192);
		g_wait_dlg_img_lst.Create(32,32,ILC_COLOR8|ILC_MASK,0,10);
		g_wait_dlg_img_lst.Add(&bmp,mask);
		
		//AfxSetResourceHandle(hres);
		new CDynLinkLibrary(Apl_guiDLL);

		CaplUIColors::SetScheme(CaplUIColors::GetCurScheme());

		CaplTreeView::LoadXpMode();
		//CaplMenu::LoadXpMode();
		InitializeCriticalSection(&list_threads_protect);
	}
	else if (dwReason == DLL_PROCESS_DETACH)
	{
		TRACE0("APL_GUI.DLL Terminating!\n");
		// Terminate the library before destructors are called
		AfxTermExtensionModule(Apl_guiDLL);
		
		DeleteCriticalSection(&list_threads_protect);

		if (0 != g_logo_bmp) {delete g_logo_bmp; g_logo_bmp=0;}

		if(0!=CaplFindInTableDlg_HookProc_hk) {UnhookWindowsHookEx(CaplFindInTableDlg_HookProc_hk);CaplFindInTableDlg_HookProc_hk=0;}
	}
	return 1;   // ok
}

CaplSetResourceHandle::CaplSetResourceHandle(HINSTANCE inst)
{
	m_old_inst_resources=AfxGetResourceHandle();
	AfxSetResourceHandle(inst);
}

CaplSetResourceHandle::~CaplSetResourceHandle()
{
	RestoreHandle();
}

void CaplSetResourceHandle::RestoreHandle()
{
	AfxSetResourceHandle(m_old_inst_resources);
}




HICON AFX_EXT_API GetAplStdIco32(int index)
{
	//if (index>=APLSTDICO_COUNT) return 0;
	return g_icons_32.ExtractIcon(index);
}
HICON AFX_EXT_API GetAplStdIco24(int index)
{
	//if (index>=APLSTDICO_COUNT) return 0;
	return g_icons_16.ExtractIcon(index);
}

HICON AFX_EXT_API GetAplStdIco16(int index)
{
	if(iLastGetBitPerPixel<0) iLastGetBitPerPixel=aplGetBitPerPixel(0);

	if(iLastGetBitPerPixel>8) return g_icons_16_tc.ExtractIcon(index);
	else return g_icons_16.ExtractIcon(index);
}

HICON AFX_EXT_API GetAplTableIco(int index)
{
	if(iLastGetBitPerPixel<0) iLastGetBitPerPixel=aplGetBitPerPixel(0);

	if(iLastGetBitPerPixel>8) return g_icons_table_tc.ExtractIcon(index);
	return g_icons_table.ExtractIcon(index);
}

HICON AFX_EXT_API GetAplCheckIco(int index,BOOL truecolor)
{
	if(truecolor==0) return g_check_icons_16.ExtractIcon(index);
	return g_check_icons_256.ExtractIcon(index);
}

void AFX_EXT_API aplSetLogoBmp(CBitmap *bmp, COLORREF colorBackground)
{
	if(0==bmp) return;
	if(0==bmp->m_hObject) return;
	if(0!=g_logo_bmp) delete g_logo_bmp;
	g_logo_bmp=aplCreateCopyBitmap(bmp);
	g_logo_сolor_background=colorBackground;

}
//**********************************************************************************************

void AFX_EXT_API aplSetLogoBmp(UINT nBmpID, CBitmap *pGlobalBMP)
{
	HDC hMemDC;
	CDC memDC;
	CBitmap *pOld, tmp_bm;
	CImageList il;
	BITMAP bm;
	
	tmp_bm.LoadBitmap(nBmpID);
	tmp_bm.GetBitmap(&bm);
	il.Create(bm.bmWidth, bm.bmHeight, ILC_COLORDDB|ILC_MASK, 0, 0);
	il.Add(&tmp_bm, RGB(192, 192, 192));
	tmp_bm.DeleteObject();
	
	HDC hDC = GetDC(NULL);
	
	hMemDC = ::CreateCompatibleDC(hDC);
	memDC.Attach(hMemDC);
	pGlobalBMP->Attach(::CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight));
	pOld = memDC.SelectObject(pGlobalBMP);
	memDC.FillSolidRect(0, 0, bm.bmWidth, bm.bmHeight, ::GetSysColor(COLOR_BTNFACE));
	memDC.DrawState(CPoint(0, 0), CSize(bm.bmWidth, bm.bmHeight), il.ExtractIcon(0), DST_ICON|DSS_NORMAL, (HBRUSH)NULL);
	memDC.SelectObject(pOld);
	memDC.Detach();
	
	il.DeleteImageList();
	
	::ReleaseDC(NULL, hDC);

	g_logo_bmp = pGlobalBMP;
}

//**********************************************************************************************

int AFX_EXT_API aplGetBitPerPixel(CWnd *wnd)
{
	if(wnd==0) 
	{
		CDC hdcScreen;
		hdcScreen.CreateDC(_T("DISPLAY"), NULL, NULL, NULL); 
		int BitPerPixel=GetDeviceCaps(hdcScreen, BITSPIXEL);
		iLastGetBitPerPixel=BitPerPixel;
		return BitPerPixel;
	}
	HDC hdc=GetDC(wnd->m_hWnd);
	if(hdc==0) return 0;
	int BitPerPixel=GetDeviceCaps(hdc,BITSPIXEL);
	ReleaseDC(wnd->m_hWnd,hdc);

	iLastGetBitPerPixel=BitPerPixel;
	return BitPerPixel;
}

//**********************************************************************************************

CBitmap AFX_EXT_API *aplCreateCopyBitmap(CBitmap *srcBitmap)
{
	if(0==srcBitmap) return 0;
	if(0==srcBitmap->m_hObject) return 0;

	CBitmap *newBmp=new CBitmap;
	if(0==newBmp) return 0;

	BITMAP bmpInfo;
	srcBitmap->GetBitmap(&bmpInfo);
	newBmp->CreateBitmapIndirect(&bmpInfo);

	DWORD bitmapSize = (bmpInfo.bmWidth *	bmpInfo.bmHeight * 	bmpInfo.bmBitsPixel * 	bmpInfo.bmPlanes) / 8;
	BYTE * BYTEList = new BYTE[bitmapSize];
	VERIFY(srcBitmap->GetBitmapBits(bitmapSize, BYTEList) == bitmapSize);
	VERIFY(newBmp->SetBitmapBits(bitmapSize, BYTEList) == bitmapSize);
	delete [] BYTEList;
	return newBmp;
}

//**********************************************************************************************

void AFX_EXT_API aplSetStdLogoBmp(int num_bitmap)
{
	g_std_bmp_num=num_bitmap;
}

//**********************************************************************************************

void AFX_EXT_API aplGetLogoBmp(CBitmap &bmp, CWnd *wnd)
{
	if (0!=g_logo_bmp)
	{
		/*BITMAP b;
		g_logo_bmp->GetBitmap(&b);
		bmp.CreateBitmapIndirect(&b);
		
		int size = b.bmWidth * b.bmHeight * b.bmBitsPixel / 8;
		char *buf = new char[size];
		g_logo_bmp->GetBitmapBits( size, buf);
		bmp.SetBitmapBits( size, buf);
		delete[] buf;*/

		aplCreateMappedBitmap(bmp, g_logo_bmp, g_logo_сolor_background, GetSysColor(COLOR_BTNFACE));
	}
	else
	{
		UINT uiLogoId=IDB_APL_LOGO;
		
		if (g_std_bmp_num == 1)
		{
			uiLogoId=IDB_LOGO_KILP;
		}
		else if (g_std_bmp_num == 0)
		{

#ifdef _MOMA_
			uiLogoId=IDB_APL_LOGO_NONAME;
#else

			CFile file;
			if(file.Open(_T("kvz_logo.dll"), CFile::modeRead))
			{
				file.Close();
				uiLogoId=IDB_LOGO_KVZ_WAR;
			}
			else
			{
				LCID cur_locale=GetThreadLocale (); 

				//cur_locale=0x409; // английский вариант для отладки

				if(cur_locale==0x0419)// Текущий язык - не русский
				{
					if (aplGetBitPerPixel(wnd) > 8) uiLogoId=IDB_APL_LOGO;
					else uiLogoId=IDB_APL_LOGO_16;
				}
				else uiLogoId=IDB_APL_LOGO_ENG;
			}
#endif
		}
		
		CaplSetResourceHandle setres(module_inst);

		CBitmap srcBitmap;
		if(!srcBitmap.LoadBitmap(uiLogoId)) return;
		//bmp.LoadBitmap(uiLogoId);
		aplCreateMappedBitmap(bmp, &srcBitmap, RGB(192,192,192), GetSysColor(COLOR_BTNFACE),30);
	}
}

//**********************************************************************************************

// При установке в false - во внутренних циклах и т.п. перестает обрабатывать
// сообщения WM_PAINT. Флаг добавлен для ILS.
bool global_process_wm_paint=true;

bool guiSetGlobalProcessWmPaint(bool is_process)
{
	bool prev_val = global_process_wm_paint;
	global_process_wm_paint=is_process;
	return prev_val;
}

//***************************************************************************

BOOL CaplOleMessageFilter::OnMessagePending( const MSG* pMsg )
{
	//return COleMessageFilter::OnMessagePending(pMsg);

	BOOL bEatMessage = FALSE;
	MSG msg;


	while (::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD))
	{
		//TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	while (::PeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE|PM_NOYIELD))
	{
		//TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	if(global_process_wm_paint)
	{
		while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE|PM_NOYIELD))
		//while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE|PM_NOYIELD))
		{
			bEatMessage = TRUE;
			DispatchMessage(&msg);
		}
	}
	return bEatMessage;
}


void CaplSplitterBar::SetSizes(CRect r1, CRect r2)
{
	m_rectDragPrev = r1;
	m_rectDragCurt = r2;
	m_rectSplitter = r1;
	m_rectSplitter.left = r1.right;	
	m_rectSplitter.right = r2.left;
	Invalidate();
}



void CaplTreeListCtrlView::DeleteAllColumns()
{
	m_tree.DeleteAllColumns();
	m_LastSortCol = 0;
}

void PumpTimerPaint(){
	MSG msg; 
	if(global_process_wm_paint)
	{
		while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT,
			PM_REMOVE|  PM_NOYIELD)) 
			DispatchMessage(&msg);
	}
	while (::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER,
		PM_REMOVE|  PM_NOYIELD)) 
		DispatchMessage(&msg);
}

void  aplShowBigMsg(LPCTSTR text, LPCTSTR caption)
{

	CaplSetResourceHandle setres(module_inst);
	CBigMsgDlg dlg;
	dlg.m_caption=caption;
	dlg.m_text=text;
	dlg.m_text.Replace(_T("\n"),_T("\r\n"));
	dlg.DoModal();
}

bool apl_CopyStr2Clipboard(LPCTSTR str)
{
	//запись текста в буфер обмена
	CWnd *wnd = AfxGetMainWnd();
	if(wnd==0) return false;
	if(wnd->OpenClipboard())//открываем буфер обмена
	{
		int len=_strlen(str)+1;

		LPWSTR lpszW = new WCHAR[len]; //where sText is the CString variable.
#ifdef _UNICODE
		int nLen = len;
		_strncpy(lpszW, str, nLen);
#else
		int nLen = MultiByteToWideChar(CP_ACP,0,str,-1,lpszW,len);
#endif

		HGLOBAL hgBuffer;
		//char* chBuffer;
		LPWSTR chBuffer;

		EmptyClipboard(); //очищаем буфер
		hgBuffer= GlobalAlloc(GMEM_DDESHARE, len*2);//выделяем память
		chBuffer= (LPWSTR)GlobalLock(hgBuffer); //блокируем память
		// 			strcpy(chBuffer, LPCSTR(str));
		wcscpy(chBuffer, LPWSTR(lpszW));
		GlobalUnlock(hgBuffer);//разблокируем память
		SetClipboardData(CF_UNICODETEXT, hgBuffer);//помещаем текст в буфер обмена
		CloseClipboard(); //закрываем буфер обмена
		delete[] lpszW;
	}

	return true;
}



//**************************************************************
//**************************************************************
//**************************************************************

long aplCreateProcess(const TCHAR *lpApplicationName, const TCHAR *lpCommandLine, bool wait,
					  bool minimized, BOOL bInheritHandles)
{
	if(!((lpApplicationName!=0)||(lpCommandLine!=0))) return -1;

	HANDLE m_hProcess;
    int ExitCode=0;

    PROCESS_INFORMATION proc_inf;
    STARTUPINFO startin;
    startin.cb=sizeof(STARTUPINFO);
    startin.lpReserved=NULL;
    startin.lpDesktop=NULL;
    startin.lpTitle=NULL;
    startin.dwFlags=STARTF_USESHOWWINDOW;
    startin.cbReserved2=0;
    startin.lpReserved2=NULL;

	if(minimized)startin.wShowWindow=SW_SHOWMINIMIZED;
    else startin.wShowWindow=SW_SHOWDEFAULT;
    
    if(0==CreateProcess(lpApplicationName,(TCHAR *)lpCommandLine,NULL,NULL,bInheritHandles,
		CREATE_NEW_CONSOLE,NULL,NULL,&startin,&proc_inf))
            return -1;
    
    m_hProcess=proc_inf.hProcess;
	CloseHandle(proc_inf.hThread);
    if(wait)
	{
		_cwait(&ExitCode,(int)m_hProcess,0);
		return ExitCode;
	}
	return (long)m_hProcess;
}

//**************************************************************

// Если wait==true, то в psOut записывается весь вывод программы в консоль
long aplCreateProcessEx(const TCHAR *lpApplicationName, const TCHAR *lpCommandLine, bool wait,
						bool minimized, CString *psOut)
{
	if(0!=psOut) *psOut=_T("");
	if(!((lpApplicationName!=0)||(lpCommandLine!=0))) return -1;

	SECURITY_ATTRIBUTES sa;  memset(&sa,0,sizeof(sa));
	SECURITY_DESCRIPTOR sd;  memset(&sd,0,sizeof(sd));      //структура security для пайпов
	HANDLE newstdin=0, newstdout=0, read_stdout=0, write_stdin=0;  //дескрипторы пайпов

	if(wait && 0!=psOut)
	{
		OSVERSIONINFO osv;
		osv.dwOSVersionInfoSize = sizeof(osv);
		GetVersionEx(&osv);

		if(osv.dwPlatformId == VER_PLATFORM_WIN32_NT) //инициализация security для Windows NT
		{
			InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
			SetSecurityDescriptorDacl(&sd, true, NULL, false);
			sa.lpSecurityDescriptor = &sd;
		}
		else sa.lpSecurityDescriptor = NULL;

		sa.nLength = sizeof(SECURITY_ATTRIBUTES);
		sa.bInheritHandle = true;       //разрешаем наследование дескрипторов

		CreatePipe(&newstdin,&write_stdin,&sa,0);   //создаем пайп для stdin
		CreatePipe(&read_stdout,&newstdout,&sa,0);  //создаем пайп для stdout
	}

	HANDLE m_hProcess=0;
	int ExitCode=0;

	PROCESS_INFORMATION proc_inf;	memset(&proc_inf,0,sizeof(proc_inf));
	STARTUPINFO startin;			memset(&startin,0,sizeof(startin));
	startin.cb=sizeof(STARTUPINFO);
	startin.lpReserved=NULL;
	startin.lpDesktop=NULL;
	startin.lpTitle=NULL;
	startin.dwFlags=STARTF_USESHOWWINDOW;
	startin.cbReserved2=0;
	startin.lpReserved2=NULL;

	if(minimized)startin.wShowWindow=SW_SHOWMINIMIZED;
	else startin.wShowWindow=SW_SHOWDEFAULT;

	if(wait && 0!=psOut)
	{
		startin.dwFlags|=STARTF_USESTDHANDLES;
		startin.hStdOutput=newstdout;
		startin.hStdError=newstdout;
		startin.hStdInput=newstdin;
	}

	if(0==CreateProcess(lpApplicationName,(TCHAR *)lpCommandLine,NULL,NULL,TRUE,
		CREATE_NEW_CONSOLE,NULL,NULL,&startin,&proc_inf))
		return -1;

	m_hProcess=proc_inf.hProcess;
	CloseHandle(proc_inf.hThread);
	if(wait)
	{
		_cwait(&ExitCode,(int)m_hProcess,0);

		if(0!=psOut)
		{
			unsigned long avail=0;   //кол-во доступных байт
			unsigned long bread=0;   //кол-во прочитанных байт

			PeekNamedPipe(read_stdout,0,0,&bread,&avail,NULL);
			if (avail> 0) //Проверяем, есть ли данные для чтения в stdout
			{
				unsigned long bufsize=4094;
				if(avail<bufsize) bufsize=avail;
				char *buf=new char[bufsize+2]; //буфер ввода/вывода (2 - на 0 в конце)
				while (avail>0)
				{
					//memset(buf,0,bufsize+2);
					bread=bufsize;
					ReadFile(read_stdout,buf,bufsize,&bread,NULL);  //читаем из
					if(bread<=0) break;
					buf[bread]=_T('\0');
					*psOut+=buf;

					avail-=bread;
				}
				delete buf;
			}
		}
	}
	else ExitCode= (long)m_hProcess;

	if(0!=newstdout) {CloseHandle(newstdout); newstdout=0;}
	if(0!=newstdin) {CloseHandle(newstdin); newstdin=0;}
	if(0!=read_stdout) {CloseHandle(read_stdout); read_stdout=0;}
	if(0!=newstdin) {CloseHandle(write_stdin); write_stdin=0;}

	return ExitCode;
};

//**************************************************************
//**************************************************************
//**************************************************************


HINSTANCE aplShellExecute(HWND hwnd, LPCTSTR lpOperation, LPCTSTR lpFile, LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd, bool bShowMsg)
{
	if(0==lpFile) return (HINSTANCE) SE_ERR_FNF;
	if(_T('\0')==lpFile[0]) return (HINSTANCE)SE_ERR_FNF;

	SHELLEXECUTEINFO ExInfo; memset(&ExInfo,0,sizeof(ExInfo));
	ExInfo.cbSize = sizeof(SHELLEXECUTEINFO);
	ExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
	ExInfo.fMask |= SEE_MASK_FLAG_NO_UI;
	ExInfo.hwnd = hwnd;
	
	if(0!=lpOperation)
	{
		if(_T('\0')!=lpOperation[0]) ExInfo.lpVerb=lpOperation;
	}
	if(_T('\0')!=ExInfo.lpVerb) ExInfo.lpVerb=_T("open");

	ExInfo.lpFile = lpFile;
	ExInfo.lpParameters = lpParameters;
	ExInfo.lpDirectory = lpDirectory;
	ExInfo.nShow = nShowCmd;

	ShellExecuteEx(&ExInfo);

	if((int)ExInfo.hInstApp>=32)
	{
		// ЯАИ 12.04.2024 непонятно с каких пор в ExInfo.hInstApp стал возвращяться не запущенный процесс,
		// как раньше, а 0x2a. Теперь используем ExInfo.hProcess
		if(0!=ExInfo.hProcess) return (HINSTANCE) ExInfo.hProcess; 
		return ExInfo.hInstApp;
	}

	if(SE_ERR_ASSOCINCOMPLETE==(int)ExInfo.hInstApp  || SE_ERR_NOASSOC==(int)ExInfo.hInstApp) 
	{
		// Запасной вариант на случай кривой регистрации расширения
		CString sOperation(lpOperation);
		sOperation.MakeLower();
		if(sOperation==_T("open") || sOperation==_T("view") || sOperation==_T("edit") || sOperation==_T("print") )
		{
			TCHAR *psRegApp=new TCHAR[MAX_PATH];   memset(psRegApp,0,MAX_PATH);
			HINSTANCE hi0=FindExecutable(lpFile,0,psRegApp);
			if(psRegApp[0]!=_T('\0'))
			{
				CString sParam;
				if(sOperation==_T("print"))  sParam+=_T("/P ");
				sParam=_T('"'); sParam+=lpFile; sParam+=_T('"');
				HINSTANCE hInst=ShellExecute(0,_T("open"),psRegApp,(LPCTSTR)sParam,0,1);
				if((int)hInst>32) 
				{
					// Возвращает 31 вместо 43 почему-то return ExInfo.hInstApp;
					return hInst;
				}
			}
			delete psRegApp;
		}
	}

	if(bShowMsg)
	{
		HINSTANCE hRes=ExInfo.hInstApp;
		if(SE_ERR_ASSOCINCOMPLETE==(int)hRes || SE_ERR_NOASSOC==(int)hRes) AfxMessageBox( APL_T("Нет ассоциированного приложения")); 
		else if(SE_ERR_FNF==(int)hRes ) AfxMessageBox( APL_T("Файл не найден")); 
		else if(SE_ERR_PNF==(int)hRes ) AfxMessageBox( APL_T("Путь не найден")); 
		else if(SE_ERR_ACCESSDENIED==(int)hRes ) AfxMessageBox( APL_T("Нет доступа")); 
		else if(SE_ERR_OOM==(int)hRes ) AfxMessageBox( APL_T("Недостаточно памяти")); 
		else if(SE_ERR_DDEFAIL==(int)hRes ) AfxMessageBox( APL_T("Ошибка: SE_ERR_DDEFAIL")); 
		else if(SE_ERR_DDEBUSY==(int)hRes ) AfxMessageBox( APL_T("Ошибка: SE_ERR_DDEBUSY")); 
		else if(SE_ERR_DDETIMEOUT==(int)hRes ) AfxMessageBox( APL_T("Ошибка: SE_ERR_DDETIMEOUT")); 
		else AfxMessageBox( APL_T("Ошибка запуска приложения")); 
	}	

	return ExInfo.hInstApp;
}



//**************************************************************
//**************************************************************
//**************************************************************

bool LoadResource2String(HMODULE hModule, DWORD res_id, LPCTSTR res_type, CString &text)
{
	CaplStackLogger stack_logger(__APL_FUNC__);

	CString buf;
	buf.Format(_T("#%i"), res_id);

	HRSRC def_source = FindResourceEx(hModule, res_type, buf, 0);
	DWORD res_size = SizeofResource(hModule, def_source);
	HGLOBAL hglb = LoadResource(hModule, def_source);
	LPVOID res_data =LockResource(hglb);
	char *tbuf = new char[res_size+2];
	memcpy(tbuf, res_data, res_size);
	tbuf[res_size]=0;
	tbuf[res_size+1]=0;
	UnlockResource(hglb);

	aplTextEncoding res_enc = aplANSI;

	if(res_size > 5){res_enc = CaplStringFile::GetBufferEncode((byte*)tbuf, 5);}

	if(res_enc == aplUCS2)
	{
		wchar_t *wbuf = (wchar_t*)(tbuf + 2);
		text = wbuf;
	}
	else if(res_enc == aplUTF8)
	{
		// из ресурсов да в UTF? Нереально
		text = tbuf;
		return false;
	}
	else if(res_enc == aplANSI)
	{
		text = tbuf;
	}

	delete[] tbuf;

	return true;
}


//**************************************************************
//**************************************************************
//**************************************************************

CString CaplDefWindowParam::m_font_face;
CString CaplDefWindowParam::m_system_font_face;
int CaplDefWindowParam::m_font_size=0;
int CaplDefWindowParam::m_system_font_size=0;
COLORREF CaplDefWindowParam::m_win_bk_color=RGB(0,0,0);
COLORREF CaplDefWindowParam::m_system_win_bk_color=RGB(0,0,0);


const TCHAR CaplDefWindowParam_KeyName[]=_T("Software\\CALS Centre \"Applied Logistic\"");
const TCHAR ValName[]=_T("XP_Tree");

void CaplDefWindowParam::Save()
{
	/*
	CWinApp* pApp = AfxGetApp();
	if(0==pApp) return;
	CString Section="aplDefaultWindowParam";
	pApp->WriteProfileInt(Section, _T("def_font_size"), m_font_size);
	pApp->WriteProfileString(Section, _T(""), m_font_face);
	pApp->WriteProfileInt(Section, _T("def_window_bk_color"),(UINT)m_win_bk_color);
	*/

	HKEY key=0;
	if(ERROR_SUCCESS!=RegOpenKeyEx(HKEY_CURRENT_USER,CaplDefWindowParam_KeyName,0,KEY_ALL_ACCESS,&key))
	{
		if(ERROR_SUCCESS!=RegCreateKey(HKEY_CURRENT_USER,CaplDefWindowParam_KeyName,&key))	return;
	}
	if(0==key) return;
	RegSetValueEx(key,_T("def_font_face"),0,REG_SZ,(BYTE*)(LPCTSTR(m_font_face)),m_font_face.GetLength()+1);
	RegSetValueEx(key,_T("def_font_size"),0,REG_DWORD,(BYTE*)(&m_font_size),sizeof(DWORD));
	RegSetValueEx(key,_T("def_window_bk_color"),0,REG_DWORD,(BYTE*)(&m_win_bk_color),sizeof(DWORD));
	RegCloseKey(key);
}

void CaplDefWindowParam::Load()
{
	/*CWinApp* pApp = AfxGetApp();
	if(0==pApp) return;
	CString Section="aplDefaultWindowParam";
	m_font_size= pApp->GetProfileInt(Section, _T("def_font_size"), 0);
	m_font_face=pApp->GetProfileString(Section, _T("def_font_face"), "");
	m_win_bk_color =(COLORREF) pApp->GetProfileInt(Section, _T("def_window_bk_color"),0);*/

	HKEY key=0;
	if(ERROR_SUCCESS!=RegOpenKeyEx(HKEY_CURRENT_USER,CaplDefWindowParam_KeyName,0,KEY_QUERY_VALUE,&key))return;
	if(0==key) return;
	char *buf=new char[1024];
	buf[0] = 0;
	DWORD size=1024; DWORD type=0;
	RegQueryValueEx(key,_T("def_font_face"),0,&type,(BYTE*)buf,&size);
	m_font_face=buf;
	size=sizeof(DWORD);
	RegQueryValueEx(key,_T("def_font_size"),0,&type,(BYTE*)(&m_font_size),&size);
	size=sizeof(DWORD);
	RegQueryValueEx(key,_T("def_window_bk_color"),0,&type,(BYTE*)(&m_win_bk_color),&size);
	delete buf;
	RegCloseKey(key);
}

bool CaplDefWindowParam::GetDefaultFont(LOGFONT &lf)
{
	if(0==m_system_font_size)
	{
		CFont *tmpFont=CFont::FromHandle((HFONT)GetStockObject(ANSI_VAR_FONT));
		if(0!=tmpFont)
		{
			LOGFONT lf;
			memset(&lf, 0, sizeof(LOGFONT));
			tmpFont->GetLogFont(&lf);
			m_system_font_face=lf.lfFaceName;
			m_system_font_size=lf.lfHeight;

			m_system_win_bk_color=GetSysColor(COLOR_WINDOW);
		}
		Load();
	}

	memset(&lf, 0, sizeof(LOGFONT));
	lf.lfCharSet=RUSSIAN_CHARSET;
	lf.lfWeight=FW_NORMAL;

	if(m_font_size!=0) lf.lfHeight=m_font_size;
	else lf.lfHeight=m_system_font_size;

	TCHAR *p_font_face=0;
	if(m_font_face!=_T(""))p_font_face=(TCHAR*)((LPCTSTR)m_font_face);
	else p_font_face=(TCHAR*)(LPCTSTR)m_system_font_face;

	CopyFontFaceName(p_font_face, lf.lfFaceName);
	return true;
}

bool CaplDefWindowParam::CopyFontFaceName(const TCHAR *from, TCHAR *to)
{
	if(0== from || 0==to) return false;

	int i;
	for(i=0; i<LF_FACESIZE;i++)
	{
		TCHAR c=from[i];
		to[i]=c;
		if(c==_T('\0')) break;
	}
	to[LF_FACESIZE-1]=_T('\0');
	return true;
}

bool aplSelectMultilineString(CString& sFullString, LPCTSTR lpTitle /*= NULL*/, LPAplMakeStrFunction lpStrFun /*= NULL*/, LPCTSTR lpDelimeters /*= NULL*/)
{
	CaplMultilineStringDlg dlg(lpTitle, sFullString, lpStrFun, lpDelimeters);
	if (dlg.DoModal())
	{
		sFullString = dlg.GetFullString();
		return true;
	}

	return false;
}

int FindMenuItem(CMenu* Menu, LPCTSTR MenuString)
{
	ASSERT(Menu);
	ASSERT(::IsMenu(Menu->GetSafeHmenu()));

	int count = Menu->GetMenuItemCount();
	for (int i = 0; i < count; i++)
	{
		CString str;
		if (Menu->GetMenuString(i, str, MF_BYPOSITION) &&
			str.Compare(MenuString) == 0)
			return i;
	}

	return -1;
}


unsigned int g_langMenuBase=0; // запомненная база для меню переключения языка

bool aplFillLanguageMenu(CMenu* pMenu, LPCTSTR lpMenuName /*= NULL*/, LPCTSTR lpSubmenuName /*= NULL*/, unsigned int langMenuBase /*= 64000*/)
{
	if (pMenu==NULL)
		return false;

	#ifndef _UNICODE
		// В ANSI версии при переключении потока на английский системные функции воспринимают
		// русские символы как кодировку 1252 и получаются кракозябры. Например, в диалоге выбора файлов.
		// Поэтому возможность перевода лучше отключить нафиг 
		return false;   
	#endif


	g_langMenuBase=langMenuBase;

	CMenu *pSubMenu = NULL;
	if (lpMenuName)
	{
		int iSub = FindMenuItem(pMenu, lpMenuName);
		if (iSub>-1)
			pSubMenu = pMenu->GetSubMenu(iSub);
	}
	else
		pSubMenu = pMenu;

	if (pSubMenu==NULL)
	{
		HMENU sub = CreatePopupMenu();
		pMenu->AppendMenu( MF_POPUP, (UINT_PTR)sub,  lpMenuName);
		int iSub = FindMenuItem(pMenu, lpMenuName);
		if (iSub>-1)
			pSubMenu = pMenu->GetSubMenu(iSub);
	}
	if (pSubMenu==NULL)
	{
		return false;
	}

	if (lpSubmenuName)
	{
		int iSub = FindMenuItem(pSubMenu, lpSubmenuName);
		if (iSub>-1)
			pSubMenu = pSubMenu->GetSubMenu(iSub);
	}

	if (pSubMenu==NULL)
		return false;

	// очищаем меню
	while(pSubMenu->GetMenuItemCount()>0)
	{
		pSubMenu->RemoveMenu(0, MF_BYPOSITION);
	}

	// грузим список доступных языков (вернее номеров в массиве языков)
	TIntSet nums;
	CString sPath;
	GetExePath(GetModuleHandle(NULL), sPath);
	CaplTranslate::GetTranslateFiles(sPath, nums);
	// добавляем в любом случае русский язык
	for(int i=0; i<APL_LANG_COUNT; ++i)
	{
		if (apl_langs[i].id==0x0419)
		{
			nums.insert(i);
			break;
		}
	}

	int nCount(0);
	UINT uFlags;
	for(TIntSet_it it=nums.begin(); it!=nums.end(); ++it)
	{
		if(apl_langs[*it].id == GetThreadLocale()) uFlags = MF_BYPOSITION|MF_STRING|MF_CHECKED;
		else uFlags = MF_BYPOSITION|MF_STRING;
		pSubMenu->InsertMenu(nCount++, uFlags, langMenuBase+(*it), apl_langs[*it].description);
	}

	pSubMenu->InsertMenu(pSubMenu->GetMenuItemCount(),MF_BYPOSITION|MF_SEPARATOR,123,_T(""));
	pSubMenu->InsertMenu(pSubMenu->GetMenuItemCount(),uFlags,langMenuBase-1,_T("Show string ID"));


	return true;
}


// Функция проверяет сообщение, и если это смена языка, то вызывает смену языка
// Должна вызываться внутри CMainFrame::OnCommand -> OnCommand_SetLanguageHandler(wParam,lParam,this);

void aplSetLanguageOnCommandHandler(WPARAM wParam, LPARAM lParam, CWnd *wnd)
{
	if(0==g_langMenuBase) return;  // Меню ещё не инициализировано

	unsigned int iCommand= wParam;
	if(iCommand==(g_langMenuBase-1))
	{
		CaplTranslate::SaveShowStringId(!CaplTranslate::GetShowStringId());
		AfxMessageBox(APL_T("Значение сохранено, но отображение измененится после перезапуска программы."));
	}
	else if ((iCommand>=g_langMenuBase) && (iCommand<(g_langMenuBase+APL_LANG_COUNT)))
	{
		// это выбор языка
		int nLang = iCommand - g_langMenuBase;
		int lang_id = apl_langs[nLang].id;
		if(CaplTranslate::GetGurLocale()!=lang_id)
		{
			CaplTranslate::SaveUILangToReg(lang_id);

			CString msg;
			msg+=APL_NO_T("To change the language, you must restart the program!\n\nRestart the program ?");
			msg+=_T("\n\n\n");
			msg+=APL_NO_T("Для изменения языка необходимо перезапустить программу!\n\nПерезапустить программу?");

			if(IDYES==AfxMessageBox(msg,MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON1))
			{
				// Сохраняем изменения
				CWnd *mainWnd=AfxGetMainWnd();
				if(0!=mainWnd)
				{
					if(mainWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)))
					{
						CDocument *doc=((CFrameWnd*)(mainWnd))->GetActiveDocument();
						if(0!=doc) doc->SaveModified();
					}
				}

				// Закрываем приложение
				CString sCmd;
				CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
				if(0==app)  return;
				
				sCmd=app->m_pszHelpFilePath;
				sCmd.MakeLower();
				sCmd.Replace(_T(".hlp"),_T(".exe"));
				sCmd+=_T(" ");
				sCmd+=app->m_lpCmdLine;
				aplCreateProcess(0, sCmd, false);
				if(0!=wnd) wnd->PostMessage(WM_CLOSE, 0, 0);
			}
		}
	}
}

// Функция проверяет обработку сообщений. 
// И если обработчик вызывается для галочки языка в меню, устанавливает значение галочки
// должна вызываться в CMainFrame::OnCmdMsg  ->  OnCmdMsg_SetLaguageCheck( nID, nCode, pExtra);

void aplSetLaguageOnCmdMsgHandler(UINT nID, int nCode, void* pExtra)
{
	if(0==g_langMenuBase) return;  // Меню ещё не инициализировано

	if (nCode==CN_UPDATE_COMMAND_UI)
	{
		if(nID==(g_langMenuBase-1)) 
		{
			CCmdUI *pCmdUI = (CCmdUI*)pExtra;
			if(0!=pCmdUI) pCmdUI->SetCheck(CaplTranslate::GetShowStringId());
		}
		else if ((nID>=g_langMenuBase) && (nID<(g_langMenuBase+APL_LANG_COUNT)))
		{
			// это выбор языка
			UINT nLang = nID - g_langMenuBase;
			int lang_id = apl_langs[nLang].id;
			CCmdUI *pCmdUI = (CCmdUI*)pExtra;
			if (pCmdUI)
			{
				unsigned long curLocale=CaplTranslate::GetGurLocale();
				
				pCmdUI->SetCheck( (curLocale==lang_id) || (0==curLocale && lang_id==0x419) );
			}
		}
	}
}


//*********************************************************************************************************

int aplTestSelectLanguage(LPCTSTR lpSection /* = _T("Settings") */, LPCTSTR lpEntry /* = _T("DefLangCode") */)
{
	CString sSection;
	if (lpSection)
		sSection = lpSection;
	if (sSection.IsEmpty())
		return -1;

	CString sEntry;
	if (lpEntry)
		sEntry = lpEntry;
	if (sEntry.IsEmpty())
		return -1;

	int iCodeLang = -1;
	CaplLangSelectDlg dlg;
	if (dlg.DoModal())
	{
		iCodeLang = dlg.GetLangCode();
		if (iCodeLang>-1)
		{
			CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
			if(0!=app) app->WriteProfileInt(sSection, sEntry, iCodeLang);
		}
	}

	return iCodeLang;
}

void aplTranslateMenu(CMenu* menu, bool bRecursive /*= false*/)
{
	if (menu==NULL)
		return;

	if (CaplTranslate::IsNeedTranslate())
	{
		TCHAR buf[256];
		for(UINT i=0;i<menu->GetMenuItemCount();i++)
		{
			MENUITEMINFO mii;
			mii.cbSize=sizeof(MENUITEMINFO); 
			mii.fMask=MIIM_STRING;
			mii.dwTypeData=buf;
			mii.cch=256;
			mii.dwItemData=0;
			buf[0] = _T('\0');

			menu->GetMenuItemInfo(i,&mii,TRUE);

			if (mii.dwTypeData)
			{
				_strcpy(mii.dwTypeData, CaplTranslate::Translate(mii.dwTypeData));
				menu->SetMenuItemInfo(i,&mii,TRUE);
			}

			if (bRecursive)
			{
				CMenu *pSubMenu = menu->GetSubMenu(i);
				if (pSubMenu)
					aplTranslateMenu(pSubMenu, bRecursive);
			}
		}
	}
}