diff --git a/ZbaSDK/Package/ZbaEngine.dll b/ZbaSDK/Package/ZbaEngine.dll new file mode 100644 index 0000000000000000000000000000000000000000..750e713fde23637ef3e5cafabfc6f2bf1ec96bde Binary files /dev/null and b/ZbaSDK/Package/ZbaEngine.dll differ diff --git a/ZbaSDK/Package/ZbaPackage.exe b/ZbaSDK/Package/ZbaPackage.exe new file mode 100644 index 0000000000000000000000000000000000000000..0954f70d57ab190ac715962968434d82273cea94 Binary files /dev/null and b/ZbaSDK/Package/ZbaPackage.exe differ diff --git a/ZbaSDK/Package/ZbaSafe.wdb b/ZbaSDK/Package/ZbaSafe.wdb new file mode 100644 index 0000000000000000000000000000000000000000..2971a0830d7f8ad5cfd0adcb3623ed326e9d2048 Binary files /dev/null and b/ZbaSDK/Package/ZbaSafe.wdb differ diff --git "a/ZbaSDK/PluginOK\344\270\255\351\227\264\344\273\266\345\256\211\345\205\250\350\247\243\345\206\263\346\226\271\346\241\210.doc" "b/ZbaSDK/PluginOK\344\270\255\351\227\264\344\273\266\345\256\211\345\205\250\350\247\243\345\206\263\346\226\271\346\241\210.doc" new file mode 100644 index 0000000000000000000000000000000000000000..78a77352af96adef37a5a0d7e6ce838b61055df4 Binary files /dev/null and "b/ZbaSDK/PluginOK\344\270\255\351\227\264\344\273\266\345\256\211\345\205\250\350\247\243\345\206\263\346\226\271\346\241\210.doc" differ diff --git "a/ZbaSDK/PluginOK\344\270\255\351\227\264\344\273\266\346\216\210\346\235\203\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256\350\257\264\346\230\216.doc" "b/ZbaSDK/PluginOK\344\270\255\351\227\264\344\273\266\346\216\210\346\235\203\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256\350\257\264\346\230\216.doc" new file mode 100644 index 0000000000000000000000000000000000000000..9ef287bfd4c0b6df6283a1f9ae6c3616a9aa7b91 Binary files /dev/null and "b/ZbaSDK/PluginOK\344\270\255\351\227\264\344\273\266\346\216\210\346\235\203\346\234\215\345\212\241\345\231\250\351\205\215\347\275\256\350\257\264\346\230\216.doc" differ diff --git "a/ZbaSDK/PluginOK\345\274\200\345\217\221\350\200\205\346\211\213\345\206\214.doc" "b/ZbaSDK/PluginOK\345\274\200\345\217\221\350\200\205\346\211\213\345\206\214.doc" new file mode 100644 index 0000000000000000000000000000000000000000..df57d5060168376b06a572f50b7c20318c597171 Binary files /dev/null and "b/ZbaSDK/PluginOK\345\274\200\345\217\221\350\200\205\346\211\213\345\206\214.doc" differ diff --git "a/ZbaSDK/PluginOK\346\240\270\345\277\203\347\273\204\344\273\266\346\216\245\345\217\243\350\257\264\346\230\216.xls" "b/ZbaSDK/PluginOK\346\240\270\345\277\203\347\273\204\344\273\266\346\216\245\345\217\243\350\257\264\346\230\216.xls" new file mode 100644 index 0000000000000000000000000000000000000000..481b71ee549cf1008ef4095f2d83de06313158a5 Binary files /dev/null and "b/ZbaSDK/PluginOK\346\240\270\345\277\203\347\273\204\344\273\266\346\216\245\345\217\243\350\257\264\346\230\216.xls" differ diff --git a/ZbaSDK/SampleCode/Bin/ZbaApplet.dll b/ZbaSDK/SampleCode/Bin/ZbaApplet.dll new file mode 100644 index 0000000000000000000000000000000000000000..c886f287d811635043b669de7c6f9aa7f3266974 Binary files /dev/null and b/ZbaSDK/SampleCode/Bin/ZbaApplet.dll differ diff --git a/ZbaSDK/SampleCode/Bin/ZbaBase.dll b/ZbaSDK/SampleCode/Bin/ZbaBase.dll new file mode 100644 index 0000000000000000000000000000000000000000..859dda027fbb5e05d359bbfd3f7d05fd0d498a0e Binary files /dev/null and b/ZbaSDK/SampleCode/Bin/ZbaBase.dll differ diff --git a/ZbaSDK/SampleCode/Bin/ZbaEngine.dll b/ZbaSDK/SampleCode/Bin/ZbaEngine.dll new file mode 100644 index 0000000000000000000000000000000000000000..750e713fde23637ef3e5cafabfc6f2bf1ec96bde Binary files /dev/null and b/ZbaSDK/SampleCode/Bin/ZbaEngine.dll differ diff --git a/ZbaSDK/SampleCode/PluginComDll/PluginComDll.cpp b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f0a0d3490806f005558cde8918457c960c10445 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.cpp @@ -0,0 +1,86 @@ +// PluginComDll.cpp : DLL 导出的实现。 + +#include "stdafx.h" +#include "resource.h" +#include "PluginComDll_i.h" +#include "dllmain.h" +#include "xdlldata.h" + +// 用于确定 DLL 是否可由 OLE 卸载。 +STDAPI DllCanUnloadNow(void) +{ +#ifdef _MERGE_PROXYSTUB + HRESULT hr = PrxDllCanUnloadNow(); + if (hr != S_OK) + return hr; +#endif + return _AtlModule.DllCanUnloadNow(); +} + +// 返回一个类工厂以创建所请求类型的对象。 +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ +#ifdef _MERGE_PROXYSTUB + if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK) + return S_OK; +#endif + return _AtlModule.DllGetClassObject(rclsid, riid, ppv); +} + +// DllRegisterServer - 在系统注册表中添加项。 +STDAPI DllRegisterServer(void) +{ + // 注册对象、类型库和类型库中的所有接口 + HRESULT hr = _AtlModule.DllRegisterServer(); +#ifdef _MERGE_PROXYSTUB + if (FAILED(hr)) + return hr; + hr = PrxDllRegisterServer(); +#endif + return hr; +} + +// DllUnregisterServer - 在系统注册表中移除项。 +STDAPI DllUnregisterServer(void) +{ + HRESULT hr = _AtlModule.DllUnregisterServer(); +#ifdef _MERGE_PROXYSTUB + if (FAILED(hr)) + return hr; + hr = PrxDllRegisterServer(); + if (FAILED(hr)) + return hr; + hr = PrxDllUnregisterServer(); +#endif + return hr; +} + +// DllInstall - 按用户和计算机在系统注册表中逐一添加/移除项。 +STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine) +{ + HRESULT hr = E_FAIL; + static const wchar_t szUserSwitch[] = L"user"; + + if (pszCmdLine != NULL) + { + if (_wcsnicmp(pszCmdLine, szUserSwitch, _countof(szUserSwitch)) == 0) + { + ATL::AtlSetPerUserRegistration(true); + } + } + + if (bInstall) + { + hr = DllRegisterServer(); + if (FAILED(hr)) + { + DllUnregisterServer(); + } + } + else + { + hr = DllUnregisterServer(); + } + + return hr; +} \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginComDll/PluginComDll.def b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.def new file mode 100644 index 0000000000000000000000000000000000000000..762038f675a9249c09fcddc1d5d07ee641eebcf5 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.def @@ -0,0 +1,10 @@ +; PluginComDll.def : 定义模块参数。 + +LIBRARY + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + DllInstall PRIVATE diff --git a/ZbaSDK/SampleCode/PluginComDll/PluginComDll.idl b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.idl new file mode 100644 index 0000000000000000000000000000000000000000..5026697238b251acbbab818e834a19afe1d7dc36 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.idl @@ -0,0 +1,74 @@ +// PluginComDll.idl : PluginComDll 的 IDL 源 +// + +// 此文件将由 MIDL 工具处理以 +// 产生类型库(PluginComDll.tlb)和封送处理代码。 + +import "oaidl.idl"; +import "ocidl.idl"; + +[ + object, + uuid(C38672FA-B5C8-4D9D-89B5-2D71F0760661), + dual, + nonextensible, + pointer_default(unique) +] +interface ITextFile : IDispatch{ +}; + +[ + object, + uuid(E46E1B5B-2891-414F-A21A-17B00231E650), + dual, + nonextensible, + pointer_default(unique) +] +interface ISysInfo : IDispatch{ +}; + +[ + uuid(A22E18F1-95F8-4FDB-99D2-188E5FB12B23), + version(1.0), +] +library PluginComDllLib +{ + importlib("stdole2.tlb"); + + [ + uuid(40756D41-E6C7-4648-80C4-AB70A325F831) + ] + dispinterface _ITextFileEvents + { + properties: + methods: + }; + + [ + uuid(40613676-C8A5-4879-A59B-9CE6406476F6) + ] + coclass TextFile + { + [default] interface ITextFile; + [default, source] dispinterface _ITextFileEvents; + }; + + [ + uuid(FAC6FC19-9B22-4904-A656-581FCB35EC98) + ] + dispinterface _ISysInfoEvents + { + properties: + methods: + }; + + [ + uuid(6D7595BD-BFB0-4D2C-906B-247028691A50) + ] + coclass SysInfo + { + [default] interface ISysInfo; + [default, source] dispinterface _ISysInfoEvents; + }; +}; + diff --git a/ZbaSDK/SampleCode/PluginComDll/PluginComDll.rc b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.rc new file mode 100644 index 0000000000000000000000000000000000000000..24a37d1d104fb282c3fa86dfeb7c542933ae228e Binary files /dev/null and b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.rc differ diff --git a/ZbaSDK/SampleCode/PluginComDll/PluginComDll.rgs b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.rgs new file mode 100644 index 0000000000000000000000000000000000000000..e7d37400e19a24d70c54739df67e0024251a65b6 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.rgs @@ -0,0 +1,3 @@ +HKCR +{ +} diff --git a/ZbaSDK/SampleCode/PluginComDll/PluginComDll.sln b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.sln new file mode 100644 index 0000000000000000000000000000000000000000..03a33b3ff7c6f128f58c9d9ba6be6123ef6aa786 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.sln @@ -0,0 +1,26 @@ +锘 +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PluginComDll", "PluginComDll.vcxproj", "{880E1365-4E58-469D-809B-6BE3B1D1EC5F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {880E1365-4E58-469D-809B-6BE3B1D1EC5F}.Debug|Win32.ActiveCfg = Debug|Win32 + {880E1365-4E58-469D-809B-6BE3B1D1EC5F}.Debug|Win32.Build.0 = Debug|Win32 + {880E1365-4E58-469D-809B-6BE3B1D1EC5F}.Debug|x64.ActiveCfg = Debug|x64 + {880E1365-4E58-469D-809B-6BE3B1D1EC5F}.Debug|x64.Build.0 = Debug|x64 + {880E1365-4E58-469D-809B-6BE3B1D1EC5F}.Release|Win32.ActiveCfg = Release|Win32 + {880E1365-4E58-469D-809B-6BE3B1D1EC5F}.Release|Win32.Build.0 = Release|Win32 + {880E1365-4E58-469D-809B-6BE3B1D1EC5F}.Release|x64.ActiveCfg = Release|x64 + {880E1365-4E58-469D-809B-6BE3B1D1EC5F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ZbaSDK/SampleCode/PluginComDll/PluginComDll.suo b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.suo new file mode 100644 index 0000000000000000000000000000000000000000..6e74689e9c38f5d30ce8a2fe92bf27afde7a85bf Binary files /dev/null and b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.suo differ diff --git a/ZbaSDK/SampleCode/PluginComDll/PluginComDll.vcxproj b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.vcxproj new file mode 100644 index 0000000000000000000000000000000000000000..b579fb733f390bcf423f211f7e6553da5091ff21 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.vcxproj @@ -0,0 +1,316 @@ +锘 + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {880E1365-4E58-469D-809B-6BE3B1D1EC5F} + AtlProj + + + + + + + + + + DynamicLibrary + true + Dynamic + Unicode + + + DynamicLibrary + true + Dynamic + Unicode + + + DynamicLibrary + false + Static + Unicode + + + DynamicLibrary + false + Static + Unicode + + + + + + + + + + + + + + + + + + + true + true + \$(Configuration)\$(Platform)\Plugins\$(ProjectName)\ + $(Configuration)\$(Platform)\$(ProjectName)\ + + + true + true + \$(Configuration)\$(Platform)\Plugins\$(ProjectName)\ + $(Configuration)\$(Platform)\$(ProjectName)\ + + + true + false + \$(Configuration)\$(Platform)\Plugins\$(ProjectName)\ + \$(Configuration)\$(Platform)\$(ProjectName)\ + + + true + false + \$(Configuration)\$(Platform)\Plugins\$(ProjectName)\ + \$(Configuration)\$(Platform)\$(ProjectName)\ + + + + Use + Level3 + Disabled + WIN32;_WINDOWS;_DEBUG;_USRDLL;%(PreprocessorDefinitions) + MultiThreadedDebug + + + false + Win32 + _DEBUG;%(PreprocessorDefinitions) + PluginComDll_i.h + PluginComDll_i.c + PluginComDll_p.c + true + $(IntDir)PluginComDll.tlb + + + true + + + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + _DEBUG;%(PreprocessorDefinitions) + + + Windows + .\PluginComDll.def + true + false + \$(Configuration)\$(Platform)\$(TargetName).pdb + + + + + Use + Level3 + Disabled + _WIN64;WIN32;_WINDOWS;_DEBUG;_USRDLL;%(PreprocessorDefinitions) + MultiThreadedDebug + + + false + _DEBUG;%(PreprocessorDefinitions) + PluginComDll_i.h + PluginComDll_i.c + PluginComDll_p.c + true + $(IntDir)PluginComDll.tlb + + + + + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + _DEBUG;%(PreprocessorDefinitions) + + + Windows + .\PluginComDll.def + true + false + \$(Configuration)\$(Platform)\$(TargetName).pdb + + + + + Use + Level3 + MaxSpeed + WIN32;_WINDOWS;NDEBUG;_USRDLL;%(PreprocessorDefinitions) + MultiThreaded + + + false + Win32 + NDEBUG;%(PreprocessorDefinitions) + PluginComDll_i.h + PluginComDll_i.c + PluginComDll_p.c + true + $(IntDir)PluginComDll.tlb + + + true + + + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + NDEBUG;%(PreprocessorDefinitions) + + + Windows + .\PluginComDll.def + true + true + true + false + \$(Configuration)\$(Platform)\$(TargetName).pdb + + + + + Use + Level3 + MaxSpeed + _WIN64;WIN32;_WINDOWS;NDEBUG;_USRDLL;%(PreprocessorDefinitions) + MultiThreaded + + + false + NDEBUG;%(PreprocessorDefinitions) + PluginComDll_i.h + PluginComDll_i.c + PluginComDll_p.c + true + $(IntDir)PluginComDll.tlb + + + + + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + NDEBUG;%(PreprocessorDefinitions) + + + Windows + .\PluginComDll.def + true + true + true + false + \$(Configuration)\$(Platform)\$(TargetName).pdb + + + + + false + false + + + + + false + false + + + + + + + + false + false + + + + + false + false + + + + + + + Create + Create + Create + Create + + + + + + false + false + + + + + false + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginComDll/PluginComDll.vcxproj.filters b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.vcxproj.filters new file mode 100644 index 0000000000000000000000000000000000000000..aaebbe2129c403cbfb9b3f0f34ffe211842b6673 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/PluginComDll.vcxproj.filters @@ -0,0 +1,110 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {8153f5ab-ee41-475a-9302-f858f98c99a9} + False + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 鐢熸垚鐨勬枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 鐢熸垚鐨勬枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + + + 璧勬簮鏂囦欢 + + + + + + 璧勬簮鏂囦欢 + + + 婧愭枃浠 + + + 璧勬簮鏂囦欢 + + + 璧勬簮鏂囦欢 + + + 璧勬簮鏂囦欢 + + + + + 婧愭枃浠 + + + \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginComDll/PluginConfig.json b/ZbaSDK/SampleCode/PluginComDll/PluginConfig.json new file mode 100644 index 0000000000000000000000000000000000000000..a154d3ea10127716d8d5f15b39f283fe91d62772 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/PluginConfig.json @@ -0,0 +1,27 @@ +{ + "Type": 1, + "OS": 1, + "Control": 0, + "OSMinVer": "5.0", + "Version": "2.0.2.1", + "Name": "鏃犵獥鍙e皬绋嬪簭鑼冧緥(C++璇█)", + "Corp": "ZorroSoft", + "Icon": "", + "Date": "2020.08.25", + "Desc": "鏃犵獥鍙e皬绋嬪簭(C++璇█)-璇诲啓TXT璁颁簨鏈強鑾峰彇褰撳墠绯荤粺淇℃伅", + "Home": "http://zorrosoft.com/WRL", + "Down": "http://zorrosoft.com/WRL", + "Module": "PluginComDll.dll", + "PID": "A22E18F1-95F8-4FDB-99D2-188E5FB12B23", + "Objects": [ + { + "ProgID": "C38672FA-B5C8-4D9D-89B5-2D71F0760661", + "ClassID": "40613676-C8A5-4879-A59B-9CE6406476F6" + }, + { + "ProgID": "E46E1B5B-2891-414F-A21A-17B00231E650", + "ClassID": "6D7595BD-BFB0-4D2C-906B-247028691A50" + } + ], + "Updates": [] +} \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginComDll/ReadMe.txt b/ZbaSDK/SampleCode/PluginComDll/ReadMe.txt new file mode 100644 index 0000000000000000000000000000000000000000..2b18d781a4e0e3245483a795f99ee552095e57e2 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/ReadMe.txt @@ -0,0 +1,60 @@ +锘======================================================================== + 娲诲姩妯℃澘搴 : PluginComDll 椤圭洰姒傝堪 +======================================================================== + +搴旂敤绋嬪簭鍚戝宸蹭负鎮ㄥ垱寤轰簡姝 PluginComDll 椤圭洰锛屼綔涓虹紪鍐欏姩鎬侀摼鎺ュ簱 (DLL) +鐨勮捣鐐广 + +鏈枃浠舵瑕佷粙缁嶇粍鎴愰」鐩殑姣忎釜鏂囦欢鐨勫唴瀹广 + +PluginComDll.vcxproj + 杩欐槸浣跨敤搴旂敤绋嬪簭鍚戝鐢熸垚鐨 VC++ 椤圭洰鐨勪富椤圭洰鏂囦欢锛 + 鍏朵腑鍖呭惈鐢熸垚璇ユ枃浠剁殑 Visual C++ 鐨勭増鏈俊鎭紝 + 浠ュ強鏈夊叧浣跨敤搴旂敤绋嬪簭鍚戝閫夋嫨鐨勫钩鍙般侀厤缃拰椤圭洰鍔熻兘鐨勪俊鎭 + +PluginComDll.vcxproj.filters + 杩欐槸浣跨敤鈥滃簲鐢ㄧ▼搴忓悜瀵尖濈敓鎴愮殑 VC++ 椤圭洰绛涢夊櫒鏂囦欢銆 + 瀹冨寘鍚湁鍏抽」鐩枃浠朵笌绛涢夊櫒涔嬮棿鐨勫叧鑱斾俊鎭 鍦 IDE 涓紝閫氳繃杩欑鍏宠仈锛 + 鍦ㄧ壒瀹氳妭鐐逛笅浠ュ垎缁勫舰寮忔樉绀哄叿鏈夌浉浼兼墿灞曞悕鐨勬枃浠躲 + 渚嬪锛屸.cpp鈥濇枃浠朵笌鈥滄簮鏂囦欢鈥濈瓫閫夊櫒鍏宠仈銆 + +PluginComDll.idl + 姝ゆ枃浠跺寘鍚」鐩腑瀹氫箟鐨勭被鍨嬪簱銆佹帴鍙e拰缁勪欢绫荤殑 IDL 瀹氫箟銆 + 姝ゆ枃浠跺皢鐢 MIDL 缂栬瘧鍣ㄥ鐞嗕互鐢熸垚锛 + C++ 鎺ュ彛瀹氫箟鍜 GUID 澹版槑 (PluginComDll.h) + GUID 瀹氫箟 (PluginComDll_i.c) + 绫诲瀷搴 (PluginComDll.tlb) + 灏侀佸鐞嗕唬鐮 (PluginComDll_p.c 鍜 + dlldata.c锛 + +PluginComDll.h + 姝ゆ枃浠跺寘鍚 PluginComDll.idl 涓畾涔夌殑椤圭洰鐨 C++ 鎺ュ彛瀹氫箟 + 鍜 GUID 澹版槑銆 瀹冨皢鍦ㄧ紪璇戣繃绋嬩腑鐢 MIDL 閲嶆柊鐢熸垚銆 + +PluginComDll.cpp + 姝ゆ枃浠跺寘鍚璞℃槧灏勫拰 DLL 瀵煎嚭鐨勫疄鐜般 + +PluginComDll.rc + 杩欐槸绋嬪簭浣跨敤鐨勬墍鏈 Microsoft Windows 璧勬簮鐨勫垪琛ㄣ + +PluginComDll.def + 姝ゆā鍧楀畾涔夋枃浠朵负閾炬帴鍣ㄦ彁渚涙湁鍏 DLL 鎵瑕佹眰鐨勫鍑虹殑淇℃伅锛 + 瀹冨寘鍚敤浜庝互涓嬪唴瀹圭殑瀵煎嚭锛 + DllGetClassObject + DllCanUnloadNow + DllRegisterServer + DllUnregisterServer + DllInstall + +///////////////////////////////////////////////////////////////////////////// +鍏朵粬鏍囧噯鏂囦欢锛 + +StdAfx.h锛孲tdAfx.cpp + 杩欎簺鏂囦欢鐢ㄤ簬鐢熸垚鍚嶄负 PluginComDll.pch 鐨勯缂栬瘧澶 (PCH) 鏂囦欢鍜 + 鍚嶄负 StdAfx.obj 鐨勯缂栬瘧绫诲瀷鏂囦欢銆 + +Resource.h + 杩欐槸鐢ㄤ簬瀹氫箟璧勬簮 ID 鐨勬爣鍑嗗ご鏂囦欢銆 + + +///////////////////////////////////////////////////////////////////////////// diff --git a/ZbaSDK/SampleCode/PluginComDll/SysInfo.cpp b/ZbaSDK/SampleCode/PluginComDll/SysInfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa2eb6d7840964c2fd014fef578c0f3a0e4f703a --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/SysInfo.cpp @@ -0,0 +1,29 @@ +// SysInfo.cpp : CSysInfo 的实现 + +#include "stdafx.h" +#include "SysInfo.h" +#include + +// CSysInfo +STDMETHODIMP CSysInfo::RecText(BSTR bstrContent) +{ + // TODO: Add your implementation code here + ATLASSERT(NULL != m_spiSocketConnect); + if(NULL == bstrContent || NULL == m_spiSocketConnect) + return E_POINTER; + m_spiSocketConnect->put_ActiveTime(COleDateTime::GetCurrentTime().m_dt); + /// 请处理收到的文本信息,这里演示直接回复原内容 + ULONG nReqID = 0; + m_spiSocketConnect->AsynSendText(bstrContent,&nReqID); + return S_OK; +} + +STDMETHODIMP CSysInfo::RecJson(ULONG nReqID,BSTR bstrReqName,BSTR bstrContent) +{ + // TODO: Add your implementation code here + ATLASSERT(NULL != m_spiSocketConnect); + if(NULL == bstrContent || NULL == m_spiSocketConnect) + return E_POINTER; + /// 请处理收到的普通JSON数据包 + return S_OK; +} diff --git a/ZbaSDK/SampleCode/PluginComDll/SysInfo.h b/ZbaSDK/SampleCode/PluginComDll/SysInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..e32b90348c14c36bdbfebdf8da190faed26151e3 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/SysInfo.h @@ -0,0 +1,116 @@ +// SysInfo.h : CSysInfo 的声明 + +#pragma once +#include "resource.h" // 主符号 +#ifdef _USRDLL +#include "PluginComDll_i.h" +#else +#include "PluginComExe_i.h" +#endif +#include "_ISysInfoEvents_CP.h" + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Windows CE 平台(如不提供完全 DCOM 支持的 Windows Mobile 平台)上无法正确支持单线程 COM 对象。定义 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可强制 ATL 支持创建单线程 COM 对象实现并允许使用其单线程 COM 对象实现。rgs 文件中的线程模型已被设置为“Free”,原因是该模型是非 DCOM Windows CE 平台支持的唯一线程模型。" +#endif + +// CSysInfo + +class ATL_NO_VTABLE CSysInfo : + public CComObjectRootEx, + public CComCoClass, + public IConnectionPointContainerImpl, + public CProxy_ISysInfoEvents, +#ifdef _USRDLL + public IDispatchImpl, +#else + public IDispatchImpl, +#endif + public IDispatchImpl +{ +protected: + /// WEB SOCKET连接对象 + IWebSocketConnectPtr m_spiSocketConnect; + +public: + CSysInfo() + :m_spiSocketConnect(NULL) + { + } + + DECLARE_REGISTRY_RESOURCEID(IDR_SYSINFO) + + BEGIN_COM_MAP(CSysInfo) + COM_INTERFACE_ENTRY(ISysInfo) + COM_INTERFACE_ENTRY2(IDispatch, IWrlConn) + COM_INTERFACE_ENTRY(IConnectionPointContainer) + COM_INTERFACE_ENTRY(IWrlConn) + END_COM_MAP() + + BEGIN_CONNECTION_POINT_MAP(CSysInfo) + CONNECTION_POINT_ENTRY(__uuidof(_ISysInfoEvents)) + END_CONNECTION_POINT_MAP() + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct() + { + return S_OK; + } + + void FinalRelease() + { + if (NULL != m_spiSocketConnect) + m_spiSocketConnect = NULL; + } + +public: + + // IWrlConn Methods + STDMETHOD(Load)(LPDISPATCH piDispatch,BSTR bstrAuthInfo,BSTR bstrLang) + { + HRESULT hRet = piDispatch->QueryInterface(IID_IWebSocketConnect,(LPVOID *)&m_spiSocketConnect); + ATLASSERT(NULL != m_spiSocketConnect); + return hRet; + } + + STDMETHOD(Unload)(EWrlCloseConnType eCloseConnType, BSTR bstrReason) + { + if(NULL != m_spiSocketConnect) + m_spiSocketConnect = NULL; + return S_OK; + } + + STDMETHOD(UsbChanged)(BSTR bstrDisk, ULONG nStatus, BSTR bstrName) + { + /// 收到USB变化通知 + return S_OK; + } + + STDMETHOD(SendJson)(BSTR bstrContent) + { + HRESULT hRet(S_FALSE); + if (NULL != m_spiSocketConnect) + { + ULONG nRet = 0; + hRet = m_spiSocketConnect->AsynSendText(bstrContent, &nRet); + } + return hRet; + } + + STDMETHOD(RecText)(BSTR bstrContent); + + STDMETHOD(RecJson)(ULONG nReqID,BSTR bstrReqName,BSTR bstrContent); + + STDMETHOD(RecByte)(BYTE* pContent,ULONG nLen) + { + return S_FALSE; + } + + STDMETHOD(HttpRequst)(BSTR bstrUrl,BSTR bstrPara, BSTR* pVal) + { + /// HTTP服务请求响应 + return E_NOTIMPL; + } +}; + +OBJECT_ENTRY_AUTO(__uuidof(SysInfo), CSysInfo) diff --git a/ZbaSDK/SampleCode/PluginComDll/SysInfo.rgs b/ZbaSDK/SampleCode/PluginComDll/SysInfo.rgs new file mode 100644 index 0000000000000000000000000000000000000000..bafa94b88814bfa0828b584ec5bfe067560ffe20 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/SysInfo.rgs @@ -0,0 +1,26 @@ +HKCR +{ + PluginComDll.SysInfo.1 = s 'SysInfo Class' + { + CLSID = s '{6D7595BD-BFB0-4D2C-906B-247028691A50}' + } + PluginComDll.SysInfo = s 'SysInfo Class' + { + CurVer = s 'PluginComDll.SysInfo.1' + } + NoRemove CLSID + { + ForceRemove {6D7595BD-BFB0-4D2C-906B-247028691A50} = s 'SysInfo Class' + { + ProgID = s 'PluginComDll.SysInfo.1' + VersionIndependentProgID = s 'PluginComDll.SysInfo' + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{A22E18F1-95F8-4FDB-99D2-188E5FB12B23}' + Version = s '1.0' + } + } +} diff --git a/ZbaSDK/SampleCode/PluginComDll/TextFile.cpp b/ZbaSDK/SampleCode/PluginComDll/TextFile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b300cfea07c486a2b3c6f716c4c5c344e3e5cf8f --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/TextFile.cpp @@ -0,0 +1,122 @@ +// TextFile.cpp : CTextFile 的实现 + +#include "stdafx.h" +#include +#include "TextFile.h" + +// CTextFile +STDMETHODIMP CTextFile::RecText(BSTR bstrContent) +{ + // TODO: Add your implementation code here + if(NULL == bstrContent || NULL == m_spiSocketConnect) + { + return E_POINTER; + } + HRESULT hRet = m_spiSocketConnect->put_ActiveTime(COleDateTime::GetCurrentTime().m_dt); + + /// 请处理收到的文本信息,这里演示直接回复原内容 + hRet = m_spiSocketConnect->AsynSendText(bstrContent,NULL); + ATLASSERT(SUCCEEDED(hRet)); + /// 也可以直接发送二进制数据流,建议把二进制流进行编码后再传输 +// BYTE szContent[] = "TestByte"; +// hRet = m_spiSocketConnect->AsynSendByte(szContent,strlen((char*)szContent),NULL); + return hRet; +} + +ATL::CString GetSpecialFolderPath(long lFoldID) +{ + TCHAR szSpecialPath[MAX_PATH]; + ::memset(szSpecialPath,0,MAX_PATH*sizeof(TCHAR)); + BOOL bGetFlag = ::SHGetSpecialFolderPath(NULL,szSpecialPath,lFoldID,TRUE); + if(!bGetFlag) + { + return _T(""); + } + + ATL::CString strSpecialPath(szSpecialPath); + ///路径后面都有"\" + if(!strSpecialPath.IsEmpty() && 0 != strSpecialPath.Right(1).CompareNoCase(_T("\\"))) + strSpecialPath+=_T("\\"); + return strSpecialPath; +} + +STDMETHODIMP CTextFile::RecJson(ULONG nReqID,BSTR bstrReqName,BSTR bstrContent) +{ + // TODO: Add your implementation code here + ATLASSERT(NULL != m_spiSocketConnect); + if(NULL == bstrContent || NULL == m_spiSocketConnect) + return E_POINTER; + m_spiSocketConnect->put_ActiveTime(COleDateTime::GetCurrentTime().m_dt); + IJsonServicePtr spiJsonService = NULL; + HRESULT hRet = spiJsonService.CreateInstance(__uuidof(JsonService)); + if(NULL == spiJsonService) + return hRet;/// 创建JSON解析器对象失败 + VARIANT_BOOL bLoadFlag = VARIANT_FALSE; + spiJsonService->put_CodingType(CODINGTYPE_US2); + hRet = spiJsonService->ParseString(bstrContent,&bLoadFlag); + if(VARIANT_FALSE == bLoadFlag) + { + spiJsonService = NULL; + return hRet; + } + /// 请处理收到的普通JSON数据包 + /// 在这里解析请求并作出回应 + CString strReqName(bstrReqName); + if(0 == strReqName.CompareNoCase(L"Demo_WriteFile")) + { + CString strFilePath = GetSpecialFolderPath(CSIDL_COMMON_DESKTOPDIRECTORY); + CComBSTR bstrVal; + spiJsonService->GetStringValue(CComBSTR(L"Name"),&bstrVal);; + strFilePath += bstrVal.m_str; + bstrVal.Empty(); + spiJsonService->GetStringValue(CComBSTR(L"Content"),&bstrVal);; + CString strContent = bstrVal.m_str; + bstrVal.Empty(); + + CTextFileWrite WriteFile(strFilePath); + WriteFile.Write(strContent); + WriteFile.Close(); + CString strReturn; + strContent.Replace(L"\"",L"\\\""); + strFilePath.Replace(L"\\",L"/"); + strReturn.Format(_T("{\"rid\":%ld,\"data\":{\"Content\":\"%s\"}}"), \ + nReqID,strFilePath + L" 文件写入完成"); + m_spiSocketConnect->AsynSendText(CComBSTR(strReturn),NULL); + } + else if(0 == strReqName.CompareNoCase(L"Demo_ReadFile")) + { + CString strFilePath = GetSpecialFolderPath(CSIDL_COMMON_DESKTOPDIRECTORY); + CComBSTR bstrVal; + spiJsonService->GetStringValue(CComBSTR(L"Name"),&bstrVal);; + strFilePath += bstrVal.m_str; + bstrVal.Empty(); + + CString strReturn; + CTextFileRead ReadFile(strFilePath); + string strLine; + while(ReadFile.ReadLine(strLine)) + { + if(!strLine.length()) + continue;/// 空行不发送 + strReturn.Empty(); + strReturn.Format(_T("{\"rid\":%ld,\"data\":{\"ReadLine\":\"%s\"}}"), \ + nReqID,CString(strLine.c_str())); + m_spiSocketConnect->AsynSendText(CComBSTR(strReturn),NULL); + strLine.clear(); + } + ReadFile.Close(); + strReturn.Empty(); + strReturn.Format(_T("{\"rid\":%ld,\"data\":{\"End\":\"%s\"}}"), \ + nReqID,L"读取完成"); + m_spiSocketConnect->AsynSendText(CComBSTR(strReturn), NULL); + } + else + { + CString strReturn,strContent(bstrContent); + strContent.Replace(L"\"",L"\\\""); + strReturn.Format(L"{\"rid\":%ld,\"data\":{\"Req\":\"%s\",\"Content\":\"%s\",\"Status\":\"不识别的请求\"}}",\ + nReqID,strReqName,strContent); + m_spiSocketConnect->AsynSendText(CComBSTR(strReturn), NULL); + } + return S_OK; +} \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginComDll/TextFile.h b/ZbaSDK/SampleCode/PluginComDll/TextFile.h new file mode 100644 index 0000000000000000000000000000000000000000..62c0303b77b6dca8df9bbd0c78c5f313fed6ad91 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/TextFile.h @@ -0,0 +1,122 @@ +// TextFile.h : CTextFile 的声明 + +#pragma once +#include "resource.h" // 主符号 +#include +#ifdef _USRDLL +#include "PluginComDll_i.h" +#else +#include "PluginComExe_i.h" +#endif +#include "_ITextFileEvents_CP.h" +#include "TextFileHelper.h" + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Windows CE 平台(如不提供完全 DCOM 支持的 Windows Mobile 平台)上无法正确支持单线程 COM 对象。定义 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可强制 ATL 支持创建单线程 COM 对象实现并允许使用其单线程 COM 对象实现。rgs 文件中的线程模型已被设置为“Free”,原因是该模型是非 DCOM Windows CE 平台支持的唯一线程模型。" +#endif + +// CTextFile + +class ATL_NO_VTABLE CTextFile : + public CComObjectRootEx, + public CComCoClass, + public IConnectionPointContainerImpl, + public CProxy_ITextFileEvents, +#ifdef _USRDLL + public IDispatchImpl, +#else + public IDispatchImpl, +#endif + public IDispatchImpl +{ +protected: + + /// WEB SOCKET连接对象 + IWebSocketConnectPtr m_spiSocketConnect; + +public: + CTextFile() + :m_spiSocketConnect(NULL) + { + } + + DECLARE_REGISTRY_RESOURCEID(IDR_TEXTFILE) + + BEGIN_COM_MAP(CTextFile) + COM_INTERFACE_ENTRY(ITextFile) + COM_INTERFACE_ENTRY2(IDispatch, IWrlConn) + COM_INTERFACE_ENTRY(IConnectionPointContainer) + COM_INTERFACE_ENTRY(IWrlConn) + END_COM_MAP() + + BEGIN_CONNECTION_POINT_MAP(CTextFile) + CONNECTION_POINT_ENTRY(__uuidof(_ITextFileEvents)) + END_CONNECTION_POINT_MAP() + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct() + { + return S_OK; + } + + void FinalRelease() + { + if (NULL != m_spiSocketConnect) + m_spiSocketConnect = NULL; + } + +public: + + // IWrlConn Methods + STDMETHOD(Load)(LPDISPATCH piDispatch,BSTR bstrAuthInfo,BSTR bstrLang) + { + if(NULL == piDispatch) + return E_POINTER; + HRESULT hRet = piDispatch->QueryInterface(IID_IWebSocketConnect,(LPVOID *)&m_spiSocketConnect); + if(NULL != m_spiSocketConnect) + hRet = m_spiSocketConnect->put_ActiveTime(COleDateTime::GetCurrentTime().m_dt); + return hRet; + } + + STDMETHOD(Unload)(EWrlCloseConnType eCloseConnType, BSTR bstrReason) + { + if(NULL != m_spiSocketConnect) + m_spiSocketConnect = NULL; + return S_OK; + } + + STDMETHOD(UsbChanged)(BSTR bstrDisk, ULONG nStatus, BSTR bstrName) + { + /// 收到USB变化通知 + return S_OK; + } + + STDMETHOD(SendJson)(BSTR bstrContent) + { + HRESULT hRet(S_FALSE); + if (NULL != m_spiSocketConnect) + { + ULONG nRet = 0; + hRet = m_spiSocketConnect->AsynSendText(bstrContent,&nRet); + } + return hRet; + } + + STDMETHOD(RecText)(BSTR bstrContent); + + STDMETHOD(RecJson)(ULONG nReqID,BSTR bstrReqName,BSTR bstrContent); + + STDMETHOD(RecByte)(BYTE* pContent,ULONG nLen) + { + return S_FALSE; + } + + STDMETHOD(HttpRequst)(BSTR bstrUrl,BSTR bstrPara, BSTR* pVal) + { + /// HTTP服务请求响应 + return E_NOTIMPL; + } +}; + +OBJECT_ENTRY_AUTO(__uuidof(TextFile), CTextFile) \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginComDll/TextFile.rgs b/ZbaSDK/SampleCode/PluginComDll/TextFile.rgs new file mode 100644 index 0000000000000000000000000000000000000000..0f807b8de0a70aa813e41e3f6b39873dee2e0cc0 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/TextFile.rgs @@ -0,0 +1,26 @@ +HKCR +{ + PluginComDll.TextFile.1 = s 'TextFile Class' + { + CLSID = s '{40613676-C8A5-4879-A59B-9CE6406476F6}' + } + PluginComDll.TextFile = s 'TextFile Class' + { + CurVer = s 'PluginComDll.TextFile.1' + } + NoRemove CLSID + { + ForceRemove {40613676-C8A5-4879-A59B-9CE6406476F6} = s 'TextFile Class' + { + ProgID = s 'PluginComDll.TextFile.1' + VersionIndependentProgID = s 'PluginComDll.TextFile' + ForceRemove Programmable + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + TypeLib = s '{A22E18F1-95F8-4FDB-99D2-188E5FB12B23}' + Version = s '1.0' + } + } +} diff --git a/ZbaSDK/SampleCode/PluginComDll/TextFileHelper.cpp b/ZbaSDK/SampleCode/PluginComDll/TextFileHelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44b8589ba7da54a11499b4b813869a146d3b73d9 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/TextFileHelper.cpp @@ -0,0 +1,1592 @@ +/* NOTE: If you running this in a none-Windows platform, + then you should remove the include file below. + */ +#include "stdafx.h" +#include "TextFileHelper.h" + +#if PEK_TX_TECHLEVEL == 0 + //Include iostream if running in ANSI mode. + #include +#endif + +#pragma warning( disable : 4996) + +//在段模式下,没条记录允许的段数 +#define ENABLESECTION_SECTION_COUNT 10 + +//Base constructor +CTextFileBase::CTextFileBase() +{ + #if PEK_TX_TECHLEVEL > 0 + m_codepage = CP_ACP; + m_unknownChar = 0; + #else + m_unknownChar = '?'; + #endif + + #if PEK_TX_TECHLEVEL == 1 + m_hFile = INVALID_HANDLE_VALUE; + #elif PEK_TX_TECHLEVEL == 2 + m_file = NULL; + m_closeAndDeleteFile = false; + #endif + + m_datalost = false; + + m_buffpos = -1; +} + +//Base destructor +CTextFileBase::~CTextFileBase() +{ + Close(); +} + +//Set which character to use when conversion can't be done +void CTextFileBase::SetUnknownChar(const char unknown) +{ + m_unknownChar = unknown; +} + +//True if data was lost during conversion +bool CTextFileBase::IsDataLost() const +{ + return m_datalost; +} + +//Reset the data lost flag +void CTextFileBase::ResetDataLostFlag() +{ + m_datalost = false; +} + +#if PEK_TX_TECHLEVEL > 0 + +//Make sure we have a legal value for code page to use when +//converting string. Used for debugging only. +#define IsLegalCodePage(cp) (cp == CP_ACP || cp == CP_MACCP || cp == CP_OEMCP || cp == CP_SYMBOL || cp == CP_THREAD_ACP || cp == CP_UTF7 || cp == CP_UTF8 || IsValidCodePage(cp)) + +//(Windows-specific) Set codepage to use when working with non-unicode strings. +void CTextFileBase::SetCodePage(const UINT codepage) +{ + ATLASSERT(IsLegalCodePage(codepage)); + m_codepage = codepage; +} + +//(Windows-specific) Get codepage to use when working with non-unicode strings. +UINT CTextFileBase::GetCodePage() const +{ + return m_codepage; +} + +//(Windows-specific) Convert string to wstring with current codepage +inline void CTextFileBase::CharToWstring(const char* from, wstring &to) const +{ + ConvertCharToWstring(from, to, m_codepage); +} + +//(Windows-specific) Convert wstring to string with current codepage +inline void CTextFileBase::WcharToString(const wchar_t* from, string &to) +{ + ConvertWcharToString(from, to, m_codepage, &m_datalost, m_unknownChar); +} + +//(Windows-specific) Convert char* to wstring +void CTextFileBase::ConvertCharToWstring(const char* from, wstring &to, UINT codepage) +{ + to = L""; + + ATLASSERT(IsLegalCodePage(codepage)); + //Use api convert routine + int wlen = MultiByteToWideChar( codepage, + 0, + from, + -1, + NULL, + 0); + + //if wlen == 0, some unknown codepage was probably used. + ATLASSERT(wlen); + if(wlen == 0) + return; + + wchar_t* wbuffer = new wchar_t[wlen+2]; + + MultiByteToWideChar( codepage, + 0, + from, + -1, + wbuffer, + wlen); + to = wbuffer; + delete [] wbuffer; + +} + +//(Windows-specific) Convert wchar_* to string +void CTextFileBase::ConvertWcharToString(const wchar_t* from, string &to, + UINT codepage, bool* datalost, char unknownchar) +{ + to = ""; + + ATLASSERT(IsLegalCodePage(codepage)); + + int alen = WideCharToMultiByte( codepage, + 0, + from, + -1, + NULL, + 0, + NULL, + NULL); + + //if alen == 0, some unknown codepage was probably used. + ATLASSERT(alen); + if(alen == 0) + return; + //Use mfc convert routine + char* abuffer = new char[alen+2]; + BOOL UsedDefault=FALSE; + + WideCharToMultiByte( codepage, + 0, + from, + -1, + abuffer, + alen, + (unknownchar != 0 ? &unknownchar : NULL), + (datalost != NULL ? &UsedDefault : NULL) + ); + + if( datalost != NULL && UsedDefault != FALSE) + *datalost = true; + + to = abuffer; + delete [] abuffer; +} + +#else + +//(None-windows-specific) Convert string to wstring +inline void CTextFileBase::CharToWstring(const char* from, wstring &to) const +{ + ConvertCharToWstring(from, to); +} + +//(None-windows-specific) Convert wstring to string +inline void CTextFileBase::WcharToString(const wchar_t* from, string &to) +{ + ConvertWcharToString(from, to, &m_datalost, m_unknownChar); +} + +//(None-windows-specific) Convert char* to wstring +void CTextFileBase::ConvertCharToWstring(const char* from, wstring &to) +{ + to = L""; + + size_t pos=0; + wchar_t temp[1]; + + while(true) + { + size_t len = mbtowc(temp, from+pos, MB_CUR_MAX); + //Found end + if(len == 0) + return; + else if(len == (size_t)-1) + { + //Unknown character, should never happen + pos++; + } + else + { + to += temp[0]; + pos += len; + } + } +} + +//(None-windows-specific) Convert wchar_* to string +void CTextFileBase::ConvertWcharToString(const wchar_t* from, string &to, bool* datalost, char unknownchar) +{ + to = ""; + char* temp = new char[MB_CUR_MAX]; + while(*from != L'\0') + { + size_t len = wctomb(temp, *from); + + //Found end + if(len == 0) + break; + else if(len == (size_t)-1) + { + //Replace with unknown character + to += unknownchar; + + if(datalost != NULL) + *datalost=true; + } + else + { + //Copy all characters + for(size_t i=0; im_hFile != CFile::hFileNull); +#endif +} + +//Close file +void CTextFileBase::Close() +{ + if(IsOpen()) + { +#if PEK_TX_TECHLEVEL == 0 + m_file.close(); +#elif PEK_TX_TECHLEVEL == 1 + ::CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; +#else + if(m_closeAndDeleteFile) + { + m_file->Close(); + } +#endif + } + +#if PEK_TX_TECHLEVEL == 2 + if(m_closeAndDeleteFile) + { + delete m_file; + m_file = NULL; + } +#endif +} + +BOOL IsPathExist(const ATL::CString& strPath) +{ + BOOL bRet = FALSE; + if(strPath.IsEmpty()) + return bRet; + WIN32_FIND_DATA data; + BOOL bFindDir = FALSE; + + ATL::CString strFind(strPath); + if (0 == strPath.Right(1).CompareNoCase( _T("\\"))) + { + /// 查找目录 + bFindDir = TRUE; + strFind+=_T("*.*"); + } + + HANDLE hFindFile = ::FindFirstFile(strFind,&data); + if(INVALID_HANDLE_VALUE != hFindFile) + { + if(bFindDir) + { + while(INVALID_HANDLE_VALUE != hFindFile) + { + if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY ) + { + + bRet = TRUE; + break; + } + if (!FindNextFile(hFindFile,&data)) + break; + } + } + else + bRet = TRUE; + ::FindClose(hFindFile); + hFindFile = NULL; + } + else + bRet=FALSE; + return bRet; +} + +BOOL CreatePath(const ATL::CString& strLocalDir) +{ + BOOL bCreateFlag = FALSE; + ATL::CString strWorkDir,strPath=strLocalDir; + int index = -2; + index = strPath.Find(_T('\\')); + if(index == -1) + return FALSE; + strWorkDir = strPath.Left(index); + strPath.Delete(0,index+1); + while(strPath.GetLength()) + { + index=strPath.Find(_T('\\')); + if(index == -1) + { + bCreateFlag = ::CreateDirectory(strLocalDir,NULL); + strWorkDir.Empty(); + strPath.Empty(); + break; + } + strWorkDir+=_T("\\"); + strWorkDir+=strPath.Left(index); + strPath.Delete(0,index+1); + if(!IsPathExist(strWorkDir+_T("\\"))) + bCreateFlag = ::CreateDirectory(strWorkDir,NULL); + } + if(!bCreateFlag) + { + DWORD dwErrCode = ::GetLastError(); + ::Sleep(100); + } + return bCreateFlag; +} + +//Create textfile +CTextFileWrite::CTextFileWrite(const FILENAMECHAR* filename, TEXTENCODING encoding) +{ + CString strFilPath(filename); + int iFind = strFilPath.ReverseFind(_T('\\')); + if(-1 != iFind) + { + /// 创建目录 + CreatePath(strFilPath.Left(iFind)); + } + +#if PEK_TX_TECHLEVEL == 0 + m_file.open(filename, ios::binary | ios::out ); +#elif PEK_TX_TECHLEVEL == 1 + + m_hFile = ::CreateFile( filename, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + +#else + m_file = new CFile; + m_file->Open(filename, CFile::modeCreate | CFile::modeWrite); + + m_closeAndDeleteFile = true; +#endif + m_buffpos = -1; + m_buffsize = 0; + + m_encoding = encoding; + + WriteBOM(); +} + +#if PEK_TX_TECHLEVEL==2 +//Create textfile from CFile object +CTextFileWrite::CTextFileWrite(CFile* file, TEXTENCODING encoding) +{ + ATLASSERT(file); + + m_file = file; + m_closeAndDeleteFile = false; + + m_encoding = encoding; + + m_buffpos = -1; + m_buffsize = 0; + + WriteBOM(); +} +#endif + +CTextFileWrite::~CTextFileWrite() +{ + Close(); +} + +void CTextFileWrite::WriteBOM() +{ + //Write BOM + if(IsOpen()) + { + if(m_encoding == UNI16_BE || m_encoding == UNI16_LE) + { + //Write BOM + WriteWchar( 0xFEFF ); + } + else if(m_encoding == UTF_8) + { + //Write UTF-8 BOM. 0xEF 0xBB 0xBF + WriteByte(0xEF); + WriteByte(0xBB); + WriteByte(0xBF); + } + } +} + +//Write one byte +void CTextFileWrite::WriteByte(const unsigned char byte) +{ + //Instead of writing, save data in buffer and write when buffer is full + if(m_buffpos+1 >= BUFFSIZE) + Flush(); + + m_buffpos++; + m_buf[m_buffpos] = byte; +} + +//Write and empty buffer +void CTextFileWrite::Flush() +{ +#if PEK_TX_TECHLEVEL==0 + m_file.write(m_buf, m_buffpos+1); +#elif PEK_TX_TECHLEVEL==1 + + DWORD nWritten; + if (!::WriteFile(m_hFile, m_buf, m_buffpos+1, &nWritten, NULL)) + { + //Something bad has happend! Close file + CTextFileBase::Close(); + + //Throw exception + throw CTextFileException(GetLastError()); + } + +#else + m_file->Write(m_buf, m_buffpos+1); +#endif + + m_buffpos = -1; +} + +void CTextFileWrite::WriteWchar(const wchar_t ch) +{ + //Write HO byte first? + if(m_encoding == UNI16_BE) + { + //Write HO byte + WriteByte((unsigned char) (ch >> 8) ); + //Write LO byte + WriteByte((unsigned char) ch); + } + else if(m_encoding == UNI16_LE) + { + //Write LO byte + WriteByte((unsigned char) ch); + //Write HO byte + WriteByte((unsigned char) (ch >> 8) ); + } + else + { + //http://www.cl.cam.ac.uk/~mgk25/unicode.html#examples + //http://www.ietf.org/rfc/rfc3629.txt + + //Just a single byte? + if(ch <= 0x7F) + { + //U-00000000 - U-0000007F: 0xxxxxxx + WriteByte( (unsigned char) ch ); + } + + //Two bytes? + else if(ch <= 0x7FF) + { + //U-00000080 - U-000007FF: 110xxxxx 10xxxxxx + WriteByte( (unsigned char) (0xC0 | (ch>>6)) ); + WriteByte( (unsigned char) (0x80 | (ch&0x3F)) ); + } + + //Three bytes? + else if(ch <= 0xFFFF) + { + //U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx + WriteByte( (unsigned char) (0xE0 | ( ch>>12) )); + WriteByte( (unsigned char) (0x80 | ( (ch>>6)&0x3F ) )); + WriteByte( (unsigned char) (0x80 | ( ch&0x3F ) )); + } + + /* //UPS! I did some coding for UTF-32, may be useful in the future :-) + //Four bytes? + else if(ch <= 0x1FFFFF) + { + //U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + WriteByte( (unsigned char) (0xF0 | ( ch>>18) )); + WriteByte( (unsigned char) (0xA0 | ( (ch>>12)&0xA0 ) )); + WriteByte( (unsigned char) (0xA0 | ( (ch>>6)&0xA0 ) )); + WriteByte( (unsigned char) (0xA0 | ( ch&0xA0 ) )); + } + + //Five bytes bytes? + else if(ch <= 0x3FFFFFF) + { + //U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + WriteByte( (unsigned char) (0xF8 | ( ch>>24) )); + WriteByte( (unsigned char) (0xA0 | ( (ch>>18)&0xA0 ) )); + WriteByte( (unsigned char) (0xA0 | ( (ch>>12)&0xA0 ) )); + WriteByte( (unsigned char) (0xA0 | ( (ch>>6)&0xA0 ) )); + WriteByte( (unsigned char) (0xA0 | ( ch&0xA0 ) )); + } + + //Five bytes bytes? + else if(ch <= 0x7FFFFFFF) + { + //U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + WriteByte( (unsigned char) (0xFC | ( ch>>30) )); + WriteByte( (unsigned char) (0xA0 | ( (ch>>24)&0xA0 ) )); + WriteByte( (unsigned char) (0xA0 | ( (ch>>18)&0xA0 ) )); + WriteByte( (unsigned char) (0xA0 | ( (ch>>12)&0xA0 ) )); + WriteByte( (unsigned char) (0xA0 | ( (ch>>6)&0xA0 ) )); + WriteByte( (unsigned char) (0xA0 | ( ch&0xA0 ) )); + }*/ + } +} + +//Write new line +void CTextFileWrite::WriteEndl() +{ + if(m_encoding == ASCII) + { + WriteByte(0x0D); + WriteByte(0x0A); + } + else + { + WriteWchar(0x0D); + WriteWchar(0x0A); + } +} + +//Write a c-string in ASCII. +//In versions before 1.02 this function wrote directly to file, +//no buffer was used. But sense WriteEndl() used buffer the file was +//written incorretly. Now buffer is used here too, this is the +//fastest solution. +void CTextFileWrite::WriteAsciiString(const char* s) +{ + while(*s != '\0') + { + WriteByte(*s); + s++; + } +} + +CTextFileWrite& CTextFileWrite::operator<< (const char* text) +{ + Write(text); + return *this; +}; + +CTextFileWrite& CTextFileWrite::operator << (const string& text) +{ + Write(text.c_str()); + return *this; +} + +CTextFileWrite& CTextFileWrite::operator<< (const wchar_t* text) +{ + Write(text); + return *this; +}; + +CTextFileWrite& CTextFileWrite::operator << (const wstring& text) +{ + Write(text.c_str()); + return *this; +} + +CTextFileWrite& CTextFileWrite::operator<< (const wchar_t wc) +{ + //Not the perfect code, but it's easy! + wstring text; + text=wc; + Write(text.c_str()); + return *this; +}; + +CTextFileWrite& CTextFileWrite::operator<< (const char c) +{ + //Not the perfect code, but it's easy! + string text; + text=c; + Write(text.c_str()); + return *this; +}; + +BOOL CTextFileWrite::Write(const string& text) +{ + try + { + Write(text.c_str()); + } + catch ( ... ) + { + return FALSE; + } + return TRUE; +} + +BOOL CTextFileWrite::Write(const wstring& text) +{ + try + { + Write(text.c_str()); + } + catch ( ... ) + { + return FALSE; + } + return TRUE; +} + +//Write char* +void CTextFileWrite::Write(const char* text) +{ + //ASCIItext file format? + if(m_encoding == ASCII) + WriteAsciiString(text); + else + { + //Convert text to unicode + wstring utext; + CharToWstring(text, utext); + + //OK, lets write unicode + for(wstring::const_iterator i=utext.begin(); + i < utext.end(); + i++) + { + WriteWchar(*i); + } + + } +} + +//Write wcar_t* +void CTextFileWrite::Write(const wchar_t* utext) +{ + //ASCII text file format? + if(m_encoding == ASCII) + { + //Convert to string and write + string text; + WcharToString(utext, text); + WriteAsciiString(text.c_str()); + } + else + { + while(*utext != 0) + { + WriteWchar(*utext); + utext++; + } + } +} + +//Close the file +void CTextFileWrite::Close() +{ + if(IsOpen()) + Flush(); + + CTextFileBase::Close(); +} + +CTextFileRead::CTextFileRead(const FILENAMECHAR* filename) +{ + +#if PEK_TX_TECHLEVEL==0 + //If not Windows, do this + m_file.open(filename, ios::binary | ios::in); +#elif PEK_TX_TECHLEVEL == 1 + + m_hFile = ::CreateFile( filename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); +#else + m_file = new CFile; + //In windows, do this + m_file->Open(filename, CFile::modeRead | CFile::shareDenyWrite ); + m_closeAndDeleteFile = true; +#endif + + m_firstLine = true; + m_endoffile = (IsOpen()==0); + + //Force reading to buffer next time + m_buffpos=-1; + + m_useExtraBuffer = false; + + //段落信息无效 + m_section_enable = false; + + m_buf_first_section = -1; + m_wbuf_first_section = -1; + + m_current_pos = 0; + m_section_count = 0; + + m_dirty = false; + + ReadBOM(); +} + +#if PEK_TX_TECHLEVEL==2 +CTextFileRead::CTextFileRead(CFile* file) +{ + ATLASSERT(file); + + m_file = file; + m_closeAndDeleteFile = false; + + m_firstLine = true; + m_endoffile = (IsOpen()==0); + + //Force reading to buffer next time + m_buffpos=-1; + + m_useExtraBuffer=false; + + ReadBOM(); +} +#endif + +void CTextFileRead::ReadBOM() +{ + if( IsOpen() ) + { + unsigned char bytes[2]; + + //Read the first two bytes + ReadByte(bytes[0]); + ReadByte(bytes[1]); + + //Figure out what format the file is in + if( bytes[0] == 0xFF && bytes[1] == 0xFE) + m_encoding = UNI16_LE; + else if( bytes[0] == 0xFE && bytes[1] == 0xFF) + m_encoding = UNI16_BE; + else if( bytes[0] == 0xEF && bytes[1] == 0xBB) + { + //This is probably UTF-8, check the third byte + unsigned char temp; + ReadByte(temp); + if( temp == 0xBF) + m_encoding = UTF_8; + else + { + //Set text format. + m_encoding = ASCII; + ResetFilePointer(); + } + } + else + { + m_encoding = ASCII; + + //Set start pos + ResetFilePointer(); + } + } +} + +//End of file? +bool CTextFileRead::Eof() const +{ + return m_endoffile; +} + +//Read one byte +void CTextFileRead::ReadByte(unsigned char& ch) +{ + //Use extrabuffer if needed + if(m_useExtraBuffer) + { + m_useExtraBuffer=false; + ch = m_extraBuffer_char; + return; + } + //In Windows, do this... + //If buffer used or not read + if(m_buffpos==-1 || m_buffpos == BUFFSIZE-1) + { +#if PEK_TX_TECHLEVEL==0 + m_buffsize = m_file.read(m_buf, BUFFSIZE).gcount(); +#elif PEK_TX_TECHLEVEL==1 + + DWORD dwRead; + if (!::ReadFile(m_hFile, m_buf, BUFFSIZE, &dwRead, NULL)) + { + //Couldn't read! + Close(); + m_buffsize = 0; + + //Throw exception + throw CTextFileException(GetLastError()); + } + else + m_buffsize = (int) dwRead; + +#else + m_buffsize=m_file->Read(m_buf, BUFFSIZE); +#endif + + if(m_buffsize == 0) + { + m_endoffile=true; + ch = 0; + return; + } + + m_buffpos=0; + } + else + { + m_buffpos++; + + if(m_buffpos >= m_buffsize) + { + m_endoffile=true; + ch = 0; + return; + } + } + + //当前位置增加 + m_current_pos++; + + ch = m_buf[m_buffpos]; +} + +void CTextFileRead::ReadWchar(wchar_t& ch) +{ + if(m_useExtraBuffer) + { + m_useExtraBuffer=false; + ch = m_extraBuffer_wchar; + return; + } + + if(m_encoding == UTF_8) + { + //This is quite tricky :-/ + //http://www.cl.cam.ac.uk/~mgk25/unicode.html#examples + unsigned char byte; + ReadByte(byte); + + int onesBeforeZero = 0; + + { //Calc how many ones before the first zero... + unsigned char temp = byte; + + while( (temp & 0x80)!=0 ) + { + temp = (unsigned char) (temp << 1); + onesBeforeZero++; + } + } + + if(onesBeforeZero==0) + { + ch = byte; + return; + } + else if(onesBeforeZero == 2) + { + //U-00000080 - U-000007FF: 110xxxxx 10xxxxxx + unsigned char byteb; + ReadByte(byteb); + + ch = (wchar_t) ( ((0x1F & byte) << 6)| + (0x3F & byteb) + ) ; + + return; + } + else if(onesBeforeZero == 3) + { + //U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx + unsigned char byteb, bytec; + ReadByte(byteb); + ReadByte(bytec); + + ch = (wchar_t) ( ((0x0F & byte) << 12) | + ((0x3F & byteb) << 6) | + (0x3F & bytec) ); + + return; + } + + //This should never happend! It it do, something is wrong with the file. + ch = 0xFFFD; + + } + else + { + + unsigned char bytes[2]; + ReadByte(bytes[0]); + ReadByte(bytes[1]); + + if(m_encoding == UNI16_BE) + ch = (wchar_t) ( ((wchar_t) bytes[0] << 8) | + (wchar_t) bytes[1] + ) ; + else + ch = (wchar_t) ( ((wchar_t) bytes[1] << 8) | + (wchar_t) bytes[0] + ); + } +} + +void CTextFileRead::ResetFilePointer() +{ + m_useExtraBuffer=false; + +#if PEK_TX_TECHLEVEL==0 + m_file.clear(); + m_file.seekg(0, ios::beg); + +#elif PEK_TX_TECHLEVEL==1 + + ::SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN); + m_section_position.clear(); + +#else + m_file->SeekToBegin(); +#endif + //Force reread buffer + m_buffpos=-1; + + m_current_pos = 0; + + m_firstLine = true; + m_endoffile = false; + +} + +bool CTextFileRead::ReadLine(string& line,bool bRecordSection ) +{ + //EOF? + if(Eof()) + return false; + + //使用章节序号获取的话,不允许正常的获取方法了 + if(!m_section_enable) + ATLASSERT(!bRecordSection); + + if(m_encoding == ASCII) + { + return ReadCharLine(line); + } + + wstring wline; + + if(!ReadWcharLine(wline)) + return false; + + //Convert + WcharToString(wline.c_str(), line); + + return true; +} + +bool CTextFileRead::ReadLine(wstring& line,bool bRecordSection) +{ + //EOF? + if(Eof()) + return false; + + if(m_encoding == ASCII) + { + string cline; + + if(!ReadCharLine(cline)) + return false; + + //Convert to wstring + CharToWstring(cline.c_str(), line); + + return true; + } + return ReadWcharLine(line); +} + +bool CTextFileRead::ReadLineByID(string& line,long section_id) +{ + ATLASSERT(m_section_enable); //段落打开 + + ATLASSERT(section_id >= 0); + ATLASSERT(section_id < m_section_count); + + ATLASSERT(m_hFile); + + if(m_buf_first_section != section_id/ENABLESECTION_SECTION_COUNT * ENABLESECTION_SECTION_COUNT) + { + //当前段不在缓冲区,填充缓冲区 + m_section_buf.clear(); + m_buf_first_section = section_id/ENABLESECTION_SECTION_COUNT * ENABLESECTION_SECTION_COUNT; + + //设置文件位置 + ::SetFilePointer(m_hFile, m_section_position[section_id/ENABLESECTION_SECTION_COUNT], NULL, FILE_BEGIN); + m_section_position[section_id/ ENABLESECTION_SECTION_COUNT]; + m_buffpos = -1; + m_endoffile = false; + m_useExtraBuffer=false; + + //跳过前几个 + for(long i = m_buf_first_section; + i < ENABLESECTION_SECTION_COUNT+m_buf_first_section && i< m_section_count; i++) + { + ReadLine(line); + m_section_buf.push_back(line); + } + } + + line = m_section_buf[section_id%ENABLESECTION_SECTION_COUNT]; + return true; +} + +bool CTextFileRead::ReadLineByID(wstring& line,long section_id) +{ + ATLASSERT(m_section_enable); //段落打开 + + ATLASSERT(section_id >= 0); + ATLASSERT(section_id < m_section_count); + + ATLASSERT(m_hFile); + + if(m_wbuf_first_section != section_id/ENABLESECTION_SECTION_COUNT * ENABLESECTION_SECTION_COUNT) + { + //当前段不在缓冲区,填充缓冲区 + m_wsection_buf.clear(); + m_wbuf_first_section = section_id/ENABLESECTION_SECTION_COUNT * ENABLESECTION_SECTION_COUNT; + + //设置文件位置 + ::SetFilePointer(m_hFile, m_section_position[section_id/ENABLESECTION_SECTION_COUNT], NULL, FILE_BEGIN); + m_section_position[section_id/ ENABLESECTION_SECTION_COUNT]; + m_buffpos = -1; + m_endoffile = false; + m_useExtraBuffer=false; + + //跳过前几个 + for(long i = m_wbuf_first_section; + i < ENABLESECTION_SECTION_COUNT+m_wbuf_first_section && i< m_section_count; i++) + { + ReadLine(line); + m_wsection_buf.push_back(line); + } + } + + line = m_wsection_buf[section_id%ENABLESECTION_SECTION_COUNT]; + return true; +} + +bool CTextFileRead::Read(string& all, const string newline) +{ + if(!IsOpen()) + return false; + + int buffsize = GuessCharacterCount()+2; + int buffpos = 0; + + //Create buffer + char* buffer = new char[buffsize]; + + //If not possible, don't use any buffer + if(buffer == NULL) + buffsize = 0; + + string temp; + all = temp; + all.reserve(buffsize); + bool firstLine=true; + + while(!Eof()) + { + if(ReadLine(temp)) + { + //Add new line, if not first line + if(!firstLine) + temp.insert(0, newline.c_str()); + else + firstLine=false; + + //Add to buffer if possible + if(buffpos + (int) temp.size() < buffsize) + { + strcpy(buffer+buffpos, temp.c_str()); + buffpos += (int) temp.size(); + } + else + { + //Copy to all string + if(buffpos != 0) + { + all.append(buffer, buffpos); + buffpos = 0; + } + all += temp; + } + } + }; + + //Copy to all string + if(buffpos != 0) + { + all.append(buffer, buffpos); + } + + if(buffer != NULL) + delete [] buffer; + + return true; +} + +bool CTextFileRead::Read(wstring& all, const wstring newline) +{ + if(!IsOpen()) + return false; + + int buffsize = GuessCharacterCount()+2; + int buffpos = 0; + + //Create buffer + wchar_t* buffer = new wchar_t[buffsize]; + + //If not possible, don't use any buffer + if(buffer == NULL) + buffsize = 0; + + wstring temp; + all = temp; + all.reserve(buffsize); + bool firstLine=true; + + while(!Eof()) + { + if(ReadLine(temp)) + { + //Add new line, if not first line + if(!firstLine) + temp.insert(0, newline.c_str()); + else + firstLine=false; + + //Add to buffer if possible + if(buffpos + (int) temp.size() < buffsize) + { + wcscpy(buffer+buffpos, temp.c_str()); + buffpos += (int) temp.size(); + } + else + { + //Copy to all string + if(buffpos != 0) + { + all.append(buffer, buffpos); + buffpos = 0; + } + + all += temp; + } + } + }; + + //Copy to all string + if(buffpos != 0) + { + all.append(buffer, buffpos); + } + + if(buffer != NULL) + delete [] buffer; + + return true; +} + +int CTextFileRead::GuessCharacterCount() +{ + #if PEK_TX_TECHLEVEL==2 + int bytecount = (int) m_file->GetLength(); + #else + //Code needed to get file size when not using MFC + int bytecount = 1024*1024; //Default: 1 MB + #endif + + //If ASCII, the number of characters is the byte count. + //If UTF-8, it can't be more than bytecount, so use byte count + if(m_encoding == ASCII || m_encoding == UTF_8) + return bytecount; + + //Otherwise, every two byte in one character + return bytecount/2; +} + +#if PEK_TX_TECHLEVEL==2 + +bool CTextFileRead::ReadLine(CString& line) +{ +#ifndef _UNICODE + string temp; +#else + wstring temp; +#endif + + if(!ReadLine(temp)) + return false; + + line = temp.c_str(); + return true; +} + +bool CTextFileRead::Read(CString& all, const CString newline) +{ +#ifndef _UNICODE + string temp, n=newline; +#else + wstring temp, n=newline; +#endif + + if(!Read(temp, n)) + return false; + + all = temp.c_str(); + return true; +} + +#endif + + +//Returns false if end-of-file was reached +//(line will not be changed). If returns true, +//it means that last line ended with a line break. +bool CTextFileRead::ReadWcharLine(wstring& line) +{ + //EOF? + if(Eof()) + return false; + + wchar_t ch=0; + + //Ignore 0x0D and 0x0A + //or 0x0D 0x0D and 0x0A + //or just 0x0D + //or just 0x0A + //except when we read the first line + ReadWchar(ch); + + if(!m_firstLine) + { + if(ch == 0x0D) //If next is 0x0A, ignore that too + { + ReadWchar(ch); + + if(ch == 0x0A) + ReadWchar(ch); + else if(ch == 0x0D) + { + ReadWchar(ch); + if(ch == 0x0A) + ReadWchar(ch); + } + + } + else if(ch == 0x0A) + { + ReadWchar(ch); + } + } + else + { + //Next time we reads we don't read the first line in file. + //(then we should ignore \r\n) + m_firstLine = false; + } + + //Clear line + line = L""; + + //It would be a lot easier if we didn't use a buffer, and added directly to + //line, but that is quite slow. + wchar_t buffer[BUFFSIZE]; + buffer[BUFFSIZE-1] = '\0'; + //Where to insert next character + int bufpos = 0; + + //Read line + while(ch != 0x0D && ch != 0x0A && !Eof()) + { + //End of buffer? + if(bufpos+1 >= BUFFSIZE) + { + //Add to line + line.append(buffer, bufpos); + bufpos=0; + } + + buffer[bufpos] = ch; + bufpos++; + + ReadWchar(ch); + }; + + buffer[bufpos] = L'\0'; + line += buffer; + + //Save currents character in extra buffer + m_useExtraBuffer=true; + m_extraBuffer_wchar=ch; + + return true; +} + +//Returns false if end-of-file was reached +//(line will not be changed). If returns true, +//it means that last line ended with a line break. +bool CTextFileRead::ReadCharLine(string& line) +{ + //EOF? + if(Eof()) + return false; + + unsigned char ch=0; + + //Ignore 0x0D and 0x0A + //or just 0x0D + //or just 0x0A + //except when we read the first line + ReadByte(ch); + + if(!m_firstLine) + { + if(ch == 0x0D) //If next is 0x0A, ignore that too + { + ReadByte(ch); + + if(ch == 0x0A) + ReadByte(ch); + else if(ch == 0x0D) + { + ReadByte(ch); + if(ch == 0x0A) + ReadByte(ch); + } + } + else if(ch == 0x0A) + { + ReadByte(ch); + } + } + else + { + //Next time we reads we don't read the first line in file. + //(then we should ignore \r\n) + m_firstLine = false; + } + + //Clear line + line = ""; + + //It would be a lot easier if we didn't use a buffer, and added directly to + //line, but that is quite slow. + char buffer[BUFFSIZE]; + buffer[BUFFSIZE-1] = '\0'; + //Where to insert next character + int bufpos = 0; + + //Read line + while(ch != 0x0D && ch != 0x0A && !Eof()) + { + //End of buffer? + if(bufpos+1 >= BUFFSIZE) + { + //Add to line + line.append(buffer, bufpos); + bufpos=0; + } + + buffer[bufpos] = ch; + bufpos++; + + ReadByte(ch); + }; + + buffer[bufpos] = L'\0'; + line += buffer; + + //Save currents character in extra buffer + m_useExtraBuffer=true; + m_extraBuffer_char=ch; + + return true; +} + + +long CTextFileRead::EnableSection(HANDLE hRecorder) +{ + ATLASSERT(m_hFile); + m_section_enable = true; + //载入成功标志 + bool load_ok = false; + + if(hRecorder) + load_ok = LoadSectionInfo(hRecorder); + + if(!load_ok) + { + //载入失败,进行重建 + m_section_count = 0; + + for(;;) + { + long last_pos = m_current_pos; + for(long loop = 0 ; loop < ENABLESECTION_SECTION_COUNT ; loop++) + { + string str; + if(!ReadLine(str,true)) + break; + m_section_count++; + str.empty(); + } + m_section_position.push_back(last_pos); + if(Eof()) + break; + } + m_dirty = true; + } + return m_section_count; +} + +bool CTextFileRead::LoadSectionInfo(HANDLE hRecorder) +{ + ATLASSERT(hRecorder); + ATLASSERT(m_hFile); + + //获取修改 + FILETIME last_write_time; //修改时间 + if(!GetFileTime(m_hFile,NULL,NULL,&last_write_time)) + return false; + + DWORD dwReadSize = 0; + BOOL bResult = FALSE; + + FILETIME last_write_time_recorder; + //读取最后修改时间 + bResult = ReadFile(hRecorder,&last_write_time_recorder,sizeof(FILETIME),&dwReadSize,NULL); + + if(!bResult || dwReadSize != sizeof(FILETIME)) + return false; + //比较修改时间 + if(memcmp(&last_write_time,&last_write_time_recorder,sizeof(FILETIME)) != 0) + return false; + + //读取每条记录的段落数 + long recorder_section_count = 0; + bResult = ReadFile(hRecorder,&recorder_section_count,sizeof(long),&dwReadSize,NULL); + if(!bResult || dwReadSize != sizeof(long)) + return false; + if(recorder_section_count != ENABLESECTION_SECTION_COUNT) + return false; + + //读取段落数 + bResult = ReadFile(hRecorder,&m_section_count,sizeof(long),&dwReadSize,NULL); + if(!bResult || dwReadSize != sizeof(long)) + return false; + m_section_position.clear(); + + long lSectionCount = m_section_count / ENABLESECTION_SECTION_COUNT; + if(m_section_count%ENABLESECTION_SECTION_COUNT) + lSectionCount++; + //读取各个段落的文件位置 + for(long section = 0; section < lSectionCount; section++) + { + long section_pos = 0; + bResult = ReadFile(hRecorder,§ion_pos,sizeof(long),&dwReadSize,NULL); + + if(!bResult || dwReadSize != sizeof(long)) + { + m_section_position.clear(); + return false; + } + m_section_position.push_back(section_pos); + } + + return true; +} + +bool CTextFileRead::SaveSectionInfo(HANDLE hRecorder) +{ + ATLASSERT(hRecorder); + + if(!m_dirty) + return true;/// 不需要保存 + + //获取修改 + FILETIME last_write_time; //修改时间 + if(!GetFileTime(m_hFile,NULL,NULL,&last_write_time)) + return false; + + DWORD dwReadSize = 0; + BOOL bResult = 0; + + //写入最后修改时间 + bResult = WriteFile(hRecorder,&last_write_time,sizeof(FILETIME),&dwReadSize,NULL); + + if(!bResult || dwReadSize != sizeof(FILETIME)) + return false; + + //写入每条记录段落数 + long recorder_section_count = ENABLESECTION_SECTION_COUNT; + bResult = WriteFile(hRecorder,&recorder_section_count,sizeof(long),&dwReadSize,NULL); + + if(!bResult || dwReadSize != sizeof(long)) + return false; + + //写入段落数 + bResult = WriteFile(hRecorder,&m_section_count,sizeof(long),&dwReadSize,NULL); + + if(!bResult || dwReadSize != sizeof(long)) + return false; + long lSectionCount = m_section_count / ENABLESECTION_SECTION_COUNT; + if(m_section_count%ENABLESECTION_SECTION_COUNT) + lSectionCount++; + for(long section = 0; section < lSectionCount ; section++) + { + long section_pos = m_section_position[section]; + bResult = WriteFile(hRecorder,§ion_pos,sizeof(long),&dwReadSize,NULL); + + if(!bResult || dwReadSize != sizeof(long)) + return false; + } + + return ::FlushFileBuffers(hRecorder)?true:false; +} + +DWORD CTextFileRead::GetFileSize() +{ + ATLASSERT(m_hFile); + return ::GetFileSize(m_hFile,NULL); +} diff --git a/ZbaSDK/SampleCode/PluginComDll/TextFileHelper.h b/ZbaSDK/SampleCode/PluginComDll/TextFileHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..c9d25bdbecd75b1e70082d7b5918bb3544362d9b --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/TextFileHelper.h @@ -0,0 +1,413 @@ +// TextFileHelper.h: interface for the CTextFile class. +// +////////////////////////////////////////////////////////////////////// + +#pragma once + +/* + CTextFileDocument let you write and read text files with + different encodings (ASCII, UTF-8, Unicode 16 little/big + endian is supported). When you work with ASCII-files + CTextFileDocument will help you convert strings to/from + different code-pages. + + Let me now if you find something strange or just gets + a clever idea... + + Get the latest version at + http://www.codeproject.com/file/textfiledocument.asp + + Version 1.22 - 21 May 2005 + ! Reading a line before reading everything could add an + extra line break. + ! A member variable wasn't always initialized, could cause + problems when reading single lines. + ! A smarter/easier algorithm is used when reading single lines. + + Version 1.21 - 10 Apr 2005 + ! Fix by sammyc: If it was not possible to open a file in techlevel 1, + IsOpen returned a bad result. + + Version 1.20 - 15 Jan 2005 + ! Fixed some problems when converting multi-byte string to Unicode, + and vice versa. + + Improved conversion routines. It's now possible to define + which code-page to use. + + It's now possible to set which character to use when it's + not possible to convert an Unicode character to an multi-byte character. + + It's now possible to see if data was lost during conversion. + + Better support for other platforms, it's no longer necessary to use + MFC in Windows. + ! Reading very small files (1 byte) failed. + + Version 1.13 - 26 Dec 2004 + ! Fixes by drinktea: + ! If a text file begun with an empty line, the file + wasn't read correctly (first empty line was ignored). + ! Fixes in CharToWstring and WcharToString. + + Version 1.12 - 17 Oct 2004 + + Minor memory leak when open file failed, fixed. + + Version 1.11 - 28 Aug 2004 + ! Calling WriteEndl() when writing an ASCII file could make + the file incorrectly written. Fixed. + + ASCII files is written faster. + + Version 1.10 - 13 Aug 2004 + Sorry about the quick update. + + Improved performance (much faster now, but code is more complicated :-/). + + Buffer is used when writing files. + + Buffer is used in non-mfc compilers + + Version 1.0 - 12 Aug 2004 + Initial version. + + PEK + */ +/* + +If you are creating a console project that doesn't support +MFC in Visual Studio, you will probably need to define +techlevel to 0: +#define PEK_TX_TECHLEVEL 0 + +In other cases it usually not necessary to define which "tech-level" +to use, the code below should do this for you. However, +if you need to this is the difference: + +#define PEK_TX_TECHLEVEL 0 +You should use this if you running on a none-Windows +platform. This uses fstream internally to read and +write files. If you want to change codepage you should +call setlocal. + +#define PEK_TX_TECHLEVEL 1 +Use this on Windows if you don't use MFC. This calls +Windows API directly to read and write files. If +something couldn't be read/written a CTextFileException +is thrown. Unicode in filenames are supported. +Codepages are supported. + +#define PEK_TX_TECHLEVEL 2 +Use this when you are using MFC. This uses CFile +internally to read and write files. If data can't be +read/written, CFile will throw an exception. Codepages +are supported. Unicode in filenames are supported. +CString is supported. + +*/ + +#define PEK_TX_TECHLEVEL 1 + +#ifndef PEK_TX_TECHLEVEL + +//Autodetect which "tech level" to use +#ifdef _MFC_VER + #define PEK_TX_TECHLEVEL 2 +#else +#ifdef _WIN32 + #define PEK_TX_TECHLEVEL 1 +#else + #define PEK_TX_TECHLEVEL 0 +#endif +#endif +#endif + +#if PEK_TX_TECHLEVEL > 0 + /* + In windows it's possible to use Unicode in filenames, + in unix it's not possible (afaik). FILENAMECHAR is the + charactertype. + */ + #ifndef _UNICODE + typedef char FILENAMECHAR; + #else + typedef wchar_t FILENAMECHAR; + #endif +#else + #include + typedef char FILENAMECHAR; +#endif + +#include +#include +using namespace std; + +class CTextFileBase +{ +public: + + enum TEXTENCODING + { + ASCII=0, + UNI16_BE, + UNI16_LE, + UTF_8 + }; + + CTextFileBase(); + ~CTextFileBase(); + + //Is the file open? + int IsOpen(); + + //Close the file + virtual void Close(); + + //Return the encoding of the file (ASCII, UNI16_BE, UNI16_LE or UTF_8); + TEXTENCODING GetEncoding() const; + + //Set which character that should be used when converting + //Unicode->multi byte and an unknown character is found ('?' is default) + void SetUnknownChar(const char unknown); + + //Returns true if data was lost + //(happens when converting Unicode->multi byte string and an unmappable + //characters is found). + bool IsDataLost() const; + + //Reset the data lost flag + void ResetDataLostFlag(); + + #if PEK_TX_TECHLEVEL > 0 + + /* Note! + The codepage is only used when converting from multibyte + to Unicode or vice versa. It is not used when reading + ANSI-files in none-Unicode strings, or reading + Unicode-files in Unicode strings. + + This means that if you want to read a ANSI-textfile + (with some code page) to an non-Unicode string you + must do the conversion yourself. But this is easy :-). + Read the file with the codepage to a wstring, then use + ConvertCharToWstring to convert the wstring to a + string. + + */ + //Set codepage to use when working with none-Unicode strings + void SetCodePage(const UINT codepage); + + //Get codepage to use when working with none-Unicode strings + UINT GetCodePage() const; + + //Convert char* to wstring + static void ConvertCharToWstring(const char* from, wstring &to, UINT codepage=CP_ACP); + + //Convert wchar_t* to string + static void ConvertWcharToString(const wchar_t* from, string &to, UINT codepage=CP_ACP, bool* datalost=NULL, char unknownchar=0); + + #else + + //Convert char* to wstring + static void ConvertCharToWstring(const char* from, wstring &to); + + //Convert wchar_t* to string + static void ConvertWcharToString(const wchar_t* from, string &to, bool* datalost=NULL, char unknownchar='a'); + #endif +protected: + //Convert char* to wstring + void CharToWstring(const char* from, wstring &to) const; + //Convert wchar_t* to string + void WcharToString(const wchar_t* from, string &to); + //The enocoding of the file + TEXTENCODING m_encoding; + //Buffersize + #define BUFFSIZE 1024 + +#if PEK_TX_TECHLEVEL == 0 + //Use fstream + fstream m_file; +#elif PEK_TX_TECHLEVEL == 1 + HANDLE m_hFile; +#else + //In windows we are using CFile + CFile* m_file; + bool m_closeAndDeleteFile; +#endif + //These controls the buffer for reading/writing + //True if end of file + bool m_endoffile; + //Readingbuffer + char m_buf[BUFFSIZE]; + //Bufferposition + int m_buffpos; + //Size of buffer + int m_buffsize; + //Character used when converting Unicode->multi byte and an unknown character was found + char m_unknownChar; + //Is true if data was lost when converting Unicode->multi-byte + bool m_datalost; + +#if PEK_TX_TECHLEVEL > 0 + UINT m_codepage; +#endif +}; + +class CTextFileWrite : public CTextFileBase +{ +public: + CTextFileWrite(const FILENAMECHAR* filename, TEXTENCODING type=ASCII); +#if PEK_TX_TECHLEVEL == 2 + CTextFileWrite(CFile* file, TEXTENCODING type=ASCII); +#endif + ~CTextFileWrite(); + + //Write routines + void Write(const char* text); + void Write(const wchar_t* text); + BOOL Write(const string& text); + BOOL Write(const wstring& text); + + CTextFileWrite& operator << (const char c); + CTextFileWrite& operator << (const char* text); + CTextFileWrite& operator << (const string& text); + + CTextFileWrite& operator << (const wchar_t wc); + CTextFileWrite& operator << (const wchar_t* text); + CTextFileWrite& operator << (const wstring& text); + + //Write new line (two characters, 13 and 10) + void WriteEndl(); + + //Close the file + virtual void Close(); + +private: + //Write and empty buffer + void Flush(); + + //Write a single one wchar_t, convert first + void WriteWchar(const wchar_t ch); + + //Write one byte + void WriteByte(const unsigned char byte); + + //Write a c-string in ASCII-format + void WriteAsciiString(const char* s); + + //Write byte order mark + void WriteBOM(); +}; + +class CTextFileRead : public CTextFileBase +{ +public: + /** + * @brief + * + * + * @param filename + * @param hRecorder 文件记录句柄 + * @return + */ + CTextFileRead(const FILENAMECHAR* filename); +#if PEK_TX_TECHLEVEL == 2 + CTextFileRead(CFile* file); +#endif + + //Returns false if end-of-file was reached + //(line will not be changed). If returns true, + //it means that last line ended with a line break. + bool ReadLine(string& line,bool bRecordSection = false); + bool ReadLine(wstring& line,bool bRecordSection = false); + + //通过段落序号,获取段落内容 + bool ReadLineByID(string& line,long section_id); + bool ReadLineByID(wstring& line,long section_id); + + //Returns everything from current position. + bool Read(string& all, const string newline="\r\n"); + bool Read(wstring& all, const wstring newline=L"\r\n"); + + //保存和载入段落信息 + bool LoadSectionInfo(HANDLE hRecorder); + bool SaveSectionInfo(HANDLE hRecorder); + + /** + * @brief 段落信息有效 + * + * + * @param hRecorder 有效段落信息的文件句柄 + */ + long EnableSection(HANDLE hRecorder = NULL); + + //获取文件大小 + DWORD GetFileSize(); + +#if PEK_TX_TECHLEVEL == 2 + bool ReadLine(CString& line); + bool Read(CString& all, const CString newline=_T("\r\n")); +#endif + + //End of file? + bool Eof() const; + +private: + //Guess the number of characters in the file + int GuessCharacterCount(); + + //Read line to wstring + bool ReadWcharLine(wstring& line); + + //Read line to string + bool ReadCharLine(string& line); + + //Reset the filepointer to start + void ResetFilePointer(); + + //Read one wchar_t + void ReadWchar(wchar_t& ch); + + //Read one byte + void ReadByte(unsigned char& ch); + + //Detect encoding + void ReadBOM(); + + //Use extra buffer. Sometimes we read one character to much, save it. + bool m_useExtraBuffer; + + //Used to read see if the first line in file is to read + //(so we know how to handle \n\r) + bool m_firstLine; + + //Extra buffer. It's ok to share the memory + union + { + char m_extraBuffer_char; + wchar_t m_extraBuffer_wchar; + }; + + //段落位置映射表 + std::vector m_section_position; + bool m_section_enable; + long m_current_pos; //当前读取的位置 + bool m_dirty; //写文件标志 + long m_section_count; //段数 + + std::vector m_section_buf; //段落的缓存 + long m_buf_first_section; //段落缓存首段号 + + std::vector m_wsection_buf; //段落的缓存 + long m_wbuf_first_section; //段落缓存首段号 +}; + +#if PEK_TX_TECHLEVEL == 1 + +//This is only used in Windows mode (no MFC) +//An exception is thrown will data couldn't be read or written +class CTextFileException +{ +public: + CTextFileException(DWORD err) + { + m_errorCode = err; + } + + //Value returned by GetLastError() + DWORD m_errorCode; +}; + +#endif \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginComDll/_ISysInfoEvents_CP.h b/ZbaSDK/SampleCode/PluginComDll/_ISysInfoEvents_CP.h new file mode 100644 index 0000000000000000000000000000000000000000..d10c8440d130be77b659e8bc6806eb551ee81844 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/_ISysInfoEvents_CP.h @@ -0,0 +1,10 @@ +#pragma once + +using namespace ATL; + +template +class CProxy_ISysInfoEvents : public IConnectionPointImpl +{ + // 警告: 此类可以由向导重新生成 +public: +}; diff --git a/ZbaSDK/SampleCode/PluginComDll/_ITextFileEvents_CP.h b/ZbaSDK/SampleCode/PluginComDll/_ITextFileEvents_CP.h new file mode 100644 index 0000000000000000000000000000000000000000..0421fc3c12874a8dbf8167fe5c5116031744c38c --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/_ITextFileEvents_CP.h @@ -0,0 +1,10 @@ +#pragma once + +using namespace ATL; + +template +class CProxy_ITextFileEvents : public IConnectionPointImpl +{ + // 警告: 此类可以由向导重新生成 +public: +}; diff --git a/ZbaSDK/SampleCode/PluginComDll/dlldata.c b/ZbaSDK/SampleCode/PluginComDll/dlldata.c new file mode 100644 index 0000000000000000000000000000000000000000..8d80751d1a92b537ad0c1dbc2cadee689a181188 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/dlldata.c @@ -0,0 +1,38 @@ +/********************************************************* + DllData file -- generated by MIDL compiler + + DO NOT ALTER THIS FILE + + This file is regenerated by MIDL on every IDL file compile. + + To completely reconstruct this file, delete it and rerun MIDL + on all the IDL files in this DLL, specifying this file for the + /dlldata command line option + +*********************************************************/ + +#define PROXY_DELEGATION + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +EXTERN_PROXY_FILE( PluginComDll ) + + +PROXYFILE_LIST_START +/* Start of list */ + REFERENCE_PROXY_FILE( PluginComDll ), +/* End of list */ +PROXYFILE_LIST_END + + +DLLDATA_ROUTINES( aProxyFileList, GET_DLL_CLSID ) + +#ifdef __cplusplus +} /*extern "C" */ +#endif + +/* end of generated dlldata file */ diff --git a/ZbaSDK/SampleCode/PluginComDll/dllmain.cpp b/ZbaSDK/SampleCode/PluginComDll/dllmain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6c0772818fe5639bf4c59abb199b7f6ff54d279 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/dllmain.cpp @@ -0,0 +1,20 @@ +// dllmain.cpp : DllMain 的实现。 + +#include "stdafx.h" +#include "resource.h" +#include "PluginComDll_i.h" +#include "dllmain.h" +#include "xdlldata.h" + +CPluginComDllModule _AtlModule; + +// DLL 入口点 +extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ +#ifdef _MERGE_PROXYSTUB + if (!PrxDllMain(hInstance, dwReason, lpReserved)) + return FALSE; +#endif + hInstance; + return _AtlModule.DllMain(dwReason, lpReserved); +} diff --git a/ZbaSDK/SampleCode/PluginComDll/dllmain.h b/ZbaSDK/SampleCode/PluginComDll/dllmain.h new file mode 100644 index 0000000000000000000000000000000000000000..c4fcf6743e43053211c7d3f41f853ba4f19272cd --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/dllmain.h @@ -0,0 +1,10 @@ +// dllmain.h : 模块类的声明。 + +class CPluginComDllModule : public ATL::CAtlDllModuleT< CPluginComDllModule > +{ +public : + DECLARE_LIBID(LIBID_PluginComDllLib) + DECLARE_REGISTRY_APPID_RESOURCEID(IDR_PLUGINCOMDLL, "{F0FFF18E-E8C7-4778-8B38-45C9CD71912E}") +}; + +extern class CPluginComDllModule _AtlModule; diff --git a/ZbaSDK/SampleCode/PluginComDll/resource.h b/ZbaSDK/SampleCode/PluginComDll/resource.h new file mode 100644 index 0000000000000000000000000000000000000000..8b2ca51fc2c3a8c6be9797e6ba7a27a198466967 Binary files /dev/null and b/ZbaSDK/SampleCode/PluginComDll/resource.h differ diff --git a/ZbaSDK/SampleCode/PluginComDll/stdafx.cpp b/ZbaSDK/SampleCode/PluginComDll/stdafx.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f7a93b91a3a315faf53a779c607f3440f1d4fb18 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/stdafx.cpp @@ -0,0 +1,5 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// PluginComDll.pch 将作为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" diff --git a/ZbaSDK/SampleCode/PluginComDll/stdafx.h b/ZbaSDK/SampleCode/PluginComDll/stdafx.h new file mode 100644 index 0000000000000000000000000000000000000000..16b99e89858d42e3c1eda9fbc4749e9f313fc435 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/stdafx.h @@ -0,0 +1,35 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 特定于项目的包含文件 + +#pragma once + +#ifndef STRICT +#define STRICT +#endif + +#include "targetver.h" + +#define _ATL_APARTMENT_THREADED + +#define _ATL_NO_AUTOMATIC_NAMESPACE + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +#define ATL_NO_ASSERT_ON_DESTROY_NONEXISTENT_WINDOW + +#include "resource.h" +#include +#include +#include +#include + +using namespace ATL; + +#pragma warning( disable : 4100 ) +#pragma warning( disable : 4510 ) +#pragma warning( disable : 4610 ) +#pragma warning( disable : 4206 ) + +#import "..\\Bin\\\ZbaEngine.dll" no_namespace, raw_interfaces_only, raw_native_types, named_guids +#import "..\\Bin\\\ZbaBase.dll" no_namespace, raw_interfaces_only, raw_native_types, named_guids diff --git a/ZbaSDK/SampleCode/PluginComDll/targetver.h b/ZbaSDK/SampleCode/PluginComDll/targetver.h new file mode 100644 index 0000000000000000000000000000000000000000..7a7d2c83b87e4a064a51e5fd8a18393201ddfaeb --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。 + +// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将 +// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。 + +#include diff --git a/ZbaSDK/SampleCode/PluginComDll/xdlldata.c b/ZbaSDK/SampleCode/PluginComDll/xdlldata.c new file mode 100644 index 0000000000000000000000000000000000000000..b43d3a9b99286266edd066b29212edc3f2ac5c88 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/xdlldata.c @@ -0,0 +1,18 @@ +// dlldata.c 的包装 + +#ifdef _MERGE_PROXYSTUB // 合并代理存根(stub) DLL + +#define REGISTER_PROXY_DLL //DllRegisterServer 等 + +#define _WIN32_WINNT 0x0500 //对于 WinNT 4.0 或安装了 DCOM 的 Win95 +#define USE_STUBLESS_PROXY //仅当使用 MIDL 开关 /Oicf 时定义 + +#pragma comment(lib, "rpcns4.lib") +#pragma comment(lib, "rpcrt4.lib") + +#define ENTRY_PREFIX Prx + +#include "dlldata.c" +#include "PluginComDll_p.c" + +#endif //_MERGE_PROXYSTUB diff --git a/ZbaSDK/SampleCode/PluginComDll/xdlldata.h b/ZbaSDK/SampleCode/PluginComDll/xdlldata.h new file mode 100644 index 0000000000000000000000000000000000000000..89313c5cc1b9a6784051bf0b8145068143e26f49 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginComDll/xdlldata.h @@ -0,0 +1,15 @@ +#pragma once + +#ifdef _MERGE_PROXYSTUB + +extern "C" +{ +BOOL WINAPI PrxDllMain(HINSTANCE hInstance, DWORD dwReason, + LPVOID lpReserved); +STDAPI PrxDllCanUnloadNow(void); +STDAPI PrxDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv); +STDAPI PrxDllRegisterServer(void); +STDAPI PrxDllUnregisterServer(void); +} + +#endif diff --git a/ZbaSDK/SampleCode/PluginExeDemo/Config.json b/ZbaSDK/SampleCode/PluginExeDemo/Config.json new file mode 100644 index 0000000000000000000000000000000000000000..df74b525d165ee7b8baad558dea3de7cfdcab49c --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/Config.json @@ -0,0 +1,3 @@ +{ + "PORT": 12900 +} \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginExeDemo/Form1.Designer.cs b/ZbaSDK/SampleCode/PluginExeDemo/Form1.Designer.cs new file mode 100644 index 0000000000000000000000000000000000000000..d5ad6b95c559f97a6973abd7a225ed78355452b5 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/Form1.Designer.cs @@ -0,0 +1,96 @@ +锘縩amespace PluginExeDemo +{ + partial class Form1 + { + /// + /// 蹇呴渶鐨勮璁″櫒鍙橀噺銆 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 娓呯悊鎵鏈夋鍦ㄤ娇鐢ㄧ殑璧勬簮銆 + /// + /// 濡傛灉搴旈噴鏀炬墭绠¤祫婧愶紝涓 true锛涘惁鍒欎负 false銆 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows 绐椾綋璁捐鍣ㄧ敓鎴愮殑浠g爜 + + /// + /// 璁捐鍣ㄦ敮鎸佹墍闇鐨勬柟娉 - 涓嶈 + /// 浣跨敤浠g爜缂栬緫鍣ㄤ慨鏀规鏂规硶鐨勫唴瀹广 + /// + private void InitializeComponent() + { + this.IEBrowser = new System.Windows.Forms.WebBrowser(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // IEBrowser + // + this.IEBrowser.Location = new System.Drawing.Point(12, 12); + this.IEBrowser.MinimumSize = new System.Drawing.Size(20, 20); + this.IEBrowser.Name = "IEBrowser"; + this.IEBrowser.Size = new System.Drawing.Size(699, 604); + this.IEBrowser.TabIndex = 0; + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(732, 12); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(459, 258); + this.textBox1.TabIndex = 1; + // + // textBox2 + // + this.textBox2.Location = new System.Drawing.Point(732, 318); + this.textBox2.Multiline = true; + this.textBox2.Name = "textBox2"; + this.textBox2.Size = new System.Drawing.Size(459, 298); + this.textBox2.TabIndex = 2; + // + // button1 + // + this.button1.Location = new System.Drawing.Point(732, 281); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 26); + this.button1.TabIndex = 3; + this.button1.Text = "鍙戦佸唴瀹"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1203, 628); + this.Controls.Add(this.button1); + this.Controls.Add(this.textBox2); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.IEBrowser); + this.Name = "Form1"; + this.Text = "C#寮圭獥灏忕▼搴忚寖渚"; + this.Load += new System.EventHandler(this.Form1_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.WebBrowser IEBrowser; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Button button1; + } +} + diff --git a/ZbaSDK/SampleCode/PluginExeDemo/Form1.cs b/ZbaSDK/SampleCode/PluginExeDemo/Form1.cs new file mode 100644 index 0000000000000000000000000000000000000000..794620df74f85b84f06b74456d779742318fd5e4 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/Form1.cs @@ -0,0 +1,232 @@ +锘縰sing System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.IO; +using System.Windows.Forms; + +/// 娣诲姞鏍稿績缁勪欢寮曠敤 +using ZbaEngine; +using ZbaBase; + +namespace PluginExeDemo +{ + public partial class Form1 : Form + { + /// + /// web socket鏈嶅姟瀵硅薄 + /// + SocketProxyClass WebSocketServer = null; + /// + /// web socket鏈嶅姟浜嬩欢瀵硅薄 + /// + WebSocketEventSink WebSocketEvent = null; + + /// + /// 鍛戒护琛屽惎鍔ㄥ弬鏁 + /// + Dictionary m_Para; + + public Form1(string strPara) + { + InitializeComponent(); + + m_Para = new Dictionary(); + + /// 瑙f瀽鍛戒护琛屽弬鏁 + string[] cmdArray = strPara.Split('&'); + foreach (string cmd in cmdArray) + { + string[] paraArray = cmd.Split('='); + foreach (string para in paraArray) + { + m_Para.Add(paraArray[0], paraArray[1]); + break; + } + } + } + + public void Send(string strSID,string strContent) + { + WebSocketServer.AsynSendText(strSID,strContent); + } + + public void OpenUrl(string strUrl) + { + this.IEBrowser.Navigate(strUrl); + } + + private void Form1_Load(object sender, EventArgs e) + { + WebSocketServer = new SocketProxyClass(); + if (null == WebSocketServer) + return; + WebSocketEvent = new WebSocketEventSink(); + if (null == WebSocketEvent) + return; + WebSocketEvent.SetForm(this); + ushort nPort = ushort.Parse(m_Para["PORT"]); + ushort nListenPort = WebSocketServer.Listen(nPort, m_Para["SID"], m_Para["AI"]); + + /// 寤虹珛浜嬩欢閫氱煡 + WebSocketServer.NewConnEvent += WebSocketEvent.NewConnEvent; + WebSocketServer.RecMsgEvent += WebSocketEvent.RecMsgEvent; + WebSocketServer.RecTextEvent += WebSocketEvent.RecTextEvent; + WebSocketServer.ConnCloseEvent += WebSocketEvent.ConnCloseEvent; + } + + private void Form1_Closed(object sender, EventArgs e) + { + /// 绉婚櫎浜嬩欢閫氱煡 + WebSocketServer.NewConnEvent -= WebSocketEvent.NewConnEvent; + WebSocketServer.RecMsgEvent -= WebSocketEvent.RecMsgEvent; + WebSocketServer.RecTextEvent -= WebSocketEvent.RecTextEvent; + WebSocketServer.ConnCloseEvent -= WebSocketEvent.ConnCloseEvent; + /// 閲婃斁瀵硅薄 + if (null != WebSocketServer) + { + WebSocketServer.Close(); + WebSocketServer = null; + } + + WebSocketServer = null; + } + + private void button1_Click(object sender, EventArgs e) + { + string strLastSID = WebSocketEvent.GetLastSID(); + if (null == strLastSID || 0 == strLastSID.Length) + { + MessageBox.Show("杩樻湭鏈夋潵鑷綉椤电殑杩炴帴锛"); + return; + } + Send(strLastSID, this.textBox1.Text); + this.textBox1.Text = ""; + } + + /// + /// WebSocket鏈嶅姟浜嬩欢閫氱煡 + /// + public class WebSocketEventSink : _ISocketProxyEvents + { + /// + /// 涓荤獥鍙 + /// + + Form1 m_Form; + + string m_strLastSID; + + public void SetForm(Form1 Form) + { + m_Form = Form; + } + + public string GetLastSID() + { + return m_strLastSID; + } + + public void WriteLog(string documentName, string msg) + { + string LogFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data"); + if (!System.IO.Directory.Exists(LogFilePath)) + System.IO.Directory.CreateDirectory(LogFilePath); + string logFile = System.IO.Path.Combine(LogFilePath, documentName + "@" + DateTime.Today.ToString("yyyy-MM-dd") + ".txt"); + bool writeBaseInfo = System.IO.File.Exists(logFile); + StreamWriter swLogFile = new StreamWriter(logFile, true, Encoding.Unicode); + swLogFile.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "\t" + msg); + swLogFile.Close(); + swLogFile.Dispose(); + } + + /// + /// 閫氱煡鏂拌繛鎺 + /// + /// + public void NewConnEvent(string bstrSID) + { + m_strLastSID = bstrSID; + m_Form.textBox2.AppendText("鏀跺埌鏂拌繛鎺ワ細"); + m_Form.textBox2.AppendText(bstrSID); + m_Form.textBox2.AppendText("\r\n"); + } + + /// + /// 閫氱煡杩炴帴鏀跺埌JSON鏁版嵁鍖 + /// + /// + /// + /// + /// + public void RecMsgEvent(string bstrSID, uint nReqID, string bstrPushName, string bstrMsg) + { + m_Form.textBox2.AppendText("鏀跺埌鏂版暟鎹寘锛岃姹傚簭鍙凤細"); + m_Form.textBox2.AppendText(nReqID.ToString()); + m_Form.textBox2.AppendText("鍗忚鍚嶏細"); + m_Form.textBox2.AppendText(bstrPushName); + m_Form.textBox2.AppendText("鍐呭锛"); + m_Form.textBox2.AppendText(bstrMsg); + m_Form.textBox2.AppendText("\r\n"); + + if (bstrPushName == "Demo_OpenUrl") + { + /// 鑾峰緱鎵撳紑URL鍦板潃锛岃皟鐢ㄦ祻瑙堝櫒鎵撳紑 + JsonServiceClass JsonService = new JsonServiceClass(); + JsonService.ParseString(bstrMsg); + string strUrl = JsonService.GetStringValue("url"); + JsonService = null; + m_Form.OpenUrl(strUrl); + return; + } + /// 鍥炰紶缁欑綉椤靛唴瀹 + m_Form.Send(bstrSID,"鏀跺埌璇锋眰" + bstrPushName); + } + + /// + /// 閫氱煡杩炴帴鏀跺埌鏂囨湰鍐呭 + /// + /// + /// + public void RecTextEvent(string bstrSID, string bstrText) + { + m_Form.textBox2.AppendText("鏀跺埌鏂囨湰鍐呭锛"); + m_Form.textBox2.AppendText(bstrText); + m_Form.textBox2.AppendText("\r\n"); + /// 鍥炰紶缁欑綉椤靛唴瀹 + m_Form.Send(bstrSID,"鏀跺埌鏂囨湰鍐呭" + bstrText); + } + + /// + /// + /// + /// + /// + /// + public void RecByteEvent(string bstrSID, Object Content, uint nLen) + { + } + + /// + /// + /// + /// + /// + /// + public void HttpReqEvent(uint nSessionID, string strUrl, string strPara) + { + } + + /// + /// 閫氱煡鍏抽棴杩炴帴 + /// + /// + public void ConnCloseEvent(string bstrSID) + { + } + } + } +} \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginExeDemo/Form1.resx b/ZbaSDK/SampleCode/PluginExeDemo/Form1.resx new file mode 100644 index 0000000000000000000000000000000000000000..1af7de150c99c12dd67a509fe57c10d63e4eeb04 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/Form1.resx @@ -0,0 +1,120 @@ +锘 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginExeDemo/PluginConfig.json b/ZbaSDK/SampleCode/PluginExeDemo/PluginConfig.json new file mode 100644 index 0000000000000000000000000000000000000000..f8939f678ce21e94eb30944924aec64e82db79e6 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/PluginConfig.json @@ -0,0 +1,17 @@ +{ + "Type": 2, + "OS": 1, + "Control": 0, + "OSMinVer": "5.0", + "Version": "2.0.2.1", + "Name": "寮圭獥灏忕▼搴忚寖渚(C#璇█)", + "Corp": "ZorroSoft", + "Icon": "", + "Date": "2020.08.25", + "Desc": "寮圭獥灏忕▼搴忚寖渚(C#璇█)-婕旂ず鑴氭湰璇锋眰鎵撳紑鎸囧畾缃戠珯", + "Home": "http://zorrosoft.com/WRL", + "Down": "http://zorrosoft.com/WRL", + "Module": "PluginExeDemo.exe", + "PID": "99225C6D-B7A3-441c-AEFB-3EE23ACA2209", + "Updates": [] +} \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginExeDemo/PluginExeDemo.csproj b/ZbaSDK/SampleCode/PluginExeDemo/PluginExeDemo.csproj new file mode 100644 index 0000000000000000000000000000000000000000..b7746cdf8ec1d623612edf7d69dcdc6ae80b7c31 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/PluginExeDemo.csproj @@ -0,0 +1,147 @@ +锘 + + + Debug + x86 + 8.0.30703 + 2.0 + {A293EC60-CDAD-4A3A-8BD6-953924479BBC} + WinExe + Properties + PluginExeDemo + PluginExeDemo + v4.0 + Client + 512 + + + + + + + + + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + bin\Debug\PluginExeDemo.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + bin\Release\PluginExeDemo.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + + + Form1.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + {633D01A0-8A82-40CB-9CE6-8BA26B9C778C} + 1 + 0 + 0 + tlbimp + False + False + + + {B5380DD6-64E5-462A-AB4E-2C3DFCCD2168} + 1 + 0 + 0 + tlbimp + False + False + + + + + \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginExeDemo/PluginExeDemo.sln b/ZbaSDK/SampleCode/PluginExeDemo/PluginExeDemo.sln new file mode 100644 index 0000000000000000000000000000000000000000..a509e60c0a6b7c8c7e9c3c8db5215ce2c5c235b3 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/PluginExeDemo.sln @@ -0,0 +1,23 @@ +锘 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginExeDemo", "PluginExeDemo.csproj", "{A293EC60-CDAD-4A3A-8BD6-953924479BBC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A293EC60-CDAD-4A3A-8BD6-953924479BBC}.Debug|x86.ActiveCfg = Debug|x86 + {A293EC60-CDAD-4A3A-8BD6-953924479BBC}.Debug|x86.Build.0 = Debug|x86 + {A293EC60-CDAD-4A3A-8BD6-953924479BBC}.Release|x86.ActiveCfg = Release|x86 + {A293EC60-CDAD-4A3A-8BD6-953924479BBC}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {ED83012C-0D95-4661-8381-C87370A29FDD} + EndGlobalSection +EndGlobal diff --git a/ZbaSDK/SampleCode/PluginExeDemo/Program.cs b/ZbaSDK/SampleCode/PluginExeDemo/Program.cs new file mode 100644 index 0000000000000000000000000000000000000000..7c088a04df7eb6b61e9e3542eff458ca687db140 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/Program.cs @@ -0,0 +1,28 @@ +锘縰sing System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace PluginExeDemo +{ + static class Program + { + /// + /// 搴旂敤绋嬪簭鐨勪富鍏ュ彛鐐广 + /// + [STAThread] + static void Main(string[] args) + { + if (args.Length <= 0) + { + MessageBox.Show("璇疯緭鍏ュ惎鍔ㄥ弬鏁"); + Application.Exit(); + return; + } + + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1(args[0])); + } + } +} diff --git a/ZbaSDK/SampleCode/PluginExeDemo/Properties/AssemblyInfo.cs b/ZbaSDK/SampleCode/PluginExeDemo/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..32f2de3efd85c845d050b39872e1f369c058c0e5 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +锘縰sing System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 鏈夊叧绋嬪簭闆嗙殑甯歌淇℃伅閫氳繃浠ヤ笅 +// 鐗规ч泦鎺у埗銆傛洿鏀硅繖浜涚壒鎬у煎彲淇敼 +// 涓庣▼搴忛泦鍏宠仈鐨勪俊鎭 +[assembly: AssemblyTitle("PluginExeDemo")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PluginExeDemo")] +[assembly: AssemblyCopyright("Copyright(C) 2013-? ZorroSoft. All Rights Reserved.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 灏 ComVisible 璁剧疆涓 false 浣挎绋嬪簭闆嗕腑鐨勭被鍨 +// 瀵 COM 缁勪欢涓嶅彲瑙併傚鏋滈渶瑕佷粠 COM 璁块棶姝ょ▼搴忛泦涓殑绫诲瀷锛 +// 鍒欏皢璇ョ被鍨嬩笂鐨 ComVisible 鐗规ц缃负 true銆 +[assembly: ComVisible(false)] + +// 濡傛灉姝ら」鐩悜 COM 鍏紑锛屽垯涓嬪垪 GUID 鐢ㄤ簬绫诲瀷搴撶殑 ID +[assembly: Guid("4823a65a-0ab1-4ee8-8030-24b050a00f79")] + +// 绋嬪簭闆嗙殑鐗堟湰淇℃伅鐢变笅闈㈠洓涓肩粍鎴: +// +// 涓荤増鏈 +// 娆$増鏈 +// 鍐呴儴鐗堟湰鍙 +// 淇鍙 +// +// 鍙互鎸囧畾鎵鏈夎繖浜涘硷紝涔熷彲浠ヤ娇鐢ㄢ滃唴閮ㄧ増鏈彿鈥濆拰鈥滀慨璁㈠彿鈥濈殑榛樿鍊硷紝 +// 鏂规硶鏄寜濡備笅鎵绀轰娇鐢ㄢ*鈥: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("2.0.1.1")] +[assembly: AssemblyFileVersion("2.0.1.1")] diff --git a/ZbaSDK/SampleCode/PluginExeDemo/Properties/Resources.Designer.cs b/ZbaSDK/SampleCode/PluginExeDemo/Properties/Resources.Designer.cs new file mode 100644 index 0000000000000000000000000000000000000000..67f4266522c1bbe823bbc50facc96cc8c15d27ef --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +锘//------------------------------------------------------------------------------ +// +// 姝や唬鐮佺敱宸ュ叿鐢熸垚銆 +// 杩愯鏃剁増鏈: 4.0.30319.42000 +// +// 瀵规鏂囦欢鐨勬洿鏀瑰彲鑳戒細瀵艰嚧涓嶆纭殑琛屼负锛屽苟涓斿鏋 +// 閲嶆柊鐢熸垚浠g爜锛岃繖浜涙洿鏀瑰皢涓㈠け銆 +// +//------------------------------------------------------------------------------ + +namespace PluginExeDemo.Properties +{ + + + /// + /// 涓涓己绫诲瀷鐨勮祫婧愮被锛岀敤浜庢煡鎵炬湰鍦板寲鐨勫瓧绗︿覆绛夈 + /// + // 姝ょ被鏄敱 StronglyTypedResourceBuilder + // 绫婚氳繃绫讳技浜 ResGen 鎴 Visual Studio 鐨勫伐鍏疯嚜鍔ㄧ敓鎴愮殑銆 + // 鑻ヨ娣诲姞鎴栫Щ闄ゆ垚鍛橈紝璇风紪杈 .ResX 鏂囦欢锛岀劧鍚庨噸鏂拌繍琛 ResGen + // (浠 /str 浣滀负鍛戒护閫夐」)锛屾垨閲嶆柊鐢熸垚 VS 椤圭洰銆 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// 杩斿洖姝ょ被浣跨敤鐨勩佺紦瀛樼殑 ResourceManager 瀹炰緥銆 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PluginExeDemo.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 涓烘墍鏈夎祫婧愭煡鎵鹃噸鍐欏綋鍓嶇嚎绋嬬殑 CurrentUICulture 灞炴э紝 + /// 鏂规硶鏄娇鐢ㄦ寮虹被鍨嬭祫婧愮被銆 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/ZbaSDK/SampleCode/PluginExeDemo/Properties/Resources.resx b/ZbaSDK/SampleCode/PluginExeDemo/Properties/Resources.resx new file mode 100644 index 0000000000000000000000000000000000000000..af7dbebbacef595e3089c01c05671016c21a8304 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/Properties/Resources.resx @@ -0,0 +1,117 @@ +锘 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginExeDemo/Properties/Settings.Designer.cs b/ZbaSDK/SampleCode/PluginExeDemo/Properties/Settings.Designer.cs new file mode 100644 index 0000000000000000000000000000000000000000..16e852704682b682623e23611fdea49e700cdff9 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +锘//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PluginExeDemo.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/ZbaSDK/SampleCode/PluginExeDemo/Properties/Settings.settings b/ZbaSDK/SampleCode/PluginExeDemo/Properties/Settings.settings new file mode 100644 index 0000000000000000000000000000000000000000..39645652af62950ebf3b28ec3a5400dcec30b1c4 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginExeDemo/Properties/Settings.settings @@ -0,0 +1,7 @@ +锘 + + + + + + diff --git a/ZbaSDK/SampleCode/PluginNetDll/PluginConfig.json b/ZbaSDK/SampleCode/PluginNetDll/PluginConfig.json new file mode 100644 index 0000000000000000000000000000000000000000..dccd312ea63d3c7688abf6b8878aa1e8312f44ff --- /dev/null +++ b/ZbaSDK/SampleCode/PluginNetDll/PluginConfig.json @@ -0,0 +1,24 @@ +{ + "Type": 1, + "OS": 1, + "Control": 0, + "Asm": 1, + "OSMinVer": "5.0", + "Version": "2.0.2.1", + "Name": "鏃犵獥鍙e皬绋嬪簭鑼冧緥(C#璇█)", + "Corp": "ZorroSoft", + "Icon": "", + "Date": "2020.08.25", + "Desc": "鏃犵獥鍙e皬绋嬪簭鑼冧緥(C#璇█)", + "Home": "http://zorrosoft.com/WRL", + "Down": "http://zorrosoft.com/WRL", + "Module": "PluginNetDll.dll", + "PID": "D10495F4-DF0F-44FA-8647-91275347214A", + "Objects": [ + { + "ProgID": "FCADA8A7-D975-42c6-B5D3-FA40F6FE1286", + "ClassID": "5DDA3CFF-6AD1-4836-B378-628B43748626" + } + ], + "Updates": [] +} \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginNetDll/PluginNetDll.csproj b/ZbaSDK/SampleCode/PluginNetDll/PluginNetDll.csproj new file mode 100644 index 0000000000000000000000000000000000000000..b36f35ef9d9c51b0724c4198e5e8ab8a1217c57a --- /dev/null +++ b/ZbaSDK/SampleCode/PluginNetDll/PluginNetDll.csproj @@ -0,0 +1,124 @@ +锘 + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {4B48FC7A-94AC-45C1-9361-D12ADF21893A} + Library + Properties + PluginNetDll + PluginNetDll + v4.0 + 512 + + + + + + + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + false + + + true + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + bin\Debug\PluginNetDll.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + false + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + bin\Release\PluginNetDll.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + true + + + + + + + + + + + + + + + + + + + + {633D01A0-8A82-40CB-9CE6-8BA26B9C778C} + 1 + 0 + 0 + tlbimp + False + False + + + {B5380DD6-64E5-462A-AB4E-2C3DFCCD2168} + 1 + 0 + 0 + tlbimp + False + False + + + + + \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginNetDll/PluginNetDll.sln b/ZbaSDK/SampleCode/PluginNetDll/PluginNetDll.sln new file mode 100644 index 0000000000000000000000000000000000000000..f7cae84eb0fd46a361a407704598710dcff68b3b --- /dev/null +++ b/ZbaSDK/SampleCode/PluginNetDll/PluginNetDll.sln @@ -0,0 +1,20 @@ +锘 +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginNetDll", "PluginNetDll.csproj", "{4B48FC7A-94AC-45C1-9361-D12ADF21893A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4B48FC7A-94AC-45C1-9361-D12ADF21893A}.Debug|x86.ActiveCfg = Debug|x86 + {4B48FC7A-94AC-45C1-9361-D12ADF21893A}.Debug|x86.Build.0 = Debug|x86 + {4B48FC7A-94AC-45C1-9361-D12ADF21893A}.Release|x86.ActiveCfg = Release|x86 + {4B48FC7A-94AC-45C1-9361-D12ADF21893A}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ZbaSDK/SampleCode/PluginNetDll/PluginNetDll.suo b/ZbaSDK/SampleCode/PluginNetDll/PluginNetDll.suo new file mode 100644 index 0000000000000000000000000000000000000000..9de3912b264c5e253d00ff7bea4ec36230b8043f Binary files /dev/null and b/ZbaSDK/SampleCode/PluginNetDll/PluginNetDll.suo differ diff --git a/ZbaSDK/SampleCode/PluginNetDll/Properties/AssemblyInfo.cs b/ZbaSDK/SampleCode/PluginNetDll/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..a22632cbf22696c854bee3c041b2f0eab76e9be2 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginNetDll/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +锘縰sing System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 鏈夊叧绋嬪簭闆嗙殑甯歌淇℃伅閫氳繃浠ヤ笅 +// 鐗规ч泦鎺у埗銆傛洿鏀硅繖浜涚壒鎬у煎彲淇敼 +// 涓庣▼搴忛泦鍏宠仈鐨勪俊鎭 +[assembly: AssemblyTitle("PluginNetDll")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("WRL")] +[assembly: AssemblyCopyright("ZorroSoft Copyright 漏 2013-2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 灏 ComVisible 璁剧疆涓 false 浣挎绋嬪簭闆嗕腑鐨勭被鍨 +// 瀵 COM 缁勪欢涓嶅彲瑙併傚鏋滈渶瑕佷粠 COM 璁块棶姝ょ▼搴忛泦涓殑绫诲瀷锛 +// 鍒欏皢璇ョ被鍨嬩笂鐨 ComVisible 鐗规ц缃负 true銆 +[assembly: ComVisible(true)] + +// 濡傛灉姝ら」鐩悜 COM 鍏紑锛屽垯涓嬪垪 GUID 鐢ㄤ簬绫诲瀷搴撶殑 ID +[assembly: Guid("D10495F4-DF0F-44FA-8647-91275347214A")] + +// 绋嬪簭闆嗙殑鐗堟湰淇℃伅鐢变笅闈㈠洓涓肩粍鎴: +// +// 涓荤増鏈 +// 娆$増鏈 +// 鍐呴儴鐗堟湰鍙 +// 淇鍙 +// +// 鍙互鎸囧畾鎵鏈夎繖浜涘硷紝涔熷彲浠ヤ娇鐢ㄢ滃唴閮ㄧ増鏈彿鈥濆拰鈥滀慨璁㈠彿鈥濈殑榛樿鍊硷紝 +// 鏂规硶鏄寜濡備笅鎵绀轰娇鐢ㄢ*鈥: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("2.0.1.1")] +[assembly: AssemblyFileVersion("12.0.1.1")] diff --git a/ZbaSDK/SampleCode/PluginNetDll/TestWrl.cs b/ZbaSDK/SampleCode/PluginNetDll/TestWrl.cs new file mode 100644 index 0000000000000000000000000000000000000000..1e180efe23d05d4431cbdac62c37ff3272116b30 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginNetDll/TestWrl.cs @@ -0,0 +1,141 @@ +锘縰sing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; + +using ZbaEngine; +using ZbaBase; + +[Guid("FCADA8A7-D975-42c6-B5D3-FA40F6FE1286")] +[TypeLibType(4160)] +[ComVisible(true)] +public interface ITestWrl +{ +} + +namespace PluginNetDll +{ + [Guid("5DDA3CFF-6AD1-4836-B378-628B43748626")] + [TypeLibType(4160)] + [ClassInterface(ClassInterfaceType.None)] + [ComDefaultInterface(typeof(ITestWrl))] + [ComSourceInterfaces(typeof(ITestWrl))] + public class TestWrl : ITestWrl, IWrlConn + { + /// + /// Web Socket杩炴帴瀵硅薄 + /// + IWebSocketConnect m_WebSocketConnect; + + #region IWrlConn Members + void IWrlConn.Load(object piDispatch, string bstrAuthInfo, string bstrLang) + { + m_WebSocketConnect = piDispatch as IWebSocketConnect; + if (null != m_WebSocketConnect) + WriteLog("PluginNetDll", "鎴愬姛鑾峰緱WS鎺ュ彛"); + else + WriteLog("PluginNetDll", "鑾峰彇WS鎺ュ彛澶辫触"); + } + + void IWrlConn.Unload(EWrlCloseConnType eCloseConnType, string bstrReason) + { + m_WebSocketConnect = null; + WriteLog("PluginNetDll", "璇锋眰鍗稿皬绋嬪簭"); + } + + string IWrlConn.HttpRequst(string bstrUrl, string bstrPara) + { + /// 鏀跺埌HTTP绫诲瀷璇锋眰锛屾殏鏈疄鐜 + return ""; + } + + void IWrlConn.RecByte(ref byte pContent, uint nLen) + { + /// 鏀跺埌浜岃繘鍒舵暟鎹祦锛岀壒娈婄敤閫 + WriteLog("PluginNetDll", "鎴戜笉鏄満鍣ㄤ汉锛"); + } + /// + /// 閲嶇偣澶勭悊姝ゅ嚱鏁 + /// + /// + /// + /// + void IWrlConn.RecJson(uint nReqID, string bstrPushName, string bstrContent) + { + /// 鍒涘缓JSON瑙f瀽鍣 + JsonServiceClass JsonService = new JsonServiceClass(); + + bool bRet = JsonService.ParseString(bstrContent); + /// 鏍规嵁璇锋眰鍚嶇ОbstrPushName鍜岃姹傚弬鏁癰strContent鍒嗗埆瀹氫箟鑷繁鐨勫崗璁繘琛屽鐞嗐 + string strReturn = ""; + if(bstrPushName == "Demo_Return") + { + strReturn = "鏀跺埌璇锋眰 "; + strReturn += bstrPushName; + strReturn += " 鍐呭锛"; + strReturn += bstrContent; + strReturn += " 搴忓彿锛"; + strReturn += nReqID.ToString(); + } + else if(bstrPushName == "Demo_WriteFile") + { + string strName = JsonService.GetStringValue("Name"); + string strContent = JsonService.GetStringValue("Content"); + + string strAppPath = this.GetType().Assembly.Location; + strAppPath.Replace(".exe",""); + strAppPath += "\\Data\\"; + StreamWriter swFile = new StreamWriter(strAppPath + strName, true, Encoding.Unicode); + swFile.WriteLine(strContent); + swFile.Close(); + swFile.Dispose(); + strReturn = strAppPath + strName + "鍐欏叆鍐呭" ; + } + else + strReturn = "鏀跺埌鏈煡璇锋眰:" + bstrPushName; + + WriteLog(bstrPushName, strReturn); + /// 缁欏墠绔洖澶嶈姹 + m_WebSocketConnect.AsynSendText(strReturn); + } + + void IWrlConn.RecText(string bstrContent) + { + /// 鏀跺埌鏂囨湰璇锋眰锛屼竴鑸兘鏄疛SON鍖 + m_WebSocketConnect.AsynSendText("浣犵‘瀹氭病鍙戦敊锛"); + } + + /// + /// 妗嗘灦璋冪敤鍙戦侀氱煡 + /// + /// + void IWrlConn.SendJson(string bstrContent) + { + if (null != m_WebSocketConnect) + m_WebSocketConnect.AsynSendText(bstrContent); + } + + void IWrlConn.UsbChanged(string bstrDisk, uint nStatus, string bstrName) + { + /// USB瀛樺偍璁惧鎻掓嫈閫氱煡 + } + + #endregion + + public void WriteLog(string documentName, string msg) + { + string LogFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data"); + if (!System.IO.Directory.Exists(LogFilePath)) + System.IO.Directory.CreateDirectory(LogFilePath); + string logFile = System.IO.Path.Combine(LogFilePath, documentName + "@" + DateTime.Today.ToString("yyyy-MM-dd") + ".txt"); + bool writeBaseInfo = System.IO.File.Exists(logFile); + StreamWriter swLogFile = new StreamWriter(logFile, true, Encoding.Unicode); + swLogFile.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "\t" + msg); + swLogFile.Close(); + swLogFile.Dispose(); + } + } +} \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginWinExe/BrowserHost.h b/ZbaSDK/SampleCode/PluginWinExe/BrowserHost.h new file mode 100644 index 0000000000000000000000000000000000000000..5509f648fdb576f8f0be3c829b25d1e9c55aa30e --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/BrowserHost.h @@ -0,0 +1,276 @@ +#pragma once + +#include // browser control definitions +#include // browser event dispatch IDs +#include + +enum CONTEXT_MENU_MODE // 上下文菜单 + { + NoContextMenu, // 无菜单 + DefaultMenu, // 默认菜单 + TextSelectionOnly, // 仅文本选择菜单 + CustomMenu // 自定义菜单 + }; + +class CDocHostUIHandler : + public IDocHostUIHandler, + public IOleCommandTarget +{ +protected: + + LONG m_cRef; + + // Default interface pointers + CComQIPtr m_spDefaultDocHostUIHandler; + + CComQIPtr m_spDefaultOleCommandTarget; + +public: + CDocHostUIHandler() + :m_cRef(0) + { + } + + void ReleaseCom() + { + m_cRef = 0; + + if(NULL != m_spDefaultDocHostUIHandler) + m_spDefaultDocHostUIHandler.Release(); + if(NULL != m_spDefaultOleCommandTarget) + m_spDefaultOleCommandTarget.Release(); + } + + HRESULT STDMETHODCALLTYPE SetHandler(CComPtr spWebBrowser) + { + HRESULT result = E_NOINTERFACE; + if(NULL == spWebBrowser) + return E_POINTER; + CComPtr spDisp = NULL; + HRESULT hr = spWebBrowser->get_Document(&spDisp); + if (SUCCEEDED(hr) && spDisp) + { + // If this is not an HTML document (e.g., it's a Word doc or a PDF), don't sink. + CComQIPtr spHTML(spDisp); + if (spHTML) + { + // Get pointers to default interfaces + CComQIPtr spOleObject(spDisp); + if (spOleObject) + { + CComPtr spClientSite = NULL; + hr = spOleObject->GetClientSite(&spClientSite); + if (SUCCEEDED(hr) && spClientSite) + { + m_spDefaultDocHostUIHandler = spClientSite; + m_spDefaultOleCommandTarget = spClientSite; + } + } + + // Set this class to be the IDocHostUIHandler + CComQIPtr spCustomDoc(spDisp); + if (spCustomDoc) + { + spCustomDoc->SetUIHandler(this); + result = S_OK; + } + } + } + spDisp = NULL; + return result; + } + + /// IDocHostUIHandler + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + HRESULT result = S_OK; + + if (IsBadWritePtr(ppvObject, sizeof(LPVOID))) + result = E_INVALIDARG; + + if (result == S_OK) + { + *ppvObject = NULL; + + if ( IsEqualIID( riid, IID_IUnknown ) ) + *ppvObject = this; + else if ( IsEqualIID( riid, IID_IDispatch ) ) + *ppvObject = (IDispatch *) this; + else if ( IsEqualIID( riid, IID_IDocHostUIHandler ) ) + *ppvObject = (IDocHostUIHandler *) this; + else if ( IsEqualIID( riid, IID_IOleCommandTarget ) ) + *ppvObject = (IOleCommandTarget *) this; + else + result = E_NOINTERFACE; + } + + if (result == S_OK) + this->AddRef(); + + return result; + } + + ULONG STDMETHODCALLTYPE AddRef() + { + InterlockedIncrement(&m_cRef); + return m_cRef; + } + + ULONG STDMETHODCALLTYPE Release() + { + ULONG ulRefCount = InterlockedDecrement(&m_cRef); + if(m_cRef == 0) + { + delete this; + } + return ulRefCount; + } + + STDMETHOD(ShowContextMenu)(DWORD dwID, POINT FAR* ppt, IUnknown FAR* pcmdTarget, IDispatch FAR* pdispReserved) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->ShowContextMenu(dwID, ppt, pcmdTarget, pdispReserved); + return S_FALSE; + } + + STDMETHOD(ShowUI)(DWORD dwID, IOleInPlaceActiveObject FAR* pActiveObject, + IOleCommandTarget FAR* pCommandTarget, + IOleInPlaceFrame FAR* pFrame, + IOleInPlaceUIWindow FAR* pDoc) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->ShowUI(dwID, pActiveObject, pCommandTarget, pFrame, pDoc); + return S_FALSE; + } + + STDMETHOD(GetHostInfo)(DOCHOSTUIINFO FAR *pInfo) + { + pInfo->cbSize = sizeof(DOCHOSTUIINFO); + pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_ENABLE_REDIRECT_NOTIFICATION; + pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT; + pInfo->pchHostCss = 0; + pInfo->pchHostNS = 0; +// if(m_spDefaultDocHostUIHandler) + // return m_spDefaultDocHostUIHandler->GetHostInfo(pInfo); + return S_OK; + } + + STDMETHOD(HideUI)(void) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->HideUI(); + return S_OK; + } + + STDMETHOD(UpdateUI)(void) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->UpdateUI(); + return S_OK; + } + + STDMETHOD(EnableModeless)(BOOL fEnable) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->EnableModeless(fEnable); + return S_OK; + } + + STDMETHOD(OnDocWindowActivate)(BOOL fActivate) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->OnDocWindowActivate(fActivate); + return S_OK; + } + + STDMETHOD(OnFrameWindowActivate)(BOOL fActivate) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->OnFrameWindowActivate(fActivate); + return S_OK; + } + + STDMETHOD(ResizeBorder)(LPCRECT prcBorder, IOleInPlaceUIWindow FAR* pUIWindow, BOOL fFrameWindow) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->ResizeBorder(prcBorder, pUIWindow, fFrameWindow); + return S_OK; + } + + STDMETHOD(TranslateAccelerator)(LPMSG lpMsg, const GUID FAR* pguidCmdGroup, DWORD nCmdID) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->TranslateAccelerator(lpMsg, pguidCmdGroup, nCmdID); + return E_NOTIMPL; + } + + STDMETHOD(GetOptionKeyPath)(LPOLESTR FAR* pchKey, DWORD dw) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->GetOptionKeyPath(pchKey, dw); + return E_FAIL; + } + + STDMETHOD(GetDropTarget)(IDropTarget* pDropTarget, IDropTarget** ppDropTarget) + { + if (m_spDefaultDocHostUIHandler) + m_spDefaultDocHostUIHandler->GetDropTarget(pDropTarget, ppDropTarget); + return S_OK; + } + + STDMETHOD(GetExternal)(IDispatch** ppDispatch) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->GetExternal(ppDispatch); + return S_FALSE; + } + + STDMETHOD(TranslateUrl)(DWORD dwTranslate, OLECHAR* pchURLIn, OLECHAR** ppchURLOut) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->TranslateUrl(dwTranslate, pchURLIn, ppchURLOut); + return S_FALSE; + } + + STDMETHOD(FilterDataObject)(IDataObject* pDO, IDataObject** ppDORet) + { + if (m_spDefaultDocHostUIHandler) + return m_spDefaultDocHostUIHandler->FilterDataObject(pDO, ppDORet); + return S_FALSE; + } + + // + // IOleCommandTarget + // + STDMETHOD(QueryStatus)( + /*[in]*/ const GUID *pguidCmdGroup, + /*[in]*/ ULONG cCmds, + /*[in,out][size_is(cCmds)]*/ OLECMD *prgCmds, + /*[in,out]*/ OLECMDTEXT *pCmdText) + { + if(NULL == m_spDefaultOleCommandTarget) + return E_NOINTERFACE; + return m_spDefaultOleCommandTarget->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText); + } + + /// 屏蔽JS脚本错误 + STDMETHOD(Exec)( + /*[in]*/ const GUID *pguidCmdGroup, + /*[in]*/ DWORD nCmdID, + /*[in]*/ DWORD nCmdExecOpt, + /*[in]*/ VARIANTARG *pvaIn, + /*[in,out]*/ VARIANTARG *pvaOut) + { + if (nCmdID == OLECMDID_SHOWSCRIPTERROR) + { + // Don't show the error dialog, but + // continue running scripts on the page. + (*pvaOut).vt = VT_BOOL; + (*pvaOut).boolVal = VARIANT_TRUE; + return S_OK; + } + if(NULL == m_spDefaultOleCommandTarget) + return E_NOINTERFACE; + return m_spDefaultOleCommandTarget->Exec(pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn, pvaOut); + } +}; \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginWinExe/Config.json b/ZbaSDK/SampleCode/PluginWinExe/Config.json new file mode 100644 index 0000000000000000000000000000000000000000..e2f2dd527d5554394a59853a7365a2da79276429 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/Config.json @@ -0,0 +1,3 @@ +{ + "PORT": 12800 +} \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginWinExe/MainDlg.cpp b/ZbaSDK/SampleCode/PluginWinExe/MainDlg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..55b61132797ab595b674704c416cffb93e981802 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/MainDlg.cpp @@ -0,0 +1,414 @@ +// MainDlg.cpp : implementation of the CMainDlg class +// +///////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "resource.h" + +#include "MainDlg.h" + +CComVariant g_varWebHeader = CComVariant(L"Accept: */*\r\nAccept-Language: zh-CN\r\nAccept-Charset: utf-8\r\nContent-Type: application/x-www-form-urlencoded\r\n"); + +int Us2ToChar(const ATL::CString& strSrc, char** pDst,int nCodePage) +{ + int iLength=::WideCharToMultiByte(nCodePage,0,strSrc,-1,NULL,0,NULL,NULL); + if(!iLength) + return iLength; + iLength++; + char *strA=NULL; + strA= new char[iLength]; + if(strA==NULL) + return 0; + ::memset(strA,0,iLength*sizeof(char)); + int iLength1 = 0; + if(nCodePage) + iLength1 = ::WideCharToMultiByte(nCodePage,WC_COMPOSITECHECK,strSrc,-1,strA,iLength-1,NULL,NULL); + else + iLength1 = ::WideCharToMultiByte(nCodePage,0,strSrc,-1,strA,iLength-1,NULL,NULL); + *pDst=strA; + return iLength1; +} + +LRESULT CMainDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) +{ + // center the dialog on the screen + CenterWindow(); + + // set icons + HICON hIcon = AtlLoadIconImage(IDR_MAINFRAME, LR_DEFAULTCOLOR, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON)); + SetIcon(hIcon, TRUE); + HICON hIconSmall = AtlLoadIconImage(IDR_MAINFRAME, LR_DEFAULTCOLOR, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON)); + SetIcon(hIconSmall, FALSE); + + m_spiWebBrowser = NULL; + m_spiHtmlDoc = NULL; + + m_nSocketProxyCookie = 0; + m_spiSocketProxy = NULL; + m_spiSocketProxyEvent = NULL; + + this->PostMessage(WM_APP,0,0); /// 异步初始化侦听服务 + return TRUE; +} + +void CMainDlg::InitWebCtrl() +{ + CRect rcClient; + this->GetClientRect(&rcClient); + rcClient.left += 5; + rcClient.top += 5; + rcClient.right -= 5; + rcClient.bottom -= 150; + + if(!m_ctlWebWindow.IsWindow()) + { + HWND hWndWB = m_ctlWebWindow.Create(m_hWnd,rcClient,NULL, + WS_CHILD|WS_VISIBLE,0,IDC_WEB_BROWSER); + ATLASSERT(hWndWB); + if(!::IsWindow(hWndWB)) + this->MessageBox(L"初始化IE控件窗口失败!"); + } + m_ctlWebWindow.SetWindowPos(this->m_hWnd,rcClient.left,rcClient.top,rcClient.Width(),rcClient.Height(),SWP_SHOWWINDOW); + + if(NULL == m_spiWebBrowser) + { + //Create the WebBrowser control(IE) with CLSID + CComPtr spUnkWebBrowser = NULL; + HRESULT hr = spUnkWebBrowser.CoCreateInstance(CLSID_WebBrowser); + ATLASSERT(SUCCEEDED(hr)); + //Attach the WebBrowser control to host window + if(NULL != spUnkWebBrowser) + { + m_ctlWebWindow.AttachControl(spUnkWebBrowser,NULL); + spUnkWebBrowser = NULL; + } + + //Advise sink map + hr = AtlAdviseSinkMap(this,true); + ATLASSERT(SUCCEEDED(hr)); + + //Query interface + hr = m_ctlWebWindow.QueryControl(&m_spiWebBrowser); + if(FAILED(hr)) + this->MessageBox(L"获取IE控件对象失败!"); + + if(NULL != m_spiWebBrowser) + { + m_spiWebBrowser->put_Silent(VARIANT_TRUE); + CComVariant varVal; + varVal.Clear(); + m_spiWebBrowser->Navigate(CComBSTR(L"about:blank"),&varVal,&varVal,&varVal,&g_varWebHeader); + } + } +} + +LRESULT CMainDlg::OnOpenUrl(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) +{ + if(NULL == m_spiWebBrowser) + { + this->MessageBox(L"还未初始化IE控件!"); + return 0; + } + if(m_strOpenUrl.IsEmpty()) + { + this->MessageBox(L"打开URL为空!"); + return 0; + } + CComVariant varVal; + varVal.Clear(); + HRESULT hRet = m_spiWebBrowser->Navigate(CComBSTR(m_strOpenUrl),\ + &varVal,&varVal,&varVal,&g_varWebHeader); + if(SUCCEEDED(hRet)) + m_ctlWebWindow.SetFocus(); + else + { + CString strErrCode; + strErrCode.Format(L"打开网站失败,错误码:%ld",hRet); + this->MessageBox(strErrCode); + } + return 1; +} + +void CMainDlg::NavigateComplete2(IDispatch *pDisp, VARIANT *pvarURL) +{ + if(NULL == pvarURL) + return; + if(NULL == m_spiHtmlDoc) + m_spiHtmlDoc = this->GetHtmlDoc(); + if(NULL != m_spiHtmlDoc) + { + m_DocHostUIHandler.SetHandler(m_spiWebBrowser); + } +} + +void CMainDlg::BeforeNavigate2(IDispatch *pDisp, + CComVariant &URL, CComVariant &Flags, CComVariant &TargetFrameName, + CComVariant &PostData, CComVariant &Headers, VARIANT_BOOL* Cancel) +{ + (*Cancel) = VARIANT_FALSE; + CString strUrl(URL.bstrVal); +} + +void CMainDlg::OnNewWindow3(LPDISPATCH* ppDisp, VARIANT_BOOL * Cancel, DWORD dwFlags, BSTR bstrUrlContext, BSTR bstrUrl) +{ + /// 取消新窗口 + (*Cancel) = VARIANT_TRUE; + + if(NULL == m_spiWebBrowser) + return; + HRESULT hRet(E_FAIL); + if(NULL == m_spiHtmlDoc) + m_spiHtmlDoc = GetHtmlDoc(); + if (NULL == m_spiHtmlDoc) + return; + CComPtr spiHtmlElement = NULL; + hRet = m_spiHtmlDoc->get_activeElement(&spiHtmlElement); + if(NULL == spiHtmlElement) + return; + CComPtr spiAnchorElement = NULL; + hRet = spiHtmlElement->QueryInterface(IID_IHTMLAnchorElement, (void**)&spiAnchorElement); + if (NULL == spiAnchorElement) + { + spiHtmlElement = NULL; + return; + } + CComBSTR bstrElementHref; + /// 获取当前点击的链接地址 + hRet = spiAnchorElement->get_href(&bstrElementHref); + spiAnchorElement = NULL; + spiHtmlElement = NULL; + + ATLASSERT(bstrElementHref.Length()); + CString strReqUrl(bstrElementHref.m_str); + bstrElementHref.Empty(); + if(0 == strReqUrl.Left(2).CompareNoCase(L"//")) + { + strReqUrl.Insert(0,L"http:"); + } + CComVariant varVal; + varVal.Clear(); + hRet = m_spiWebBrowser->Navigate(CComBSTR(strReqUrl),&varVal,&varVal,&varVal,&g_varWebHeader); + strReqUrl.Empty(); +} + +CComPtr CMainDlg::GetHtmlDoc() +{ + CComPtr spiHtmlDoc = NULL; + if(NULL == m_spiWebBrowser) + return spiHtmlDoc; + CComPtr< IDispatch > spdispDoc = NULL; + HRESULT hRet = m_spiWebBrowser->get_Document(&spdispDoc); + if (FAILED(hRet) || NULL == spdispDoc) + return spiHtmlDoc; + CComPtr spDoc = NULL; + hRet = spdispDoc->QueryInterface(IID_IHTMLDocument2,(void **)&spiHtmlDoc); + spdispDoc = NULL; + return spiHtmlDoc; +} + +void CMainDlg::DocumentComplete(IDispatch *pDisp, VARIANT *pvarURL) +{ + CString strUrl(pvarURL->bstrVal); +} + +LRESULT CMainDlg::OnInitConn(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) +{ + if(NULL != m_spiSocketProxy) + return 0;/// 已经初始化 + HRESULT hRet = m_spiSocketProxy.CreateInstance(__uuidof(SocketProxy)); + ATLASSERT(SUCCEEDED(hRet)); + if(FAILED(hRet)) + { + this->MessageBox(L"Web Socket基础组件还未正常注册成功!"); + InitWebCtrl(); + return 0; + } +#ifdef NEED_FINAL_CONSTRUCT + CComObject::CreateInstance(&(m_spiSocketProxyEvent)); +#else + m_spiSocketProxyEvent = new CComObject< CProxyServerEvent >; +#endif + ATLASSERT(m_spiSocketProxyEvent); + if(NULL != m_spiSocketProxyEvent) + { + m_spiSocketProxyEvent->SetCallPara(this->m_hWnd); + //建立事件连接 + hRet = AtlAdvise(m_spiSocketProxy,this->m_spiSocketProxyEvent->GetUnknown(), + DIID__ISocketProxyEvents,&this->m_nSocketProxyCookie); + ATLASSERT(SUCCEEDED(hRet)); + if(!m_nPort) + m_nPort = 12800; + USHORT nTruePort = 0; + hRet = m_spiSocketProxy->Listen(m_nPort,CComBSTR(m_strSID),CComBSTR(m_strAuthInfo),&nTruePort); + if(FAILED(hRet)) + { + CComBSTR bstrErr; + m_spiSocketProxy->get_LastErrInfo(NULL,&bstrErr); + this->MessageBox(bstrErr.m_str); + bstrErr.Empty(); + } + } + InitWebCtrl(); + return 1; +} + +LRESULT CMainDlg::OnNewConnect(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) +{ + BSTR bstrSID = (BSTR)lParam; + /// 这里记录连接标识,然后可以调用通知发送信息 + m_mapConnID[bstrSID] = bstrSID; + this->GetDlgItem(IDC_EDIT_LOG).SetWindowText(CString(L"收到新连接通知:") + bstrSID); + return 0; +} + +LRESULT CMainDlg::OnRecMessage(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) +{ + CString strReqName = (BSTR)wParam; + BSTR bstrContent = (BSTR)lParam; + + CString strMsg; + strMsg.Format(L"收到请求为 %s 的JSON数据包:%s",strReqName,(CString)bstrContent); + this->GetDlgItem(IDC_EDIT_LOG).SetWindowText(strMsg); + strMsg.Empty(); + ULONG nReqID = 0; + m_spiSocketProxy->AsynSendText(CComBSTR(m_mapConnID.begin()->first),\ + CComBSTR(CString(L"桌面APP收到请求参数:")+bstrContent),&nReqID); + /// 解析收到的命令 + IJsonServicePtr spiJsonService = NULL; + HRESULT hRet = spiJsonService.CreateInstance(__uuidof(JsonService)); + if(NULL == spiJsonService) + return 0; + VARIANT_BOOL bLoadFlag = VARIANT_FALSE; + spiJsonService->put_CodingType(CODINGTYPE_US2); + spiJsonService->ParseString(bstrContent,&bLoadFlag); + if(VARIANT_FALSE == bLoadFlag) + { + spiJsonService = NULL; + return 0; + } + if(0 == strReqName.CompareNoCase(L"Demo_OpenUrl")) + { + CComBSTR bstrVal; + spiJsonService->GetStringValue(CComBSTR(L"url"),&bstrVal); + m_strOpenUrl.Empty(); + m_strOpenUrl = bstrVal.m_str; + bstrVal.Empty(); + /// 通知打开网站 + this->PostMessage(WM_APP_OPENURL,0,0); + } + spiJsonService = NULL; + return 0; +} + +LRESULT CMainDlg::OnRecText(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) +{ + BSTR bstrContent = (BSTR)lParam; + CString strMsg; + strMsg.Format(L"收到文本数据包:%s",(CString)bstrContent); + this->GetDlgItem(IDC_EDIT_LOG).SetWindowText(strMsg); + strMsg.Empty(); + ULONG nReqID = 0; + m_spiSocketProxy->AsynSendText((BSTR)wParam,CComBSTR(CString(L"桌面APP收到内容:")+bstrContent),&nReqID); + return 0; +} + +LRESULT CMainDlg::OnCloseConnect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) +{ + BSTR bstrSID = (BSTR)wParam; + BSTR bstrContent = (BSTR)lParam; + CString strMsg; + strMsg.Format(L"收到标识为 %s 的连接通知关闭:%s",(CString)bstrSID,(CString)bstrContent); + this->GetDlgItem(IDC_EDIT_LOG).SetWindowText(strMsg); + strMsg.Empty(); + return 0; +} + +LRESULT CMainDlg::OnRecByte(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) +{ + /// 暂未实现,通知收到字节流 + return 0; +} + +void CMainDlg::UnAdviseSocket() +{ + if(0 == m_nSocketProxyCookie) + return; + AtlUnadvise(m_spiSocketProxy,DIID__ISocketProxyEvents,m_nSocketProxyCookie); + m_nSocketProxyCookie = 0; + m_spiSocketProxyEvent = NULL; + + m_spiSocketProxy->Close(); + m_spiSocketProxy = NULL; +} + +LRESULT CMainDlg::OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + CSimpleDialog dlg; + dlg.DoModal(); + return 0; +} + +LRESULT CMainDlg::OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + // TODO: Add validation code + if(NULL == m_spiSocketProxy) + return 0; + VARIANT_BOOL bIsReady = VARIANT_FALSE; + m_spiSocketProxy->get_Ready(&bIsReady); + /// 通过命令行传进来端口 + if(VARIANT_TRUE != bIsReady) + { + this->MessageBox(L"侦听服务还未就绪!"); + return 0; + } + CComBSTR bstrContent; + this->GetDlgItem(IDC_EDIT_CONTENT).GetWindowText(&bstrContent); + ULONG nReqID = 0; + CString strContent(bstrContent.m_str); + if(!m_mapConnID.size()) + { + this->MessageBox(L"还未有活动连接!"); + return 0; + } + if(strContent.IsEmpty()) + return 0; + CString strReturn; + strContent.Replace(L"\"",L"\\\""); + strReturn.Format(_T("{\"rid\":%ld,\"req\":\"Send\",\"data\":{\"Content\":\"%s\"}}"), \ + nReqID,strContent); + HRESULT hRet = m_spiSocketProxy->AsynSendText(CComBSTR(m_mapConnID.begin()->first),\ + CComBSTR(strReturn),&nReqID); + if(!nReqID || FAILED(hRet)) + { + CComBSTR bstrErrInfo; + m_spiSocketProxy->get_LastErrInfo(CComBSTR(m_mapConnID.begin()->first),&bstrErrInfo); + this->MessageBox(bstrErrInfo.m_str); + bstrErrInfo.Empty(); + } + else + { + this->GetDlgItem(IDC_EDIT_CONTENT).SetWindowText(L""); + } + return 0; +} + +LRESULT CMainDlg::OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + UnAdviseSocket(); + + m_spiHtmlDoc = NULL; + m_DocHostUIHandler.ReleaseCom(); + if(NULL != m_spiWebBrowser) + { + AtlAdviseSinkMap(this,false); + /// 调用退出 + m_spiWebBrowser->Quit(); + m_spiWebBrowser = NULL; + } + + if(m_ctlWebWindow.IsWindow()) + m_ctlWebWindow.DestroyWindow(); + + EndDialog(wID); + return 0; +} diff --git a/ZbaSDK/SampleCode/PluginWinExe/MainDlg.h b/ZbaSDK/SampleCode/PluginWinExe/MainDlg.h new file mode 100644 index 0000000000000000000000000000000000000000..f7b332705f79aa2f65e9b5bf0eddb9038c512e5f --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/MainDlg.h @@ -0,0 +1,150 @@ +// MainDlg.h : interface of the CMainDlg class +// +///////////////////////////////////////////////////////////////////////////// + +#pragma once +#include +#include "ProxyServerEvent.h" +#include "BrowserHost.h" + +#define WM_APP_OPENURL WM_USER + 500 + +typedef std::map CSTRING_MAP; + +int Us2ToChar(const ATL::CString& strSrc, char** pDst,int nCodePage = CP_ACP); + +class CMainDlg : public CAxDialogImpl,public IDispEventImpl +{ +protected: + + /// 嵌套IE控件 + CAxWindow m_ctlWebWindow; + /// 浏览器访问控件 + CComPtr m_spiWebBrowser; + /// 加载HTML页面文档对象 + CComPtr m_spiHtmlDoc; + + /// 定制行为 + CDocHostUIHandler m_DocHostUIHandler; + + /// 服务侦听端口 + USHORT m_nPort; + /// 侦听会话ID + CString m_strSID; + /// 侦听授权信息 + CString m_strAuthInfo; + + CSTRING_MAP m_mapPara; + + /// 准备打开的URL地址 + CString m_strOpenUrl; + + /// 记录所有的连接标识 + CSTRING_MAP m_mapConnID; + + /// 通讯代理 + ISocketProxyPtr m_spiSocketProxy; + /// 事件COOKIE + DWORD m_nSocketProxyCookie; + /// 任务事件对象 + CComObject* m_spiSocketProxyEvent; + + void UnAdviseSocket(); + + void InitWebCtrl(); + + /// 获得HTML文档对象 + CComPtr GetHtmlDoc(); + + /// 浏览器事件 + void __stdcall OnNewWindow3(LPDISPATCH* ppDisp, VARIANT_BOOL * Cancel, DWORD dwFlags, BSTR bstrUrlContext, BSTR bstrUrl); + void __stdcall BeforeNavigate2(IDispatch *pDisp, + CComVariant &URL, CComVariant &Flags, CComVariant &TargetFrameName, + CComVariant &PostData, CComVariant &Headers, VARIANT_BOOL* Cancel); + + void __stdcall NavigateComplete2(IDispatch *pDisp, VARIANT *pvarURL); + void __stdcall DocumentComplete(IDispatch *pDisp, VARIANT *pvarURL); + +public: + CMainDlg() + :m_nPort(12900) + ,m_spiWebBrowser(NULL) + ,m_spiHtmlDoc(NULL) + ,m_spiSocketProxy(NULL) + ,m_spiSocketProxyEvent(NULL) + ,m_nSocketProxyCookie(0) + { + } + + enum { IDD = IDD_MAINDLG }; + + void SetListenPara(CSTRING_MAP& mapPara) + { + m_mapPara = mapPara; + CSTRING_MAP::iterator it = m_mapPara.find(L"PORT"); + ATLASSERT(it != m_mapPara.end()); + if(it != m_mapPara.end()) + { + char* szCmd = NULL; + Us2ToChar(it->second,&szCmd); + if(NULL != szCmd) + { + m_nPort = atoi(szCmd); + delete []szCmd; + szCmd = NULL; + } + ATLASSERT(m_nPort > 0 && m_nPort < 65536); + } + if(!m_nPort) + m_nPort = 12800; + it = m_mapPara.find(L"SID"); + ATLASSERT(it != m_mapPara.end()); + if(it != m_mapPara.end()) + m_strSID = it->second; + it = m_mapPara.find(L"AI"); + ATLASSERT(it != m_mapPara.end()); + if(it != m_mapPara.end()) + m_strAuthInfo = it->second; + } + + BEGIN_SINK_MAP(CMainDlg) + SINK_ENTRY(IDC_WEB_BROWSER,DISPID_NEWWINDOW3, OnNewWindow3) + SINK_ENTRY(IDC_WEB_BROWSER,DISPID_DOCUMENTCOMPLETE, DocumentComplete) + SINK_ENTRY(IDC_WEB_BROWSER,DISPID_BEFORENAVIGATE2, BeforeNavigate2) + SINK_ENTRY(IDC_WEB_BROWSER,DISPID_NAVIGATECOMPLETE2, NavigateComplete2) + END_SINK_MAP() + + BEGIN_MSG_MAP(CMainDlg) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + MESSAGE_HANDLER(WM_APP, OnInitConn) + MESSAGE_HANDLER(WM_APP_OPENURL, OnOpenUrl) + MESSAGE_HANDLER(WM_PROXYSEREREVENT_NEWCONNECT, OnNewConnect) + MESSAGE_HANDLER(WM_PROXYSEREREVENT_RECMESSAGE, OnRecMessage) + MESSAGE_HANDLER(WM_PROXYSEREREVENT_RECTEXT, OnRecText) + MESSAGE_HANDLER(WM_PROXYSEREREVENT_CLOSECONN, OnCloseConnect) + MESSAGE_HANDLER(WM_PROXYSEREREVENT_BYTE, OnRecByte) + + COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout) + COMMAND_ID_HANDLER(IDOK, OnOK) + COMMAND_ID_HANDLER(IDCANCEL, OnCancel) + END_MSG_MAP() + +// Handler prototypes (uncomment arguments if needed): +// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) +// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + LRESULT OnInitConn(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/ ); + LRESULT OnOpenUrl(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/ ); + + LRESULT OnNewConnect(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + LRESULT OnRecMessage(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + LRESULT OnRecText(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + LRESULT OnRecByte(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + LRESULT OnCloseConnect(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + + LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); +}; diff --git a/ZbaSDK/SampleCode/PluginWinExe/PluginConfig.json b/ZbaSDK/SampleCode/PluginWinExe/PluginConfig.json new file mode 100644 index 0000000000000000000000000000000000000000..0cbec4e2f6513269e3b8d0edcde308f8d334a500 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/PluginConfig.json @@ -0,0 +1,17 @@ +{ + "Type": 2, + "OS": 1, + "Control": 0, + "OSMinVer": "5.0", + "Version": "2.0.2.1", + "Name": "寮圭獥灏忕▼搴忚寖渚(C++璇█)", + "Corp": "ZorroSoft", + "Icon": "", + "Date": "2020.08.25", + "Desc": "寮圭獥灏忕▼搴(C++璇█)-婕旂ず鑴氭湰璇锋眰鎵撳紑鎸囧畾缃戠珯", + "Home": "http://zorrosoft.com/WRL", + "Down": "http://zorrosoft.com/WRL", + "Module": "PluginWinExe.exe", + "PID": "F90B1CF0-8485-40ec-B4E8-B87598AAB35D", + "Updates": [] +} \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.cpp b/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5bcac1eaa176e3f4e41b037fde41fede6aa411a1 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.cpp @@ -0,0 +1,106 @@ +// PluginWinExe.cpp : main source file for PluginWinExe.exe +// + +#include "stdafx.h" +#include "resource.h" +#include "MainDlg.h" +#include "WrlRegKey.h" + +CAppModule _Module; + +void InitBrowerConfig() +{ + /// 使用API函数IsHungAppWindow,可以判断窗口是否已经停止响应 + TCHAR szPath[MAX_PATH]; + ::memset(szPath,0,MAX_PATH*sizeof(TCHAR)); + ::GetModuleFileName(NULL,szPath,MAX_PATH); + CString strFileName(szPath); + int nFind = strFileName.ReverseFind(_T('\\')); + if(-1 != nFind) + strFileName.Delete(0,nFind+1); + + CString strRegPath(_T("Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl")); + CWrlRegKey reg(strRegPath,_T("FEATURE_TABBED_BROWSING"),HKEY_CURRENT_USER,KEY_WRITE); + DWORD dwRet = reg.DelKeyName(strFileName); + + /// 解决登录后获取数据失败问题,设置支持IE9,解决淘宝等问题 + reg.NewRegPath(strRegPath,_T("FEATURE_BROWSER_EMULATION"),HKEY_CURRENT_USER,KEY_WRITE); + reg.SetRegDwordVal(strFileName,9000); + + reg.NewRegPath(strRegPath,_T("FEATURE_LOCALMACHINE_LOCKDOWN"),HKEY_CURRENT_USER,KEY_WRITE); + dwRet = reg.DelKeyName(strFileName); + + /// 启用缩放 + dwRet = -1; + reg.NewRegPath(_T("Software\\Microsoft\\Internet Explorer"),_T("Zoom"),HKEY_CURRENT_USER,KEY_WRITE|KEY_READ); + if(reg.GetRegDwordVal(_T("ZoomDisabled"),dwRet)) + reg.SetRegDwordVal(_T("ZoomDisabled"),0); +} + +int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int /*nCmdShow*/) +{ +// If you are running on NT 4.0 or higher you can use the following call instead to +// make the EXE free threaded. This means that calls come in on a random RPC thread. + HRESULT hRes = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ATLASSERT(SUCCEEDED(hRes)); + hRes = CoInitializeSecurity( NULL, -1, NULL, NULL, + RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE,NULL,EOAC_NONE,NULL); + + // this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used + ::DefWindowProc(NULL, 0, 0, 0L); + + AtlInitCommonControls(ICC_BAR_CLASSES|ICC_DATE_CLASSES); // add flags to support other controls + + hRes = _Module.Init(NULL, hInstance); + ATLASSERT(SUCCEEDED(hRes)); + + AtlAxWinInit(); + + int nRet = 0; + // BLOCK: Run application + { + /// 接收命令行传递的开始侦听端口,同时接收PID参数(如果有的话) + CString strCmd(lpstrCmdLine); + if(L'\"' == strCmd.GetAt(0)) + strCmd.Delete(0); + if(strCmd.Right(1) == L'\"') + strCmd.Delete(strCmd.GetLength()-1); + CSTRING_MAP mapPara; + int nFind = strCmd.Find(L"&"); + while(-1 != nFind) + { + CString strPara(strCmd.Left(nFind)); + strCmd.Delete(0,nFind+1); + nFind = strPara.Find(L"="); + ATLASSERT(-1 != nFind); + CString strParaName(strPara.Left(nFind)); + strPara.Delete(0,nFind+1); + mapPara[strParaName] = strPara; + strPara.Empty(); + strParaName.Empty(); + nFind = strCmd.Find(L"&"); + } + if(strCmd.GetLength()) + { + nFind = strCmd.Find(L"="); + ATLASSERT(-1 != nFind); + CString strParaName(strCmd.Left(nFind)); + strCmd.Delete(0,nFind+1); + mapPara[strParaName] = strCmd; + strCmd.Empty(); + strParaName.Empty(); + } + + /// 配置浏览器 + InitBrowerConfig(); + + CMainDlg dlgMain; + dlgMain.SetListenPara(mapPara); + nRet = (int)dlgMain.DoModal(); + } + AtlAxWinTerm(); + _Module.Term(); + ::CoUninitialize(); + + return nRet; +} diff --git a/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.h b/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.h new file mode 100644 index 0000000000000000000000000000000000000000..4b7a60f6399b5f0fddfde29c42f2727afcae37f1 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.h @@ -0,0 +1 @@ +// PluginWinExe.h diff --git a/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.rc b/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.rc new file mode 100644 index 0000000000000000000000000000000000000000..33999264abfc83b31e6dd87bd8746a55b1ac79ac --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.rc @@ -0,0 +1,274 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "atlres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(简体,中国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\PluginWinExe.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG 0, 0, 187, 102 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,130,81,50,14 + CTEXT "PluginWinExe Application v1.0\n\n(c) Copyright 2018",IDC_STATIC,25,57,78,32 + ICON IDR_MAINFRAME,IDC_STATIC,55,26,18,20 + GROUPBOX "",IDC_STATIC,7,7,115,88 +END + +IDD_MAINDLG DIALOGEX 0, 0, 400, 362 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU +CAPTION "C++弹窗小程序演示" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + EDITTEXT IDC_EDIT_CONTENT,17,279,171,52,ES_MULTILINE | ES_AUTOVSCROLL + DEFPUSHBUTTON "发送",IDOK,55,335,50,16 + EDITTEXT IDC_EDIT_LOG,200,279,180,53,ES_MULTILINE | ES_AUTOVSCROLL + PUSHBUTTON "退出",IDCANCEL,113,335,50,16 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 180 + TOPMARGIN, 7 + BOTTOMMARGIN, 95 + END + + IDD_MAINDLG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 393 + TOPMARGIN, 7 + BOTTOMMARGIN, 355 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,0,1,1 + PRODUCTVERSION 2,0,1,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "弹窗小程序演示(C++语言)" + VALUE "FileVersion", "2,0,1,1" + VALUE "InternalName", "PluginWinExe" + VALUE "LegalCopyright", "Copyright(C) 2013-? ZorroSoft. All Rights Reserved." + VALUE "OriginalFilename", "PluginWinExe.exe" + VALUE "ProductName", "PluginOK" + VALUE "ProductVersion", "2,0,1,1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDR_MAINFRAME "PluginWinExe" +END + +STRINGTABLE +BEGIN + ID_FILE_NEW "Create a new document\nNew" + ID_FILE_OPEN "Open an existing document\nOpen" + ID_FILE_CLOSE "Close the active document\nClose" + ID_FILE_SAVE "Save the active document\nSave" + ID_FILE_SAVE_AS "Save the active document with a new name\nSave As" + ID_FILE_PAGE_SETUP "Change the printing options\nPage Setup" + ID_FILE_PRINT_SETUP "Change the printer and printing options\nPrint Setup" + ID_FILE_PRINT "Print the active document\nPrint" + ID_FILE_PRINT_PREVIEW "Display full pages\nPrint Preview" +END + +STRINGTABLE +BEGIN + ID_APP_ABOUT "Display program information, version number and copyright\nAbout" + ID_APP_EXIT "Quit the application; prompts to save documents\nExit" +END + +STRINGTABLE +BEGIN + ID_NEXT_PANE "Switch to the next window pane\nNext Pane" + ID_PREV_PANE "Switch back to the previous window pane\nPrevious Pane" +END + +STRINGTABLE +BEGIN + ID_WINDOW_NEW "Open another window for the active document\nNew Window" + ID_WINDOW_ARRANGE "Arrange icons at the bottom of the window\nArrange Icons" + ID_WINDOW_CASCADE "Arrange windows so they overlap\nCascade Windows" + ID_WINDOW_TILE_HORZ "Arrange windows as non-overlapping tiles\nTile Windows" + ID_WINDOW_TILE_VERT "Arrange windows as non-overlapping tiles\nTile Windows" + ID_WINDOW_SPLIT "Split the active window into panes\nSplit" +END + +STRINGTABLE +BEGIN + ID_EDIT_CLEAR "Erase the selection\nErase" + ID_EDIT_CLEAR_ALL "Erase everything\nErase All" + ID_EDIT_COPY "Copy the selection and put it on the Clipboard\nCopy" + ID_EDIT_CUT "Cut the selection and put it on the Clipboard\nCut" + ID_EDIT_FIND "Find the specified text\nFind" + ID_EDIT_PASTE "Insert Clipboard contents\nPaste" + ID_EDIT_REPEAT "Repeat the last action\nRepeat" + ID_EDIT_REPLACE "Replace specific text with different text\nReplace" + ID_EDIT_SELECT_ALL "Select the entire document\nSelect All" + ID_EDIT_UNDO "Undo the last action\nUndo" + ID_EDIT_REDO "Redo the previously undone action\nRedo" +END + +STRINGTABLE +BEGIN + ATL_IDS_SCSIZE "Change the window size" + ATL_IDS_SCMOVE "Change the window position" + ATL_IDS_SCMINIMIZE "Reduce the window to an icon" + ATL_IDS_SCMAXIMIZE "Enlarge the window to full size" + ATL_IDS_SCNEXTWINDOW "Switch to the next document window" + ATL_IDS_SCPREVWINDOW "Switch to the previous document window" + ATL_IDS_SCCLOSE "Close the active window and prompts to save the documents" +END + +STRINGTABLE +BEGIN + ATL_IDS_SCRESTORE "Restore the window to normal size" + ATL_IDS_SCTASKLIST "Activate Task List" + ATL_IDS_MDICHILD "Activate this window" +END + +STRINGTABLE +BEGIN + ATL_IDS_IDLEMESSAGE "Ready" +END + +STRINGTABLE +BEGIN + ATL_IDS_MRU_FILE "Open this document" +END + +#endif // 中文(简体,中国) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// 英语(美国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""atlres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_MAINFRAME ACCELERATORS +BEGIN + "N", ID_FILE_NEW, VIRTKEY, CONTROL + "O", ID_FILE_OPEN, VIRTKEY, CONTROL + "S", ID_FILE_SAVE, VIRTKEY, CONTROL + "P", ID_FILE_PRINT, VIRTKEY, CONTROL + "Z", ID_EDIT_UNDO, VIRTKEY, CONTROL + "X", ID_EDIT_CUT, VIRTKEY, CONTROL + "C", ID_EDIT_COPY, VIRTKEY, CONTROL + "V", ID_EDIT_PASTE, VIRTKEY, CONTROL + VK_BACK, ID_EDIT_UNDO, VIRTKEY, ALT + VK_DELETE, ID_EDIT_CUT, VIRTKEY, SHIFT + VK_INSERT, ID_EDIT_COPY, VIRTKEY, CONTROL + VK_INSERT, ID_EDIT_PASTE, VIRTKEY, SHIFT + VK_F6, ID_NEXT_PANE, VIRTKEY + VK_F6, ID_PREV_PANE, VIRTKEY, SHIFT +END + +#endif // 英语(美国) resources +///////////////////////////////////////////////////////////////////////////// + + diff --git a/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.sln b/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.sln new file mode 100644 index 0000000000000000000000000000000000000000..824f300fd1e15ada903051f0fee16a1ada0a13e8 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.sln @@ -0,0 +1,26 @@ +锘 +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PluginWinExe", "PluginWinExe.vcxproj", "{BC97A227-EBF0-41F2-93EE-C00E0F7C5C08}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BC97A227-EBF0-41F2-93EE-C00E0F7C5C08}.Debug|Win32.ActiveCfg = Debug|Win32 + {BC97A227-EBF0-41F2-93EE-C00E0F7C5C08}.Debug|Win32.Build.0 = Debug|Win32 + {BC97A227-EBF0-41F2-93EE-C00E0F7C5C08}.Debug|x64.ActiveCfg = Debug|x64 + {BC97A227-EBF0-41F2-93EE-C00E0F7C5C08}.Debug|x64.Build.0 = Debug|x64 + {BC97A227-EBF0-41F2-93EE-C00E0F7C5C08}.Release|Win32.ActiveCfg = Release|Win32 + {BC97A227-EBF0-41F2-93EE-C00E0F7C5C08}.Release|Win32.Build.0 = Release|Win32 + {BC97A227-EBF0-41F2-93EE-C00E0F7C5C08}.Release|x64.ActiveCfg = Release|x64 + {BC97A227-EBF0-41F2-93EE-C00E0F7C5C08}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.vcxproj b/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.vcxproj new file mode 100644 index 0000000000000000000000000000000000000000..762e169bd543205282dc3a36f6c030de3f573f3b --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.vcxproj @@ -0,0 +1,262 @@ +锘 + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {BC97A227-EBF0-41F2-93EE-C00E0F7C5C08} + + + + + + + + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + false + Unicode + + + Application + false + Unicode + + + + + + + + + + + + + + + + + + + true + \$(Configuration)\$(Platform)\Plugins\$(ProjectName)\ + $(Configuration)\$(Platform)\$(ProjectName)\ + W:\Src\Plugin\PluginWinExe\WTL;$(IncludePath) + + + true + \$(Configuration)\$(Platform)\Plugins\$(ProjectName)\ + $(Configuration)\$(Platform)\$(ProjectName)\ + W:\Src\Plugin\PluginWinExe\WTL;$(IncludePath) + + + false + \$(Configuration)\$(Platform)\Plugins\$(ProjectName)\ + \$(Configuration)\$(Platform)\$(ProjectName)\ + W:\Src\Plugin\PluginWinExe\WTL;$(IncludePath) + + + false + \$(Configuration)\$(Platform)\Plugins\$(ProjectName)\ + \$(Configuration)\$(Platform)\$(ProjectName)\ + W:\Src\Plugin\PluginWinExe\WTL;$(IncludePath) + + + + Use + Level3 + MultiThreadedDebug + true + EditAndContinue + EnableFastChecks + Disabled + WIN32;_WINDOWS;STRICT;_DEBUG;%(PreprocessorDefinitions) + + + + + Windows + true + \$(Configuration)\$(Platform)\$(TargetName).pdb + + + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + _DEBUG;%(PreprocessorDefinitions) + + + false + Win32 + _DEBUG;%(PreprocessorDefinitions) + PluginWinExe.h + PluginWinExe_i.c + PluginWinExe_p.c + true + $(IntDir)/PluginWinExe.tlb + + + + + + + Use + Level3 + MultiThreadedDebug + ProgramDatabase + EnableFastChecks + Disabled + _WIN64;WIN32;_WINDOWS;STRICT;_DEBUG;%(PreprocessorDefinitions) + + + + + Windows + true + \$(Configuration)\$(Platform)\$(TargetName).pdb + + + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + _DEBUG;%(PreprocessorDefinitions) + + + false + _DEBUG;%(PreprocessorDefinitions) + PluginWinExe.h + PluginWinExe_i.c + PluginWinExe_p.c + true + $(IntDir)/PluginWinExe.tlb + + + + + + + Use + Level3 + MultiThreaded + + + + + WIN32;_WINDOWS;STRICT;NDEBUG;%(PreprocessorDefinitions) + + + /EHsc %(AdditionalOptions) + + + Windows + \$(Configuration)\$(Platform)\$(TargetName).pdb + + + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + NDEBUG;%(PreprocessorDefinitions) + + + false + Win32 + NDEBUG;%(PreprocessorDefinitions) + PluginWinExe.h + PluginWinExe_i.c + PluginWinExe_p.c + true + $(IntDir)/PluginWinExe.tlb + + + + + + + Use + Level3 + MultiThreaded + + + + + _WIN64;WIN32;_WINDOWS;STRICT;NDEBUG;%(PreprocessorDefinitions) + + + /EHsc %(AdditionalOptions) + + + Windows + \$(Configuration)\$(Platform)\$(TargetName).pdb + + + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + NDEBUG;%(PreprocessorDefinitions) + + + false + NDEBUG;%(PreprocessorDefinitions) + PluginWinExe.h + PluginWinExe_i.c + PluginWinExe_p.c + true + $(IntDir)/PluginWinExe.tlb + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.vcxproj.filters b/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.vcxproj.filters new file mode 100644 index 0000000000000000000000000000000000000000..4edf20a93428ae1ba713954c0cdb3fa8c054cb3e --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/PluginWinExe.vcxproj.filters @@ -0,0 +1,67 @@ +锘 + + + + {c3bb59f7-ac5f-42a7-a7cd-9e7070d0e940} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {4ea57cef-252a-429e-bd82-d5bd175c7f25} + h;hpp;hxx;hm;inl;inc + + + {b089cbce-2c0b-4751-8093-cd85a1afd448} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginWinExe/ProxyServerEvent.cpp b/ZbaSDK/SampleCode/PluginWinExe/ProxyServerEvent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65f75d80b69e3356d78af3d0b4cd6ee832c68c90 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/ProxyServerEvent.cpp @@ -0,0 +1,209 @@ +///////////////////////////////////////////////////////////////////////// +/*@ + 文件名称: ProxyServerEvent.cpp + 文件描述: 实现代理服务事件通知处理 + 编写日期: 2018-10-25 22:00:00 + 程序作者: 汪佐怀 +*/ +///////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "ProxyServerEvent.h" + +///////////////////////////////////////////////////////////////////////////// +// CProxyServerEvent + +STDMETHODIMP CProxyServerEvent::Invoke( DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags, + DISPPARAMS *pDispParams,VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr) +{ + HRESULT hRet(S_OK); + switch( dispIdMember ) + { + case 0x00000001: + { + if ( pDispParams->cArgs != 1 ) + return DISP_E_BADPARAMCOUNT; + if ( pDispParams->cNamedArgs ) + return DISP_E_NONAMEDARGS; + + CComVariant varSID; + VariantInit(&varSID); + hRet = VariantChangeTypeEx( &varSID,&(pDispParams->rgvarg[0]),lcid,0,VT_BSTR); + if FAILED(hRet) + return DISP_E_BADVARTYPE; + hRet = NewConn(varSID.bstrVal); + VariantClear(&varSID); + break; + } + + case 0x00000002: + { + if ( pDispParams->cArgs != 4 ) + return DISP_E_BADPARAMCOUNT; + if ( pDispParams->cNamedArgs ) + return DISP_E_NONAMEDARGS; + + CComVariant varSID,varReqID,varReqName,varMsgInfo; + VariantInit(&varSID); + VariantInit(&varReqID); + VariantInit(&varReqName); + VariantInit(&varMsgInfo); + hRet = VariantChangeTypeEx( &varSID,&(pDispParams->rgvarg[3]),lcid,0,VT_BSTR); + if FAILED(hRet) + return DISP_E_BADVARTYPE; + hRet = VariantChangeTypeEx( &varReqID,&(pDispParams->rgvarg[2]),lcid,0,VT_I4); + if FAILED(hRet) + return DISP_E_BADVARTYPE; + hRet = VariantChangeTypeEx( &varReqName,&(pDispParams->rgvarg[1]),lcid,0,VT_BSTR); + if FAILED(hRet) + return DISP_E_BADVARTYPE; + hRet = VariantChangeTypeEx( &varMsgInfo,&(pDispParams->rgvarg[0]),lcid,0,VT_BSTR); + if FAILED(hRet) + return DISP_E_BADVARTYPE; + hRet = RecMsgEvent(varSID.bstrVal,varReqID.ulVal,varReqName.bstrVal,varMsgInfo.bstrVal); + VariantClear(&varMsgInfo); + VariantClear(&varReqName); + VariantClear(&varReqID); + VariantClear(&varSID); + break; + } + case 0x00000003: + { + if ( pDispParams->cArgs != 2 ) + return DISP_E_BADPARAMCOUNT; + if ( pDispParams->cNamedArgs ) + return DISP_E_NONAMEDARGS; + + CComVariant varText,varSID; + VariantInit(&varText); + VariantInit(&varSID); + hRet = VariantChangeTypeEx( &varSID,&(pDispParams->rgvarg[1]),lcid,0,VT_BSTR); + if FAILED(hRet) + return DISP_E_BADVARTYPE; + hRet = VariantChangeTypeEx( &varText,&(pDispParams->rgvarg[0]),lcid,0,VT_BSTR); + if FAILED(hRet) + return DISP_E_BADVARTYPE; + hRet = RecTextEvent(varSID.bstrVal,varText.bstrVal); + VariantClear(&varText); + VariantClear(&varSID); + break; + } + case 0x00000004: + { + if ( pDispParams->cArgs != 3 ) + return DISP_E_BADPARAMCOUNT; + if ( pDispParams->cNamedArgs ) + return DISP_E_NONAMEDARGS; + + CComVariant varSID,varByte,varLen; + VariantInit(&varSID); + VariantInit(&varByte); + VariantInit(&varLen); + hRet = VariantChangeTypeEx( &varSID,&(pDispParams->rgvarg[2]),lcid,0,VT_BSTR); + if FAILED(hRet) + return DISP_E_BADVARTYPE; + hRet = VariantChangeTypeEx( &varByte,&(pDispParams->rgvarg[1]),lcid,0,VT_PTR); + if FAILED(hRet) + return DISP_E_BADVARTYPE; + hRet = VariantChangeTypeEx( &varLen,&(pDispParams->rgvarg[0]),lcid,0,VT_UI4); + if FAILED(hRet) + return DISP_E_BADVARTYPE; + hRet = RecByte(varSID.bstrVal,varByte.pbVal,varLen.uiVal); + VariantClear(&varSID); + VariantClear(&varByte); + VariantClear(&varLen); + break; + } + + case 0x00000005: + { + if ( pDispParams->cArgs != 2 ) + return DISP_E_BADPARAMCOUNT; + if ( pDispParams->cNamedArgs ) + return DISP_E_NONAMEDARGS; + + CComVariant varReason,varSID; + VariantInit(&varReason); + VariantInit(&varSID); + hRet = VariantChangeTypeEx( &varSID,&(pDispParams->rgvarg[1]),lcid,0,VT_BSTR); + if FAILED(hRet) + return DISP_E_BADVARTYPE; + hRet = VariantChangeTypeEx( &varReason,&(pDispParams->rgvarg[0]),lcid,0,VT_BSTR); + if FAILED(hRet) + return DISP_E_BADVARTYPE; + hRet = CloseEvent(varSID.bstrVal,varReason.bstrVal); + VariantClear(&varReason); + VariantClear(&varSID); + break; + } + default: + break; + } + return hRet; +} + +STDMETHODIMP CProxyServerEvent::NewConn(BSTR bstrSID) +{ + HRESULT hRet(E_FAIL); + ATLASSERT(bstrSID); + if(NULL == bstrSID) + return hRet; + if(NULL != m_hMsgWnd && ::IsWindow(m_hMsgWnd)) + { + ::SendMessage(m_hMsgWnd,WM_PROXYSEREREVENT_NEWCONNECT,0,(LPARAM)bstrSID); + } + return hRet; +} + +STDMETHODIMP CProxyServerEvent::RecMsgEvent(BSTR bstrSID,ULONG nReqID,BSTR bstrReqName,BSTR bstrRecInfo) +{ + HRESULT hRet(E_FAIL); + if(!nReqID || NULL == bstrSID) + { + return hRet; + } + if(NULL != m_hMsgWnd && ::IsWindow(m_hMsgWnd)) + { + m_nReqID = nReqID; + if(0 != m_strSID.CompareNoCase(bstrSID)) + m_strSID = bstrSID; + ::SendMessage(m_hMsgWnd,WM_PROXYSEREREVENT_RECMESSAGE,(WPARAM)bstrReqName,(LPARAM)bstrRecInfo); + } + return hRet; +} + +STDMETHODIMP CProxyServerEvent::RecTextEvent(BSTR bstrSID,BSTR bstrText) +{ + HRESULT hRet(E_FAIL); + if(NULL == bstrSID || NULL == bstrText) + return hRet; + if(NULL != m_hMsgWnd && ::IsWindow(m_hMsgWnd)) + { + ::SendMessage(m_hMsgWnd,WM_PROXYSEREREVENT_RECTEXT,(WPARAM)bstrSID,(LPARAM)bstrText); + } + return hRet; +} + +STDMETHODIMP CProxyServerEvent::RecByte(BSTR bstrSID,BYTE* pContent,ULONG nLen) +{ + HRESULT hRet(E_FAIL); + if(NULL == bstrSID) + return hRet; + if(NULL != m_hMsgWnd && ::IsWindow(m_hMsgWnd)) + { + if(0 != m_strSID.CompareNoCase(bstrSID)) + m_strSID = bstrSID; + ::SendMessage(m_hMsgWnd,WM_PROXYSEREREVENT_BYTE,(WPARAM)pContent,(LPARAM)nLen); + } + return hRet; +} + +STDMETHODIMP CProxyServerEvent::CloseEvent(BSTR bstrSID,BSTR bstrReason) +{ + HRESULT hRet(E_FAIL); + if(NULL != m_hMsgWnd && ::IsWindow(m_hMsgWnd)) + { + ::SendMessage(m_hMsgWnd,WM_PROXYSEREREVENT_CLOSECONN,(WPARAM)bstrSID,(LPARAM)bstrReason); + } + return hRet; +} \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginWinExe/ProxyServerEvent.h b/ZbaSDK/SampleCode/PluginWinExe/ProxyServerEvent.h new file mode 100644 index 0000000000000000000000000000000000000000..af15221f753c658979c0c2a1d0ddf3b1734379ad --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/ProxyServerEvent.h @@ -0,0 +1,93 @@ +#pragma once + +#define WM_PROXYSEREREVENT_NEWCONNECT WM_USER + 2000 +#define WM_PROXYSEREREVENT_RECMESSAGE WM_USER + 2001 +#define WM_PROXYSEREREVENT_RECTEXT WM_USER + 2002 +#define WM_PROXYSEREREVENT_BYTE WM_USER + 2003 +#define WM_PROXYSEREREVENT_CLOSECONN WM_USER + 2005 + +#ifndef NEED_FINAL_CONSTRUCT +#define NEED_FINAL_CONSTRUCT +#endif + +// CProxyServerEvent +class CProxyServerEvent : + public CComObjectRoot, + //实现事件通知接口 + public _ISocketProxyEvents +{ +protected: + + /// 消息窗口 + HWND m_hMsgWnd; + + /// 当前会话ID + CString m_strSID; + + /// 当前请求序号 + ULONG m_nReqID; + +public: + CProxyServerEvent() + :m_hMsgWnd(NULL) + { + } + + ~CProxyServerEvent() + { + } + + CString GetCurSID() + { + return m_strSID; + } + + ULONG GetCurReqID() + { + return m_nReqID; + } + + void SetCallPara(HWND hMsgWnd) + { + if(NULL != hMsgWnd) + { + if(!::IsWindow(hMsgWnd)) + return; + } + m_hMsgWnd = hMsgWnd; + } + +BEGIN_COM_MAP(CProxyServerEvent) + COM_INTERFACE_ENTRY(_ISocketProxyEvents) +END_COM_MAP() + +public: + + STDMETHODIMP GetTypeInfoCount(UINT*) + { + return E_NOTIMPL; + } + + STDMETHODIMP GetTypeInfo( UINT iTInfo,LCID lcid,ITypeInfo **ppTInfo) + { + return E_NOTIMPL; + } + + STDMETHODIMP GetIDsOfNames( REFIID riid,LPOLESTR *rgszNames,UINT cNames, + LCID lcid,DISPID *rgDispId) + { + return E_NOTIMPL; + } + + STDMETHOD(Invoke)(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS *pDispParams, + VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr); + + // _ISocketProxyEvents + STDMETHOD(NewConn)(BSTR bstrSID); + + STDMETHOD(RecMsgEvent)(BSTR bstrSID,ULONG nReqID,BSTR nReqName,BSTR bstrRecText); + STDMETHOD(RecTextEvent)(BSTR bstrSID,BSTR bstrText); + STDMETHOD(RecByte)(BSTR bstrSID,BYTE* pContent,ULONG nLen); + + STDMETHOD(CloseEvent)(BSTR bstrSID,BSTR bstrReason); +}; \ No newline at end of file diff --git a/ZbaSDK/SampleCode/PluginWinExe/WRLRegKey.cpp b/ZbaSDK/SampleCode/PluginWinExe/WRLRegKey.cpp new file mode 100644 index 0000000000000000000000000000000000000000..527eecdcf984352fb839be8becbfd4420b5044e1 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WRLRegKey.cpp @@ -0,0 +1,181 @@ +// WrlRegKey.cpp : 注册表封装实现 + +#include "stdafx.h" +#include "WrlRegKey.h" + +CWrlRegKey::CWrlRegKey(const ATL::CString& strMainRegPath,\ + const ATL::CString& strChildName, HKEY hKey,REGSAM samDesired) +{ + m_bOpenFlag = FALSE; + m_dwLastErr = 0; + if(!strMainRegPath.IsEmpty()) + NewRegPath(strMainRegPath,strChildName,hKey,samDesired); +} + +void CWrlRegKey::Close() +{ + if(!m_bOpenFlag) + return; + CRegKey::Close(); + m_dwLastErr = 0; + m_bOpenFlag = FALSE; +} + +BOOL CWrlRegKey::NewRegPath(const ATL::CString& strMainRegPath,\ + const ATL::CString& strChildName, HKEY hKey,REGSAM samDesired) +{ + Close(); + + ATL::CString strRegPath; + if(!strChildName.IsEmpty()) + { + if(strMainRegPath.GetLength()) + strRegPath.Format(_T("%s\\%s"),strMainRegPath,strChildName); + else + strRegPath = strChildName; + } + else + strRegPath = strMainRegPath; + + m_dwLastErr = Open(hKey,strRegPath,samDesired); + if(ERROR_SUCCESS != m_dwLastErr) + { + if(ERROR_ACCESS_DENIED != m_dwLastErr) + { + /// 不存在,自动创建 + m_dwLastErr = Create(hKey,strRegPath,NULL,0,samDesired); + } + } + if(ERROR_SUCCESS == m_dwLastErr) + { + m_bOpenFlag = TRUE; + } + return m_bOpenFlag; +} + +BOOL CWrlRegKey::GetRegStringVal(const ATL::CString& strKeyName, + ATL::CString& strKeyValue) +{ + BOOL bGetFlag = FALSE; + if(!m_bOpenFlag) + return bGetFlag; + DWORD dwSize = 0; + m_dwLastErr = CRegKey::QueryStringValue(strKeyName,NULL,&dwSize); + + TCHAR *szBuf = new TCHAR[dwSize+1]; + if(NULL == szBuf) + return bGetFlag; + memset(szBuf,0,(dwSize+1)*sizeof(TCHAR)); + m_dwLastErr = CRegKey::QueryStringValue(strKeyName,szBuf,&dwSize); + if(m_dwLastErr != ERROR_SUCCESS) + { + if(NULL != szBuf) + { + delete []szBuf; + szBuf = NULL; + } + return bGetFlag; + } + bGetFlag = TRUE; + strKeyValue = szBuf; + if(NULL != szBuf) + { + delete []szBuf; + szBuf = NULL; + } + return bGetFlag; +} + +BOOL CWrlRegKey::SetRegStringVal(const ATL::CString& strKeyName, + const ATL::CString& strKeyValue) +{ + if(!m_bOpenFlag) + return FALSE; + m_dwLastErr = CRegKey::SetStringValue(strKeyName,strKeyValue); + if(m_dwLastErr != ERROR_SUCCESS) + return FALSE; + return TRUE; +} + +BOOL CWrlRegKey::GetRegDwordVal(const ATL::CString& strKeyName, + DWORD& dwKeyValue) +{ + dwKeyValue = 0; + if(!m_bOpenFlag) + return FALSE; + m_dwLastErr = CRegKey::QueryDWORDValue(strKeyName,dwKeyValue); + if(m_dwLastErr != ERROR_SUCCESS) + return FALSE; + return TRUE; +} + +BOOL CWrlRegKey::SetRegDwordVal(const ATL::CString& strKeyName, + DWORD dwKeyValue) +{ + if(!m_bOpenFlag) + return FALSE; + m_dwLastErr = CRegKey::SetDWORDValue(strKeyName,dwKeyValue); + if(m_dwLastErr != ERROR_SUCCESS) + return FALSE; + return TRUE; +} + +BOOL CWrlRegKey::GetRegBinaryValue(const ATL::CString &strKeyName,BYTE **ppValue,ULONG* pnBytes) +{ + if(!m_bOpenFlag) + return FALSE; + ATLASSERT(ppValue && pnBytes); + m_dwLastErr = CRegKey::QueryBinaryValue(strKeyName,NULL,pnBytes); + if(0 == *pnBytes || m_dwLastErr != ERROR_SUCCESS) + { + *ppValue = NULL; + return FALSE; + } + ULONG nLen = (*pnBytes)+1; + *ppValue = new BYTE[nLen]; + memset(*ppValue,0,nLen*sizeof(BYTE)); + m_dwLastErr = CRegKey::QueryBinaryValue(strKeyName,*ppValue,pnBytes); + if(m_dwLastErr != ERROR_SUCCESS) + return FALSE; + return TRUE; +} + +BOOL CWrlRegKey::SetRegBinaryValue(const ATL::CString &strKeyName,const BYTE* Value,ULONG nBytes) +{ + if(!m_bOpenFlag) + return FALSE; + m_dwLastErr = CRegKey::SetBinaryValue(strKeyName,Value,nBytes); + if(m_dwLastErr != ERROR_SUCCESS) + return FALSE; + return TRUE; +} + +BOOL CWrlRegKey::GetRegGuidValue(const ATL::CString &strKeyName,GUID &Value) +{ + if(!m_bOpenFlag) + return FALSE; + m_dwLastErr = CRegKey::QueryGUIDValue(strKeyName,Value)==ERROR_SUCCESS; + if(m_dwLastErr != ERROR_SUCCESS) + return FALSE; + return TRUE; +} + +BOOL CWrlRegKey::SetRegGuidValue(const ATL::CString &strKeyName,GUID Value) +{ + if(!m_bOpenFlag) + return FALSE; + m_dwLastErr = CRegKey::SetGUIDValue(strKeyName,Value); + if(m_dwLastErr != ERROR_SUCCESS) + return FALSE; + return TRUE; +} + +BOOL CWrlRegKey::DelKeyName(const ATL::CString& strKeyName) +{ + if(!m_bOpenFlag) + return FALSE; + m_dwLastErr = CRegKey::DeleteValue(strKeyName); + if(m_dwLastErr != ERROR_SUCCESS) + return FALSE; + return TRUE; +} diff --git a/ZbaSDK/SampleCode/PluginWinExe/WRLRegKey.h b/ZbaSDK/SampleCode/PluginWinExe/WRLRegKey.h new file mode 100644 index 0000000000000000000000000000000000000000..e016079df457abb61be7f49f641f2029b7dd7a95 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WRLRegKey.h @@ -0,0 +1,149 @@ +// WRLRegKey.h : 注册表操作头文件定义 +// +////////////////////////////////////////////////////////////////////// + +#pragma once + +class CWrlRegKey : public CRegKey +{ +public: + CWrlRegKey(const ATL::CString& strMainRegPath,\ + const ATL::CString& strChildName, \ + HKEY hKey,REGSAM samDesired); + + virtual ~CWrlRegKey(void) + { + /// 销毁时自动关闭,避免句柄泄露 + Close(); + } + + /// 判断是否打开了注册表 + BOOL IsOpen() + { + return m_bOpenFlag; + } + + /** + * @brief 设置新路径,重用类实例 + * + * + * @param strMainRegPath 注册表主位置 + * @param strChildName 注册表子目录名称 + * @param bCurrentUser 是否为用户注册表,否则为系统注册表 + * @return + */ + BOOL NewRegPath(const ATL::CString& strMainRegPath,\ + const ATL::CString& strChildName,\ + HKEY hKey,REGSAM samDesired); + + /** + * @brief 根据键名称获得字符串类型键值 + * + * + * @param strKeyName 键名 + * @param strKeyValue 键值 + * @return 是否成功获取 + */ + BOOL GetRegStringVal(const ATL::CString& strKeyName,ATL::CString& strKeyValue); + + /** + * @brief 设置注册表字符串类型值 + * + * + * @param strKeyName 键名 + * @param strKeyValue 键值 + * @return 是否成功设置 + */ + BOOL SetRegStringVal(const ATL::CString& strKeyName,const ATL::CString& strKeyValue); + + /** + * @brief 获得注册表DWORD类型值 + * + * + * @param strKeyName 键名 + * @param dwKeyValue 键值 + * @return 是否获取成功 + */ + BOOL GetRegDwordVal(const ATL::CString& strKeyName,DWORD& dwKeyValue); + + /** + * @brief 设置注册表DWORD类型值 + * + * + * @param strKeyName 键名 + * @param dwKeyValue 键值 + * @return 设置是否成功 + */ + BOOL SetRegDwordVal(const ATL::CString& strKeyName,DWORD dwKeyValue); + + /** + * @brief 获得注册表二进制值 + * + * + * @param strKeyName 键名 + * @param ppValue 键值 + * @param pnBytes 返回长度 + * @return 是否获取成功 + */ + BOOL GetRegBinaryValue(const ATL::CString &strKeyName,BYTE **ppValue,ULONG* pnBytes); + + /** + * @brief 设置二进制值 + * + * + * @param strKeyName 键名 + * @param Value 键值 + * @param pnBytes 返回长度 + * @return 是否设置成功 + */ + BOOL SetRegBinaryValue(const ATL::CString &strKeyName,const BYTE* Value,ULONG nBytes); + + /** + * @brief 获得GUID类型注册表值 + * + * + * @param strKeyName 键名 + * @param Value 键值 + * @return 返回是否获取成功 + */ + BOOL GetRegGuidValue(const ATL::CString &strKeyName,GUID &Value); + + /** + * @brief 设置GUID类型注册表值 + * + * + * @param strKeyName 键名 + * @param Value 键值 + * @return 返回是否设置成功 + */ + BOOL SetRegGuidValue(const ATL::CString &strKeyName,GUID Value); + + /** + * @brief 删除指定的键值 + * + * + * @param strKeyName 键名 + * @return + */ + BOOL DelKeyName(const ATL::CString& strKeyName); + + DWORD GetLastErr() + { + return m_dwLastErr; + } + + /** + * @brief 关闭注册表句柄 + * + * + */ + virtual void Close(); + +protected: + + /// 错误码 + DWORD m_dwLastErr; + + /// 是否打开了注册表 + BOOL m_bOpenFlag; +}; diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlapp.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlapp.h new file mode 100644 index 0000000000000000000000000000000000000000..4b3fe38d846da65e2f04257dec2bd4c0bb63cf8e --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlapp.h @@ -0,0 +1,2268 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLAPP_H__ +#define __ATLAPP_H__ + +#pragma once + +#ifndef __cplusplus + #error WTL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLBASE_H__ + #error atlapp.h requires atlbase.h to be included first +#endif + +#ifndef _WIN32_WCE + #if (WINVER < 0x0400) + #error WTL requires Windows version 4.0 or higher + #endif + + #if (_WIN32_IE < 0x0300) + #error WTL requires IE version 3.0 or higher + #endif +#endif + +#ifdef _ATL_NO_COMMODULE + #error WTL requires that _ATL_NO_COMMODULE is not defined +#endif + +#if (_ATL_VER >= 0x0900) && defined(_ATL_MIN_CRT) + #error _ATL_MIN_CRT is not supported with ATL 9.0 and higher +#endif + +#if defined(_WIN32_WCE) && defined(_ATL_MIN_CRT) + #pragma message("Warning: WTL for Windows CE doesn't use _ATL_MIN_CRT") +#endif + +#include +#if !defined(_ATL_MIN_CRT) && defined(_MT) && !defined(_WIN32_WCE) + #include // for _beginthreadex +#endif + +#if (_ATL_VER < 0x0800) && !defined(_DEBUG) + #include +#endif + +#include +#ifndef _WIN32_WCE + #pragma comment(lib, "comctl32.lib") +#endif + +#if defined(_SYSINFOAPI_H_) && defined(NOT_BUILD_WINDOWS_DEPRECATE) && (_WIN32_WINNT >= 0x0501) + #include +#endif + +#ifndef _WIN32_WCE + #include "atlres.h" +#else // CE specific + #include "atlresce.h" +#endif // _WIN32_WCE + +// We need to disable this warning because of template class arguments +#pragma warning(disable: 4127) + +#if (_ATL_VER >= 0x0900) && !defined(_SECURE_ATL) + #define _SECURE_ATL 1 +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// WTL version number + +#define _WTL_VER 0x0910 + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CMessageFilter +// CIdleHandler +// CMessageLoop +// +// CAppModule +// CServerAppModule +// +// CRegKeyEx +// +// Global functions: +// AtlGetDefaultGuiFont() +// AtlCreateControlFont() +// AtlCreateBoldFont() +// AtlInitCommonControls() + + +/////////////////////////////////////////////////////////////////////////////// +// Global support for Windows CE + +#ifdef _WIN32_WCE + +#ifndef SW_SHOWDEFAULT + #define SW_SHOWDEFAULT SW_SHOWNORMAL +#endif // !SW_SHOWDEFAULT + +// These get's OR-ed in a constant and will have no effect. +// Defining them reduces the number of #ifdefs required for CE. +#define LR_DEFAULTSIZE 0 +#define LR_LOADFROMFILE 0 + +#ifndef SM_CXCURSOR + #define SM_CXCURSOR 13 +#endif +#ifndef SM_CYCURSOR + #define SM_CYCURSOR 14 +#endif + +inline BOOL IsMenu(HMENU hMenu) +{ + MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; + ::SetLastError(0); + BOOL bRet = ::GetMenuItemInfo(hMenu, 0, TRUE, &mii); + if(!bRet) + bRet = (::GetLastError() != ERROR_INVALID_MENU_HANDLE) ? TRUE : FALSE; + return bRet; +} + +#if (_WIN32_WCE >= 410) +extern "C" void WINAPI ListView_SetItemSpacing(HWND hwndLV, int iHeight); +#endif // (_WIN32_WCE >= 410) + +inline int MulDiv(IN int nNumber, IN int nNumerator, IN int nDenominator) +{ + __int64 multiple = nNumber * nNumerator; + return static_cast(multiple / nDenominator); +} + +#if (_ATL_VER >= 0x0800) + +#ifndef _WTL_KEEP_WS_OVERLAPPEDWINDOW + #ifdef WS_OVERLAPPEDWINDOW + #undef WS_OVERLAPPEDWINDOW + #define WS_OVERLAPPEDWINDOW 0 + #endif // WS_OVERLAPPEDWINDOW +#endif // !_WTL_KEEP_WS_OVERLAPPEDWINDOW + +#ifndef RDW_FRAME + #define RDW_FRAME 0 +#endif // !RDW_FRAME + +#ifndef WM_WINDOWPOSCHANGING + #define WM_WINDOWPOSCHANGING 0 +#endif // !WM_WINDOWPOSCHANGING + +#define FreeResource(x) +#define UnlockResource(x) + +namespace ATL +{ + inline HRESULT CComModule::RegisterClassObjects(DWORD /*dwClsContext*/, DWORD /*dwFlags*/) throw() + { return E_NOTIMPL; } + inline HRESULT CComModule::RevokeClassObjects() throw() + { return E_NOTIMPL; } +}; // namespace ATL + +#ifndef lstrlenW + #define lstrlenW (int)ATL::lstrlenW +#endif // lstrlenW + +inline int WINAPI lstrlenA(LPCSTR lpszString) +{ return ATL::lstrlenA(lpszString); } + +#ifdef lstrcpyn + #undef lstrcpyn + #define lstrcpyn ATL::lstrcpynW +#endif // lstrcpyn + +#ifndef SetWindowLongPtrW + inline LONG_PTR tmp_SetWindowLongPtrW( HWND hWnd, int nIndex, LONG_PTR dwNewLong ) + { + return( ::SetWindowLongW( hWnd, nIndex, LONG( dwNewLong ) ) ); + } + #define SetWindowLongPtrW tmp_SetWindowLongPtrW +#endif + +#ifndef GetWindowLongPtrW + inline LONG_PTR tmp_GetWindowLongPtrW( HWND hWnd, int nIndex ) + { + return( ::GetWindowLongW( hWnd, nIndex ) ); + } + #define GetWindowLongPtrW tmp_GetWindowLongPtrW +#endif + +#ifndef LongToPtr + #define LongToPtr(x) ((void*)x) +#endif + +#ifndef PtrToInt + #define PtrToInt( p ) ((INT)(INT_PTR) (p) ) +#endif + +#else // !(_ATL_VER >= 0x0800) + +#ifdef lstrlenW + #undef lstrlenW + #define lstrlenW (int)::wcslen +#endif // lstrlenW + +#define lstrlenA (int)strlen + +#ifndef lstrcpyn + inline LPTSTR lstrcpyn(LPTSTR lpstrDest, LPCTSTR lpstrSrc, int nLength) + { + if(lpstrDest == NULL || lpstrSrc == NULL || nLength <= 0) + return NULL; + int nLen = __min(lstrlen(lpstrSrc), nLength - 1); + LPTSTR lpstrRet = (LPTSTR)memcpy(lpstrDest, lpstrSrc, nLen * sizeof(TCHAR)); + lpstrDest[nLen] = 0; + return lpstrRet; + } +#endif // !lstrcpyn + +#ifndef lstrcpynW + inline LPWSTR lstrcpynW(LPWSTR lpstrDest, LPCWSTR lpstrSrc, int nLength) + { + return lstrcpyn(lpstrDest, lpstrSrc, nLength); // WinCE is Unicode only + } +#endif // !lstrcpynW + +#ifndef lstrcpynA + inline LPSTR lstrcpynA(LPSTR lpstrDest, LPCSTR lpstrSrc, int nLength) + { + if(lpstrDest == NULL || lpstrSrc == NULL || nLength <= 0) + return NULL; + int nLen = __min(lstrlenA(lpstrSrc), nLength - 1); + LPSTR lpstrRet = (LPSTR)memcpy(lpstrDest, lpstrSrc, nLen * sizeof(char)); + lpstrDest[nLen] = 0; + return lpstrRet; + } +#endif // !lstrcpyn + +#ifdef TrackPopupMenu + #undef TrackPopupMenu +#endif // TrackPopupMenu + +#define DECLARE_WND_CLASS_EX(WndClassName, style, bkgnd) \ +static CWndClassInfo& GetWndClassInfo() \ +{ \ + static CWndClassInfo wc = \ + { \ + { style, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \ + }; \ + return wc; \ +} + +#ifndef _MAX_FNAME + #define _MAX_FNAME _MAX_PATH +#endif // _MAX_FNAME + +#if (_WIN32_WCE < 400) + #define MAKEINTATOM(i) (LPTSTR)((ULONG_PTR)((WORD)(i))) +#endif // (_WIN32_WCE < 400) + +#if (_WIN32_WCE < 410) + #define WHEEL_PAGESCROLL (UINT_MAX) + #define WHEEL_DELTA 120 +#endif // (_WIN32_WCE < 410) + +#ifdef DrawIcon + #undef DrawIcon +#endif + +#ifndef VARCMP_LT + #define VARCMP_LT 0 +#endif +#ifndef VARCMP_EQ + #define VARCMP_EQ 1 +#endif +#ifndef VARCMP_GT + #define VARCMP_GT 2 +#endif +#ifndef VARCMP_NULL + #define VARCMP_NULL 3 +#endif + +#ifndef RDW_ALLCHILDREN + #define RDW_ALLCHILDREN 0 +#endif + +#endif // !(_ATL_VER >= 0x0800) + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// Global support for using original VC++ 6.0 headers with WTL + +#if (_MSC_VER < 1300) && !defined(_WIN32_WCE) + #ifndef REG_QWORD + #define REG_QWORD 11 + #endif + + #ifndef BS_PUSHBOX + #define BS_PUSHBOX 0x0000000AL + #endif + + struct __declspec(uuid("000214e6-0000-0000-c000-000000000046")) IShellFolder; + struct __declspec(uuid("000214f9-0000-0000-c000-000000000046")) IShellLinkW; + struct __declspec(uuid("000214ee-0000-0000-c000-000000000046")) IShellLinkA; +#endif // (_MSC_VER < 1300) && !defined(_WIN32_WCE) + +#ifndef _ATL_NO_OLD_HEADERS_WIN64 +#if !defined(_WIN64) && (_ATL_VER < 0x0700) + + #ifndef PSM_INSERTPAGE + #define PSM_INSERTPAGE (WM_USER + 119) + #endif // !PSM_INSERTPAGE + + #ifndef GetClassLongPtr + #define GetClassLongPtrA GetClassLongA + #define GetClassLongPtrW GetClassLongW + #ifdef UNICODE + #define GetClassLongPtr GetClassLongPtrW + #else + #define GetClassLongPtr GetClassLongPtrA + #endif // !UNICODE + #endif // !GetClassLongPtr + + #ifndef GCLP_HICONSM + #define GCLP_HICONSM (-34) + #endif // !GCLP_HICONSM + + #ifndef GetWindowLongPtr + #define GetWindowLongPtrA GetWindowLongA + #define GetWindowLongPtrW GetWindowLongW + #ifdef UNICODE + #define GetWindowLongPtr GetWindowLongPtrW + #else + #define GetWindowLongPtr GetWindowLongPtrA + #endif // !UNICODE + #endif // !GetWindowLongPtr + + #ifndef SetWindowLongPtr + #define SetWindowLongPtrA SetWindowLongA + #define SetWindowLongPtrW SetWindowLongW + #ifdef UNICODE + #define SetWindowLongPtr SetWindowLongPtrW + #else + #define SetWindowLongPtr SetWindowLongPtrA + #endif // !UNICODE + #endif // !SetWindowLongPtr + + #ifndef GWLP_WNDPROC + #define GWLP_WNDPROC (-4) + #endif + #ifndef GWLP_HINSTANCE + #define GWLP_HINSTANCE (-6) + #endif + #ifndef GWLP_HWNDPARENT + #define GWLP_HWNDPARENT (-8) + #endif + #ifndef GWLP_USERDATA + #define GWLP_USERDATA (-21) + #endif + #ifndef GWLP_ID + #define GWLP_ID (-12) + #endif + + #ifndef DWLP_MSGRESULT + #define DWLP_MSGRESULT 0 + #endif + + typedef long LONG_PTR; + typedef unsigned long ULONG_PTR; + typedef ULONG_PTR DWORD_PTR; + + #ifndef HandleToUlong + #define HandleToUlong( h ) ((ULONG)(ULONG_PTR)(h) ) + #endif + #ifndef HandleToLong + #define HandleToLong( h ) ((LONG)(LONG_PTR) (h) ) + #endif + #ifndef LongToHandle + #define LongToHandle( h) ((HANDLE)(LONG_PTR) (h)) + #endif + #ifndef PtrToUlong + #define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) ) + #endif + #ifndef PtrToLong + #define PtrToLong( p ) ((LONG)(LONG_PTR) (p) ) + #endif + #ifndef PtrToUint + #define PtrToUint( p ) ((UINT)(UINT_PTR) (p) ) + #endif + #ifndef PtrToInt + #define PtrToInt( p ) ((INT)(INT_PTR) (p) ) + #endif + #ifndef PtrToUshort + #define PtrToUshort( p ) ((unsigned short)(ULONG_PTR)(p) ) + #endif + #ifndef PtrToShort + #define PtrToShort( p ) ((short)(LONG_PTR)(p) ) + #endif + #ifndef IntToPtr + #define IntToPtr( i ) ((VOID *)(INT_PTR)((int)i)) + #endif + #ifndef UIntToPtr + #define UIntToPtr( ui ) ((VOID *)(UINT_PTR)((unsigned int)ui)) + #endif + #ifndef LongToPtr + #define LongToPtr( l ) ((VOID *)(LONG_PTR)((long)l)) + #endif + #ifndef ULongToPtr + #define ULongToPtr( ul ) ((VOID *)(ULONG_PTR)((unsigned long)ul)) + #endif + +#endif // !defined(_WIN64) && (_ATL_VER < 0x0700) +#endif // !_ATL_NO_OLD_HEADERS_WIN64 + + +/////////////////////////////////////////////////////////////////////////////// +// Global support for using original VC++ 7.x headers with WTL + +#if (_MSC_VER >= 1300) && (_MSC_VER < 1400) + + #ifndef BS_PUSHBOX + #define BS_PUSHBOX 0x0000000AL + #endif + + #pragma warning(disable: 4244) // conversion from 'type1' to 'type2', possible loss of data + +#endif // (_MSC_VER >= 1300) && (_MSC_VER < 1400) + + +/////////////////////////////////////////////////////////////////////////////// +// Global support for old SDK headers + +#ifndef BTNS_BUTTON + #define BTNS_BUTTON TBSTYLE_BUTTON +#endif + +#ifndef BTNS_SEP + #define BTNS_SEP TBSTYLE_SEP +#endif + +#ifndef BTNS_CHECK + #define BTNS_CHECK TBSTYLE_CHECK +#endif + +#ifndef BTNS_GROUP + #define BTNS_GROUP TBSTYLE_GROUP +#endif + +#ifndef BTNS_CHECKGROUP + #define BTNS_CHECKGROUP TBSTYLE_CHECKGROUP +#endif + +#if (_WIN32_IE >= 0x0300) + #ifndef BTNS_DROPDOWN + #define BTNS_DROPDOWN TBSTYLE_DROPDOWN + #endif +#endif + +#if (_WIN32_IE >= 0x0400) + #ifndef BTNS_AUTOSIZE + #define BTNS_AUTOSIZE TBSTYLE_AUTOSIZE + #endif + + #ifndef BTNS_NOPREFIX + #define BTNS_NOPREFIX TBSTYLE_NOPREFIX + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Global support for SecureHelper functions + +#ifndef _TRUNCATE + #define _TRUNCATE ((size_t)-1) +#endif + +#ifndef _ERRCODE_DEFINED + #define _ERRCODE_DEFINED + typedef int errno_t; +#endif + +#ifndef _SECURECRT_ERRCODE_VALUES_DEFINED + #define _SECURECRT_ERRCODE_VALUES_DEFINED + #define EINVAL 22 + #define STRUNCATE 80 +#endif + +#ifndef _countof + #define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Miscellaneous global support + +// define useful macros from winuser.h +#ifndef IS_INTRESOURCE + #define IS_INTRESOURCE(_r) (((ULONG_PTR)(_r) >> 16) == 0) +#endif // IS_INTRESOURCE + +// protect template members from windowsx.h macros +#ifdef _INC_WINDOWSX + #undef SubclassWindow +#endif // _INC_WINDOWSX + +// define useful macros from windowsx.h +#ifndef GET_X_LPARAM + #define GET_X_LPARAM(lParam) ((int)(short)LOWORD(lParam)) +#endif +#ifndef GET_Y_LPARAM + #define GET_Y_LPARAM(lParam) ((int)(short)HIWORD(lParam)) +#endif + +// Dummy structs for compiling with /CLR +#if (_MSC_VER >= 1300) && defined(_MANAGED) + __if_not_exists(_IMAGELIST::_IMAGELIST) { struct _IMAGELIST { }; } + __if_not_exists(_TREEITEM::_TREEITEM) { struct _TREEITEM { }; } + __if_not_exists(_PSP::_PSP) { struct _PSP { }; } +#endif + +// Define ATLVERIFY macro for ATL3 +#if (_ATL_VER < 0x0700) + #ifndef ATLVERIFY + #ifdef _DEBUG + #define ATLVERIFY(expr) ATLASSERT(expr) + #else + #define ATLVERIFY(expr) (expr) + #endif // DEBUG + #endif // ATLVERIFY +#endif // (_ATL_VER < 0x0700) + +// Forward declaration for ATL3 and ATL11 fix +#if (((_ATL_VER < 0x0700) && defined(_ATL_DLL)) || (_ATL_VER >= 0x0B00)) && !defined(_WIN32_WCE) + namespace ATL { HRESULT AtlGetCommCtrlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor); }; +#endif + +#ifndef WM_MOUSEHWHEEL + #define WM_MOUSEHWHEEL 0x020E +#endif + + +namespace WTL +{ + +#if (_ATL_VER >= 0x0700) + DECLARE_TRACE_CATEGORY(atlTraceUI); + #ifdef _DEBUG + __declspec(selectany) ATL::CTraceCategory atlTraceUI(_T("atlTraceUI")); + #endif // _DEBUG +#else // !(_ATL_VER >= 0x0700) + enum wtlTraceFlags + { + atlTraceUI = 0x10000000 + }; +#endif // !(_ATL_VER >= 0x0700) + +// Windows version helper +inline bool AtlIsOldWindows() +{ +#ifdef _versionhelpers_H_INCLUDED_ + return !::IsWindowsVersionOrGreater(4, 90, 0); +#else // !_versionhelpers_H_INCLUDED_ +OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; + BOOL bRet = ::GetVersionEx(&ovi); + return (!bRet || !((ovi.dwMajorVersion >= 5) || (ovi.dwMajorVersion == 4 && ovi.dwMinorVersion >= 90))); +#endif // _versionhelpers_H_INCLUDED_ +} + +// Default GUI font helper - "MS Shell Dlg" stock font +inline HFONT AtlGetDefaultGuiFont() +{ +#ifndef _WIN32_WCE + return (HFONT)::GetStockObject(DEFAULT_GUI_FONT); +#else // CE specific + return (HFONT)::GetStockObject(SYSTEM_FONT); +#endif // _WIN32_WCE +} + +// Control font helper - default font for controls not in a dialog +// (NOTE: Caller owns the font, and should destroy it when it's no longer needed) +inline HFONT AtlCreateControlFont() +{ +#ifndef _WIN32_WCE + LOGFONT lf = { 0 }; + ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE); + HFONT hFont = ::CreateFontIndirect(&lf); + ATLASSERT(hFont != NULL); + return hFont; +#else // CE specific + return (HFONT)::GetStockObject(SYSTEM_FONT); +#endif // _WIN32_WCE +} + +// Bold font helper +// (NOTE: Caller owns the font, and should destroy it when it's no longer needed) +inline HFONT AtlCreateBoldFont(HFONT hFont = NULL) +{ + LOGFONT lf = { 0 }; +#ifndef _WIN32_WCE + if(hFont == NULL) + ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE); + else + ATLVERIFY(::GetObject(hFont, sizeof(LOGFONT), &lf) == sizeof(LOGFONT)); +#else // CE specific + if(hFont == NULL) + hFont = (HFONT)::GetStockObject(SYSTEM_FONT); + ATLVERIFY(::GetObject(hFont, sizeof(LOGFONT), &lf) == sizeof(LOGFONT)); +#endif // _WIN32_WCE + lf.lfWeight = FW_BOLD; + HFONT hFontBold = ::CreateFontIndirect(&lf); + ATLASSERT(hFontBold != NULL); + return hFontBold; +} + +// Common Controls initialization helper +inline BOOL AtlInitCommonControls(DWORD dwFlags) +{ + INITCOMMONCONTROLSEX iccx = { sizeof(INITCOMMONCONTROLSEX), dwFlags }; + BOOL bRet = ::InitCommonControlsEx(&iccx); + ATLASSERT(bRet); + return bRet; +} + + +/////////////////////////////////////////////////////////////////////////////// +// RunTimeHelper - helper functions for Windows version and structure sizes + +// Not for Windows CE +#if defined(_WIN32_WCE) && !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) + #define _WTL_NO_RUNTIME_STRUCT_SIZE +#endif + +#ifndef _WTL_NO_RUNTIME_STRUCT_SIZE + +#ifndef _SIZEOF_STRUCT + #define _SIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) +#endif + +#if (_WIN32_WINNT >= 0x0600) && !defined(REBARBANDINFO_V6_SIZE) + #define REBARBANDINFO_V6_SIZE _SIZEOF_STRUCT(REBARBANDINFO, cxHeader) +#endif // (_WIN32_WINNT >= 0x0600) && !defined(REBARBANDINFO_V6_SIZE) + +#if (_WIN32_WINNT >= 0x0600) && !defined(LVGROUP_V5_SIZE) + #define LVGROUP_V5_SIZE _SIZEOF_STRUCT(LVGROUP, uAlign) +#endif // (_WIN32_WINNT >= 0x0600) && !defined(LVGROUP_V5_SIZE) + +#if (_WIN32_WINNT >= 0x0600) && !defined(LVTILEINFO_V5_SIZE) + #define LVTILEINFO_V5_SIZE _SIZEOF_STRUCT(LVTILEINFO, puColumns) +#endif // (_WIN32_WINNT >= 0x0600) && !defined(LVTILEINFO_V5_SIZE) + +#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) && !defined(MCHITTESTINFO_V1_SIZE) + #define MCHITTESTINFO_V1_SIZE _SIZEOF_STRUCT(MCHITTESTINFO, st) +#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) && !defined(MCHITTESTINFO_V1_SIZE) + +#if !defined(_WIN32_WCE) && (WINVER >= 0x0600) && !defined(NONCLIENTMETRICS_V1_SIZE) + #define NONCLIENTMETRICS_V1_SIZE _SIZEOF_STRUCT(NONCLIENTMETRICS, lfMessageFont) +#endif // !defined(_WIN32_WCE) && (WINVER >= 0x0600) && !defined(NONCLIENTMETRICS_V1_SIZE) + +#if !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0501) && !defined(TTTOOLINFO_V2_SIZE) + #define TTTOOLINFO_V2_SIZE _SIZEOF_STRUCT(TTTOOLINFO, lParam) +#endif // !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0501) && !defined(TTTOOLINFO_V2_SIZE) + +#endif // !_WTL_NO_RUNTIME_STRUCT_SIZE + +namespace RunTimeHelper +{ +#ifndef _WIN32_WCE + inline bool IsCommCtrl6() + { + DWORD dwMajor = 0, dwMinor = 0; + HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor); + return (SUCCEEDED(hRet) && (dwMajor >= 6)); + } + + inline bool IsVista() + { +#ifdef _versionhelpers_H_INCLUDED_ + return ::IsWindowsVistaOrGreater(); +#else // !_versionhelpers_H_INCLUDED_ + OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; + BOOL bRet = ::GetVersionEx(&ovi); + return ((bRet != FALSE) && (ovi.dwMajorVersion >= 6)); +#endif // _versionhelpers_H_INCLUDED_ + } + + inline bool IsThemeAvailable() + { + bool bRet = false; + + if(IsCommCtrl6()) + { + HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll")); + if(hThemeDLL != NULL) + { + typedef BOOL (STDAPICALLTYPE *PFN_IsThemeActive)(); + PFN_IsThemeActive pfnIsThemeActive = (PFN_IsThemeActive)::GetProcAddress(hThemeDLL, "IsThemeActive"); + ATLASSERT(pfnIsThemeActive != NULL); + bRet = (pfnIsThemeActive != NULL) && (pfnIsThemeActive() != FALSE); + if(bRet) + { + typedef BOOL (STDAPICALLTYPE *PFN_IsAppThemed)(); + PFN_IsAppThemed pfnIsAppThemed = (PFN_IsAppThemed)::GetProcAddress(hThemeDLL, "IsAppThemed"); + ATLASSERT(pfnIsAppThemed != NULL); + bRet = (pfnIsAppThemed != NULL) && (pfnIsAppThemed() != FALSE); + } + + ::FreeLibrary(hThemeDLL); + } + } + + return bRet; + } + + inline bool IsWin7() + { +#ifdef _versionhelpers_H_INCLUDED_ + return ::IsWindows7OrGreater(); +#else // !_versionhelpers_H_INCLUDED_ + OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; + BOOL bRet = ::GetVersionEx(&ovi); + return ((bRet != FALSE) && (ovi.dwMajorVersion == 6) && (ovi.dwMinorVersion >= 1)); +#endif // _versionhelpers_H_INCLUDED_ + } + + inline bool IsRibbonUIAvailable() + { + static INT iRibbonUI = -1; + +#if defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7) + if (iRibbonUI == -1) + { + HMODULE hRibbonDLL = ::LoadLibrary(_T("propsys.dll")); + if (hRibbonDLL != NULL) + { + const GUID CLSID_UIRibbonFramework = { 0x926749fa, 0x2615, 0x4987, { 0x88, 0x45, 0xc3, 0x3e, 0x65, 0xf2, 0xb9, 0x57 } }; + // block - create instance + { + ATL::CComPtr pIUIFramework; + iRibbonUI = SUCCEEDED(pIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework)) ? 1 : 0; + } + ::FreeLibrary(hRibbonDLL); + } + else + { + iRibbonUI = 0; + } + } +#endif // defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7) + + return (iRibbonUI == 1); + } + +#endif // !_WIN32_WCE + + inline UINT SizeOf_REBARBANDINFO() + { + UINT uSize = sizeof(REBARBANDINFO); +#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) + if(!(IsVista() && IsCommCtrl6())) + uSize = REBARBANDINFO_V6_SIZE; +#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) + return uSize; + } + +#if (_WIN32_WINNT >= 0x501) + inline UINT SizeOf_LVGROUP() + { + UINT uSize = sizeof(LVGROUP); +#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) + if(!IsVista()) + uSize = LVGROUP_V5_SIZE; +#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) + return uSize; + } + + inline UINT SizeOf_LVTILEINFO() + { + UINT uSize = sizeof(LVTILEINFO); +#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) + if(!IsVista()) + uSize = LVTILEINFO_V5_SIZE; +#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) + return uSize; + } +#endif // (_WIN32_WINNT >= 0x501) + + inline UINT SizeOf_MCHITTESTINFO() + { + UINT uSize = sizeof(MCHITTESTINFO); +#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + if(!(IsVista() && IsCommCtrl6())) + uSize = MCHITTESTINFO_V1_SIZE; +#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + return uSize; + } + +#ifndef _WIN32_WCE + inline UINT SizeOf_NONCLIENTMETRICS() + { + UINT uSize = sizeof(NONCLIENTMETRICS); +#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (WINVER >= 0x0600) + if(!IsVista()) + uSize = NONCLIENTMETRICS_V1_SIZE; +#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (WINVER >= 0x0600) + return uSize; + } + + inline UINT SizeOf_TOOLINFO() + { + UINT uSize = sizeof(TOOLINFO); +#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0501) + if(!IsVista()) + uSize = TTTOOLINFO_V2_SIZE; +#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0501) + return uSize; + } +#endif // !_WIN32_WCE +}; + + +/////////////////////////////////////////////////////////////////////////////// +// ModuleHelper - helper functions for ATL3 and ATL7 module classes + +namespace ModuleHelper +{ + inline HINSTANCE GetModuleInstance() + { +#if (_ATL_VER >= 0x0700) + return ATL::_AtlBaseModule.GetModuleInstance(); +#else // !(_ATL_VER >= 0x0700) + return ATL::_pModule->GetModuleInstance(); +#endif // !(_ATL_VER >= 0x0700) + } + + inline HINSTANCE GetResourceInstance() + { +#if (_ATL_VER >= 0x0700) + return ATL::_AtlBaseModule.GetResourceInstance(); +#else // !(_ATL_VER >= 0x0700) + return ATL::_pModule->GetResourceInstance(); +#endif // !(_ATL_VER >= 0x0700) + } + + inline void AddCreateWndData(ATL::_AtlCreateWndData* pData, void* pObject) + { +#if (_ATL_VER >= 0x0700) + ATL::_AtlWinModule.AddCreateWndData(pData, pObject); +#else // !(_ATL_VER >= 0x0700) + ATL::_pModule->AddCreateWndData(pData, pObject); +#endif // !(_ATL_VER >= 0x0700) + } + + inline void* ExtractCreateWndData() + { +#if (_ATL_VER >= 0x0700) + return ATL::_AtlWinModule.ExtractCreateWndData(); +#else // !(_ATL_VER >= 0x0700) + return ATL::_pModule->ExtractCreateWndData(); +#endif // !(_ATL_VER >= 0x0700) + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// SecureHelper - helper functions for VS2005 secure CRT + +namespace SecureHelper +{ + inline void strcpyA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc) + { +#if _SECURE_ATL + ATL::Checked::strcpy_s(lpstrDest, cchDest, lpstrSrc); +#else + if(cchDest > (size_t)lstrlenA(lpstrSrc)) + ATLVERIFY(lstrcpyA(lpstrDest, lpstrSrc) != NULL); + else + ATLASSERT(FALSE); +#endif + } + + inline void strcpyW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc) + { +#if _SECURE_ATL + ATL::Checked::wcscpy_s(lpstrDest, cchDest, lpstrSrc); +#else + if(cchDest > (size_t)lstrlenW(lpstrSrc)) + ATLVERIFY(lstrcpyW(lpstrDest, lpstrSrc) != NULL); + else + ATLASSERT(FALSE); +#endif + } + + inline void strcpy_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc) + { +#ifdef _UNICODE + strcpyW_x(lpstrDest, cchDest, lpstrSrc); +#else + strcpyA_x(lpstrDest, cchDest, lpstrSrc); +#endif + } + + inline errno_t strncpyA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc, size_t cchCount) + { +#if _SECURE_ATL + return ATL::Checked::strncpy_s(lpstrDest, cchDest, lpstrSrc, cchCount); +#else + errno_t nRet = 0; + if(lpstrDest == NULL || cchDest == 0 || lpstrSrc == NULL) + { + nRet = EINVAL; + } + else if(cchCount == _TRUNCATE) + { + cchCount = __min(cchDest - 1, size_t(lstrlenA(lpstrSrc))); + nRet = STRUNCATE; + } + else if(cchDest <= cchCount) + { + lpstrDest[0] = 0; + nRet = EINVAL; + } + if(nRet == 0 || nRet == STRUNCATE) + nRet = (lstrcpynA(lpstrDest, lpstrSrc, (int)cchCount + 1) != NULL) ? nRet : EINVAL; + ATLASSERT(nRet == 0 || nRet == STRUNCATE); + return nRet; +#endif + } + + inline errno_t strncpyW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc, size_t cchCount) + { +#if _SECURE_ATL + return ATL::Checked::wcsncpy_s(lpstrDest, cchDest, lpstrSrc, cchCount); +#else + errno_t nRet = 0; + if(lpstrDest == NULL || cchDest == 0 || lpstrSrc == NULL) + { + nRet = EINVAL; + } + else if(cchCount == _TRUNCATE) + { + cchCount = __min(cchDest - 1, size_t(lstrlenW(lpstrSrc))); + nRet = STRUNCATE; + } + else if(cchDest <= cchCount) + { + lpstrDest[0] = 0; + nRet = EINVAL; + } + if(nRet == 0 || nRet == STRUNCATE) + nRet = (lstrcpynW(lpstrDest, lpstrSrc, (int)cchCount + 1) != NULL) ? nRet : EINVAL; + ATLASSERT(nRet == 0 || nRet == STRUNCATE); + return nRet; +#endif + } + + inline errno_t strncpy_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc, size_t cchCount) + { +#ifdef _UNICODE + return strncpyW_x(lpstrDest, cchDest, lpstrSrc, cchCount); +#else + return strncpyA_x(lpstrDest, cchDest, lpstrSrc, cchCount); +#endif + } + + inline void strcatA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc) + { +#if _SECURE_ATL + ATL::Checked::strcat_s(lpstrDest, cchDest, lpstrSrc); +#else + if(cchDest > (size_t)lstrlenA(lpstrSrc)) + ATLVERIFY(lstrcatA(lpstrDest, lpstrSrc) != NULL); + else + ATLASSERT(FALSE); +#endif + } + + inline void strcatW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc) + { +#if _SECURE_ATL + ATL::Checked::wcscat_s(lpstrDest, cchDest, lpstrSrc); +#else + if(cchDest > (size_t)lstrlenW(lpstrSrc)) + ATLVERIFY(lstrcatW(lpstrDest, lpstrSrc) != NULL); + else + ATLASSERT(FALSE); +#endif + } + + inline void strcat_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc) + { +#ifdef _UNICODE + strcatW_x(lpstrDest, cchDest, lpstrSrc); +#else + strcatA_x(lpstrDest, cchDest, lpstrSrc); +#endif + } + + inline void memcpy_x(void* pDest, size_t cbDest, const void* pSrc, size_t cbSrc) + { +#if _SECURE_ATL + ATL::Checked::memcpy_s(pDest, cbDest, pSrc, cbSrc); +#else + if(cbDest >= cbSrc) + memcpy(pDest, pSrc, cbSrc); + else + ATLASSERT(FALSE); +#endif + } + + inline void memmove_x(void* pDest, size_t cbDest, const void* pSrc, size_t cbSrc) + { +#if _SECURE_ATL + ATL::Checked::memmove_s(pDest, cbDest, pSrc, cbSrc); +#else + if(cbDest >= cbSrc) + memmove(pDest, pSrc, cbSrc); + else + ATLASSERT(FALSE); +#endif + } + + inline int vsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, va_list args) + { +#if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE) + return _vstprintf_s(lpstrBuff, cchBuff, lpstrFormat, args); +#else + cchBuff; // Avoid unused argument warning + #pragma warning(push) + #pragma warning(disable: 4996) + return _vstprintf(lpstrBuff, lpstrFormat, args); + #pragma warning(pop) +#endif + } + + inline int wvsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, va_list args) + { +#if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE) + return _vstprintf_s(lpstrBuff, cchBuff, lpstrFormat, args); +#else + cchBuff; // Avoid unused argument warning + return ::wvsprintf(lpstrBuff, lpstrFormat, args); +#endif + } + + inline int sprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, ...) + { + va_list args; + va_start(args, lpstrFormat); + int nRes = vsprintf_x(lpstrBuff, cchBuff, lpstrFormat, args); + va_end(args); + return nRes; + } + + inline int wsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, ...) + { + va_list args; + va_start(args, lpstrFormat); + int nRes = wvsprintf_x(lpstrBuff, cchBuff, lpstrFormat, args); + va_end(args); + return nRes; + } +}; // namespace SecureHelper + + +/////////////////////////////////////////////////////////////////////////////// +// MinCrtHelper - helper functions for using _ATL_MIN_CRT + +namespace MinCrtHelper +{ + inline int _isspace(TCHAR ch) + { +#ifndef _ATL_MIN_CRT + return _istspace(ch); +#else // _ATL_MIN_CRT + WORD type = 0; + ::GetStringTypeEx(::GetThreadLocale(), CT_CTYPE1, &ch, 1, &type); + return (type & C1_SPACE) == C1_SPACE; +#endif // _ATL_MIN_CRT + } + + inline int _isdigit(TCHAR ch) + { +#ifndef _ATL_MIN_CRT + return _istdigit(ch); +#else // _ATL_MIN_CRT + WORD type = 0; + ::GetStringTypeEx(::GetThreadLocale(), CT_CTYPE1, &ch, 1, &type); + return (type & C1_DIGIT) == C1_DIGIT; +#endif // _ATL_MIN_CRT + } + + inline int _atoi(LPCTSTR str) + { +#ifndef _ATL_MIN_CRT + return _ttoi(str); +#else // _ATL_MIN_CRT + while(_isspace(*str) != 0) + ++str; + + TCHAR ch = *str++; + TCHAR sign = ch; // save sign indication + if(ch == _T('-') || ch == _T('+')) + ch = *str++; // skip sign + + int total = 0; + while(_isdigit(ch) != 0) + { + total = 10 * total + (ch - '0'); // accumulate digit + ch = *str++; // get next char + } + + return (sign == '-') ? -total : total; // return result, negated if necessary +#endif // _ATL_MIN_CRT + } + + inline LPCTSTR _strrchr(LPCTSTR str, TCHAR ch) + { +#ifndef _ATL_MIN_CRT + return _tcsrchr(str, ch); +#else // _ATL_MIN_CRT + LPCTSTR lpsz = NULL; + while(*str != 0) + { + if(*str == ch) + lpsz = str; + str = ::CharNext(str); + } + return lpsz; +#endif // _ATL_MIN_CRT + } + + inline LPTSTR _strrchr(LPTSTR str, TCHAR ch) + { +#ifndef _ATL_MIN_CRT + return _tcsrchr(str, ch); +#else // _ATL_MIN_CRT + LPTSTR lpsz = NULL; + while(*str != 0) + { + if(*str == ch) + lpsz = str; + str = ::CharNext(str); + } + return lpsz; +#endif // _ATL_MIN_CRT + } +}; // namespace MinCrtHelper + + +/////////////////////////////////////////////////////////////////////////////// +// GenericWndClass - generic window class usable for subclassing + +// Use in dialog templates to specify a placeholder to be subclassed +// Specify as a custom control with class name WTL_GenericWindow +// Call Rregister() before creating dialog (for example, in WinMain) +namespace GenericWndClass +{ + inline LPCTSTR GetName() + { + return _T("WTL_GenericWindow"); + } + + inline ATOM Register() + { +#ifndef _WIN32_WCE + WNDCLASSEX wc = { sizeof(WNDCLASSEX) }; +#else + WNDCLASS wc = { 0 }; +#endif + wc.lpfnWndProc = ::DefWindowProc; + wc.hInstance = ModuleHelper::GetModuleInstance(); + wc.hCursor = ::LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszClassName = GetName(); +#ifndef _WIN32_WCE + ATOM atom = ::RegisterClassEx(&wc); +#else + ATOM atom = ::RegisterClass(&wc); +#endif + ATLASSERT(atom != 0); + return atom; + } + + inline BOOL Unregister() // only needed for DLLs or tmp use + { + return ::UnregisterClass(GetName(), ModuleHelper::GetModuleInstance()); + } +}; // namespace GenericWndClass + + +/////////////////////////////////////////////////////////////////////////////// +// CMessageFilter - Interface for message filter support + +class CMessageFilter +{ +public: + virtual BOOL PreTranslateMessage(MSG* pMsg) = 0; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CIdleHandler - Interface for idle processing + +class CIdleHandler +{ +public: + virtual BOOL OnIdle() = 0; +}; + +#ifndef _ATL_NO_OLD_NAMES + // for compatilibility with old names only + typedef CIdleHandler CUpdateUIObject; + #define DoUpdate OnIdle +#endif // !_ATL_NO_OLD_NAMES + + +/////////////////////////////////////////////////////////////////////////////// +// CMessageLoop - message loop implementation + +class CMessageLoop +{ +public: + ATL::CSimpleArray m_aMsgFilter; + ATL::CSimpleArray m_aIdleHandler; + MSG m_msg; + +// Message filter operations + BOOL AddMessageFilter(CMessageFilter* pMessageFilter) + { + return m_aMsgFilter.Add(pMessageFilter); + } + + BOOL RemoveMessageFilter(CMessageFilter* pMessageFilter) + { + return m_aMsgFilter.Remove(pMessageFilter); + } + +// Idle handler operations + BOOL AddIdleHandler(CIdleHandler* pIdleHandler) + { + return m_aIdleHandler.Add(pIdleHandler); + } + + BOOL RemoveIdleHandler(CIdleHandler* pIdleHandler) + { + return m_aIdleHandler.Remove(pIdleHandler); + } + +#ifndef _ATL_NO_OLD_NAMES + // for compatilibility with old names only + BOOL AddUpdateUI(CIdleHandler* pIdleHandler) + { + ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIObject and AddUpdateUI are deprecated. Please change your code to use CIdleHandler and OnIdle\n")); + return AddIdleHandler(pIdleHandler); + } + + BOOL RemoveUpdateUI(CIdleHandler* pIdleHandler) + { + ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIObject and RemoveUpdateUI are deprecated. Please change your code to use CIdleHandler and OnIdle\n")); + return RemoveIdleHandler(pIdleHandler); + } +#endif // !_ATL_NO_OLD_NAMES + +// message loop + int Run() + { + BOOL bDoIdle = TRUE; + int nIdleCount = 0; + BOOL bRet; + + for(;;) + { + while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE)) + { + if(!OnIdle(nIdleCount++)) + bDoIdle = FALSE; + } + + bRet = ::GetMessage(&m_msg, NULL, 0, 0); + + if(bRet == -1) + { + ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n")); + continue; // error, don't process + } + else if(!bRet) + { + ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting\n")); + break; // WM_QUIT, exit message loop + } + + if(!PreTranslateMessage(&m_msg)) + { + ::TranslateMessage(&m_msg); + ::DispatchMessage(&m_msg); + } + + if(IsIdleMessage(&m_msg)) + { + bDoIdle = TRUE; + nIdleCount = 0; + } + } + + return (int)m_msg.wParam; + } + + static BOOL IsIdleMessage(MSG* pMsg) + { + // These messages should NOT cause idle processing + switch(pMsg->message) + { + case WM_MOUSEMOVE: +#ifndef _WIN32_WCE + case WM_NCMOUSEMOVE: +#endif // !_WIN32_WCE + case WM_PAINT: + case 0x0118: // WM_SYSTIMER (caret blink) + return FALSE; + } + + return TRUE; + } + +// Overrideables + // Override to change message filtering + virtual BOOL PreTranslateMessage(MSG* pMsg) + { + // loop backwards + for(int i = m_aMsgFilter.GetSize() - 1; i >= 0; i--) + { + CMessageFilter* pMessageFilter = m_aMsgFilter[i]; + if(pMessageFilter != NULL && pMessageFilter->PreTranslateMessage(pMsg)) + return TRUE; + } + return FALSE; // not translated + } + + // override to change idle processing + virtual BOOL OnIdle(int /*nIdleCount*/) + { + for(int i = 0; i < m_aIdleHandler.GetSize(); i++) + { + CIdleHandler* pIdleHandler = m_aIdleHandler[i]; + if(pIdleHandler != NULL) + pIdleHandler->OnIdle(); + } + return FALSE; // don't continue + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CStaticDataInitCriticalSectionLock and CWindowCreateCriticalSectionLock +// internal classes to manage critical sections for both ATL3 and ATL7 + +class CStaticDataInitCriticalSectionLock +{ +public: +#if (_ATL_VER >= 0x0700) + ATL::CComCritSecLock m_cslock; + + CStaticDataInitCriticalSectionLock() : m_cslock(ATL::_pAtlModule->m_csStaticDataInitAndTypeInfo, false) + { } +#endif // (_ATL_VER >= 0x0700) + + HRESULT Lock() + { +#if (_ATL_VER >= 0x0700) + return m_cslock.Lock(); +#else // !(_ATL_VER >= 0x0700) + ::EnterCriticalSection(&ATL::_pModule->m_csStaticDataInit); + return S_OK; +#endif // !(_ATL_VER >= 0x0700) + } + + void Unlock() + { +#if (_ATL_VER >= 0x0700) + m_cslock.Unlock(); +#else // !(_ATL_VER >= 0x0700) + ::LeaveCriticalSection(&ATL::_pModule->m_csStaticDataInit); +#endif // !(_ATL_VER >= 0x0700) + } +}; + + +class CWindowCreateCriticalSectionLock +{ +public: +#if (_ATL_VER >= 0x0700) + ATL::CComCritSecLock m_cslock; + + CWindowCreateCriticalSectionLock() : m_cslock(ATL::_AtlWinModule.m_csWindowCreate, false) + { } +#endif // (_ATL_VER >= 0x0700) + + HRESULT Lock() + { +#if (_ATL_VER >= 0x0700) + return m_cslock.Lock(); +#else // !(_ATL_VER >= 0x0700) + ::EnterCriticalSection(&ATL::_pModule->m_csWindowCreate); + return S_OK; +#endif // !(_ATL_VER >= 0x0700) + } + + void Unlock() + { +#if (_ATL_VER >= 0x0700) + m_cslock.Unlock(); +#else // !(_ATL_VER >= 0x0700) + ::LeaveCriticalSection(&ATL::_pModule->m_csWindowCreate); +#endif // !(_ATL_VER >= 0x0700) + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CTempBuffer - helper class for stack allocations for ATL3 + +#ifndef _WTL_STACK_ALLOC_THRESHOLD + #define _WTL_STACK_ALLOC_THRESHOLD 512 +#endif + +#if (_ATL_VER >= 0x0700) + +using ATL::CTempBuffer; + +#else // !(_ATL_VER >= 0x0700) + +#ifndef SIZE_MAX + #ifdef _WIN64 + #define SIZE_MAX _UI64_MAX + #else + #define SIZE_MAX UINT_MAX + #endif +#endif + +#pragma warning(push) +#pragma warning(disable: 4284) // warning for operator -> + +template +class CTempBuffer +{ +public: + CTempBuffer() : m_p(NULL) + { + } + + CTempBuffer(size_t nElements) : m_p(NULL) + { + Allocate(nElements); + } + + ~CTempBuffer() + { + if(m_p != reinterpret_cast(m_abFixedBuffer)) + free(m_p); + } + + operator T*() const + { + return m_p; + } + + T* operator ->() const + { + ATLASSERT(m_p != NULL); + return m_p; + } + + T* Allocate(size_t nElements) + { + ATLASSERT(nElements <= (SIZE_MAX / sizeof(T))); + return AllocateBytes(nElements * sizeof(T)); + } + + T* AllocateBytes(size_t nBytes) + { + ATLASSERT(m_p == NULL); + if(nBytes > t_nFixedBytes) + m_p = static_cast(malloc(nBytes)); + else + m_p = reinterpret_cast(m_abFixedBuffer); + + return m_p; + } + +private: + T* m_p; + BYTE m_abFixedBuffer[t_nFixedBytes]; +}; + +#pragma warning(pop) + +#endif // !(_ATL_VER >= 0x0700) + + +/////////////////////////////////////////////////////////////////////////////// +// CAppModule - module class for an application + +class CAppModule : public ATL::CComModule +{ +public: + DWORD m_dwMainThreadID; + ATL::CSimpleMap* m_pMsgLoopMap; + ATL::CSimpleArray* m_pSettingChangeNotify; + +// Overrides of CComModule::Init and Term + HRESULT Init(ATL::_ATL_OBJMAP_ENTRY* pObjMap, HINSTANCE hInstance, const GUID* pLibID = NULL) + { + HRESULT hRet = CComModule::Init(pObjMap, hInstance, pLibID); + if(FAILED(hRet)) + return hRet; + + m_dwMainThreadID = ::GetCurrentThreadId(); + typedef ATL::CSimpleMap _mapClass; + m_pMsgLoopMap = NULL; + ATLTRY(m_pMsgLoopMap = new _mapClass); + if(m_pMsgLoopMap == NULL) + return E_OUTOFMEMORY; + m_pSettingChangeNotify = NULL; + + return hRet; + } + + void Term() + { + TermSettingChangeNotify(); + delete m_pMsgLoopMap; + CComModule::Term(); + } + +// Message loop map methods + BOOL AddMessageLoop(CMessageLoop* pMsgLoop) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::AddMessageLoop.\n")); + ATLASSERT(FALSE); + return FALSE; + } + + ATLASSERT(pMsgLoop != NULL); + ATLASSERT(m_pMsgLoopMap->Lookup(::GetCurrentThreadId()) == NULL); // not in map yet + + BOOL bRet = m_pMsgLoopMap->Add(::GetCurrentThreadId(), pMsgLoop); + + lock.Unlock(); + + return bRet; + } + + BOOL RemoveMessageLoop() + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::RemoveMessageLoop.\n")); + ATLASSERT(FALSE); + return FALSE; + } + + BOOL bRet = m_pMsgLoopMap->Remove(::GetCurrentThreadId()); + + lock.Unlock(); + + return bRet; + } + + CMessageLoop* GetMessageLoop(DWORD dwThreadID = ::GetCurrentThreadId()) const + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::GetMessageLoop.\n")); + ATLASSERT(FALSE); + return NULL; + } + + CMessageLoop* pLoop = m_pMsgLoopMap->Lookup(dwThreadID); + + lock.Unlock(); + + return pLoop; + } + +// Setting change notify methods + // Note: Call this from the main thread for MSDI apps + BOOL InitSettingChangeNotify(DLGPROC pfnDlgProc = _SettingChangeDlgProc) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::InitSettingChangeNotify.\n")); + ATLASSERT(FALSE); + return FALSE; + } + + if(m_pSettingChangeNotify == NULL) + { + typedef ATL::CSimpleArray _notifyClass; + ATLTRY(m_pSettingChangeNotify = new _notifyClass); + ATLASSERT(m_pSettingChangeNotify != NULL); + } + + BOOL bRet = (m_pSettingChangeNotify != NULL); + if(bRet && m_pSettingChangeNotify->GetSize() == 0) + { + // init everything + _ATL_EMPTY_DLGTEMPLATE templ; + HWND hNtfWnd = ::CreateDialogIndirect(GetModuleInstance(), &templ, NULL, pfnDlgProc); + ATLASSERT(::IsWindow(hNtfWnd)); + if(::IsWindow(hNtfWnd)) + { +// need conditional code because types don't match in winuser.h +#ifdef _WIN64 + ::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, (LONG_PTR)this); +#else + ::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, PtrToLong(this)); +#endif + bRet = m_pSettingChangeNotify->Add(hNtfWnd); + } + else + { + bRet = FALSE; + } + } + + lock.Unlock(); + + return bRet; + } + + void TermSettingChangeNotify() + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::TermSettingChangeNotify.\n")); + ATLASSERT(FALSE); + return; + } + + if(m_pSettingChangeNotify != NULL && m_pSettingChangeNotify->GetSize() > 0) + ::DestroyWindow((*m_pSettingChangeNotify)[0]); + delete m_pSettingChangeNotify; + m_pSettingChangeNotify = NULL; + + lock.Unlock(); + } + + BOOL AddSettingChangeNotify(HWND hWnd) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::AddSettingChangeNotify.\n")); + ATLASSERT(FALSE); + return FALSE; + } + + ATLASSERT(::IsWindow(hWnd)); + BOOL bRet = FALSE; + if(InitSettingChangeNotify() != FALSE) + bRet = m_pSettingChangeNotify->Add(hWnd); + + lock.Unlock(); + + return bRet; + } + + BOOL RemoveSettingChangeNotify(HWND hWnd) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::RemoveSettingChangeNotify.\n")); + ATLASSERT(FALSE); + return FALSE; + } + + BOOL bRet = FALSE; + if(m_pSettingChangeNotify != NULL) + bRet = m_pSettingChangeNotify->Remove(hWnd); + + lock.Unlock(); + + return bRet; + } + +// Implementation - setting change notify dialog template and dialog procedure + struct _ATL_EMPTY_DLGTEMPLATE : DLGTEMPLATE + { + _ATL_EMPTY_DLGTEMPLATE() + { + memset(this, 0, sizeof(_ATL_EMPTY_DLGTEMPLATE)); + style = WS_POPUP; + } + WORD wMenu, wClass, wTitle; + }; + +#ifdef _WIN64 + static INT_PTR CALLBACK _SettingChangeDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +#else + static BOOL CALLBACK _SettingChangeDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +#endif + { + if(uMsg == WM_SETTINGCHANGE) + { +// need conditional code because types don't match in winuser.h +#ifdef _WIN64 + CAppModule* pModule = (CAppModule*)::GetWindowLongPtr(hWnd, GWLP_USERDATA); +#else + CAppModule* pModule = (CAppModule*)LongToPtr(::GetWindowLongPtr(hWnd, GWLP_USERDATA)); +#endif + ATLASSERT(pModule != NULL); + ATLASSERT(pModule->m_pSettingChangeNotify != NULL); + const UINT uTimeout = 1500; // ms + for(int i = 1; i < pModule->m_pSettingChangeNotify->GetSize(); i++) + { +#if !defined(_WIN32_WCE) + ::SendMessageTimeout((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam, SMTO_ABORTIFHUNG, uTimeout, NULL); +#elif(_WIN32_WCE >= 400) // CE specific + ::SendMessageTimeout((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam, SMTO_NORMAL, uTimeout, NULL); +#else // _WIN32_WCE < 400 specific + uTimeout; + ::SendMessage((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam); +#endif + } + return TRUE; + } + return FALSE; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CServerAppModule - module class for a COM server application + +class CServerAppModule : public CAppModule +{ +public: + HANDLE m_hEventShutdown; + bool m_bActivity; + DWORD m_dwTimeOut; + DWORD m_dwPause; + +// Override of CAppModule::Init + HRESULT Init(ATL::_ATL_OBJMAP_ENTRY* pObjMap, HINSTANCE hInstance, const GUID* pLibID = NULL) + { + m_dwTimeOut = 5000; + m_dwPause = 1000; + return CAppModule::Init(pObjMap, hInstance, pLibID); + } + + void Term() + { + if(m_hEventShutdown != NULL && ::CloseHandle(m_hEventShutdown)) + m_hEventShutdown = NULL; + CAppModule::Term(); + } + +// COM Server methods +#if (_MSC_VER >= 1300) + LONG Unlock() throw() +#else + LONG Unlock() +#endif + { + LONG lRet = CComModule::Unlock(); + if(lRet == 0) + { + m_bActivity = true; + ::SetEvent(m_hEventShutdown); // tell monitor that we transitioned to zero + } + return lRet; + } + + void MonitorShutdown() + { + for(;;) + { + ::WaitForSingleObject(m_hEventShutdown, INFINITE); + DWORD dwWait = 0; + do + { + m_bActivity = false; + dwWait = ::WaitForSingleObject(m_hEventShutdown, m_dwTimeOut); + } + while(dwWait == WAIT_OBJECT_0); + // timed out + if(!m_bActivity && m_nLockCnt == 0) // if no activity let's really bail + { +#if ((_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)) && defined(_ATL_FREE_THREADED) && !defined(_WIN32_WCE) + ::CoSuspendClassObjects(); + if(!m_bActivity && m_nLockCnt == 0) +#endif + break; + } + } + // This handle should be valid now. If it isn't, + // check if _Module.Term was called first (it shouldn't) + if(::CloseHandle(m_hEventShutdown)) + m_hEventShutdown = NULL; + ::PostThreadMessage(m_dwMainThreadID, WM_QUIT, 0, 0); + } + + bool StartMonitor() + { + m_hEventShutdown = ::CreateEvent(NULL, false, false, NULL); + if(m_hEventShutdown == NULL) + return false; + DWORD dwThreadID = 0; +#if !defined(_ATL_MIN_CRT) && defined(_MT) && !defined(_WIN32_WCE) + HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))MonitorProc, this, 0, (UINT*)&dwThreadID); +#else + HANDLE hThread = ::CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID); +#endif + bool bRet = (hThread != NULL); + if(bRet) + ::CloseHandle(hThread); + return bRet; + } + + static DWORD WINAPI MonitorProc(void* pv) + { + CServerAppModule* p = (CServerAppModule*)pv; + p->MonitorShutdown(); + return 0; + } + +#if (_ATL_VER < 0x0700) + // search for an occurence of string p2 in string p1 + static LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2) + { + while(p1 != NULL && *p1 != NULL) + { + LPCTSTR p = p2; + while(p != NULL && *p != NULL) + { + if(*p1 == *p) + return ::CharNext(p1); + p = ::CharNext(p); + } + p1 = ::CharNext(p1); + } + return NULL; + } +#endif // (_ATL_VER < 0x0700) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CRegKeyEx - adds type-specific methods to ATL3 CRegKey + +#if (_ATL_VER < 0x0700) + +class CRegKeyEx : public ATL::CRegKey +{ +public: +// Constructors and operators + CRegKeyEx(HKEY hKey = NULL) + { + m_hKey = hKey; + } + + CRegKeyEx(CRegKeyEx& key) + { + Attach(key.Detach()); + } + + CRegKeyEx& operator =(CRegKeyEx& key) + { + Close(); + Attach(key.Detach()); + return *this; + } + +// Methods + LONG SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes) + { + ATLASSERT(m_hKey != NULL); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, static_cast(pValue), nBytes); + } + + LONG SetGUIDValue(LPCTSTR pszValueName, REFGUID guidValue) + { + ATLASSERT(m_hKey != NULL); + + OLECHAR szGUID[64] = { 0 }; + ::StringFromGUID2(guidValue, szGUID, 64); + + USES_CONVERSION; + LPCTSTR lpstr = OLE2CT(szGUID); +#ifndef _UNICODE + if(lpstr == NULL) + return E_OUTOFMEMORY; +#endif + return SetStringValue(pszValueName, lpstr); + } + + LONG SetBinaryValue(LPCTSTR pszValueName, const void* pValue, ULONG nBytes) + { + ATLASSERT(m_hKey != NULL); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_BINARY, reinterpret_cast(pValue), nBytes); + } + + LONG SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue) + { + ATLASSERT(m_hKey != NULL); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_DWORD, reinterpret_cast(&dwValue), sizeof(DWORD)); + } + +#ifndef _WIN32_WCE + LONG SetQWORDValue(LPCTSTR pszValueName, ULONGLONG qwValue) + { + ATLASSERT(m_hKey != NULL); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_QWORD, reinterpret_cast(&qwValue), sizeof(ULONGLONG)); + } +#endif + + LONG SetStringValue(LPCTSTR pszValueName, LPCTSTR pszValue, DWORD dwType = REG_SZ) + { + ATLASSERT(m_hKey != NULL); + if(pszValue == NULL) + { + ATLASSERT(FALSE); + return ERROR_INVALID_DATA; + } + ATLASSERT((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)); + + return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, reinterpret_cast(pszValue), (lstrlen(pszValue) + 1) * sizeof(TCHAR)); + } + + LONG SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue) + { + ATLASSERT(m_hKey != NULL); + if(pszValue == NULL) + { + ATLASSERT(FALSE); + return ERROR_INVALID_DATA; + } + + ULONG nBytes = 0; + ULONG nLength = 0; + LPCTSTR pszTemp = pszValue; + do + { + nLength = lstrlen(pszTemp) + 1; + pszTemp += nLength; + nBytes += nLength * sizeof(TCHAR); + } while (nLength != 1); + + return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_MULTI_SZ, reinterpret_cast(pszValue), nBytes); + } + + LONG QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes) + { + ATLASSERT(m_hKey != NULL); + return ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, static_cast(pData), pnBytes); + } + + LONG QueryGUIDValue(LPCTSTR pszValueName, GUID& guidValue) + { + ATLASSERT(m_hKey != NULL); + + guidValue = GUID_NULL; + + TCHAR szGUID[64] = { 0 }; + ULONG nCount = 64; + LONG lRes = QueryStringValue(pszValueName, szGUID, &nCount); + + if (lRes != ERROR_SUCCESS) + return lRes; + + if(szGUID[0] != _T('{')) + return ERROR_INVALID_DATA; + + USES_CONVERSION; + LPOLESTR lpstr = T2OLE(szGUID); +#ifndef _UNICODE + if(lpstr == NULL) + return E_OUTOFMEMORY; +#endif + + HRESULT hr = ::CLSIDFromString(lpstr, &guidValue); + if (FAILED(hr)) + return ERROR_INVALID_DATA; + + return ERROR_SUCCESS; + } + + LONG QueryBinaryValue(LPCTSTR pszValueName, void* pValue, ULONG* pnBytes) + { + ATLASSERT(pnBytes != NULL); + ATLASSERT(m_hKey != NULL); + + DWORD dwType = 0; + LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(pValue), pnBytes); + if (lRes != ERROR_SUCCESS) + return lRes; + if (dwType != REG_BINARY) + return ERROR_INVALID_DATA; + + return ERROR_SUCCESS; + } + + LONG QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue) + { + ATLASSERT(m_hKey != NULL); + + ULONG nBytes = sizeof(DWORD); + DWORD dwType = 0; + LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(&dwValue), &nBytes); + if (lRes != ERROR_SUCCESS) + return lRes; + if (dwType != REG_DWORD) + return ERROR_INVALID_DATA; + + return ERROR_SUCCESS; + } + +#ifndef _WIN32_WCE + LONG QueryQWORDValue(LPCTSTR pszValueName, ULONGLONG& qwValue) + { + ATLASSERT(m_hKey != NULL); + + ULONG nBytes = sizeof(ULONGLONG); + DWORD dwType = 0; + LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(&qwValue), &nBytes); + if (lRes != ERROR_SUCCESS) + return lRes; + if (dwType != REG_QWORD) + return ERROR_INVALID_DATA; + + return ERROR_SUCCESS; + } +#endif + + LONG QueryStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars) + { + ATLASSERT(m_hKey != NULL); + ATLASSERT(pnChars != NULL); + + ULONG nBytes = (*pnChars) * sizeof(TCHAR); + DWORD dwType = 0; + *pnChars = 0; + LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(pszValue), &nBytes); + + if (lRes != ERROR_SUCCESS) + { + return lRes; + } + + if(dwType != REG_SZ && dwType != REG_EXPAND_SZ) + { + return ERROR_INVALID_DATA; + } + + if (pszValue != NULL) + { + if(nBytes != 0) + { + if ((nBytes % sizeof(TCHAR) != 0) || (pszValue[nBytes / sizeof(TCHAR) -1] != 0)) + return ERROR_INVALID_DATA; + } + else + { + pszValue[0] = _T('\0'); + } + } + + *pnChars = nBytes / sizeof(TCHAR); + + return ERROR_SUCCESS; + } + + LONG QueryMultiStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars) + { + ATLASSERT(m_hKey != NULL); + ATLASSERT(pnChars != NULL); + + if (pszValue != NULL && *pnChars < 2) + return ERROR_INSUFFICIENT_BUFFER; + + ULONG nBytes = (*pnChars) * sizeof(TCHAR); + DWORD dwType = 0; + *pnChars = 0; + LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(pszValue), &nBytes); + if (lRes != ERROR_SUCCESS) + return lRes; + if (dwType != REG_MULTI_SZ) + return ERROR_INVALID_DATA; + if (pszValue != NULL && (nBytes % sizeof(TCHAR) != 0 || nBytes / sizeof(TCHAR) < 1 || pszValue[nBytes / sizeof(TCHAR) - 1] != 0 || ((nBytes / sizeof(TCHAR)) > 1 && pszValue[nBytes / sizeof(TCHAR) - 2] != 0))) + return ERROR_INVALID_DATA; + + *pnChars = nBytes / sizeof(TCHAR); + + return ERROR_SUCCESS; + } +}; + +#else // !(_ATL_VER < 0x0700) + +typedef ATL::CRegKey CRegKeyEx; + +#endif // !(_ATL_VER < 0x0700) + + +/////////////////////////////////////////////////////////////////////////////// +// CString forward reference (enables CString use in atluser.h and atlgdi.h) + +#if defined(_WTL_FORWARD_DECLARE_CSTRING) && !defined(_WTL_USE_CSTRING) + #define _WTL_USE_CSTRING +#endif // defined(_WTL_FORWARD_DECLARE_CSTRING) && !defined(_WTL_USE_CSTRING) + +#ifdef _WTL_USE_CSTRING + class CString; // forward declaration (include atlmisc.h for the whole class) +#endif // _WTL_USE_CSTRING + +// CString namespace +#ifndef _CSTRING_NS + #ifdef __ATLSTR_H__ + #define _CSTRING_NS ATL + #else + #define _CSTRING_NS WTL + #endif +#endif // _CSTRING_NS + +// Type classes namespace +#ifndef _WTYPES_NS + #ifdef __ATLTYPES_H__ + #define _WTYPES_NS + #else + #define _WTYPES_NS WTL + #endif +#endif // _WTYPES_NS + +}; // namespace WTL + + +/////////////////////////////////////////////////////////////////////////////// +// General DLL version helpers +// (ATL3: excluded from atlbase.h if _ATL_DLL is defined; ATL11: removed) + +#if (((_ATL_VER < 0x0700) && defined(_ATL_DLL)) || (_ATL_VER >= 0x0B00)) && !defined(_WIN32_WCE) + +namespace ATL +{ + +inline HRESULT AtlGetDllVersion(HINSTANCE hInstDLL, DLLVERSIONINFO* pDllVersionInfo) +{ + ATLASSERT(pDllVersionInfo != NULL); + if(pDllVersionInfo == NULL) + return E_INVALIDARG; + + // We must get this function explicitly because some DLLs don't implement it. + DLLGETVERSIONPROC pfnDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(hInstDLL, "DllGetVersion"); + if(pfnDllGetVersion == NULL) + return E_NOTIMPL; + + return (*pfnDllGetVersion)(pDllVersionInfo); +} + +inline HRESULT AtlGetDllVersion(LPCTSTR lpstrDllName, DLLVERSIONINFO* pDllVersionInfo) +{ + HINSTANCE hInstDLL = ::LoadLibrary(lpstrDllName); + if(hInstDLL == NULL) + return E_FAIL; + HRESULT hRet = AtlGetDllVersion(hInstDLL, pDllVersionInfo); + ::FreeLibrary(hInstDLL); + return hRet; +} + +// Common Control Versions: +// Win95/WinNT 4.0 maj=4 min=00 +// IE 3.x maj=4 min=70 +// IE 4.0 maj=4 min=71 +inline HRESULT AtlGetCommCtrlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor) +{ + ATLASSERT(pdwMajor != NULL && pdwMinor != NULL); + if(pdwMajor == NULL || pdwMinor == NULL) + return E_INVALIDARG; + + DLLVERSIONINFO dvi; + ::ZeroMemory(&dvi, sizeof(dvi)); + dvi.cbSize = sizeof(dvi); + HRESULT hRet = AtlGetDllVersion(_T("comctl32.dll"), &dvi); + + if(SUCCEEDED(hRet)) + { + *pdwMajor = dvi.dwMajorVersion; + *pdwMinor = dvi.dwMinorVersion; + } + else if(hRet == E_NOTIMPL) + { + // If DllGetVersion is not there, then the DLL is a version + // previous to the one shipped with IE 3.x + *pdwMajor = 4; + *pdwMinor = 0; + hRet = S_OK; + } + + return hRet; +} + +// Shell Versions: +// Win95/WinNT 4.0 maj=4 min=00 +// IE 3.x, IE 4.0 without Web Integrated Desktop maj=4 min=00 +// IE 4.0 with Web Integrated Desktop maj=4 min=71 +// IE 4.01 with Web Integrated Desktop maj=4 min=72 +inline HRESULT AtlGetShellVersion(LPDWORD pdwMajor, LPDWORD pdwMinor) +{ + ATLASSERT(pdwMajor != NULL && pdwMinor != NULL); + if(pdwMajor == NULL || pdwMinor == NULL) + return E_INVALIDARG; + + DLLVERSIONINFO dvi; + ::ZeroMemory(&dvi, sizeof(dvi)); + dvi.cbSize = sizeof(dvi); + HRESULT hRet = AtlGetDllVersion(_T("shell32.dll"), &dvi); + + if(SUCCEEDED(hRet)) + { + *pdwMajor = dvi.dwMajorVersion; + *pdwMinor = dvi.dwMinorVersion; + } + else if(hRet == E_NOTIMPL) + { + // If DllGetVersion is not there, then the DLL is a version + // previous to the one shipped with IE 4.x + *pdwMajor = 4; + *pdwMinor = 0; + hRet = S_OK; + } + + return hRet; +} + +}; // namespace ATL + +#endif // (_ATL_VER < 0x0700) && defined(_ATL_DLL) && !defined(_WIN32_WCE) + + +// These are always included +#include "atlwinx.h" +#include "atluser.h" +#include "atlgdi.h" + +#ifndef _WTL_NO_AUTOMATIC_NAMESPACE +using namespace WTL; +#endif // !_WTL_NO_AUTOMATIC_NAMESPACE + +#endif // __ATLAPP_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlcrack.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlcrack.h new file mode 100644 index 0000000000000000000000000000000000000000..e824966f8bbe81babd1407ec17697b758a0013ea --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlcrack.h @@ -0,0 +1,2395 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLCRACK_H__ +#define __ATLCRACK_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atlcrack.h requires atlapp.h to be included first +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Message map macro for cracked handlers + +// Note about message maps with cracked handlers: +// For ATL 3.0, a message map using cracked handlers MUST use BEGIN_MSG_MAP_EX. +// For ATL 7.0 or higher, you can use BEGIN_MSG_MAP for CWindowImpl/CDialogImpl derived classes, +// but must use BEGIN_MSG_MAP_EX for classes that don't derive from CWindowImpl/CDialogImpl. + +#define BEGIN_MSG_MAP_EX(theClass) \ +public: \ + BOOL m_bMsgHandled; \ + /* "handled" management for cracked handlers */ \ + BOOL IsMsgHandled() const \ + { \ + return m_bMsgHandled; \ + } \ + void SetMsgHandled(BOOL bHandled) \ + { \ + m_bMsgHandled = bHandled; \ + } \ + BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) \ + { \ + BOOL bOldMsgHandled = m_bMsgHandled; \ + BOOL bRet = _ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); \ + m_bMsgHandled = bOldMsgHandled; \ + return bRet; \ + } \ + BOOL _ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID) \ + { \ + BOOL bHandled = TRUE; \ + (hWnd); \ + (uMsg); \ + (wParam); \ + (lParam); \ + (lResult); \ + (bHandled); \ + switch(dwMsgMapID) \ + { \ + case 0: + + +/////////////////////////////////////////////////////////////////////////////// +// Standard Windows message macros + +// int OnCreate(LPCREATESTRUCT lpCreateStruct) +#define MSG_WM_CREATE(func) \ + if (uMsg == WM_CREATE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam) +#define MSG_WM_INITDIALOG(func) \ + if (uMsg == WM_INITDIALOG) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HWND)wParam, lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnCopyData(CWindow wnd, PCOPYDATASTRUCT pCopyDataStruct) +#define MSG_WM_COPYDATA(func) \ + if (uMsg == WM_COPYDATA) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HWND)wParam, (PCOPYDATASTRUCT)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDestroy() +#define MSG_WM_DESTROY(func) \ + if (uMsg == WM_DESTROY) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMove(CPoint ptPos) +#define MSG_WM_MOVE(func) \ + if (uMsg == WM_MOVE) \ + { \ + SetMsgHandled(TRUE); \ + func(_WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSize(UINT nType, CSize size) +#define MSG_WM_SIZE(func) \ + if (uMsg == WM_SIZE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnActivate(UINT nState, BOOL bMinimized, CWindow wndOther) +#define MSG_WM_ACTIVATE(func) \ + if (uMsg == WM_ACTIVATE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)LOWORD(wParam), (BOOL)HIWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSetFocus(CWindow wndOld) +#define MSG_WM_SETFOCUS(func) \ + if (uMsg == WM_SETFOCUS) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnKillFocus(CWindow wndFocus) +#define MSG_WM_KILLFOCUS(func) \ + if (uMsg == WM_KILLFOCUS) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnEnable(BOOL bEnable) +#define MSG_WM_ENABLE(func) \ + if (uMsg == WM_ENABLE) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPaint(CDCHandle dc) +#define MSG_WM_PAINT(func) \ + if (uMsg == WM_PAINT) \ + { \ + SetMsgHandled(TRUE); \ + func((HDC)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnClose() +#define MSG_WM_CLOSE(func) \ + if (uMsg == WM_CLOSE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnQueryEndSession(UINT nSource, UINT uLogOff) +#define MSG_WM_QUERYENDSESSION(func) \ + if (uMsg == WM_QUERYENDSESSION) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)wParam, (UINT)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnQueryOpen() +#define MSG_WM_QUERYOPEN(func) \ + if (uMsg == WM_QUERYOPEN) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnEraseBkgnd(CDCHandle dc) +#define MSG_WM_ERASEBKGND(func) \ + if (uMsg == WM_ERASEBKGND) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSysColorChange() +#define MSG_WM_SYSCOLORCHANGE(func) \ + if (uMsg == WM_SYSCOLORCHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnEndSession(BOOL bEnding, UINT uLogOff) +#define MSG_WM_ENDSESSION(func) \ + if (uMsg == WM_ENDSESSION) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam, (UINT)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnShowWindow(BOOL bShow, UINT nStatus) +#define MSG_WM_SHOWWINDOW(func) \ + if (uMsg == WM_SHOWWINDOW) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam, (int)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnCtlColorEdit(CDCHandle dc, CEdit edit) +#define MSG_WM_CTLCOLOREDIT(func) \ + if (uMsg == WM_CTLCOLOREDIT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnCtlColorListBox(CDCHandle dc, CListBox listBox) +#define MSG_WM_CTLCOLORLISTBOX(func) \ + if (uMsg == WM_CTLCOLORLISTBOX) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnCtlColorBtn(CDCHandle dc, CButton button) +#define MSG_WM_CTLCOLORBTN(func) \ + if (uMsg == WM_CTLCOLORBTN) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnCtlColorDlg(CDCHandle dc, CWindow wnd) +#define MSG_WM_CTLCOLORDLG(func) \ + if (uMsg == WM_CTLCOLORDLG) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar) +#define MSG_WM_CTLCOLORSCROLLBAR(func) \ + if (uMsg == WM_CTLCOLORSCROLLBAR) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnCtlColorStatic(CDCHandle dc, CStatic wndStatic) +#define MSG_WM_CTLCOLORSTATIC(func) \ + if (uMsg == WM_CTLCOLORSTATIC) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSettingChange(UINT uFlags, LPCTSTR lpszSection) +#define MSG_WM_SETTINGCHANGE(func) \ + if (uMsg == WM_SETTINGCHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPCTSTR)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDevModeChange(LPCTSTR lpDeviceName) +#define MSG_WM_DEVMODECHANGE(func) \ + if (uMsg == WM_DEVMODECHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func((LPCTSTR)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnActivateApp(BOOL bActive, DWORD dwThreadID) +#define MSG_WM_ACTIVATEAPP(func) \ + if (uMsg == WM_ACTIVATEAPP) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam, (DWORD)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnFontChange() +#define MSG_WM_FONTCHANGE(func) \ + if (uMsg == WM_FONTCHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnTimeChange() +#define MSG_WM_TIMECHANGE(func) \ + if (uMsg == WM_TIMECHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCancelMode() +#define MSG_WM_CANCELMODE(func) \ + if (uMsg == WM_CANCELMODE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnSetCursor(CWindow wnd, UINT nHitTest, UINT message) +#define MSG_WM_SETCURSOR(func) \ + if (uMsg == WM_SETCURSOR) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, UINT message) +#define MSG_WM_MOUSEACTIVATE(func) \ + if (uMsg == WM_MOUSEACTIVATE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnChildActivate() +#define MSG_WM_CHILDACTIVATE(func) \ + if (uMsg == WM_CHILDACTIVATE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnGetMinMaxInfo(LPMINMAXINFO lpMMI) +#define MSG_WM_GETMINMAXINFO(func) \ + if (uMsg == WM_GETMINMAXINFO) \ + { \ + SetMsgHandled(TRUE); \ + func((LPMINMAXINFO)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnIconEraseBkgnd(CDCHandle dc) +#define MSG_WM_ICONERASEBKGND(func) \ + if (uMsg == WM_ICONERASEBKGND) \ + { \ + SetMsgHandled(TRUE); \ + func((HDC)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSpoolerStatus(UINT nStatus, UINT nJobs) +#define MSG_WM_SPOOLERSTATUS(func) \ + if (uMsg == WM_SPOOLERSTATUS) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (UINT)LOWORD(lParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) +#define MSG_WM_DRAWITEM(func) \ + if (uMsg == WM_DRAWITEM) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) +#define MSG_WM_MEASUREITEM(func) \ + if (uMsg == WM_MEASUREITEM) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct) +#define MSG_WM_DELETEITEM(func) \ + if (uMsg == WM_DELETEITEM) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +//int OnCharToItem(UINT nChar, UINT nIndex, CListBox listBox) +#define MSG_WM_CHARTOITEM(func) \ + if (uMsg == WM_CHARTOITEM) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox) +#define MSG_WM_VKEYTOITEM(func) \ + if (uMsg == WM_VKEYTOITEM) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HCURSOR OnQueryDragIcon() +#define MSG_WM_QUERYDRAGICON(func) \ + if (uMsg == WM_QUERYDRAGICON) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT lpCompareItemStruct) +#define MSG_WM_COMPAREITEM(func) \ + if (uMsg == WM_COMPAREITEM) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCompacting(UINT nCpuTime) +#define MSG_WM_COMPACTING(func) \ + if (uMsg == WM_COMPACTING) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct) +#define MSG_WM_NCCREATE(func) \ + if (uMsg == WM_NCCREATE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcDestroy() +#define MSG_WM_NCDESTROY(func) \ + if (uMsg == WM_NCDESTROY) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNcCalcSize(BOOL bCalcValidRects, LPARAM lParam) +#define MSG_WM_NCCALCSIZE(func) \ + if (uMsg == WM_NCCALCSIZE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((BOOL)wParam, lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// UINT OnNcHitTest(CPoint point) +#define MSG_WM_NCHITTEST(func) \ + if (uMsg == WM_NCHITTEST) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func(_WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcPaint(CRgnHandle rgn) +#define MSG_WM_NCPAINT(func) \ + if (uMsg == WM_NCPAINT) \ + { \ + SetMsgHandled(TRUE); \ + func((HRGN)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnNcActivate(BOOL bActive) +#define MSG_WM_NCACTIVATE(func) \ + if (uMsg == WM_NCACTIVATE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((BOOL)wParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// UINT OnGetDlgCode(LPMSG lpMsg) +#define MSG_WM_GETDLGCODE(func) \ + if (uMsg == WM_GETDLGCODE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((LPMSG)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcMouseMove(UINT nHitTest, CPoint point) +#define MSG_WM_NCMOUSEMOVE(func) \ + if (uMsg == WM_NCMOUSEMOVE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcLButtonDown(UINT nHitTest, CPoint point) +#define MSG_WM_NCLBUTTONDOWN(func) \ + if (uMsg == WM_NCLBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcLButtonUp(UINT nHitTest, CPoint point) +#define MSG_WM_NCLBUTTONUP(func) \ + if (uMsg == WM_NCLBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcLButtonDblClk(UINT nHitTest, CPoint point) +#define MSG_WM_NCLBUTTONDBLCLK(func) \ + if (uMsg == WM_NCLBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcRButtonDown(UINT nHitTest, CPoint point) +#define MSG_WM_NCRBUTTONDOWN(func) \ + if (uMsg == WM_NCRBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcRButtonUp(UINT nHitTest, CPoint point) +#define MSG_WM_NCRBUTTONUP(func) \ + if (uMsg == WM_NCRBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcRButtonDblClk(UINT nHitTest, CPoint point) +#define MSG_WM_NCRBUTTONDBLCLK(func) \ + if (uMsg == WM_NCRBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcMButtonDown(UINT nHitTest, CPoint point) +#define MSG_WM_NCMBUTTONDOWN(func) \ + if (uMsg == WM_NCMBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcMButtonUp(UINT nHitTest, CPoint point) +#define MSG_WM_NCMBUTTONUP(func) \ + if (uMsg == WM_NCMBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcMButtonDblClk(UINT nHitTest, CPoint point) +#define MSG_WM_NCMBUTTONDBLCLK(func) \ + if (uMsg == WM_NCMBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_KEYDOWN(func) \ + if (uMsg == WM_KEYDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_KEYUP(func) \ + if (uMsg == WM_KEYUP) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_CHAR(func) \ + if (uMsg == WM_CHAR) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_DEADCHAR(func) \ + if (uMsg == WM_DEADCHAR) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_SYSKEYDOWN(func) \ + if (uMsg == WM_SYSKEYDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_SYSKEYUP(func) \ + if (uMsg == WM_SYSKEYUP) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_SYSCHAR(func) \ + if (uMsg == WM_SYSCHAR) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSysDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_SYSDEADCHAR(func) \ + if (uMsg == WM_SYSDEADCHAR) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSysCommand(UINT nID, CPoint point) +#define MSG_WM_SYSCOMMAND(func) \ + if (uMsg == WM_SYSCOMMAND) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnTCard(UINT idAction, DWORD dwActionData) +#define MSG_WM_TCARD(func) \ + if (uMsg == WM_TCARD) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (DWORD)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnTimer(UINT_PTR nIDEvent) +#define MSG_WM_TIMER(func) \ + if (uMsg == WM_TIMER) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT_PTR)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar) +#define MSG_WM_HSCROLL(func) \ + if (uMsg == WM_HSCROLL) \ + { \ + SetMsgHandled(TRUE); \ + func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar) +#define MSG_WM_VSCROLL(func) \ + if (uMsg == WM_VSCROLL) \ + { \ + SetMsgHandled(TRUE); \ + func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnInitMenu(CMenuHandle menu) +#define MSG_WM_INITMENU(func) \ + if (uMsg == WM_INITMENU) \ + { \ + SetMsgHandled(TRUE); \ + func((HMENU)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnInitMenuPopup(CMenuHandle menuPopup, UINT nIndex, BOOL bSysMenu) +#define MSG_WM_INITMENUPOPUP(func) \ + if (uMsg == WM_INITMENUPOPUP) \ + { \ + SetMsgHandled(TRUE); \ + func((HMENU)wParam, (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMenuSelect(UINT nItemID, UINT nFlags, CMenuHandle menu) +#define MSG_WM_MENUSELECT(func) \ + if (uMsg == WM_MENUSELECT) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnMenuChar(UINT nChar, UINT nFlags, CMenuHandle menu) +#define MSG_WM_MENUCHAR(func) \ + if (uMsg == WM_MENUCHAR) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((TCHAR)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNotify(int idCtrl, LPNMHDR pnmh) +#define MSG_WM_NOTIFY(func) \ + if (uMsg == WM_NOTIFY) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((int)wParam, (LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnEnterIdle(UINT nWhy, CWindow wndWho) +#define MSG_WM_ENTERIDLE(func) \ + if (uMsg == WM_ENTERIDLE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMouseMove(UINT nFlags, CPoint point) +#define MSG_WM_MOUSEMOVE(func) \ + if (uMsg == WM_MOUSEMOVE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) +#define MSG_WM_MOUSEWHEEL(func) \ + if (uMsg == WM_MOUSEWHEEL) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)LOWORD(wParam), (short)HIWORD(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnLButtonDown(UINT nFlags, CPoint point) +#define MSG_WM_LBUTTONDOWN(func) \ + if (uMsg == WM_LBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnLButtonUp(UINT nFlags, CPoint point) +#define MSG_WM_LBUTTONUP(func) \ + if (uMsg == WM_LBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnLButtonDblClk(UINT nFlags, CPoint point) +#define MSG_WM_LBUTTONDBLCLK(func) \ + if (uMsg == WM_LBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnRButtonDown(UINT nFlags, CPoint point) +#define MSG_WM_RBUTTONDOWN(func) \ + if (uMsg == WM_RBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnRButtonUp(UINT nFlags, CPoint point) +#define MSG_WM_RBUTTONUP(func) \ + if (uMsg == WM_RBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnRButtonDblClk(UINT nFlags, CPoint point) +#define MSG_WM_RBUTTONDBLCLK(func) \ + if (uMsg == WM_RBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMButtonDown(UINT nFlags, CPoint point) +#define MSG_WM_MBUTTONDOWN(func) \ + if (uMsg == WM_MBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMButtonUp(UINT nFlags, CPoint point) +#define MSG_WM_MBUTTONUP(func) \ + if (uMsg == WM_MBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMButtonDblClk(UINT nFlags, CPoint point) +#define MSG_WM_MBUTTONDBLCLK(func) \ + if (uMsg == WM_MBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnParentNotify(UINT message, UINT nChildID, LPARAM lParam) +#define MSG_WM_PARENTNOTIFY(func) \ + if (uMsg == WM_PARENTNOTIFY) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMDIActivate(CWindow wndActivate, CWindow wndDeactivate) +#define MSG_WM_MDIACTIVATE(func) \ + if (uMsg == WM_MDIACTIVATE) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnRenderFormat(UINT nFormat) +#define MSG_WM_RENDERFORMAT(func) \ + if (uMsg == WM_RENDERFORMAT) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnRenderAllFormats() +#define MSG_WM_RENDERALLFORMATS(func) \ + if (uMsg == WM_RENDERALLFORMATS) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDestroyClipboard() +#define MSG_WM_DESTROYCLIPBOARD(func) \ + if (uMsg == WM_DESTROYCLIPBOARD) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDrawClipboard() +#define MSG_WM_DRAWCLIPBOARD(func) \ + if (uMsg == WM_DRAWCLIPBOARD) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPaintClipboard(CWindow wndViewer, const LPPAINTSTRUCT lpPaintStruct) +#define MSG_WM_PAINTCLIPBOARD(func) \ + if (uMsg == WM_PAINTCLIPBOARD) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, (const LPPAINTSTRUCT)::GlobalLock((HGLOBAL)lParam)); \ + ::GlobalUnlock((HGLOBAL)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnVScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos) +#define MSG_WM_VSCROLLCLIPBOARD(func) \ + if (uMsg == WM_VSCROLLCLIPBOARD) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnContextMenu(CWindow wnd, CPoint point) +#define MSG_WM_CONTEXTMENU(func) \ + if (uMsg == WM_CONTEXTMENU) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSizeClipboard(CWindow wndViewer, const LPRECT lpRect) +#define MSG_WM_SIZECLIPBOARD(func) \ + if (uMsg == WM_SIZECLIPBOARD) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, (const LPRECT)::GlobalLock((HGLOBAL)lParam)); \ + ::GlobalUnlock((HGLOBAL)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnAskCbFormatName(UINT nMaxCount, LPTSTR lpszString) +#define MSG_WM_ASKCBFORMATNAME(func) \ + if (uMsg == WM_ASKCBFORMATNAME) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPTSTR)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnChangeCbChain(CWindow wndRemove, CWindow wndAfter) +#define MSG_WM_CHANGECBCHAIN(func) \ + if (uMsg == WM_CHANGECBCHAIN) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnHScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos) +#define MSG_WM_HSCROLLCLIPBOARD(func) \ + if (uMsg == WM_HSCROLLCLIPBOARD) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnQueryNewPalette() +#define MSG_WM_QUERYNEWPALETTE(func) \ + if (uMsg == WM_QUERYNEWPALETTE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPaletteChanged(CWindow wndFocus) +#define MSG_WM_PALETTECHANGED(func) \ + if (uMsg == WM_PALETTECHANGED) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPaletteIsChanging(CWindow wndPalChg) +#define MSG_WM_PALETTEISCHANGING(func) \ + if (uMsg == WM_PALETTEISCHANGING) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDropFiles(HDROP hDropInfo) +#define MSG_WM_DROPFILES(func) \ + if (uMsg == WM_DROPFILES) \ + { \ + SetMsgHandled(TRUE); \ + func((HDROP)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnWindowPosChanging(LPWINDOWPOS lpWndPos) +#define MSG_WM_WINDOWPOSCHANGING(func) \ + if (uMsg == WM_WINDOWPOSCHANGING) \ + { \ + SetMsgHandled(TRUE); \ + func((LPWINDOWPOS)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnWindowPosChanged(LPWINDOWPOS lpWndPos) +#define MSG_WM_WINDOWPOSCHANGED(func) \ + if (uMsg == WM_WINDOWPOSCHANGED) \ + { \ + SetMsgHandled(TRUE); \ + func((LPWINDOWPOS)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnExitMenuLoop(BOOL fIsTrackPopupMenu) +#define MSG_WM_EXITMENULOOP(func) \ + if (uMsg == WM_EXITMENULOOP) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnEnterMenuLoop(BOOL fIsTrackPopupMenu) +#define MSG_WM_ENTERMENULOOP(func) \ + if (uMsg == WM_ENTERMENULOOP) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnStyleChanged(int nStyleType, LPSTYLESTRUCT lpStyleStruct) +#define MSG_WM_STYLECHANGED(func) \ + if (uMsg == WM_STYLECHANGED) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPSTYLESTRUCT)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnStyleChanging(int nStyleType, LPSTYLESTRUCT lpStyleStruct) +#define MSG_WM_STYLECHANGING(func) \ + if (uMsg == WM_STYLECHANGING) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPSTYLESTRUCT)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSizing(UINT fwSide, LPRECT pRect) +#define MSG_WM_SIZING(func) \ + if (uMsg == WM_SIZING) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPRECT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMoving(UINT fwSide, LPRECT pRect) +#define MSG_WM_MOVING(func) \ + if (uMsg == WM_MOVING) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPRECT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCaptureChanged(CWindow wnd) +#define MSG_WM_CAPTURECHANGED(func) \ + if (uMsg == WM_CAPTURECHANGED) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnDeviceChange(UINT nEventType, DWORD_PTR dwData) +#define MSG_WM_DEVICECHANGE(func) \ + if (uMsg == WM_DEVICECHANGE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)wParam, (DWORD_PTR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl) +#define MSG_WM_COMMAND(func) \ + if (uMsg == WM_COMMAND) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDisplayChange(UINT uBitsPerPixel, CSize sizeScreen) +#define MSG_WM_DISPLAYCHANGE(func) \ + if (uMsg == WM_DISPLAYCHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnEnterSizeMove() +#define MSG_WM_ENTERSIZEMOVE(func) \ + if (uMsg == WM_ENTERSIZEMOVE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnExitSizeMove() +#define MSG_WM_EXITSIZEMOVE(func) \ + if (uMsg == WM_EXITSIZEMOVE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HFONT OnGetFont() +#define MSG_WM_GETFONT(func) \ + if (uMsg == WM_GETFONT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnGetHotKey() +#define MSG_WM_GETHOTKEY(func) \ + if (uMsg == WM_GETHOTKEY) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HICON OnGetIcon() +#define MSG_WM_GETICON(func) \ + if (uMsg == WM_GETICON) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)wParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnGetText(int cchTextMax, LPTSTR lpszText) +#define MSG_WM_GETTEXT(func) \ + if (uMsg == WM_GETTEXT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((int)wParam, (LPTSTR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnGetTextLength() +#define MSG_WM_GETTEXTLENGTH(func) \ + if (uMsg == WM_GETTEXTLENGTH) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnHelp(LPHELPINFO lpHelpInfo) +#define MSG_WM_HELP(func) \ + if (uMsg == WM_HELP) \ + { \ + SetMsgHandled(TRUE); \ + func((LPHELPINFO)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnHotKey(int nHotKeyID, UINT uModifiers, UINT uVirtKey) +#define MSG_WM_HOTKEY(func) \ + if (uMsg == WM_HOTKEY) \ + { \ + SetMsgHandled(TRUE); \ + func((int)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnInputLangChange(DWORD dwCharSet, HKL hKbdLayout) +#define MSG_WM_INPUTLANGCHANGE(func) \ + if (uMsg == WM_INPUTLANGCHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func((DWORD)wParam, (HKL)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnInputLangChangeRequest(BOOL bSysCharSet, HKL hKbdLayout) +#define MSG_WM_INPUTLANGCHANGEREQUEST(func) \ + if (uMsg == WM_INPUTLANGCHANGEREQUEST) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam, (HKL)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNextDlgCtl(BOOL bHandle, WPARAM wCtlFocus) +#define MSG_WM_NEXTDLGCTL(func) \ + if (uMsg == WM_NEXTDLGCTL) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)LOWORD(lParam), wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNextMenu(int nVirtKey, LPMDINEXTMENU lpMdiNextMenu) +#define MSG_WM_NEXTMENU(func) \ + if (uMsg == WM_NEXTMENU) \ + { \ + SetMsgHandled(TRUE); \ + func((int)wParam, (LPMDINEXTMENU)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnNotifyFormat(CWindow wndFrom, int nCommand) +#define MSG_WM_NOTIFYFORMAT(func) \ + if (uMsg == WM_NOTIFYFORMAT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HWND)wParam, (int)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnPowerBroadcast(DWORD dwPowerEvent, DWORD_PTR dwData) +#define MSG_WM_POWERBROADCAST(func) \ + if (uMsg == WM_POWERBROADCAST) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((DWORD)wParam, (DWORD_PTR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPrint(CDCHandle dc, UINT uFlags) +#define MSG_WM_PRINT(func) \ + if (uMsg == WM_PRINT) \ + { \ + SetMsgHandled(TRUE); \ + func((HDC)wParam, (UINT)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPrintClient(CDCHandle dc, UINT uFlags) +#define MSG_WM_PRINTCLIENT(func) \ + if (uMsg == WM_PRINTCLIENT) \ + { \ + SetMsgHandled(TRUE); \ + func((HDC)wParam, (UINT)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnRasDialEvent(RASCONNSTATE rasconnstate, DWORD dwError) +#define MSG_WM_RASDIALEVENT(func) \ + if (uMsg == WM_RASDIALEVENT) \ + { \ + SetMsgHandled(TRUE); \ + func((RASCONNSTATE)wParam, (DWORD)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSetFont(CFontHandle font, BOOL bRedraw) +#define MSG_WM_SETFONT(func) \ + if (uMsg == WM_SETFONT) \ + { \ + SetMsgHandled(TRUE); \ + func((HFONT)wParam, (BOOL)LOWORD(lParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnSetHotKey(int nVirtKey, UINT uFlags) +#define MSG_WM_SETHOTKEY(func) \ + if (uMsg == WM_SETHOTKEY) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((int)LOBYTE(LOWORD(wParam)), (UINT)HIBYTE(LOWORD(wParam))); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HICON OnSetIcon(UINT uType, HICON hIcon) +#define MSG_WM_SETICON(func) \ + if (uMsg == WM_SETICON) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)wParam, (HICON)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSetRedraw(BOOL bRedraw) +#define MSG_WM_SETREDRAW(func) \ + if (uMsg == WM_SETREDRAW) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnSetText(LPCTSTR lpstrText) +#define MSG_WM_SETTEXT(func) \ + if (uMsg == WM_SETTEXT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((LPCTSTR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnUserChanged() +#define MSG_WM_USERCHANGED(func) \ + if (uMsg == WM_USERCHANGED) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// New NT4 & NT5 messages + +#if (_WIN32_WINNT >= 0x0400) + +// void OnMouseHover(WPARAM wParam, CPoint ptPos) +#define MSG_WM_MOUSEHOVER(func) \ + if (uMsg == WM_MOUSEHOVER) \ + { \ + SetMsgHandled(TRUE); \ + func(wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMouseLeave() +#define MSG_WM_MOUSELEAVE(func) \ + if (uMsg == WM_MOUSELEAVE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +#endif // _WIN32_WINNT >= 0x0400 + +#if (WINVER >= 0x0500) + +// void OnMenuRButtonUp(WPARAM wParam, CMenuHandle menu) +#define MSG_WM_MENURBUTTONUP(func) \ + if (uMsg == WM_MENURBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func(wParam, (HMENU)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnMenuDrag(WPARAM wParam, CMenuHandle menu) +#define MSG_WM_MENUDRAG(func) \ + if (uMsg == WM_MENUDRAG) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func(wParam, (HMENU)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnMenuGetObject(PMENUGETOBJECTINFO info) +#define MSG_WM_MENUGETOBJECT(func) \ + if (uMsg == WM_MENUGETOBJECT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((PMENUGETOBJECTINFO)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnUnInitMenuPopup(UINT nID, CMenuHandle menu) +#define MSG_WM_UNINITMENUPOPUP(func) \ + if (uMsg == WM_UNINITMENUPOPUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(lParam), (HMENU)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMenuCommand(WPARAM nIndex, CMenuHandle menu) +#define MSG_WM_MENUCOMMAND(func) \ + if (uMsg == WM_MENUCOMMAND) \ + { \ + SetMsgHandled(TRUE); \ + func(wParam, (HMENU)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +#endif // WINVER >= 0x0500 + +#if (_WIN32_WINNT >= 0x0500) + +// BOOL OnAppCommand(CWindow wndFocus, short cmd, WORD uDevice, int dwKeys) +#define MSG_WM_APPCOMMAND(func) \ + if (uMsg == WM_APPCOMMAND) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HWND)wParam, GET_APPCOMMAND_LPARAM(lParam), GET_DEVICE_LPARAM(lParam), GET_KEYSTATE_LPARAM(lParam)); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNCXButtonDown(int fwButton, short nHittest, CPoint ptPos) +#define MSG_WM_NCXBUTTONDOWN(func) \ + if (uMsg == WM_NCXBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNCXButtonUp(int fwButton, short nHittest, CPoint ptPos) +#define MSG_WM_NCXBUTTONUP(func) \ + if (uMsg == WM_NCXBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNCXButtonDblClk(int fwButton, short nHittest, CPoint ptPos) +#define MSG_WM_NCXBUTTONDBLCLK(func) \ + if (uMsg == WM_NCXBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnXButtonDown(int fwButton, int dwKeys, CPoint ptPos) +#define MSG_WM_XBUTTONDOWN(func) \ + if (uMsg == WM_XBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnXButtonUp(int fwButton, int dwKeys, CPoint ptPos) +#define MSG_WM_XBUTTONUP(func) \ + if (uMsg == WM_XBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnXButtonDblClk(int fwButton, int dwKeys, CPoint ptPos) +#define MSG_WM_XBUTTONDBLCLK(func) \ + if (uMsg == WM_XBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnChangeUIState(WORD nAction, WORD nState) +#define MSG_WM_CHANGEUISTATE(func) \ + if (uMsg == WM_CHANGEUISTATE) \ + { \ + SetMsgHandled(TRUE); \ + func(LOWORD(wParam), HIWORD(wParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnUpdateUIState(WORD nAction, WORD nState) +#define MSG_WM_UPDATEUISTATE(func) \ + if (uMsg == WM_UPDATEUISTATE) \ + { \ + SetMsgHandled(TRUE); \ + func(LOWORD(wParam), HIWORD(wParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnQueryUIState() +#define MSG_WM_QUERYUISTATE(func) \ + if (uMsg == WM_QUERYUISTATE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +#endif // (_WIN32_WINNT >= 0x0500) + +#if(_WIN32_WINNT >= 0x0501) + +// void OnInput(WPARAM RawInputCode, HRAWINPUT hRawInput) +#define MSG_WM_INPUT(func) \ + if (uMsg == WM_INPUT) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_RAWINPUT_CODE_WPARAM(wParam), (HRAWINPUT)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnUniChar(TCHAR nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_UNICHAR(func) \ + if (uMsg == WM_UNICHAR) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + if(IsMsgHandled()) \ + { \ + lResult = (wParam == UNICODE_NOCHAR) ? TRUE : FALSE; \ + return TRUE; \ + } \ + } + +// void OnWTSSessionChange(WPARAM nStatusCode, PWTSSESSION_NOTIFICATION nSessionID) +#define MSG_WM_WTSSESSION_CHANGE(func) \ + if (uMsg == WM_WTSSESSION_CHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func(wParam, (PWTSSESSION_NOTIFICATION)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnThemeChanged() +#define MSG_WM_THEMECHANGED(func) \ + if (uMsg == WM_THEMECHANGED) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +#endif // _WIN32_WINNT >= 0x0501 + +#if (_WIN32_WINNT >= 0x0600) + +// BOOL OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt) +#define MSG_WM_MOUSEHWHEEL(func) \ + if (uMsg == WM_MOUSEHWHEEL) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)LOWORD(wParam), (short)HIWORD(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +#endif // (_WIN32_WINNT >= 0x0600) + +/////////////////////////////////////////////////////////////////////////////// +// ATL defined messages + +// BOOL OnForwardMsg(LPMSG Msg, DWORD nUserData) +#define MSG_WM_FORWARDMSG(func) \ + if (uMsg == WM_FORWARDMSG) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((LPMSG)lParam, (DWORD)wParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// Dialog specific messages + +// LRESULT OnDMGetDefID() +#define MSG_DM_GETDEFID(func) \ + if (uMsg == DM_GETDEFID) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDMSetDefID(UINT DefID) +#define MSG_DM_SETDEFID(func) \ + if (uMsg == DM_SETDEFID) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDMReposition() +#define MSG_DM_REPOSITION(func) \ + if (uMsg == DM_REPOSITION) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// Reflected messages + +// void OnReflectedCommand(UINT uNotifyCode, int nID, CWindow wndCtl) +#define MSG_OCM_COMMAND(func) \ + if (uMsg == OCM_COMMAND) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedNotify(int idCtrl, LPNMHDR pnmh) +#define MSG_OCM_NOTIFY(func) \ + if (uMsg == OCM_NOTIFY) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((int)wParam, (LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedParentNotify(UINT message, UINT nChildID, LPARAM lParam) +#define MSG_OCM_PARENTNOTIFY(func) \ + if (uMsg == OCM_PARENTNOTIFY) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) +#define MSG_OCM_DRAWITEM(func) \ + if (uMsg == OCM_DRAWITEM) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) +#define MSG_OCM_MEASUREITEM(func) \ + if (uMsg == OCM_MEASUREITEM) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnReflectedCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT lpCompareItemStruct) +#define MSG_OCM_COMPAREITEM(func) \ + if (uMsg == OCM_COMPAREITEM) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct) +#define MSG_OCM_DELETEITEM(func) \ + if (uMsg == OCM_DELETEITEM) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnReflectedVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox) +#define MSG_OCM_VKEYTOITEM(func) \ + if (uMsg == OCM_VKEYTOITEM) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +//int OnReflectedCharToItem(UINT nChar, UINT nIndex, CListBox listBox) +#define MSG_OCM_CHARTOITEM(func) \ + if (uMsg == OCM_CHARTOITEM) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar) +#define MSG_OCM_HSCROLL(func) \ + if (uMsg == OCM_HSCROLL) \ + { \ + SetMsgHandled(TRUE); \ + func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar) +#define MSG_OCM_VSCROLL(func) \ + if (uMsg == OCM_VSCROLL) \ + { \ + SetMsgHandled(TRUE); \ + func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnReflectedCtlColorEdit(CDCHandle dc, CEdit edit) +#define MSG_OCM_CTLCOLOREDIT(func) \ + if (uMsg == OCM_CTLCOLOREDIT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnReflectedCtlColorListBox(CDCHandle dc, CListBox listBox) +#define MSG_OCM_CTLCOLORLISTBOX(func) \ + if (uMsg == OCM_CTLCOLORLISTBOX) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnReflectedCtlColorBtn(CDCHandle dc, CButton button) +#define MSG_OCM_CTLCOLORBTN(func) \ + if (uMsg == OCM_CTLCOLORBTN) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnReflectedCtlColorDlg(CDCHandle dc, CWindow wnd) +#define MSG_OCM_CTLCOLORDLG(func) \ + if (uMsg == OCM_CTLCOLORDLG) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnReflectedCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar) +#define MSG_OCM_CTLCOLORSCROLLBAR(func) \ + if (uMsg == OCM_CTLCOLORSCROLLBAR) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnReflectedCtlColorStatic(CDCHandle dc, CStatic wndStatic) +#define MSG_OCM_CTLCOLORSTATIC(func) \ + if (uMsg == OCM_CTLCOLORSTATIC) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// Edit specific messages + +// void OnClear() +#define MSG_WM_CLEAR(func) \ + if (uMsg == WM_CLEAR) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCopy() +#define MSG_WM_COPY(func) \ + if (uMsg == WM_COPY) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCut() +#define MSG_WM_CUT(func) \ + if (uMsg == WM_CUT) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPaste() +#define MSG_WM_PASTE(func) \ + if (uMsg == WM_PASTE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnUndo() +#define MSG_WM_UNDO(func) \ + if (uMsg == WM_UNDO) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// Generic message handlers + +// LRESULT OnMessageHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam) +#define MESSAGE_HANDLER_EX(msg, func) \ + if(uMsg == msg) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func(uMsg, wParam, lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnMessageRangeHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam) +#define MESSAGE_RANGE_HANDLER_EX(msgFirst, msgLast, func) \ + if(uMsg >= msgFirst && uMsg <= msgLast) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func(uMsg, wParam, lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// Commands and notifications + +// void OnCommandHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define COMMAND_HANDLER_EX(id, code, func) \ + if (uMsg == WM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define COMMAND_ID_HANDLER_EX(id, func) \ + if (uMsg == WM_COMMAND && id == LOWORD(wParam)) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define COMMAND_CODE_HANDLER_EX(code, func) \ + if (uMsg == WM_COMMAND && code == HIWORD(wParam)) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNotifyHandlerEX(LPNMHDR pnmh) +#define NOTIFY_HANDLER_EX(id, cd, func) \ + if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && id == ((LPNMHDR)lParam)->idFrom) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNotifyIDHandlerEX(LPNMHDR pnmh) +#define NOTIFY_ID_HANDLER_EX(id, func) \ + if (uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNotifyCodeHandlerEX(LPNMHDR pnmh) +#define NOTIFY_CODE_HANDLER_EX(cd, func) \ + if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \ + if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define COMMAND_RANGE_CODE_HANDLER_EX(idFirst, idLast, code, func) \ + if(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNotifyRangeHandlerEX(LPNMHDR pnmh) +#define NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \ + if(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNotifyRangeCodeHandlerEX(LPNMHDR pnmh) +#define NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \ + if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedCommandHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define REFLECTED_COMMAND_HANDLER_EX(id, code, func) \ + if (uMsg == OCM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define REFLECTED_COMMAND_ID_HANDLER_EX(id, func) \ + if (uMsg == OCM_COMMAND && id == LOWORD(wParam)) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define REFLECTED_COMMAND_CODE_HANDLER_EX(code, func) \ + if (uMsg == OCM_COMMAND && code == HIWORD(wParam)) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedNotifyHandlerEX(LPNMHDR pnmh) +#define REFLECTED_NOTIFY_HANDLER_EX(id, cd, func) \ + if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && id == ((LPNMHDR)lParam)->idFrom) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedNotifyIDHandlerEX(LPNMHDR pnmh) +#define REFLECTED_NOTIFY_ID_HANDLER_EX(id, func) \ + if (uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedNotifyCodeHandlerEX(LPNMHDR pnmh) +#define REFLECTED_NOTIFY_CODE_HANDLER_EX(cd, func) \ + if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define REFLECTED_COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \ + if(uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define REFLECTED_COMMAND_RANGE_CODE_HANDLER_EX(idFirst, idLast, code, func) \ + if(uMsg == OCM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedNotifyRangeHandlerEX(LPNMHDR pnmh) +#define REFLECTED_NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \ + if(uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedNotifyRangeCodeHandlerEX(LPNMHDR pnmh) +#define REFLECTED_NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \ + if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +#endif // __ATLCRACK_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlctrls.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlctrls.h new file mode 100644 index 0000000000000000000000000000000000000000..cd015102877313057277bb7a746aacd16509d743 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlctrls.h @@ -0,0 +1,10252 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLCTRLS_H__ +#define __ATLCTRLS_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atlctrls.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlctrls.h requires atlwin.h to be included first +#endif + +#ifndef _WIN32_WCE + #include + #include +#elif defined(WIN32_PLATFORM_WFSP) && !defined(_WINUSERM_H_) + #include +#endif // !_WIN32_WCE + +// protect template members from windowsx.h macros +#ifdef _INC_WINDOWSX + #undef GetNextSibling + #undef GetPrevSibling +#endif // _INC_WINDOWSX + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CStaticT - CStatic +// CButtonT - CButton +// CListBoxT - CListBox +// CComboBoxT - CComboBox +// CEditT - CEdit +// CEditCommands +// CScrollBarT - CScrollBar +// +// CImageListT - CImageList, CImageListManaged +// CListViewCtrlT - CListViewCtrl +// CTreeViewCtrlT - CTreeViewCtrl +// CTreeItemT - CTreeItem +// CTreeViewCtrlExT - CTreeViewCtrlEx +// CHeaderCtrlT - CHeaderCtrl +// CToolBarCtrlT - CToolBarCtrl +// CStatusBarCtrlT - CStatusBarCtrl +// CTabCtrlT - CTabCtrl +// CToolInfo +// CToolTipCtrlT - CToolTipCtrl +// CTrackBarCtrlT - CTrackBarCtrl +// CUpDownCtrlT - CUpDownCtrl +// CProgressBarCtrlT - CProgressBarCtrl +// CHotKeyCtrlT - CHotKeyCtrl +// CAnimateCtrlT - CAnimateCtrl +// CRichEditCtrlT - CRichEditCtrl +// CRichEditCommands +// CDragListBoxT - CDragListBox +// CDragListNotifyImpl +// CReBarCtrlT - CReBarCtrl +// CComboBoxExT - CComboBoxEx +// CDateTimePickerCtrlT - CDateTimePickerCtrl +// CMonthCalendarCtrlT - CMonthCalendarCtrl +// CFlatScrollBarImpl +// CFlatScrollBarT - CFlatScrollBar +// CIPAddressCtrlT - CIPAddressCtrl +// CPagerCtrlT - CPagerCtrl +// CLinkCtrlT - CLinkCtrl +// +// CCustomDraw +// +// CCECommandBarCtrlT - CCECommandBarCtrl +// CCECommandBandsCtrlT - CCECommandBandsCtrl + + +namespace WTL +{ + +// These are wrapper classes for Windows standard and common controls. +// To implement a window based on a control, use following: +// Example: Implementing a window based on a list box +// +// class CMyListBox : CWindowImpl +// { +// public: +// BEGIN_MSG_MAP(CMyListBox) +// // put your message handler entries here +// END_MSG_MAP() +// }; + + + +// --- Standard Windows controls --- + +/////////////////////////////////////////////////////////////////////////////// +// CStatic - client side for a Windows STATIC control + +template +class CStaticT : public TBase +{ +public: +// Constructors + CStaticT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CStaticT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return _T("STATIC"); + } + +#ifndef _WIN32_WCE + HICON GetIcon() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HICON)::SendMessage(m_hWnd, STM_GETICON, 0, 0L); + } + + HICON SetIcon(HICON hIcon) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HICON)::SendMessage(m_hWnd, STM_SETICON, (WPARAM)hIcon, 0L); + } + + HENHMETAFILE GetEnhMetaFile() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HENHMETAFILE)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_ENHMETAFILE, 0L); + } + + HENHMETAFILE SetEnhMetaFile(HENHMETAFILE hMetaFile) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HENHMETAFILE)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_ENHMETAFILE, (LPARAM)hMetaFile); + } +#else // CE specific + HICON GetIcon() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HICON)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_ICON, 0L); + } + + HICON SetIcon(HICON hIcon) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HICON)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); + } +#endif // _WIN32_WCE + + CBitmapHandle GetBitmap() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_BITMAP, 0L)); + } + + CBitmapHandle SetBitmap(HBITMAP hBitmap) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap)); + } + + HCURSOR GetCursor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HCURSOR)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_CURSOR, 0L); + } + + HCURSOR SetCursor(HCURSOR hCursor) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HCURSOR)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_CURSOR, (LPARAM)hCursor); + } +}; + +typedef CStaticT CStatic; + + +/////////////////////////////////////////////////////////////////////////////// +// CButton - client side for a Windows BUTTON control + +template +class CButtonT : public TBase +{ +public: +// Constructors + CButtonT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CButtonT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return _T("BUTTON"); + } + + UINT GetState() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, BM_GETSTATE, 0, 0L); + } + + void SetState(BOOL bHighlight) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, BM_SETSTATE, bHighlight, 0L); + } + + int GetCheck() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, BM_GETCHECK, 0, 0L); + } + + void SetCheck(int nCheck) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, BM_SETCHECK, nCheck, 0L); + } + + UINT GetButtonStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::GetWindowLong(m_hWnd, GWL_STYLE) & 0xFFFF; + } + + void SetButtonStyle(UINT nStyle, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, BM_SETSTYLE, nStyle, (LPARAM)bRedraw); + } + +#ifndef _WIN32_WCE + HICON GetIcon() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HICON)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_ICON, 0L); + } + + HICON SetIcon(HICON hIcon) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HICON)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); + } + + CBitmapHandle GetBitmap() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_BITMAP, 0L)); + } + + CBitmapHandle SetBitmap(HBITMAP hBitmap) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap)); + } +#endif // !_WIN32_WCE + +#if (_WIN32_WINNT >= 0x0501) + BOOL GetIdealSize(LPSIZE lpSize) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, BCM_GETIDEALSIZE, 0, (LPARAM)lpSize); + } + + BOOL GetImageList(PBUTTON_IMAGELIST pButtonImagelist) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, BCM_GETIMAGELIST, 0, (LPARAM)pButtonImagelist); + } + + BOOL SetImageList(PBUTTON_IMAGELIST pButtonImagelist) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, BCM_SETIMAGELIST, 0, (LPARAM)pButtonImagelist); + } + + BOOL GetTextMargin(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, BCM_GETTEXTMARGIN, 0, (LPARAM)lpRect); + } + + BOOL SetTextMargin(LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, BCM_SETTEXTMARGIN, 0, (LPARAM)lpRect); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (WINVER >= 0x0600) + void SetDontClick(BOOL bDontClick) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, BM_SETDONTCLICK, (WPARAM)bDontClick, 0L); + } +#endif // (WINVER >= 0x0600) + +#if (_WIN32_WINNT >= 0x0600) + BOOL SetDropDownState(BOOL bDropDown) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0); + return (BOOL)::SendMessage(m_hWnd, BCM_SETDROPDOWNSTATE, (WPARAM)bDropDown, 0L); + } + + BOOL GetSplitInfo(PBUTTON_SPLITINFO pSplitInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0); + return (BOOL)::SendMessage(m_hWnd, BCM_GETSPLITINFO, 0, (LPARAM)pSplitInfo); + } + + BOOL SetSplitInfo(PBUTTON_SPLITINFO pSplitInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0); + return (BOOL)::SendMessage(m_hWnd, BCM_SETSPLITINFO, 0, (LPARAM)pSplitInfo); + } + + int GetNoteLength() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0); + return (int)::SendMessage(m_hWnd, BCM_GETNOTELENGTH, 0, 0L); + } + + BOOL GetNote(LPWSTR lpstrNoteText, int cchNoteText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0); + return (BOOL)::SendMessage(m_hWnd, BCM_GETNOTE, cchNoteText, (LPARAM)lpstrNoteText); + } + + BOOL SetNote(LPCWSTR lpstrNoteText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0); + return (BOOL)::SendMessage(m_hWnd, BCM_SETNOTE, 0, (LPARAM)lpstrNoteText); + } + + LRESULT SetElevationRequiredState(BOOL bSet) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::SendMessage(m_hWnd, BCM_SETSHIELD, 0, (LPARAM)bSet); + } +#endif // (_WIN32_WINNT >= 0x0600) + +// Operations + void Click() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, BM_CLICK, 0, 0L); + } +}; + +typedef CButtonT CButton; + + +/////////////////////////////////////////////////////////////////////////////// +// CListBox - client side for a Windows LISTBOX control + +template +class CListBoxT : public TBase +{ +public: +// Constructors + CListBoxT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CListBoxT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return _T("LISTBOX"); + } + + // for entire listbox + int GetCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETCOUNT, 0, 0L); + } + +#ifndef _WIN32_WCE + int SetCount(int cItems) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(((GetStyle() & LBS_NODATA) != 0) && ((GetStyle() & LBS_HASSTRINGS) == 0)); + return (int)::SendMessage(m_hWnd, LB_SETCOUNT, cItems, 0L); + } +#endif // !_WIN32_WCE + + int GetHorizontalExtent() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETHORIZONTALEXTENT, 0, 0L); + } + + void SetHorizontalExtent(int cxExtent) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LB_SETHORIZONTALEXTENT, cxExtent, 0L); + } + + int GetTopIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETTOPINDEX, 0, 0L); + } + + int SetTopIndex(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_SETTOPINDEX, nIndex, 0L); + } + + LCID GetLocale() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LCID)::SendMessage(m_hWnd, LB_GETLOCALE, 0, 0L); + } + + LCID SetLocale(LCID nNewLocale) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LCID)::SendMessage(m_hWnd, LB_SETLOCALE, (WPARAM)nNewLocale, 0L); + } + +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + DWORD GetListBoxInfo() const + { + ATLASSERT(::IsWindow(m_hWnd)); +#if (_WIN32_WINNT >= 0x0501) + return (DWORD)::SendMessage(m_hWnd, LB_GETLISTBOXINFO, 0, 0L); +#else // !(_WIN32_WINNT >= 0x0501) + return ::GetListBoxInfo(m_hWnd); +#endif // !(_WIN32_WINNT >= 0x0501) + } +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) + + // for single-selection listboxes + int GetCurSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0); + return (int)::SendMessage(m_hWnd, LB_GETCURSEL, 0, 0L); + } + + int SetCurSel(int nSelect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0); + return (int)::SendMessage(m_hWnd, LB_SETCURSEL, nSelect, 0L); + } + + // for multiple-selection listboxes + int GetSel(int nIndex) const // also works for single-selection + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETSEL, nIndex, 0L); + } + + int SetSel(int nIndex, BOOL bSelect = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); + return (int)::SendMessage(m_hWnd, LB_SETSEL, bSelect, nIndex); + } + + int GetSelCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); + return (int)::SendMessage(m_hWnd, LB_GETSELCOUNT, 0, 0L); + } + + int GetSelItems(int nMaxItems, LPINT rgIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); + return (int)::SendMessage(m_hWnd, LB_GETSELITEMS, nMaxItems, (LPARAM)rgIndex); + } + + int GetAnchorIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); + return (int)::SendMessage(m_hWnd, LB_GETANCHORINDEX, 0, 0L); + } + + void SetAnchorIndex(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); + ::SendMessage(m_hWnd, LB_SETANCHORINDEX, nIndex, 0L); + } + + int GetCaretIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETCARETINDEX, 0, 0); + } + + int SetCaretIndex(int nIndex, BOOL bScroll = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_SETCARETINDEX, nIndex, MAKELONG(bScroll, 0)); + } + + // for listbox items + DWORD_PTR GetItemData(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD_PTR)::SendMessage(m_hWnd, LB_GETITEMDATA, nIndex, 0L); + } + + int SetItemData(int nIndex, DWORD_PTR dwItemData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_SETITEMDATA, nIndex, (LPARAM)dwItemData); + } + + void* GetItemDataPtr(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (void*)::SendMessage(m_hWnd, LB_GETITEMDATA, nIndex, 0L); + } + + int SetItemDataPtr(int nIndex, void* pData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItemData(nIndex, (DWORD_PTR)pData); + } + + int GetItemRect(int nIndex, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETITEMRECT, nIndex, (LPARAM)lpRect); + } + + int GetText(int nIndex, LPTSTR lpszBuffer) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETTEXT, nIndex, (LPARAM)lpszBuffer); + } + +#ifndef _ATL_NO_COM +#ifdef _OLEAUTO_H_ + BOOL GetTextBSTR(int nIndex, BSTR& bstrText) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrText == NULL); + + int nLen = GetTextLen(nIndex); + if(nLen == LB_ERR) + return FALSE; + + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(nLen + 1); + if(lpstrText == NULL) + return FALSE; + + if(GetText(nIndex, lpstrText) == LB_ERR) + return FALSE; + + bstrText = ::SysAllocString(T2OLE(lpstrText)); + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // _OLEAUTO_H_ +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetText(int nIndex, _CSTRING_NS::CString& strText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int cchLen = GetTextLen(nIndex); + if(cchLen == LB_ERR) + return LB_ERR; + int nRet = LB_ERR; + LPTSTR lpstr = strText.GetBufferSetLength(cchLen); + if(lpstr != NULL) + { + nRet = GetText(nIndex, lpstr); + strText.ReleaseBuffer(); + } + return nRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + int GetTextLen(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETTEXTLEN, nIndex, 0L); + } + + int GetItemHeight(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETITEMHEIGHT, nIndex, 0L); + } + + int SetItemHeight(int nIndex, UINT cyItemHeight) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_SETITEMHEIGHT, nIndex, MAKELONG(cyItemHeight, 0)); + } + + // Settable only attributes + void SetColumnWidth(int cxWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LB_SETCOLUMNWIDTH, cxWidth, 0L); + } + + BOOL SetTabStops(int nTabStops, LPINT rgTabStops) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0); + return (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops); + } + + BOOL SetTabStops() + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0); + return (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, 0, 0L); + } + + BOOL SetTabStops(const int& cxEachStop) // takes an 'int' + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0); + return (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop); + } + +// Operations + int InitStorage(int nItems, UINT nBytes) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_INITSTORAGE, (WPARAM)nItems, nBytes); + } + + void ResetContent() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LB_RESETCONTENT, 0, 0L); + } + + UINT ItemFromPoint(POINT pt, BOOL& bOutside) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dw = (DWORD)::SendMessage(m_hWnd, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y)); + bOutside = (BOOL)HIWORD(dw); + return (UINT)LOWORD(dw); + } + + // manipulating listbox items + int AddString(LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_ADDSTRING, 0, (LPARAM)lpszItem); + } + + int DeleteString(UINT nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_DELETESTRING, nIndex, 0L); + } + + int InsertString(int nIndex, LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_INSERTSTRING, nIndex, (LPARAM)lpszItem); + } + +#ifndef _WIN32_WCE + int Dir(UINT attr, LPCTSTR lpszWildCard) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_DIR, attr, (LPARAM)lpszWildCard); + } + + int AddFile(LPCTSTR lpstrFileName) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_ADDFILE, 0, (LPARAM)lpstrFileName); + } +#endif // !_WIN32_WCE + + // selection helpers + int FindString(int nStartAfter, LPCTSTR lpszItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_FINDSTRING, nStartAfter, (LPARAM)lpszItem); + } + + int FindStringExact(int nIndexStart, LPCTSTR lpszFind) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_FINDSTRINGEXACT, nIndexStart, (LPARAM)lpszFind); + } + + int SelectString(int nStartAfter, LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_SELECTSTRING, nStartAfter, (LPARAM)lpszItem); + } + + int SelItemRange(BOOL bSelect, int nFirstItem, int nLastItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); + ATLASSERT(nFirstItem <= nLastItem); + return bSelect ? (int)::SendMessage(m_hWnd, LB_SELITEMRANGEEX, nFirstItem, nLastItem) : (int)::SendMessage(m_hWnd, LB_SELITEMRANGEEX, nLastItem, nFirstItem); + } + +#ifdef WIN32_PLATFORM_WFSP // SmartPhone only messages + DWORD GetInputMode(BOOL bCurrentMode = TRUE) + { + return SendMessage(LB_GETINPUTMODE, 0, (LPARAM)bCurrentMode); + } + + BOOL SetInputMode(DWORD dwMode) + { + return SendMessage(LB_SETINPUTMODE, 0, (LPARAM)dwMode); + } +#endif // WIN32_PLATFORM_WFSP +}; + +typedef CListBoxT CListBox; + + +/////////////////////////////////////////////////////////////////////////////// +// CComboBox - client side for a Windows COMBOBOX control + +#ifndef WIN32_PLATFORM_WFSP // No COMBOBOX on SmartPhones + +template +class CComboBoxT : public TBase +{ +public: +// Constructors + CComboBoxT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CComboBoxT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return _T("COMBOBOX"); + } + + // for entire combo box + int GetCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETCOUNT, 0, 0L); + } + + int GetCurSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETCURSEL, 0, 0L); + } + + int SetCurSel(int nSelect) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SETCURSEL, nSelect, 0L); + } + + LCID GetLocale() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LCID)::SendMessage(m_hWnd, CB_GETLOCALE, 0, 0L); + } + + LCID SetLocale(LCID nNewLocale) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LCID)::SendMessage(m_hWnd, CB_SETLOCALE, (WPARAM)nNewLocale, 0L); + } + + int GetTopIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETTOPINDEX, 0, 0L); + } + + int SetTopIndex(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SETTOPINDEX, nIndex, 0L); + } + + UINT GetHorizontalExtent() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, CB_GETHORIZONTALEXTENT, 0, 0L); + } + + void SetHorizontalExtent(UINT nExtent) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, CB_SETHORIZONTALEXTENT, nExtent, 0L); + } + + int GetDroppedWidth() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETDROPPEDWIDTH, 0, 0L); + } + + int SetDroppedWidth(UINT nWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SETDROPPEDWIDTH, nWidth, 0L); + } + +#if ((WINVER >= 0x0500) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) + BOOL GetComboBoxInfo(PCOMBOBOXINFO pComboBoxInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); +#if ((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) + return (BOOL)::SendMessage(m_hWnd, CB_GETCOMBOBOXINFO, 0, (LPARAM)pComboBoxInfo); +#else // !((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) + return ::GetComboBoxInfo(m_hWnd, pComboBoxInfo); +#endif // !((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) + } +#endif // ((WINVER >= 0x0500) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) + + // for edit control + DWORD GetEditSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, CB_GETEDITSEL, 0, 0L); + } + + BOOL SetEditSel(int nStartChar, int nEndChar) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_SETEDITSEL, 0, MAKELONG(nStartChar, nEndChar)); + } + + // for combobox item + DWORD_PTR GetItemData(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD_PTR)::SendMessage(m_hWnd, CB_GETITEMDATA, nIndex, 0L); + } + + int SetItemData(int nIndex, DWORD_PTR dwItemData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SETITEMDATA, nIndex, (LPARAM)dwItemData); + } + + void* GetItemDataPtr(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (void*)GetItemData(nIndex); + } + + int SetItemDataPtr(int nIndex, void* pData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItemData(nIndex, (DWORD_PTR)pData); + } + + int GetLBText(int nIndex, LPTSTR lpszText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETLBTEXT, nIndex, (LPARAM)lpszText); + } + +#ifndef _ATL_NO_COM + BOOL GetLBTextBSTR(int nIndex, BSTR& bstrText) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrText == NULL); + + int nLen = GetLBTextLen(nIndex); + if(nLen == CB_ERR) + return FALSE; + + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(nLen + 1); + if(lpstrText == NULL) + return FALSE; + + if(GetLBText(nIndex, lpstrText) == CB_ERR) + return FALSE; + + bstrText = ::SysAllocString(T2OLE(lpstrText)); + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetLBText(int nIndex, _CSTRING_NS::CString& strText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int cchLen = GetLBTextLen(nIndex); + if(cchLen == CB_ERR) + return CB_ERR; + int nRet = CB_ERR; + LPTSTR lpstr = strText.GetBufferSetLength(cchLen); + if(lpstr != NULL) + { + nRet = GetLBText(nIndex, lpstr); + strText.ReleaseBuffer(); + } + return nRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + int GetLBTextLen(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETLBTEXTLEN, nIndex, 0L); + } + + int GetItemHeight(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETITEMHEIGHT, nIndex, 0L); + } + + int SetItemHeight(int nIndex, UINT cyItemHeight) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SETITEMHEIGHT, nIndex, MAKELONG(cyItemHeight, 0)); + } + + BOOL GetExtendedUI() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_GETEXTENDEDUI, 0, 0L); + } + + int SetExtendedUI(BOOL bExtended = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SETEXTENDEDUI, bExtended, 0L); + } + + void GetDroppedControlRect(LPRECT lprect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)lprect); + } + + BOOL GetDroppedState() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_GETDROPPEDSTATE, 0, 0L); + } + +#if (_WIN32_WINNT >= 0x0501) + int GetMinVisible() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETMINVISIBLE, 0, 0L); + } + + BOOL SetMinVisible(int nMinVisible) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_SETMINVISIBLE, nMinVisible, 0L); + } + + // Vista only + BOOL GetCueBannerText(LPWSTR lpwText, int cchText) const + { +#ifndef CB_GETCUEBANNER + const UINT CB_GETCUEBANNER = (CBM_FIRST + 4); +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_GETCUEBANNER, (WPARAM)lpwText, cchText); + } + + // Vista only + BOOL SetCueBannerText(LPCWSTR lpcwText) + { +#ifndef CB_SETCUEBANNER + const UINT CB_SETCUEBANNER = (CBM_FIRST + 3); +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_SETCUEBANNER, 0, (LPARAM)lpcwText); + } +#endif // (_WIN32_WINNT >= 0x0501) + +// Operations + int InitStorage(int nItems, UINT nBytes) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_INITSTORAGE, (WPARAM)nItems, nBytes); + } + + void ResetContent() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, CB_RESETCONTENT, 0, 0L); + } + + // for edit control + BOOL LimitText(int nMaxChars) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_LIMITTEXT, nMaxChars, 0L); + } + + // for drop-down combo boxes + void ShowDropDown(BOOL bShowIt = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, CB_SHOWDROPDOWN, bShowIt, 0L); + } + + // manipulating listbox items + int AddString(LPCTSTR lpszString) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_ADDSTRING, 0, (LPARAM)lpszString); + } + + int DeleteString(UINT nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_DELETESTRING, nIndex, 0L); + } + + int InsertString(int nIndex, LPCTSTR lpszString) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_INSERTSTRING, nIndex, (LPARAM)lpszString); + } + +#ifndef _WIN32_WCE + int Dir(UINT attr, LPCTSTR lpszWildCard) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_DIR, attr, (LPARAM)lpszWildCard); + } +#endif // !_WIN32_WCE + + // selection helpers + int FindString(int nStartAfter, LPCTSTR lpszString) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_FINDSTRING, nStartAfter, (LPARAM)lpszString); + } + + int FindStringExact(int nIndexStart, LPCTSTR lpszFind) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_FINDSTRINGEXACT, nIndexStart, (LPARAM)lpszFind); + } + + int SelectString(int nStartAfter, LPCTSTR lpszString) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SELECTSTRING, nStartAfter, (LPARAM)lpszString); + } + + // Clipboard operations + void Clear() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L); + } + + void Copy() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_COPY, 0, 0L); + } + + void Cut() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CUT, 0, 0L); + } + + void Paste() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_PASTE, 0, 0L); + } +}; + +typedef CComboBoxT CComboBox; + +#endif // !WIN32_PLATFORM_WFSP + +/////////////////////////////////////////////////////////////////////////////// +// CEdit - client side for a Windows EDIT control + +template +class CEditT : public TBase +{ +public: +// Constructors + CEditT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CEditT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return _T("EDIT"); + } + + BOOL CanUndo() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L); + } + + int GetLineCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETLINECOUNT, 0, 0L); + } + + BOOL GetModify() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L); + } + + void SetModify(BOOL bModified = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETMODIFY, bModified, 0L); + } + + void GetRect(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_GETRECT, 0, (LPARAM)lpRect); + } + + DWORD GetSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETSEL, 0, 0L); + } + + void GetSel(int& nStartChar, int& nEndChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); + } + +#ifndef _WIN32_WCE + HLOCAL GetHandle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HLOCAL)::SendMessage(m_hWnd, EM_GETHANDLE, 0, 0L); + } + + void SetHandle(HLOCAL hBuffer) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETHANDLE, (WPARAM)hBuffer, 0L); + } +#endif // !_WIN32_WCE + + DWORD GetMargins() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETMARGINS, 0, 0L); + } + + void GetMargins(UINT& nLeft, UINT& nRight) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_GETMARGINS, 0, 0L); + nLeft = LOWORD(dwRet); + nRight = HIWORD(dwRet); + } + + void SetMargins(UINT nLeft, UINT nRight, WORD wFlags = EC_LEFTMARGIN | EC_RIGHTMARGIN) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETMARGINS, wFlags, MAKELONG(nLeft, nRight)); + } + + UINT GetLimitText() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETLIMITTEXT, 0, 0L); + } + + void SetLimitText(UINT nMax) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETLIMITTEXT, nMax, 0L); + } + + POINT PosFromChar(UINT nChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_POSFROMCHAR, nChar, 0); + POINT point = { GET_X_LPARAM(dwRet), GET_Y_LPARAM(dwRet) }; + return point; + } + + int CharFromPos(POINT pt, int* pLine = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, pt.y)); + if(pLine != NULL) + *pLine = (int)(short)HIWORD(dwRet); + return (int)(short)LOWORD(dwRet); + } + + // NOTE: first word in lpszBuffer must contain the size of the buffer! + int GetLine(int nIndex, LPTSTR lpszBuffer) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer); + } + + int GetLine(int nIndex, LPTSTR lpszBuffer, int nMaxLength) const + { + ATLASSERT(::IsWindow(m_hWnd)); + *(LPWORD)lpszBuffer = (WORD)nMaxLength; + return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer); + } + + TCHAR GetPasswordChar() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (TCHAR)::SendMessage(m_hWnd, EM_GETPASSWORDCHAR, 0, 0L); + } + + void SetPasswordChar(TCHAR ch) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETPASSWORDCHAR, ch, 0L); + } + +#ifndef _WIN32_WCE + EDITWORDBREAKPROC GetWordBreakProc() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (EDITWORDBREAKPROC)::SendMessage(m_hWnd, EM_GETWORDBREAKPROC, 0, 0L); + } + + void SetWordBreakProc(EDITWORDBREAKPROC ewbprc) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETWORDBREAKPROC, 0, (LPARAM)ewbprc); + } +#endif // !_WIN32_WCE + + int GetFirstVisibleLine() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L); + } + +#ifndef _WIN32_WCE + int GetThumb() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & ES_MULTILINE) != 0); + return (int)::SendMessage(m_hWnd, EM_GETTHUMB, 0, 0L); + } +#endif // !_WIN32_WCE + + BOOL SetReadOnly(BOOL bReadOnly = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETREADONLY, bReadOnly, 0L); + } + +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + UINT GetImeStatus(UINT uStatus) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETIMESTATUS, uStatus, 0L); + } + + UINT SetImeStatus(UINT uStatus, UINT uData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_SETIMESTATUS, uStatus, uData); + } +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0501) + BOOL GetCueBannerText(LPCWSTR lpstrText, int cchText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETCUEBANNER, (WPARAM)lpstrText, cchText); + } + + // bKeepWithFocus - Vista only + BOOL SetCueBannerText(LPCWSTR lpstrText, BOOL bKeepWithFocus = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETCUEBANNER, (WPARAM)bKeepWithFocus, (LPARAM)(lpstrText)); + } +#endif // (_WIN32_WINNT >= 0x0501) + +// Operations + void EmptyUndoBuffer() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_EMPTYUNDOBUFFER, 0, 0L); + } + + BOOL FmtLines(BOOL bAddEOL) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_FMTLINES, bAddEOL, 0L); + } + + void LimitText(int nChars = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_LIMITTEXT, nChars, 0L); + } + + int LineFromChar(int nIndex = -1) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_LINEFROMCHAR, nIndex, 0L); + } + + int LineIndex(int nLine = -1) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_LINEINDEX, nLine, 0L); + } + + int LineLength(int nLine = -1) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_LINELENGTH, nLine, 0L); + } + + void LineScroll(int nLines, int nChars = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_LINESCROLL, nChars, nLines); + } + + void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM) bCanUndo, (LPARAM)lpszNewText); + } + + void SetRect(LPCRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETRECT, 0, (LPARAM)lpRect); + } + + void SetRectNP(LPCRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETRECTNP, 0, (LPARAM)lpRect); + } + + void SetSel(DWORD dwSelection, BOOL bNoScroll = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETSEL, LOWORD(dwSelection), HIWORD(dwSelection)); + if(!bNoScroll) + ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L); + } + + void SetSel(int nStartChar, int nEndChar, BOOL bNoScroll = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETSEL, nStartChar, nEndChar); + if(!bNoScroll) + ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L); + } + + void SetSelAll(BOOL bNoScroll = FALSE) + { + SetSel(0, -1, bNoScroll); + } + + void SetSelNone(BOOL bNoScroll = FALSE) + { + SetSel(-1, 0, bNoScroll); + } + + BOOL SetTabStops(int nTabStops, LPINT rgTabStops) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops); + } + + BOOL SetTabStops() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 0, 0L); + } + + BOOL SetTabStops(const int& cxEachStop) // takes an 'int' + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop); + } + + void ScrollCaret() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L); + } + + int Scroll(int nScrollAction) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & ES_MULTILINE) != 0); + LRESULT lRet = ::SendMessage(m_hWnd, EM_SCROLL, nScrollAction, 0L); + if(!(BOOL)HIWORD(lRet)) + return -1; // failed + return (int)(short)LOWORD(lRet); + + } + + void InsertText(int nInsertAfterChar, LPCTSTR lpstrText, BOOL bNoScroll = FALSE, BOOL bCanUndo = FALSE) + { + SetSel(nInsertAfterChar, nInsertAfterChar, bNoScroll); + ReplaceSel(lpstrText, bCanUndo); + } + + void AppendText(LPCTSTR lpstrText, BOOL bNoScroll = FALSE, BOOL bCanUndo = FALSE) + { + InsertText(GetWindowTextLength(), lpstrText, bNoScroll, bCanUndo); + } + +#if (_WIN32_WINNT >= 0x0501) + BOOL ShowBalloonTip(PEDITBALLOONTIP pEditBaloonTip) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SHOWBALLOONTIP, 0, (LPARAM)pEditBaloonTip); + } + + BOOL HideBalloonTip() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_HIDEBALLOONTIP, 0, 0L); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_WINNT >= 0x0600) + DWORD GetHilite() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETHILITE, 0, 0L); + } + + void GetHilite(int& nStartChar, int& nEndChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_GETHILITE, 0, 0L); + nStartChar = (int)(short)LOWORD(dwRet); + nEndChar = (int)(short)HIWORD(dwRet); + } + + void SetHilite(int nStartChar, int nEndChar) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETHILITE, nStartChar, nEndChar); + } +#endif // (_WIN32_WINNT >= 0x0600) + + // Clipboard operations + BOOL Undo() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_UNDO, 0, 0L); + } + + void Clear() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L); + } + + void Copy() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_COPY, 0, 0L); + } + + void Cut() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CUT, 0, 0L); + } + + void Paste() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_PASTE, 0, 0L); + } + +#ifdef WIN32_PLATFORM_WFSP // SmartPhone only messages + DWORD GetExtendedStyle() + { + return SendMessage(EM_GETEXTENDEDSTYLE); + } + + DWORD SetExtendedStyle(DWORD dwMask, DWORD dwExStyle) + { + return SendMessage(EM_SETEXTENDEDSTYLE, (WPARAM)dwMask, (LPARAM)dwExStyle); + } + + DWORD GetInputMode(BOOL bCurrentMode = TRUE) + { + return SendMessage(EM_GETINPUTMODE, 0, (LPARAM)bCurrentMode); + } + + BOOL SetInputMode(DWORD dwMode) + { + return SendMessage(EM_SETINPUTMODE, 0, (LPARAM)dwMode); + } + + BOOL SetSymbols(LPCTSTR szSymbols) + { + return SendMessage(EM_SETSYMBOLS, 0, (LPARAM)szSymbols); + } + + BOOL ResetSymbols() + { + return SendMessage(EM_SETSYMBOLS); + } +#endif // WIN32_PLATFORM_WFSP +}; + +typedef CEditT CEdit; + + +/////////////////////////////////////////////////////////////////////////////// +// CEditCommands - message handlers for standard EDIT commands + +// Chain to CEditCommands message map. Your class must also derive from CEdit. +// Example: +// class CMyEdit : public CWindowImpl, +// public CEditCommands +// { +// public: +// BEGIN_MSG_MAP(CMyEdit) +// // your handlers... +// CHAIN_MSG_MAP_ALT(CEditCommands, 1) +// END_MSG_MAP() +// // other stuff... +// }; + +template +class CEditCommands +{ +public: + BEGIN_MSG_MAP(CEditCommands< T >) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_EDIT_CLEAR, OnEditClear) + COMMAND_ID_HANDLER(ID_EDIT_CLEAR_ALL, OnEditClearAll) + COMMAND_ID_HANDLER(ID_EDIT_COPY, OnEditCopy) + COMMAND_ID_HANDLER(ID_EDIT_CUT, OnEditCut) + COMMAND_ID_HANDLER(ID_EDIT_PASTE, OnEditPaste) + COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, OnEditSelectAll) + COMMAND_ID_HANDLER(ID_EDIT_UNDO, OnEditUndo) + END_MSG_MAP() + + LRESULT OnEditClear(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Clear(); + return 0; + } + + LRESULT OnEditClearAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->SetSel(0, -1); + pT->Clear(); + return 0; + } + + LRESULT OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Copy(); + return 0; + } + + LRESULT OnEditCut(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Cut(); + return 0; + } + + LRESULT OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Paste(); + return 0; + } + + LRESULT OnEditSelectAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->SetSel(0, -1); + return 0; + } + + LRESULT OnEditUndo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Undo(); + return 0; + } + +// State (update UI) helpers + BOOL CanCut() const + { return HasSelection(); } + + BOOL CanCopy() const + { return HasSelection(); } + + BOOL CanClear() const + { return HasSelection(); } + + BOOL CanSelectAll() const + { return HasText(); } + + BOOL CanFind() const + { return HasText(); } + + BOOL CanRepeat() const + { return HasText(); } + + BOOL CanReplace() const + { return HasText(); } + + BOOL CanClearAll() const + { return HasText(); } + +// Implementation + BOOL HasSelection() const + { + const T* pT = static_cast(this); + int nMin = 0, nMax = 0; + ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nMin, (LPARAM)&nMax); + return (nMin != nMax); + } + + BOOL HasText() const + { + const T* pT = static_cast(this); + return (pT->GetWindowTextLength() > 0); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CScrollBar - client side for a Windows SCROLLBAR control + +template +class CScrollBarT : public TBase +{ +public: +// Constructors + CScrollBarT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CScrollBarT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return _T("SCROLLBAR"); + } + +#ifndef _WIN32_WCE + int GetScrollPos() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::GetScrollPos(m_hWnd, SB_CTL); + } +#endif // !_WIN32_WCE + + int SetScrollPos(int nPos, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::SetScrollPos(m_hWnd, SB_CTL, nPos, bRedraw); + } + +#ifndef _WIN32_WCE + void GetScrollRange(LPINT lpMinPos, LPINT lpMaxPos) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::GetScrollRange(m_hWnd, SB_CTL, lpMinPos, lpMaxPos); + } +#endif // !_WIN32_WCE + + void SetScrollRange(int nMinPos, int nMaxPos, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SetScrollRange(m_hWnd, SB_CTL, nMinPos, nMaxPos, bRedraw); + } + + BOOL GetScrollInfo(LPSCROLLINFO lpScrollInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::GetScrollInfo(m_hWnd, SB_CTL, lpScrollInfo); + } + + int SetScrollInfo(LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::SetScrollInfo(m_hWnd, SB_CTL, lpScrollInfo, bRedraw); + } + +#ifndef _WIN32_WCE + int GetScrollLimit() const + { + SCROLLINFO info = { sizeof(SCROLLINFO), SIF_RANGE | SIF_PAGE }; + ::GetScrollInfo(m_hWnd, SB_CTL, &info); + if(info.nPage > 1) + info.nMax -= info.nPage - 1; + + return info.nMax; + } + +#if (WINVER >= 0x0500) + BOOL GetScrollBarInfo(PSCROLLBARINFO pScrollBarInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); +#if (_WIN32_WINNT >= 0x0501) + return (BOOL)::SendMessage(m_hWnd, SBM_GETSCROLLBARINFO, 0, (LPARAM)pScrollBarInfo); +#else // !(_WIN32_WINNT >= 0x0501) + return ::GetScrollBarInfo(m_hWnd, OBJID_CLIENT, pScrollBarInfo); +#endif // !(_WIN32_WINNT >= 0x0501) + } +#endif // (WINVER >= 0x0500) + +// Operations + void ShowScrollBar(BOOL bShow = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::ShowScrollBar(m_hWnd, SB_CTL, bShow); + } + + BOOL EnableScrollBar(UINT nArrowFlags = ESB_ENABLE_BOTH) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::EnableScrollBar(m_hWnd, SB_CTL, nArrowFlags); + } +#endif // !_WIN32_WCE +}; + +typedef CScrollBarT CScrollBar; + + +// --- Windows Common Controls --- + +/////////////////////////////////////////////////////////////////////////////// +// CImageList + +// forward declarations +template class CImageListT; +typedef CImageListT CImageList; +typedef CImageListT CImageListManaged; + + +template +class CImageListT +{ +public: +// Data members + HIMAGELIST m_hImageList; + +// Constructor/destructor/operators + CImageListT(HIMAGELIST hImageList = NULL) : m_hImageList(hImageList) + { } + + ~CImageListT() + { + if(t_bManaged && (m_hImageList != NULL)) + Destroy(); + } + + CImageListT& operator =(HIMAGELIST hImageList) + { + Attach(hImageList); + return *this; + } + + void Attach(HIMAGELIST hImageList) + { + if(t_bManaged && (m_hImageList != NULL) && (m_hImageList != hImageList)) + ImageList_Destroy(m_hImageList); + m_hImageList = hImageList; + } + + HIMAGELIST Detach() + { + HIMAGELIST hImageList = m_hImageList; + m_hImageList = NULL; + return hImageList; + } + + operator HIMAGELIST() const { return m_hImageList; } + + bool IsNull() const { return (m_hImageList == NULL); } + +// Attributes + int GetImageCount() const + { + ATLASSERT(m_hImageList != NULL); + return ImageList_GetImageCount(m_hImageList); + } + + COLORREF GetBkColor() const + { + ATLASSERT(m_hImageList != NULL); + return ImageList_GetBkColor(m_hImageList); + } + + COLORREF SetBkColor(COLORREF cr) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetBkColor(m_hImageList, cr); + } + + BOOL GetImageInfo(int nImage, IMAGEINFO* pImageInfo) const + { + ATLASSERT(m_hImageList != NULL); + return ImageList_GetImageInfo(m_hImageList, nImage, pImageInfo); + } + + HICON GetIcon(int nIndex, UINT uFlags = ILD_NORMAL) const + { + ATLASSERT(m_hImageList != NULL); + return ImageList_GetIcon(m_hImageList, nIndex, uFlags); + } + + BOOL GetIconSize(int& cx, int& cy) const + { + ATLASSERT(m_hImageList != NULL); + return ImageList_GetIconSize(m_hImageList, &cx, &cy); + } + + BOOL GetIconSize(SIZE& size) const + { + ATLASSERT(m_hImageList != NULL); + return ImageList_GetIconSize(m_hImageList, (int*)&size.cx, (int*)&size.cy); + } + + BOOL SetIconSize(int cx, int cy) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetIconSize(m_hImageList, cx, cy); + } + + BOOL SetIconSize(SIZE size) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetIconSize(m_hImageList, size.cx, size.cy); + } + + BOOL SetImageCount(UINT uNewCount) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetImageCount(m_hImageList, uNewCount); + } + + BOOL SetOverlayImage(int nImage, int nOverlay) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetOverlayImage(m_hImageList, nImage, nOverlay); + } + +// Operations + BOOL Create(int cx, int cy, UINT nFlags, int nInitial, int nGrow) + { + ATLASSERT(m_hImageList == NULL); + m_hImageList = ImageList_Create(cx, cy, nFlags, nInitial, nGrow); + return (m_hImageList != NULL) ? TRUE : FALSE; + } + + BOOL Create(ATL::_U_STRINGorID bitmap, int cx, int nGrow, COLORREF crMask) + { + ATLASSERT(m_hImageList == NULL); + m_hImageList = ImageList_LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr, cx, nGrow, crMask); + return (m_hImageList != NULL) ? TRUE : FALSE; + } + + BOOL CreateFromImage(ATL::_U_STRINGorID image, int cx, int nGrow, COLORREF crMask, UINT uType, UINT uFlags = LR_DEFAULTCOLOR | LR_DEFAULTSIZE) + { + ATLASSERT(m_hImageList == NULL); + m_hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), image.m_lpstr, cx, nGrow, crMask, uType, uFlags); + return (m_hImageList != NULL) ? TRUE : FALSE; + } + + BOOL Merge(HIMAGELIST hImageList1, int nImage1, HIMAGELIST hImageList2, int nImage2, int dx, int dy) + { + ATLASSERT(m_hImageList == NULL); + m_hImageList = ImageList_Merge(hImageList1, nImage1, hImageList2, nImage2, dx, dy); + return (m_hImageList != NULL) ? TRUE : FALSE; + } + +#ifndef _WIN32_WCE +#ifdef __IStream_INTERFACE_DEFINED__ + BOOL CreateFromStream(LPSTREAM lpStream) + { + ATLASSERT(m_hImageList == NULL); + m_hImageList = ImageList_Read(lpStream); + return (m_hImageList != NULL) ? TRUE : FALSE; + } +#endif // __IStream_INTERFACE_DEFINED__ +#endif // !_WIN32_WCE + + BOOL Destroy() + { + if (m_hImageList == NULL) + return FALSE; + BOOL bRet = ImageList_Destroy(m_hImageList); + if(bRet) + m_hImageList = NULL; + return bRet; + } + + int Add(HBITMAP hBitmap, HBITMAP hBitmapMask = NULL) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_Add(m_hImageList, hBitmap, hBitmapMask); + } + + int Add(HBITMAP hBitmap, COLORREF crMask) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_AddMasked(m_hImageList, hBitmap, crMask); + } + + BOOL Remove(int nImage) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_Remove(m_hImageList, nImage); + } + + BOOL RemoveAll() + { + ATLASSERT(m_hImageList != NULL); + return ImageList_RemoveAll(m_hImageList); + } + + BOOL Replace(int nImage, HBITMAP hBitmap, HBITMAP hBitmapMask) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_Replace(m_hImageList, nImage, hBitmap, hBitmapMask); + } + + int AddIcon(HICON hIcon) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_AddIcon(m_hImageList, hIcon); + } + + int ReplaceIcon(int nImage, HICON hIcon) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_ReplaceIcon(m_hImageList, nImage, hIcon); + } + + HICON ExtractIcon(int nImage) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_ExtractIcon(NULL, m_hImageList, nImage); + } + + BOOL Draw(HDC hDC, int nImage, int x, int y, UINT nStyle) + { + ATLASSERT(m_hImageList != NULL); + ATLASSERT(hDC != NULL); + return ImageList_Draw(m_hImageList, nImage, hDC, x, y, nStyle); + } + + BOOL Draw(HDC hDC, int nImage, POINT pt, UINT nStyle) + { + ATLASSERT(m_hImageList != NULL); + ATLASSERT(hDC != NULL); + return ImageList_Draw(m_hImageList, nImage, hDC, pt.x, pt.y, nStyle); + } + + BOOL DrawEx(int nImage, HDC hDC, int x, int y, int dx, int dy, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle) + { + ATLASSERT(m_hImageList != NULL); + ATLASSERT(hDC != NULL); + return ImageList_DrawEx(m_hImageList, nImage, hDC, x, y, dx, dy, rgbBk, rgbFg, fStyle); + } + + BOOL DrawEx(int nImage, HDC hDC, RECT& rect, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle) + { + ATLASSERT(m_hImageList != NULL); + ATLASSERT(hDC != NULL); + return ImageList_DrawEx(m_hImageList, nImage, hDC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, rgbBk, rgbFg, fStyle); + } + + static BOOL DrawIndirect(IMAGELISTDRAWPARAMS* pimldp) + { + return ImageList_DrawIndirect(pimldp); + } + + BOOL Copy(int nSrc, int nDst, UINT uFlags = ILCF_MOVE) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_Copy(m_hImageList, nDst, m_hImageList, nSrc, uFlags); + } + +#ifdef __IStream_INTERFACE_DEFINED__ +#ifndef _WIN32_WCE + static HIMAGELIST Read(LPSTREAM lpStream) + { + return ImageList_Read(lpStream); + } + + BOOL Write(LPSTREAM lpStream) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_Write(m_hImageList, lpStream); + } +#endif // !_WIN32_WCE + +#if (_WIN32_WINNT >= 0x0501) + static HRESULT ReadEx(DWORD dwFlags, LPSTREAM lpStream, REFIID riid, PVOID* ppv) + { + return ImageList_ReadEx(dwFlags, lpStream, riid, ppv); + } + + HRESULT WriteEx(DWORD dwFlags, LPSTREAM lpStream) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_WriteEx(m_hImageList, dwFlags, lpStream); + } +#endif // (_WIN32_WINNT >= 0x0501) +#endif // __IStream_INTERFACE_DEFINED__ + + // Drag operations + BOOL BeginDrag(int nImage, POINT ptHotSpot) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_BeginDrag(m_hImageList, nImage, ptHotSpot.x, ptHotSpot.y); + } + + BOOL BeginDrag(int nImage, int xHotSpot, int yHotSpot) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_BeginDrag(m_hImageList, nImage, xHotSpot, yHotSpot); + } + + static void EndDrag() + { + ImageList_EndDrag(); + } + + static BOOL DragMove(POINT pt) + { + return ImageList_DragMove(pt.x, pt.y); + } + + static BOOL DragMove(int x, int y) + { + return ImageList_DragMove(x, y); + } + + BOOL SetDragCursorImage(int nDrag, POINT ptHotSpot) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetDragCursorImage(m_hImageList, nDrag, ptHotSpot.x, ptHotSpot.y); + } + + BOOL SetDragCursorImage(int nDrag, int xHotSpot, int yHotSpot) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetDragCursorImage(m_hImageList, nDrag, xHotSpot, yHotSpot); + } + + static BOOL DragShowNolock(BOOL bShow = TRUE) + { + return ImageList_DragShowNolock(bShow); + } + + static CImageList GetDragImage(LPPOINT lpPoint, LPPOINT lpPointHotSpot) + { + return CImageList(ImageList_GetDragImage(lpPoint, lpPointHotSpot)); + } + + static BOOL DragEnter(HWND hWnd, POINT point) + { + return ImageList_DragEnter(hWnd, point.x, point.y); + } + + static BOOL DragEnter(HWND hWnd, int x, int y) + { + return ImageList_DragEnter(hWnd, x, y); + } + + static BOOL DragLeave(HWND hWnd) + { + return ImageList_DragLeave(hWnd); + } + +#if (_WIN32_IE >= 0x0400) + CImageList Duplicate() const + { + ATLASSERT(m_hImageList != NULL); + return CImageList(ImageList_Duplicate(m_hImageList)); + } + + static CImageList Duplicate(HIMAGELIST hImageList) + { + ATLASSERT(hImageList != NULL); + return CImageList(ImageList_Duplicate(hImageList)); + } +#endif // (_WIN32_IE >= 0x0400) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CToolTipCtrl + +#ifndef _WIN32_WCE + +class CToolInfo : public TOOLINFO +{ +public: + CToolInfo(UINT nFlags, HWND hWnd, UINT_PTR nIDTool = 0, LPRECT lpRect = NULL, LPTSTR lpstrText = LPSTR_TEXTCALLBACK, LPARAM lUserParam = NULL) + { + Init(nFlags, hWnd, nIDTool, lpRect, lpstrText, lUserParam); + } + + operator LPTOOLINFO() { return this; } + + operator LPARAM() { return (LPARAM)this; } + + void Init(UINT nFlags, HWND hWnd, UINT_PTR nIDTool = 0, LPRECT lpRect = NULL, LPTSTR lpstrText = LPSTR_TEXTCALLBACK, LPARAM lUserParam = NULL) + { + ATLASSERT(::IsWindow(hWnd)); + memset(this, 0, sizeof(TOOLINFO)); + cbSize = RunTimeHelper::SizeOf_TOOLINFO(); + uFlags = nFlags; + if(nIDTool == 0) + { + hwnd = ::GetParent(hWnd); + uFlags |= TTF_IDISHWND; + uId = (UINT_PTR)hWnd; + } + else + { + hwnd = hWnd; + uId = nIDTool; + } + if(lpRect != NULL) + rect = *lpRect; + hinst = ModuleHelper::GetResourceInstance(); + lpszText = lpstrText; + lParam = lUserParam; + } +}; + +template +class CToolTipCtrlT : public TBase +{ +public: +// Constructors + CToolTipCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CToolTipCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return TOOLTIPS_CLASS; + } + + void GetText(LPTOOLINFO lpToolInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_GETTEXT, 0, (LPARAM)&lpToolInfo); + } + + void GetText(LPTSTR lpstrText, HWND hWnd, UINT_PTR nIDTool = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + CToolInfo ti(0, hWnd, nIDTool, NULL, lpstrText); + ::SendMessage(m_hWnd, TTM_GETTEXT, 0, ti); + } + + BOOL GetToolInfo(LPTOOLINFO lpToolInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_GETTOOLINFO, 0, (LPARAM)lpToolInfo); + } + + BOOL GetToolInfo(HWND hWnd, UINT_PTR nIDTool, UINT* puFlags, LPRECT lpRect, LPTSTR lpstrText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + ATLASSERT(puFlags != NULL); + ATLASSERT(lpRect != NULL); + CToolInfo ti(0, hWnd, nIDTool, NULL, lpstrText); + BOOL bRet = (BOOL)::SendMessage(m_hWnd, TTM_GETTOOLINFO, 0, ti); + if(bRet != FALSE) + { + *puFlags = ti.uFlags; + *lpRect = ti.rect; + } + return bRet; + } + + void SetToolInfo(LPTOOLINFO lpToolInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_SETTOOLINFO, 0, (LPARAM)lpToolInfo); + } + + void SetToolRect(LPTOOLINFO lpToolInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_NEWTOOLRECT, 0, (LPARAM)lpToolInfo); + } + + void SetToolRect(HWND hWnd, UINT_PTR nIDTool, LPCRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + ATLASSERT(nIDTool != 0); + + CToolInfo ti(0, hWnd, nIDTool, (LPRECT)lpRect, NULL); + ::SendMessage(m_hWnd, TTM_NEWTOOLRECT, 0, ti); + } + + int GetToolCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TTM_GETTOOLCOUNT, 0, 0L); + } + + int GetDelayTime(DWORD dwType) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TTM_GETDELAYTIME, dwType, 0L); + } + + void SetDelayTime(DWORD dwType, int nTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_SETDELAYTIME, dwType, MAKELPARAM(nTime, 0)); + } + + void GetMargin(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_GETMARGIN, 0, (LPARAM)lpRect); + } + + void SetMargin(LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_SETMARGIN, 0, (LPARAM)lpRect); + } + + int GetMaxTipWidth() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TTM_GETMAXTIPWIDTH, 0, 0L); + } + + int SetMaxTipWidth(int nWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TTM_SETMAXTIPWIDTH, 0, nWidth); + } + + COLORREF GetTipBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TTM_GETTIPBKCOLOR, 0, 0L); + } + + void SetTipBkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_SETTIPBKCOLOR, (WPARAM)clr, 0L); + } + + COLORREF GetTipTextColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TTM_GETTIPTEXTCOLOR, 0, 0L); + } + + void SetTipTextColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_SETTIPTEXTCOLOR, (WPARAM)clr, 0L); + } + + BOOL GetCurrentTool(LPTOOLINFO lpToolInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_GETCURRENTTOOL, 0, (LPARAM)lpToolInfo); + } + +#if (_WIN32_IE >= 0x0500) + SIZE GetBubbleSize(LPTOOLINFO lpToolInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TTM_GETBUBBLESIZE, 0, (LPARAM)lpToolInfo); + SIZE size = { GET_X_LPARAM(dwRet), GET_Y_LPARAM(dwRet) }; + return size; + } + + BOOL SetTitle(UINT_PTR uIcon, LPCTSTR lpstrTitle) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_SETTITLE, uIcon, (LPARAM)lpstrTitle); + } + + BOOL SetTitle(HICON hIcon, LPCTSTR lpstrTitle) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_SETTITLE, (WPARAM)hIcon, (LPARAM)lpstrTitle); + } +#endif // (_WIN32_IE >= 0x0500) + +#if (_WIN32_WINNT >= 0x0501) + void GetTitle(PTTGETTITLE pTTGetTitle) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_GETTITLE, 0, (LPARAM)pTTGetTitle); + } + + void SetWindowTheme(LPCWSTR lpstrTheme) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme); + } +#endif // (_WIN32_WINNT >= 0x0501) + +// Operations + void Activate(BOOL bActivate) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_ACTIVATE, bActivate, 0L); + } + + BOOL AddTool(LPTOOLINFO lpToolInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_ADDTOOL, 0, (LPARAM)lpToolInfo); + } + + BOOL AddTool(HWND hWnd, ATL::_U_STRINGorID text = LPSTR_TEXTCALLBACK, LPCRECT lpRectTool = NULL, UINT_PTR nIDTool = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + // the toolrect and toolid must both be zero or both valid + ATLASSERT((lpRectTool != NULL && nIDTool != 0) || (lpRectTool == NULL && nIDTool == 0)); + + CToolInfo ti(0, hWnd, nIDTool, (LPRECT)lpRectTool, (LPTSTR)text.m_lpstr); + return (BOOL)::SendMessage(m_hWnd, TTM_ADDTOOL, 0, ti); + } + + void DelTool(LPTOOLINFO lpToolInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_DELTOOL, 0, (LPARAM)lpToolInfo); + } + + void DelTool(HWND hWnd, UINT_PTR nIDTool = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + + CToolInfo ti(0, hWnd, nIDTool, NULL, NULL); + ::SendMessage(m_hWnd, TTM_DELTOOL, 0, ti); + } + + BOOL HitTest(LPTTHITTESTINFO lpHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_HITTEST, 0, (LPARAM)lpHitTestInfo); + } + + BOOL HitTest(HWND hWnd, POINT pt, LPTOOLINFO lpToolInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + ATLASSERT(lpToolInfo != NULL); + + TTHITTESTINFO hti = { 0 }; + hti.ti.cbSize = RunTimeHelper::SizeOf_TOOLINFO(); + hti.hwnd = hWnd; + hti.pt.x = pt.x; + hti.pt.y = pt.y; + if((BOOL)::SendMessage(m_hWnd, TTM_HITTEST, 0, (LPARAM)&hti) != FALSE) + { + *lpToolInfo = hti.ti; + return TRUE; + } + return FALSE; + } + + void RelayEvent(LPMSG lpMsg) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_RELAYEVENT, 0, (LPARAM)lpMsg); + } + + void UpdateTipText(LPTOOLINFO lpToolInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_UPDATETIPTEXT, 0, (LPARAM)lpToolInfo); + } + + void UpdateTipText(ATL::_U_STRINGorID text, HWND hWnd, UINT_PTR nIDTool = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + + CToolInfo ti(0, hWnd, nIDTool, NULL, (LPTSTR)text.m_lpstr); + ::SendMessage(m_hWnd, TTM_UPDATETIPTEXT, 0, ti); + } + + BOOL EnumTools(UINT_PTR nTool, LPTOOLINFO lpToolInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_ENUMTOOLS, nTool, (LPARAM)lpToolInfo); + } + + void Pop() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_POP, 0, 0L); + } + + void TrackActivate(LPTOOLINFO lpToolInfo, BOOL bActivate) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_TRACKACTIVATE, bActivate, (LPARAM)lpToolInfo); + } + + void TrackActivate(HWND hWnd, UINT_PTR nIDTool, BOOL bActivate) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + + CToolInfo ti(0, hWnd, nIDTool); + ::SendMessage(m_hWnd, TTM_TRACKACTIVATE, bActivate, ti); + } + + void TrackPosition(int xPos, int yPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_TRACKPOSITION, 0, MAKELPARAM(xPos, yPos)); + } + +#if (_WIN32_IE >= 0x0400) + void Update() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_UPDATE, 0, 0L); + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) + BOOL AdjustRect(LPRECT lpRect, BOOL bLarger /*= TRUE*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_ADJUSTRECT, bLarger, (LPARAM)lpRect); + } +#endif // (_WIN32_IE >= 0x0500) + +#if (_WIN32_WINNT >= 0x0501) + void Popup() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_POPUP, 0, 0L); + } +#endif // (_WIN32_WINNT >= 0x0501) +}; + +typedef CToolTipCtrlT CToolTipCtrl; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CHeaderCtrl + +template +class CHeaderCtrlT : public TBase +{ +public: +// Constructors + CHeaderCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CHeaderCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_HEADER; + } + + int GetItemCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_GETITEMCOUNT, 0, 0L); + } + + BOOL GetItem(int nIndex, LPHDITEM pHeaderItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_GETITEM, nIndex, (LPARAM)pHeaderItem); + } + + BOOL SetItem(int nIndex, LPHDITEM pHeaderItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_SETITEM, nIndex, (LPARAM)pHeaderItem); + } + + CImageList GetImageList() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_GETIMAGELIST, 0, 0L)); + } + + CImageList SetImageList(HIMAGELIST hImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_SETIMAGELIST, 0, (LPARAM)hImageList)); + } + + BOOL GetOrderArray(int nSize, int* lpnArray) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_GETORDERARRAY, nSize, (LPARAM)lpnArray); + } + + BOOL SetOrderArray(int nSize, int* lpnArray) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_SETORDERARRAY, nSize, (LPARAM)lpnArray); + } + + BOOL GetItemRect(int nIndex, LPRECT lpItemRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_GETITEMRECT, nIndex, (LPARAM)lpItemRect); + } + + int SetHotDivider(BOOL bPos, DWORD dwInputValue) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_SETHOTDIVIDER, bPos, dwInputValue); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + int GetBitmapMargin() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_GETBITMAPMARGIN, 0, 0L); + } + + int SetBitmapMargin(int nWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_SETBITMAPMARGIN, nWidth, 0L); + } + + int SetFilterChangeTimeout(DWORD dwTimeOut) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_SETFILTERCHANGETIMEOUT, 0, dwTimeOut); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0600) + BOOL GetItemDropDownRect(int nIndex, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_GETITEMDROPDOWNRECT, nIndex, (LPARAM)lpRect); + } + + BOOL GetOverflowRect(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_GETOVERFLOWRECT, 0, (LPARAM)lpRect); + } + + int GetFocusedItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_GETFOCUSEDITEM, 0, 0L); + } + + BOOL SetFocusedItem(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_SETFOCUSEDITEM, 0, nIndex); + } +#endif // (_WIN32_WINNT >= 0x0600) + +// Operations + int InsertItem(int nIndex, LPHDITEM phdi) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_INSERTITEM, nIndex, (LPARAM)phdi); + } + + int AddItem(LPHDITEM phdi) + { + return InsertItem(GetItemCount(), phdi); + } + + BOOL DeleteItem(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_DELETEITEM, nIndex, 0L); + } + + BOOL Layout(HD_LAYOUT* pHeaderLayout) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_LAYOUT, 0, (LPARAM)pHeaderLayout); + } + + int HitTest(LPHDHITTESTINFO lpHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_HITTEST, 0, (LPARAM)lpHitTestInfo); + } + + int OrderToIndex(int nOrder) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_ORDERTOINDEX, nOrder, 0L); + } + + CImageList CreateDragImage(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_CREATEDRAGIMAGE, nIndex, 0L)); + } + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + int EditFilter(int nColumn, BOOL bDiscardChanges) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_EDITFILTER, nColumn, MAKELPARAM(bDiscardChanges, 0)); + } + + int ClearFilter(int nColumn) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_CLEARFILTER, nColumn, 0L); + } + + int ClearAllFilters() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_CLEARFILTER, (WPARAM)-1, 0L); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +}; + +typedef CHeaderCtrlT CHeaderCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CListViewCtrl + +template +class CListViewCtrlT : public TBase +{ +public: +// Constructors + CListViewCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CListViewCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_LISTVIEW; + } + + COLORREF GetBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_GETBKCOLOR, 0, 0L); + } + + BOOL SetBkColor(COLORREF cr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETBKCOLOR, 0, cr); + } + + CImageList GetImageList(int nImageListType) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_GETIMAGELIST, nImageListType, 0L)); + } + + CImageList SetImageList(HIMAGELIST hImageList, int nImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_SETIMAGELIST, nImageList, (LPARAM)hImageList)); + } + + int GetItemCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETITEMCOUNT, 0, 0L); + } + + BOOL SetItemCount(int nItems) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMCOUNT, nItems, 0L); + } + + BOOL GetItem(LPLVITEM pItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)pItem); + } + + BOOL SetItem(const LVITEM* pItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEM, 0, (LPARAM)pItem); + } + + BOOL SetItem(int nItem, int nSubItem, UINT nMask, LPCTSTR lpszItem, + int nImage, UINT nState, UINT nStateMask, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.mask = nMask; + lvi.iItem = nItem; + lvi.iSubItem = nSubItem; + lvi.stateMask = nStateMask; + lvi.state = nState; + lvi.pszText = (LPTSTR) lpszItem; + lvi.iImage = nImage; + lvi.lParam = lParam; + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEM, 0, (LPARAM)&lvi); + } + + UINT GetItemState(int nItem, UINT nMask) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, LVM_GETITEMSTATE, nItem, nMask); + } + + BOOL SetItemState(int nItem, UINT nState, UINT nStateMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.state = nState; + lvi.stateMask = nStateMask; + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMSTATE, nItem, (LPARAM)&lvi); + } + + BOOL SetItemState(int nItem, LPLVITEM pItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMSTATE, nItem, (LPARAM)pItem); + } + +#ifndef _ATL_NO_COM + BOOL GetItemText(int nItem, int nSubItem, BSTR& bstrText) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrText == NULL); + LVITEM lvi = { 0 }; + lvi.iSubItem = nSubItem; + + LPTSTR lpstrText = NULL; + int nRes = 0; + for(int nLen = 256; ; nLen *= 2) + { + ATLTRY(lpstrText = new TCHAR[nLen]); + if(lpstrText == NULL) + break; + lpstrText[0] = NULL; + lvi.cchTextMax = nLen; + lvi.pszText = lpstrText; + nRes = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi); + if(nRes < nLen - 1) + break; + delete [] lpstrText; + lpstrText = NULL; + } + + if(lpstrText != NULL) + { + if(nRes != 0) + bstrText = ::SysAllocString(T2OLE(lpstrText)); + delete [] lpstrText; + } + + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetItemText(int nItem, int nSubItem, _CSTRING_NS::CString& strText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.iSubItem = nSubItem; + + strText.Empty(); + int nRes = 0; + for(int nLen = 256; ; nLen *= 2) + { + lvi.cchTextMax = nLen; + lvi.pszText = strText.GetBufferSetLength(nLen); + if(lvi.pszText == NULL) + { + nRes = 0; + break; + } + nRes = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi); + if(nRes < nLen - 1) + break; + } + strText.ReleaseBuffer(); + return nRes; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + int GetItemText(int nItem, int nSubItem, LPTSTR lpszText, int nLen) const + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.iSubItem = nSubItem; + lvi.cchTextMax = nLen; + lvi.pszText = lpszText; + return (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi); + } + + BOOL SetItemText(int nItem, int nSubItem, LPCTSTR lpszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(nItem, nSubItem, LVIF_TEXT, lpszText, 0, 0, 0, 0); + } + + DWORD_PTR GetItemData(int nItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.iItem = nItem; + lvi.mask = LVIF_PARAM; + BOOL bRet = (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)&lvi); + return (DWORD_PTR)(bRet ? lvi.lParam : NULL); + } + + BOOL SetItemData(int nItem, DWORD_PTR dwData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(nItem, 0, LVIF_PARAM, NULL, 0, 0, 0, (LPARAM)dwData); + } + + UINT GetCallbackMask() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, LVM_GETCALLBACKMASK, 0, 0L); + } + + BOOL SetCallbackMask(UINT nMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETCALLBACKMASK, nMask, 0L); + } + + BOOL GetItemPosition(int nItem, LPPOINT lpPoint) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETITEMPOSITION, nItem, (LPARAM)lpPoint); + } + + BOOL SetItemPosition(int nItem, POINT pt) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(((GetStyle() & LVS_TYPEMASK) == LVS_ICON) || ((GetStyle() & LVS_TYPEMASK) == LVS_SMALLICON)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMPOSITION32, nItem, (LPARAM)&pt); + } + + BOOL SetItemPosition(int nItem, int x, int y) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(((GetStyle() & LVS_TYPEMASK) == LVS_ICON) || ((GetStyle() & LVS_TYPEMASK) == LVS_SMALLICON)); + POINT pt = { x, y }; + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMPOSITION32, nItem, (LPARAM)&pt); + } + + int GetStringWidth(LPCTSTR lpsz) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETSTRINGWIDTH, 0, (LPARAM)lpsz); + } + + CEdit GetEditControl() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CEdit((HWND)::SendMessage(m_hWnd, LVM_GETEDITCONTROL, 0, 0L)); + } + + BOOL GetColumn(int nCol, LVCOLUMN* pColumn) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETCOLUMN, nCol, (LPARAM)pColumn); + } + + BOOL SetColumn(int nCol, const LVCOLUMN* pColumn) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMN, nCol, (LPARAM)pColumn); + } + + int GetColumnWidth(int nCol) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETCOLUMNWIDTH, nCol, 0L); + } + + BOOL SetColumnWidth(int nCol, int cx) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMNWIDTH, nCol, MAKELPARAM(cx, 0)); + } + + BOOL GetViewRect(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETVIEWRECT, 0, (LPARAM)lpRect); + } + + COLORREF GetTextColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_GETTEXTCOLOR, 0, 0L); + } + + BOOL SetTextColor(COLORREF cr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETTEXTCOLOR, 0, cr); + } + + COLORREF GetTextBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_GETTEXTBKCOLOR, 0, 0L); + } + + BOOL SetTextBkColor(COLORREF cr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETTEXTBKCOLOR, 0, cr); + } + + int GetTopIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETTOPINDEX, 0, 0L); + } + + int GetCountPerPage() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETCOUNTPERPAGE, 0, 0L); + } + + BOOL GetOrigin(LPPOINT lpPoint) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETORIGIN, 0, (LPARAM)lpPoint); + } + + UINT GetSelectedCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, LVM_GETSELECTEDCOUNT, 0, 0L); + } + + BOOL GetItemRect(int nItem, LPRECT lpRect, UINT nCode) const + { + ATLASSERT(::IsWindow(m_hWnd)); + lpRect->left = nCode; + return (BOOL)::SendMessage(m_hWnd, LVM_GETITEMRECT, (WPARAM)nItem, (LPARAM)lpRect); + } + +#ifndef _WIN32_WCE + HCURSOR GetHotCursor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HCURSOR)::SendMessage(m_hWnd, LVM_GETHOTCURSOR, 0, 0L); + } + + HCURSOR SetHotCursor(HCURSOR hHotCursor) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HCURSOR)::SendMessage(m_hWnd, LVM_SETHOTCURSOR, 0, (LPARAM)hHotCursor); + } + + int GetHotItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETHOTITEM, 0, 0L); + } + + int SetHotItem(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SETHOTITEM, nIndex, 0L); + } +#endif // !_WIN32_WCE + + BOOL GetColumnOrderArray(int nCount, int* lpnArray) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETCOLUMNORDERARRAY, nCount, (LPARAM)lpnArray); + } + + BOOL SetColumnOrderArray(int nCount, int* lpnArray) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMNORDERARRAY, nCount, (LPARAM)lpnArray); + } + + CHeaderCtrl GetHeader() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CHeaderCtrl((HWND)::SendMessage(m_hWnd, LVM_GETHEADER, 0, 0L)); + } + + BOOL GetSubItemRect(int nItem, int nSubItem, int nFlag, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LVS_TYPEMASK) == LVS_REPORT); + ATLASSERT(lpRect != NULL); + lpRect->top = nSubItem; + lpRect->left = nFlag; + return (BOOL)::SendMessage(m_hWnd, LVM_GETSUBITEMRECT, nItem, (LPARAM)lpRect); + } + + DWORD SetIconSpacing(int cx, int cy) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LVS_TYPEMASK) == LVS_ICON); + return (DWORD)::SendMessage(m_hWnd, LVM_SETICONSPACING, 0, MAKELPARAM(cx, cy)); + } + + int GetISearchString(LPTSTR lpstr) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETISEARCHSTRING, 0, (LPARAM)lpstr); + } + + void GetItemSpacing(SIZE& sizeSpacing, BOOL bSmallIconView = FALSE) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, LVM_GETITEMSPACING, bSmallIconView, 0L); + sizeSpacing.cx = GET_X_LPARAM(dwRet); + sizeSpacing.cy = GET_Y_LPARAM(dwRet); + } + +#if (_WIN32_WCE >= 410) + void SetItemSpacing(INT cySpacing) + { + ATLASSERT(::IsWindow(m_hWnd)); + ListView_SetItemSpacing(m_hWnd, cySpacing); + } +#endif // (_WIN32_WCE >= 410) + + // single-selection only + int GetSelectedIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LVS_SINGLESEL) != 0); + return (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, (WPARAM)-1, MAKELPARAM(LVNI_ALL | LVNI_SELECTED, 0)); + } + + BOOL GetSelectedItem(LPLVITEM pItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LVS_SINGLESEL) != 0); + ATLASSERT(pItem != NULL); + pItem->iItem = (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, (WPARAM)-1, MAKELPARAM(LVNI_ALL | LVNI_SELECTED, 0)); + if(pItem->iItem == -1) + return FALSE; + return (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)pItem); + } + + // extended list view styles + DWORD GetExtendedListViewStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0L); + } + + // dwExMask = 0 means all styles + DWORD SetExtendedListViewStyle(DWORD dwExStyle, DWORD dwExMask = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, dwExMask, dwExStyle); + } + + // checkboxes only + BOOL GetCheckState(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetExtendedListViewStyle() & LVS_EX_CHECKBOXES) != 0); + UINT uRet = GetItemState(nIndex, LVIS_STATEIMAGEMASK); + return (uRet >> 12) - 1; + } + + BOOL SetCheckState(int nItem, BOOL bCheck) + { + int nCheck = bCheck ? 2 : 1; // one based index + return SetItemState(nItem, INDEXTOSTATEIMAGEMASK(nCheck), LVIS_STATEIMAGEMASK); + } + + // view type + DWORD GetViewType() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (GetStyle() & LVS_TYPEMASK); + } + + DWORD SetViewType(DWORD dwType) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(dwType == LVS_ICON || dwType == LVS_SMALLICON || dwType == LVS_LIST || dwType == LVS_REPORT); + DWORD dwOldType = GetViewType(); + if(dwType != dwOldType) + ModifyStyle(LVS_TYPEMASK, (dwType & LVS_TYPEMASK)); + return dwOldType; + } + +#if (_WIN32_IE >= 0x0400) +#ifndef _WIN32_WCE + BOOL GetBkImage(LPLVBKIMAGE plvbki) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETBKIMAGE, 0, (LPARAM)plvbki); + } + + BOOL SetBkImage(LPLVBKIMAGE plvbki) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETBKIMAGE, 0, (LPARAM)plvbki); + } +#endif // !_WIN32_WCE + + int GetSelectionMark() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETSELECTIONMARK, 0, 0L); + } + + int SetSelectionMark(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SETSELECTIONMARK, 0, nIndex); + } + +#ifndef _WIN32_WCE + BOOL GetWorkAreas(int nWorkAreas, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETWORKAREAS, nWorkAreas, (LPARAM)lpRect); + } + + BOOL SetWorkAreas(int nWorkAreas, LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETWORKAREAS, nWorkAreas, (LPARAM)lpRect); + } + + DWORD GetHoverTime() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetExtendedListViewStyle() & (LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE | LVS_EX_TWOCLICKACTIVATE)) != 0); + return (DWORD)::SendMessage(m_hWnd, LVM_GETHOVERTIME, 0, 0L); + } + + DWORD SetHoverTime(DWORD dwHoverTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetExtendedListViewStyle() & (LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE | LVS_EX_TWOCLICKACTIVATE)) != 0); + return (DWORD)::SendMessage(m_hWnd, LVM_SETHOVERTIME, 0, dwHoverTime); + } + + BOOL GetNumberOfWorkAreas(int* pnWorkAreas) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETNUMBEROFWORKAREAS, 0, (LPARAM)pnWorkAreas); + } +#endif // !_WIN32_WCE + + BOOL SetItemCountEx(int nItems, DWORD dwFlags) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(((GetStyle() & LVS_OWNERDATA) != 0) && (((GetStyle() & LVS_TYPEMASK) == LVS_REPORT) || ((GetStyle() & LVS_TYPEMASK) == LVS_LIST))); + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMCOUNT, nItems, dwFlags); + } + +#ifndef _WIN32_WCE + CToolTipCtrl GetToolTips() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, LVM_GETTOOLTIPS, 0, 0L)); + } + + CToolTipCtrl SetToolTips(HWND hWndTT) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, LVM_SETTOOLTIPS, (WPARAM)hWndTT, 0L)); + } + + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_WINNT >= 0x0501) + int GetSelectedColumn() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETSELECTEDCOLUMN, 0, 0L); + } + + void SetSelectedColumn(int nColumn) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_SETSELECTEDCOLUMN, nColumn, 0L); + } + + DWORD GetView() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, LVM_GETVIEW, 0, 0L); + } + + int SetView(DWORD dwView) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SETVIEW, dwView, 0L); + } + + BOOL IsGroupViewEnabled() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_ISGROUPVIEWENABLED, 0, 0L); + } + + int GetGroupInfo(int nGroupID, PLVGROUP pGroup) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETGROUPINFO, nGroupID, (LPARAM)pGroup); + } + + int SetGroupInfo(int nGroupID, PLVGROUP pGroup) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SETGROUPINFO, nGroupID, (LPARAM)pGroup); + } + + void GetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_GETGROUPMETRICS, 0, (LPARAM)pGroupMetrics); + } + + void SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_SETGROUPMETRICS, 0, (LPARAM)pGroupMetrics); + } + + void GetTileViewInfo(PLVTILEVIEWINFO pTileViewInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_GETTILEVIEWINFO, 0, (LPARAM)pTileViewInfo); + } + + BOOL SetTileViewInfo(PLVTILEVIEWINFO pTileViewInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETTILEVIEWINFO, 0, (LPARAM)pTileViewInfo); + } + + void GetTileInfo(PLVTILEINFO pTileInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_GETTILEINFO, 0, (LPARAM)pTileInfo); + } + + BOOL SetTileInfo(PLVTILEINFO pTileInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETTILEINFO, 0, (LPARAM)pTileInfo); + } + + BOOL GetInsertMark(LPLVINSERTMARK pInsertMark) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETINSERTMARK, 0, (LPARAM)pInsertMark); + } + + BOOL SetInsertMark(LPLVINSERTMARK pInsertMark) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETINSERTMARK, 0, (LPARAM)pInsertMark); + } + + int GetInsertMarkRect(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETINSERTMARKRECT, 0, (LPARAM)lpRect); + } + + COLORREF GetInsertMarkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_GETINSERTMARKCOLOR, 0, 0L); + } + + COLORREF SetInsertMarkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_SETINSERTMARKCOLOR, 0, clr); + } + + COLORREF GetOutlineColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_GETOUTLINECOLOR, 0, 0L); + } + + COLORREF SetOutlineColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_SETOUTLINECOLOR, 0, clr); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_WINNT >= 0x0600) + int GetGroupCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETGROUPCOUNT, 0, 0L); + } + + BOOL GetGroupInfoByIndex(int nIndex, PLVGROUP pGroup) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETGROUPINFOBYINDEX, nIndex, (LPARAM)pGroup); + } + + BOOL GetGroupRect(int nGroupID, int nType, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpRect != NULL); + if(lpRect != NULL) + lpRect->top = nType; + return (BOOL)::SendMessage(m_hWnd, LVM_GETGROUPRECT, nGroupID, (LPARAM)lpRect); + } + + UINT GetGroupState(int nGroupID, UINT uMask) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, LVM_GETGROUPSTATE, nGroupID, (LPARAM)uMask); + } + + int GetFocusedGroup() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETFOCUSEDGROUP, 0, 0L); + } + + BOOL GetEmptyText(LPWSTR lpstrText, int cchText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETEMPTYTEXT, cchText, (LPARAM)lpstrText); + } + + BOOL GetFooterRect(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERRECT, 0, (LPARAM)lpRect); + } + + BOOL GetFooterInfo(LPLVFOOTERINFO lpFooterInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERINFO, 0, (LPARAM)lpFooterInfo); + } + + BOOL GetFooterItemRect(int nItem, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERITEMRECT, nItem, (LPARAM)lpRect); + } + + BOOL GetFooterItem(int nItem, LPLVFOOTERITEM lpFooterItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERITEM, nItem, (LPARAM)lpFooterItem); + } + + BOOL GetItemIndexRect(PLVITEMINDEX pItemIndex, int nSubItem, int nType, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pItemIndex != NULL); + ATLASSERT(lpRect != NULL); + if(lpRect != NULL) + { + lpRect->top = nSubItem; + lpRect->left = nType; + } + return (BOOL)::SendMessage(m_hWnd, LVM_GETITEMINDEXRECT, (WPARAM)pItemIndex, (LPARAM)lpRect); + } + + BOOL SetItemIndexState(PLVITEMINDEX pItemIndex, UINT uState, UINT dwMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.state = uState; + lvi.stateMask = dwMask; + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMINDEXSTATE, (WPARAM)pItemIndex, (LPARAM)&lvi); + } + + BOOL GetNextItemIndex(PLVITEMINDEX pItemIndex, WORD wFlags) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETNEXTITEMINDEX, (WPARAM)pItemIndex, MAKELPARAM(wFlags, 0)); + } +#endif // (_WIN32_WINNT >= 0x0600) + +// Operations + int InsertColumn(int nCol, const LVCOLUMN* pColumn) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_INSERTCOLUMN, nCol, (LPARAM)pColumn); + } + + int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat = LVCFMT_LEFT, + int nWidth = -1, int nSubItem = -1, int iImage = -1, int iOrder = -1) + { + LVCOLUMN column = { 0 }; + column.mask = LVCF_TEXT|LVCF_FMT; + column.pszText = (LPTSTR)lpszColumnHeading; + column.fmt = nFormat; + if (nWidth != -1) + { + column.mask |= LVCF_WIDTH; + column.cx = nWidth; + } + if (nSubItem != -1) + { + column.mask |= LVCF_SUBITEM; + column.iSubItem = nSubItem; + } + if (iImage != -1) + { + column.mask |= LVCF_IMAGE; + column.iImage = iImage; + } + if (iOrder != -1) + { + column.mask |= LVCF_ORDER; + column.iOrder = iOrder; + } + return InsertColumn(nCol, &column); + } + + BOOL DeleteColumn(int nCol) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_DELETECOLUMN, nCol, 0L); + } + + int InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem, UINT nState, UINT nStateMask, int nImage, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM item = { 0 }; + item.mask = nMask; + item.iItem = nItem; + item.iSubItem = 0; + item.pszText = (LPTSTR)lpszItem; + item.state = nState; + item.stateMask = nStateMask; + item.iImage = nImage; + item.lParam = lParam; + return InsertItem(&item); + } + + int InsertItem(const LVITEM* pItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_INSERTITEM, 0, (LPARAM)pItem); + } + + int InsertItem(int nItem, LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return InsertItem(LVIF_TEXT, nItem, lpszItem, 0, 0, 0, 0); + } + + int InsertItem(int nItem, LPCTSTR lpszItem, int nImage) + { + ATLASSERT(::IsWindow(m_hWnd)); + return InsertItem(LVIF_TEXT|LVIF_IMAGE, nItem, lpszItem, 0, 0, nImage, 0); + } + + int GetNextItem(int nItem, int nFlags) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, nItem, MAKELPARAM(nFlags, 0)); + } + + BOOL DeleteItem(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_DELETEITEM, nItem, 0L); + } + + BOOL DeleteAllItems() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_DELETEALLITEMS, 0, 0L); + } + + int FindItem(LVFINDINFO* pFindInfo, int nStart = -1) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_FINDITEM, nStart, (LPARAM)pFindInfo); + } + + int FindItem(LPCTSTR lpstrFind, bool bPartial = true, bool bWrap = false, int nStart = -1) const + { + ATLASSERT(::IsWindow(m_hWnd)); + LVFINDINFO lvfi = { 0 }; + lvfi.flags = LVFI_STRING | (bWrap ? LVFI_WRAP : 0) | (bPartial ? LVFI_PARTIAL : 0); + lvfi.psz = lpstrFind; + return (int)::SendMessage(m_hWnd, LVM_FINDITEM, nStart, (LPARAM)&lvfi); + } + + int HitTest(LVHITTESTINFO* pHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_HITTEST, 0, (LPARAM)pHitTestInfo); + } + + int HitTest(POINT pt, UINT* pFlags) const + { + ATLASSERT(::IsWindow(m_hWnd)); + LVHITTESTINFO hti = { 0 }; + hti.pt = pt; + int nRes = (int)::SendMessage(m_hWnd, LVM_HITTEST, 0, (LPARAM)&hti); + if (pFlags != NULL) + *pFlags = hti.flags; + return nRes; + } + + BOOL EnsureVisible(int nItem, BOOL bPartialOK) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_ENSUREVISIBLE, nItem, MAKELPARAM(bPartialOK, 0)); + } + + BOOL Scroll(SIZE size) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SCROLL, size.cx, size.cy); + } + + BOOL RedrawItems(int nFirst, int nLast) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_REDRAWITEMS, nFirst, nLast); + } + + BOOL Arrange(UINT nCode) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_ARRANGE, nCode, 0L); + } + + CEdit EditLabel(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CEdit((HWND)::SendMessage(m_hWnd, LVM_EDITLABEL, nItem, 0L)); + } + + BOOL Update(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_UPDATE, nItem, 0L); + } + + BOOL SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SORTITEMS, (WPARAM)lParamSort, (LPARAM)pfnCompare); + } + + CImageList RemoveImageList(int nImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_SETIMAGELIST, (WPARAM)nImageList, NULL)); + } + + CImageList CreateDragImage(int nItem, LPPOINT lpPoint) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_CREATEDRAGIMAGE, nItem, (LPARAM)lpPoint)); + } + + DWORD ApproximateViewRect(int cx = -1, int cy = -1, int nCount = -1) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, LVM_APPROXIMATEVIEWRECT, nCount, MAKELPARAM(cx, cy)); + } + + int SubItemHitTest(LPLVHITTESTINFO lpInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SUBITEMHITTEST, 0, (LPARAM)lpInfo); + } + + int AddColumn(LPCTSTR strItem, int nItem, int nSubItem = -1, + int nMask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM, + int nFmt = LVCFMT_LEFT) + { + const int cxOffset = 15; + ATLASSERT(::IsWindow(m_hWnd)); + LVCOLUMN lvc = { 0 }; + lvc.mask = nMask; + lvc.fmt = nFmt; + lvc.pszText = (LPTSTR)strItem; + lvc.cx = GetStringWidth(lvc.pszText) + cxOffset; + if(nMask & LVCF_SUBITEM) + lvc.iSubItem = (nSubItem != -1) ? nSubItem : nItem; + return InsertColumn(nItem, &lvc); + } + + int AddItem(int nItem, int nSubItem, LPCTSTR strItem, int nImageIndex = -3) + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvItem = { 0 }; + lvItem.mask = LVIF_TEXT; + lvItem.iItem = nItem; + lvItem.iSubItem = nSubItem; + lvItem.pszText = (LPTSTR)strItem; + if(nImageIndex != -3) + { + lvItem.mask |= LVIF_IMAGE; + lvItem.iImage = nImageIndex; + } + if(nSubItem == 0) + return InsertItem(&lvItem); + return SetItem(&lvItem) ? nItem : -1; + } + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + BOOL SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SORTITEMSEX, (WPARAM)lParamSort, (LPARAM)pfnCompare); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0501) + int InsertGroup(int nItem, PLVGROUP pGroup) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_INSERTGROUP, nItem, (LPARAM)pGroup); + } + + int AddGroup(PLVGROUP pGroup) + { + return InsertGroup(-1, pGroup); + } + + int RemoveGroup(int nGroupID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_REMOVEGROUP, nGroupID, 0L); + } + + void MoveGroup(int nGroupID, int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_MOVEGROUP, nGroupID, nItem); + } + + void MoveItemToGroup(int nItem, int nGroupID) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_MOVEITEMTOGROUP, nItem, nGroupID); + } + + int EnableGroupView(BOOL bEnable) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_ENABLEGROUPVIEW, bEnable, 0L); + } + + int SortGroups(PFNLVGROUPCOMPARE pCompareFunc, LPVOID lpVoid = NULL) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SORTGROUPS, (WPARAM)pCompareFunc, (LPARAM)lpVoid); + } + + void InsertGroupSorted(PLVINSERTGROUPSORTED pInsertGroupSorted) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_INSERTGROUPSORTED, (WPARAM)pInsertGroupSorted, 0L); + } + + void RemoveAllGroups() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_REMOVEALLGROUPS, 0, 0L); + } + + BOOL HasGroup(int nGroupID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_HASGROUP, nGroupID, 0L); + } + + BOOL InsertMarkHitTest(LPPOINT lpPoint, LPLVINSERTMARK pInsertMark) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_INSERTMARKHITTEST, (WPARAM)lpPoint, (LPARAM)pInsertMark); + } + + BOOL SetInfoTip(PLVSETINFOTIP pSetInfoTip) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETINFOTIP, 0, (LPARAM)pSetInfoTip); + } + + void CancelEditLabel() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_CANCELEDITLABEL, 0, 0L); + } + + UINT MapIndexToID(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, LVM_MAPINDEXTOID, nIndex, 0L); + } + + int MapIDToIndex(UINT uID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_MAPIDTOINDEX, uID, 0L); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_WINNT >= 0x0600) + int HitTestEx(LPLVHITTESTINFO lpHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_HITTEST, (WPARAM)-1, (LPARAM)lpHitTestInfo); + } + + int HitTestEx(POINT pt, UINT* pFlags) const + { + ATLASSERT(::IsWindow(m_hWnd)); + LVHITTESTINFO hti = { 0 }; + hti.pt = pt; + int nRes = (int)::SendMessage(m_hWnd, LVM_HITTEST, (WPARAM)-1, (LPARAM)&hti); + if (pFlags != NULL) + *pFlags = hti.flags; + return nRes; + } + + int SubItemHitTestEx(LPLVHITTESTINFO lpHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SUBITEMHITTEST, (WPARAM)-1, (LPARAM)lpHitTestInfo); + } +#endif // (_WIN32_WINNT >= 0x0600) + + // Note: selects only one item + BOOL SelectItem(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + + // multi-selection only: de-select all items + if((GetStyle() & LVS_SINGLESEL) == 0) + SetItemState(-1, 0, LVIS_SELECTED); + + BOOL bRet = SetItemState(nIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); + if(bRet) + bRet = EnsureVisible(nIndex, FALSE); + + return bRet; + } +}; + +typedef CListViewCtrlT CListViewCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CTreeViewCtrl + +template +class CTreeViewCtrlT : public TBase +{ +public: +// Constructors + CTreeViewCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CTreeViewCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_TREEVIEW; + } + + UINT GetCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, TVM_GETCOUNT, 0, 0L); + } + + UINT GetIndent() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, TVM_GETINDENT, 0, 0L); + } + + void SetIndent(UINT nIndent) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TVM_SETINDENT, nIndent, 0L); + } + + CImageList GetImageList(int nImageListType = TVSIL_NORMAL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_GETIMAGELIST, (WPARAM)nImageListType, 0L)); + } + + CImageList SetImageList(HIMAGELIST hImageList, int nImageListType = TVSIL_NORMAL) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM)nImageListType, (LPARAM)hImageList)); + } + + BOOL GetItem(LPTVITEM pItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)pItem); + } + + BOOL SetItem(LPTVITEM pItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)pItem); + } + + BOOL SetItem(HTREEITEM hItem, UINT nMask, LPCTSTR lpszItem, int nImage, + int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = nMask; + item.pszText = (LPTSTR) lpszItem; + item.iImage = nImage; + item.iSelectedImage = nSelectedImage; + item.state = nState; + item.stateMask = nStateMask; + item.lParam = lParam; + return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)&item); + } + + BOOL GetItemText(HTREEITEM hItem, LPTSTR lpstrText, int nLen) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpstrText != NULL); + + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_TEXT; + item.pszText = lpstrText; + item.cchTextMax = nLen; + + return (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + } + +#ifndef _ATL_NO_COM + BOOL GetItemText(HTREEITEM hItem, BSTR& bstrText) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrText == NULL); + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_TEXT; + + LPTSTR lpstrText = NULL; + BOOL bRet = FALSE; + for(int nLen = 256; ; nLen *= 2) + { + ATLTRY(lpstrText = new TCHAR[nLen]); + if(lpstrText == NULL) + break; + lpstrText[0] = NULL; + item.pszText = lpstrText; + item.cchTextMax = nLen; + bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + if(!bRet || (lstrlen(item.pszText) < nLen - 1)) + break; + delete [] lpstrText; + lpstrText = NULL; + } + + if(lpstrText != NULL) + { + if(bRet) + bstrText = ::SysAllocString(T2OLE(lpstrText)); + delete [] lpstrText; + } + + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + BOOL GetItemText(HTREEITEM hItem, _CSTRING_NS::CString& strText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_TEXT; + + strText.Empty(); + BOOL bRet = FALSE; + for(int nLen = 256; ; nLen *= 2) + { + item.pszText = strText.GetBufferSetLength(nLen); + if(item.pszText == NULL) + { + bRet = FALSE; + break; + } + item.cchTextMax = nLen; + bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + if(!bRet || (lstrlen(item.pszText) < nLen - 1)) + break; + } + strText.ReleaseBuffer(); + return bRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + BOOL SetItemText(HTREEITEM hItem, LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(hItem, TVIF_TEXT, lpszItem, 0, 0, 0, 0, NULL); + } + + BOOL GetItemImage(HTREEITEM hItem, int& nImage, int& nSelectedImage) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE; + BOOL bRes = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + if (bRes) + { + nImage = item.iImage; + nSelectedImage = item.iSelectedImage; + } + return bRes; + } + + BOOL SetItemImage(HTREEITEM hItem, int nImage, int nSelectedImage) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(hItem, TVIF_IMAGE|TVIF_SELECTEDIMAGE, NULL, nImage, nSelectedImage, 0, 0, NULL); + } + + UINT GetItemState(HTREEITEM hItem, UINT nStateMask) const + { + ATLASSERT(::IsWindow(m_hWnd)); +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + return (((UINT)::SendMessage(m_hWnd, TVM_GETITEMSTATE, (WPARAM)hItem, (LPARAM)nStateMask)) & nStateMask); +#else // !((_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)) + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_STATE; + item.state = 0; + item.stateMask = nStateMask; + ::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + return (item.state & nStateMask); +#endif // !((_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)) + } + + BOOL SetItemState(HTREEITEM hItem, UINT nState, UINT nStateMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(hItem, TVIF_STATE, NULL, 0, 0, nState, nStateMask, NULL); + } + + DWORD_PTR GetItemData(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_PARAM; + BOOL bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + return (DWORD_PTR)(bRet ? item.lParam : NULL); + } + + BOOL SetItemData(HTREEITEM hItem, DWORD_PTR dwData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(hItem, TVIF_PARAM, NULL, 0, 0, 0, 0, (LPARAM)dwData); + } + + CEdit GetEditControl() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CEdit((HWND)::SendMessage(m_hWnd, TVM_GETEDITCONTROL, 0, 0L)); + } + + UINT GetVisibleCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, TVM_GETVISIBLECOUNT, 0, 0L); + } + + BOOL GetItemRect(HTREEITEM hItem, LPRECT lpRect, BOOL bTextOnly) const + { + ATLASSERT(::IsWindow(m_hWnd)); + *(HTREEITEM*)lpRect = hItem; + return (BOOL)::SendMessage(m_hWnd, TVM_GETITEMRECT, (WPARAM)bTextOnly, (LPARAM)lpRect); + } + + BOOL ItemHasChildren(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_CHILDREN; + ::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + return item.cChildren; + } + +#ifndef _WIN32_WCE + CToolTipCtrl GetToolTips() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TVM_GETTOOLTIPS, 0, 0L)); + } + + CToolTipCtrl SetToolTips(HWND hWndTT) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TVM_SETTOOLTIPS, (WPARAM)hWndTT, 0L)); + } +#endif // !_WIN32_WCE + + int GetISearchString(LPTSTR lpstr) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TVM_GETISEARCHSTRING, 0, (LPARAM)lpstr); + } + + // checkboxes only + BOOL GetCheckState(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & TVS_CHECKBOXES) != 0); + UINT uRet = GetItemState(hItem, TVIS_STATEIMAGEMASK); + return (uRet >> 12) - 1; + } + + BOOL SetCheckState(HTREEITEM hItem, BOOL bCheck) + { + int nCheck = bCheck ? 2 : 1; // one based index + return SetItemState(hItem, INDEXTOSTATEIMAGEMASK(nCheck), TVIS_STATEIMAGEMASK); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + COLORREF GetBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_GETBKCOLOR, 0, 0L); + } + + COLORREF SetBkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_SETBKCOLOR, 0, (LPARAM)clr); + } + + COLORREF GetInsertMarkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_GETINSERTMARKCOLOR, 0, 0L); + } + + COLORREF SetInsertMarkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_SETINSERTMARKCOLOR, 0, (LPARAM)clr); + } + + int GetItemHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TVM_GETITEMHEIGHT, 0, 0L); + } + + int SetItemHeight(int cyHeight) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TVM_SETITEMHEIGHT, cyHeight, 0L); + } + + int GetScrollTime() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TVM_GETSCROLLTIME, 0, 0L); + } + + int SetScrollTime(int nScrollTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TVM_SETSCROLLTIME, nScrollTime, 0L); + } + + COLORREF GetTextColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_GETTEXTCOLOR, 0, 0L); + } + + COLORREF SetTextColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_SETTEXTCOLOR, 0, (LPARAM)clr); + } + + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + COLORREF GetLineColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_GETLINECOLOR, 0, 0L); + } + + COLORREF SetLineColor(COLORREF clrNew /*= CLR_DEFAULT*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_SETLINECOLOR, 0, (LPARAM)clrNew); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL GetItem(LPTVITEMEX pItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)pItem); + } + + BOOL SetItem(LPTVITEMEX pItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)pItem); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + + DWORD GetExtendedStyle() const + { +#ifndef TVM_GETEXTENDEDSTYLE + const UINT TVM_GETEXTENDEDSTYLE = (TV_FIRST + 45); +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TVM_GETEXTENDEDSTYLE, 0, 0L); + } + + DWORD SetExtendedStyle(DWORD dwStyle, DWORD dwMask) + { +#ifndef TVM_SETEXTENDEDSTYLE + const UINT TVM_SETEXTENDEDSTYLE = (TV_FIRST + 44); +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TVM_SETEXTENDEDSTYLE, dwMask, dwStyle); + } + +#if (_WIN32_WINNT >= 0x0600) + BOOL SetAutoScrollInfo(UINT uPixPerSec, UINT uUpdateTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SETAUTOSCROLLINFO, (WPARAM)uPixPerSec, (LPARAM)uUpdateTime); + } + + DWORD GetSelectedCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TVM_GETSELECTEDCOUNT, 0, 0L); + } + + BOOL GetItemPartRect(HTREEITEM hItem, TVITEMPART partID, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVGETITEMPARTRECTINFO gipri = { hItem, lpRect, partID }; + return (BOOL)::SendMessage(m_hWnd, TVM_GETITEMPARTRECT, 0, (LPARAM)&gipri); + } +#endif // (_WIN32_WINNT >= 0x0600) + +// Operations + HTREEITEM InsertItem(LPTVINSERTSTRUCT lpInsertStruct) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)lpInsertStruct); + } + + HTREEITEM InsertItem(LPCTSTR lpszItem, int nImage, + int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + return InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE, lpszItem, nImage, nSelectedImage, 0, 0, 0, hParent, hInsertAfter); + } + + HTREEITEM InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + return InsertItem(TVIF_TEXT, lpszItem, 0, 0, 0, 0, 0, hParent, hInsertAfter); + } + + HTREEITEM InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage, + int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam, + HTREEITEM hParent, HTREEITEM hInsertAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + TVINSERTSTRUCT tvis = { 0 }; + tvis.hParent = hParent; + tvis.hInsertAfter = hInsertAfter; + tvis.item.mask = nMask; + tvis.item.pszText = (LPTSTR) lpszItem; + tvis.item.iImage = nImage; + tvis.item.iSelectedImage = nSelectedImage; + tvis.item.state = nState; + tvis.item.stateMask = nStateMask; + tvis.item.lParam = lParam; + return (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)&tvis); + } + + BOOL DeleteItem(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_DELETEITEM, 0, (LPARAM)hItem); + } + + BOOL DeleteAllItems() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); + } + + BOOL Expand(HTREEITEM hItem, UINT nCode = TVE_EXPAND) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_EXPAND, nCode, (LPARAM)hItem); + } + + HTREEITEM GetNextItem(HTREEITEM hItem, UINT nCode) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, nCode, (LPARAM)hItem); + } + + HTREEITEM GetChildItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + } + + HTREEITEM GetNextSiblingItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + } + + HTREEITEM GetPrevSiblingItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUS, (LPARAM)hItem); + } + + HTREEITEM GetParentItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem); + } + + HTREEITEM GetFirstVisibleItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0L); + } + + HTREEITEM GetNextVisibleItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItem); + } + + HTREEITEM GetPrevVisibleItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItem); + } + + HTREEITEM GetSelectedItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CARET, 0L); + } + + HTREEITEM GetDropHilightItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_DROPHILITE, 0L); + } + + HTREEITEM GetRootItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_ROOT, 0L); + } + +#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) + HTREEITEM GetLastVisibleItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0L); + } +#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0600) + HTREEITEM GetNextSelectedItem() const + { +#ifndef TVGN_NEXTSELECTED + const WORD TVGN_NEXTSELECTED = 0x000B; +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0L); + } +#endif // (_WIN32_IE >= 0x0600) + + BOOL Select(HTREEITEM hItem, UINT nCode) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, nCode, (LPARAM)hItem); + } + + BOOL SelectItem(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem); + } + + BOOL SelectDropTarget(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)hItem); + } + + BOOL SelectSetFirstVisible(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_FIRSTVISIBLE, (LPARAM)hItem); + } + + CEdit EditLabel(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CEdit((HWND)::SendMessage(m_hWnd, TVM_EDITLABEL, 0, (LPARAM)hItem)); + } + + BOOL EndEditLabelNow(BOOL bCancel) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_ENDEDITLABELNOW, bCancel, 0L); + } + + HTREEITEM HitTest(TVHITTESTINFO* pHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)pHitTestInfo); + } + + HTREEITEM HitTest(POINT pt, UINT* pFlags) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVHITTESTINFO hti = { 0 }; + hti.pt = pt; + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)&hti); + if (pFlags != NULL) + *pFlags = hti.flags; + return hTreeItem; + } + + BOOL SortChildren(HTREEITEM hItem, BOOL bRecurse = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SORTCHILDREN, (WPARAM)bRecurse, (LPARAM)hItem); + } + + BOOL EnsureVisible(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_ENSUREVISIBLE, 0, (LPARAM)hItem); + } + + BOOL SortChildrenCB(LPTVSORTCB pSort, BOOL bRecurse = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SORTCHILDRENCB, (WPARAM)bRecurse, (LPARAM)pSort); + } + + CImageList RemoveImageList(int nImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM)nImageList, NULL)); + } + + CImageList CreateDragImage(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_CREATEDRAGIMAGE, 0, (LPARAM)hItem)); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL SetInsertMark(HTREEITEM hTreeItem, BOOL bAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SETINSERTMARK, bAfter, (LPARAM)hTreeItem); + } + + BOOL RemoveInsertMark() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SETINSERTMARK, 0, 0L); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0501) + HTREEITEM MapAccIDToHTREEITEM(UINT uID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_MAPACCIDTOHTREEITEM, uID, 0L); + } + + UINT MapHTREEITEMToAccID(HTREEITEM hTreeItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, TVM_MAPHTREEITEMTOACCID, (WPARAM)hTreeItem, 0L); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_WINNT >= 0x0600) + void ShowInfoTip(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TVM_SHOWINFOTIP, 0, (LPARAM)hItem); + } +#endif // (_WIN32_WINNT >= 0x0600) +}; + +typedef CTreeViewCtrlT CTreeViewCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CTreeViewCtrlEx + +// forward declaration +template class CTreeViewCtrlExT; + +// Note: TBase here is for CTreeViewCtrlExT, and not for CTreeItemT itself +template +class CTreeItemT +{ +public: + HTREEITEM m_hTreeItem; + CTreeViewCtrlExT* m_pTreeView; + +// Construction + CTreeItemT(HTREEITEM hTreeItem = NULL, CTreeViewCtrlExT* pTreeView = NULL) : m_hTreeItem(hTreeItem), m_pTreeView(pTreeView) + { } + + CTreeItemT(const CTreeItemT& posSrc) + { + *this = posSrc; + } + + operator HTREEITEM() { return m_hTreeItem; } + + CTreeItemT& operator =(const CTreeItemT& itemSrc) + { + m_hTreeItem = itemSrc.m_hTreeItem; + m_pTreeView = itemSrc.m_pTreeView; + return *this; + } + +// Attributes + CTreeViewCtrlExT* GetTreeView() const { return m_pTreeView; } + + BOOL operator !() const { return m_hTreeItem == NULL; } + + BOOL IsNull() const { return m_hTreeItem == NULL; } + + BOOL GetRect(LPRECT lpRect, BOOL bTextOnly) const; + BOOL GetText(LPTSTR lpstrText, int nLen) const; +#ifndef _ATL_NO_COM + BOOL GetText(BSTR& bstrText) const; +#endif // !_ATL_NO_COM +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + BOOL GetText(_CSTRING_NS::CString& strText) const; +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + BOOL SetText(LPCTSTR lpszItem); + BOOL GetImage(int& nImage, int& nSelectedImage) const; + BOOL SetImage(int nImage, int nSelectedImage); + UINT GetState(UINT nStateMask) const; + BOOL SetState(UINT nState, UINT nStateMask); + DWORD_PTR GetData() const; + BOOL SetData(DWORD_PTR dwData); + BOOL SetItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam); + +// Operations + CTreeItemT InsertAfter(LPCTSTR lpstrItem, HTREEITEM hItemAfter, int nImageIndex) + { + return _Insert(lpstrItem, nImageIndex, hItemAfter); + } + + CTreeItemT AddHead(LPCTSTR lpstrItem, int nImageIndex) + { + return _Insert(lpstrItem, nImageIndex, TVI_FIRST); + } + + CTreeItemT AddTail(LPCTSTR lpstrItem, int nImageIndex) + { + return _Insert(lpstrItem, nImageIndex, TVI_LAST); + } + + CTreeItemT GetChild() const; + CTreeItemT GetNext(UINT nCode) const; + CTreeItemT GetNextSibling() const; + CTreeItemT GetPrevSibling() const; + CTreeItemT GetParent() const; + CTreeItemT GetFirstVisible() const; + CTreeItemT GetNextVisible() const; + CTreeItemT GetPrevVisible() const; + CTreeItemT GetSelected() const; + CTreeItemT GetDropHilight() const; + CTreeItemT GetRoot() const; +#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) + CTreeItemT GetLastVisible() const; +#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0600) + CTreeItemT GetNextSelected() const; +#endif // (_WIN32_IE >= 0x0600) + BOOL HasChildren() const; + BOOL Delete(); + BOOL Expand(UINT nCode = TVE_EXPAND); + BOOL Select(UINT nCode); + BOOL Select(); + BOOL SelectDropTarget(); + BOOL SelectSetFirstVisible(); + HWND EditLabel(); + HIMAGELIST CreateDragImage(); + BOOL SortChildren(BOOL bRecurse = FALSE); + BOOL EnsureVisible(); + CTreeItemT _Insert(LPCTSTR lpstrItem, int nImageIndex, HTREEITEM hItemAfter); + int GetImageIndex() const; +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL SetInsertMark(BOOL bAfter); +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) +#if (_WIN32_WINNT >= 0x0501) + UINT MapHTREEITEMToAccID() const; +#endif // (_WIN32_WINNT >= 0x0501) +#if (_WIN32_WINNT >= 0x0600) + void ShowInfoTip(); + BOOL GetPartRect(TVITEMPART partID, LPRECT lpRect) const; +#endif // (_WIN32_WINNT >= 0x0600) +}; + +typedef CTreeItemT CTreeItem; + + +template +class CTreeViewCtrlExT : public CTreeViewCtrlT< TBase > +{ +public: +// Constructors + CTreeViewCtrlExT(HWND hWnd = NULL) : CTreeViewCtrlT< TBase >(hWnd) + { } + + CTreeViewCtrlExT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Operations (overides that return CTreeItem) + CTreeItemT InsertItem(LPTVINSERTSTRUCT lpInsertStruct) + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)lpInsertStruct); + return CTreeItemT(hTreeItem, this); + } + + CTreeItemT InsertItem(LPCTSTR lpszItem, int nImage, + int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + return InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE, lpszItem, nImage, nSelectedImage, 0, 0, 0, hParent, hInsertAfter); + } + + CTreeItemT InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + return InsertItem(TVIF_TEXT, lpszItem, 0, 0, 0, 0, 0, hParent, hInsertAfter); + } + + CTreeItemT GetNextItem(HTREEITEM hItem, UINT nCode) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, nCode, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetChildItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetNextSiblingItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetPrevSiblingItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUS, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetParentItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetFirstVisibleItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetNextVisibleItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetPrevVisibleItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetSelectedItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CARET, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetDropHilightItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_DROPHILITE, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetRootItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_ROOT, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + +#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) + CTreeItemT GetLastVisibleItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } +#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0600) + CTreeItemT GetNextSelectedItem() const + { +#ifndef TVGN_NEXTSELECTED + const WORD TVGN_NEXTSELECTED = 0x000B; +#endif + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } +#endif // (_WIN32_IE >= 0x0600) + + CTreeItemT HitTest(TVHITTESTINFO* pHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)pHitTestInfo); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage, + int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam, + HTREEITEM hParent, HTREEITEM hInsertAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + TVINSERTSTRUCT tvis = { 0 }; + tvis.hParent = hParent; + tvis.hInsertAfter = hInsertAfter; + tvis.item.mask = nMask; + tvis.item.pszText = (LPTSTR) lpszItem; + tvis.item.iImage = nImage; + tvis.item.iSelectedImage = nSelectedImage; + tvis.item.state = nState; + tvis.item.stateMask = nStateMask; + tvis.item.lParam = lParam; + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)&tvis); + return CTreeItemT(hTreeItem, this); + } + + CTreeItemT HitTest(POINT pt, UINT* pFlags) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVHITTESTINFO hti = { 0 }; + hti.pt = pt; + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)&hti); + if (pFlags != NULL) + *pFlags = hti.flags; + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + +#if (_WIN32_WINNT >= 0x0501) + CTreeItemT MapAccIDToHTREEITEM(UINT uID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_MAPACCIDTOHTREEITEM, uID, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } +#endif // (_WIN32_WINNT >= 0x0501) +}; + +typedef CTreeViewCtrlExT CTreeViewCtrlEx; + + +// CTreeItem inline methods +template +inline BOOL CTreeItemT::GetRect(LPRECT lpRect, BOOL bTextOnly) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemRect(m_hTreeItem,lpRect,bTextOnly); +} + +template +inline CTreeItemT CTreeItemT::GetNext(UINT nCode) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetNextItem(m_hTreeItem,nCode); +} + +template +inline CTreeItemT CTreeItemT::GetChild() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetChildItem(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::GetNextSibling() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetNextSiblingItem(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::GetPrevSibling() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetPrevSiblingItem(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::GetParent() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetParentItem(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::GetFirstVisible() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetFirstVisibleItem(); +} + +template +inline CTreeItemT CTreeItemT::GetNextVisible() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetNextVisibleItem(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::GetPrevVisible() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetPrevVisibleItem(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::GetSelected() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetSelectedItem(); +} + +template +inline CTreeItemT CTreeItemT::GetDropHilight() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetDropHilightItem(); +} + +template +inline CTreeItemT CTreeItemT::GetRoot() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetRootItem(); +} + +#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) +template +inline CTreeItemT CTreeItemT::GetLastVisible() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetLastVisibleItem(); +} +#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0600) +template +inline CTreeItemT CTreeItemT::GetNextSelected() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetNextSelectedItem(); +} +#endif // (_WIN32_IE >= 0x0600) + +template +inline BOOL CTreeItemT::GetText(LPTSTR lpstrText, int nLen) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemText(m_hTreeItem, lpstrText, nLen); +} + +#ifndef _ATL_NO_COM +#ifdef _OLEAUTO_H_ +template +inline BOOL CTreeItemT::GetText(BSTR& bstrText) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemText(m_hTreeItem, bstrText); +} +#endif // _OLEAUTO_H_ +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) +template +inline BOOL CTreeItemT::GetText(_CSTRING_NS::CString& strText) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemText(m_hTreeItem, strText); +} +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + +template +inline BOOL CTreeItemT::GetImage(int& nImage, int& nSelectedImage) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemImage(m_hTreeItem,nImage,nSelectedImage); +} + +template +inline UINT CTreeItemT::GetState(UINT nStateMask) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemState(m_hTreeItem,nStateMask); +} + +template +inline DWORD_PTR CTreeItemT::GetData() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemData(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::SetItem(UINT nMask, LPCTSTR lpszItem, int nImage, + int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SetItem(m_hTreeItem, nMask, lpszItem, nImage, nSelectedImage, nState, nStateMask, lParam); +} + +template +inline BOOL CTreeItemT::SetText(LPCTSTR lpszItem) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SetItemText(m_hTreeItem,lpszItem); +} + +template +inline BOOL CTreeItemT::SetImage(int nImage, int nSelectedImage) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SetItemImage(m_hTreeItem,nImage,nSelectedImage); +} + +template +inline BOOL CTreeItemT::SetState(UINT nState, UINT nStateMask) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SetItemState(m_hTreeItem,nState,nStateMask); +} + +template +inline BOOL CTreeItemT::SetData(DWORD_PTR dwData) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SetItemData(m_hTreeItem,dwData); +} + +template +inline BOOL CTreeItemT::HasChildren() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->ItemHasChildren(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::Delete() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->DeleteItem(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::Expand(UINT nCode /*= TVE_EXPAND*/) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->Expand(m_hTreeItem,nCode); +} + +template +inline BOOL CTreeItemT::Select(UINT nCode) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->Select(m_hTreeItem,nCode); +} + +template +inline BOOL CTreeItemT::Select() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SelectItem(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::SelectDropTarget() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SelectDropTarget(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::SelectSetFirstVisible() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SelectSetFirstVisible(m_hTreeItem); +} + +template +inline HWND CTreeItemT::EditLabel() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->EditLabel(m_hTreeItem); +} + +template +inline HIMAGELIST CTreeItemT::CreateDragImage() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->CreateDragImage(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::SortChildren(BOOL bRecurse /*= FALSE*/) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SortChildren(m_hTreeItem, bRecurse); +} + +template +inline BOOL CTreeItemT::EnsureVisible() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->EnsureVisible(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::_Insert(LPCTSTR lpstrItem, int nImageIndex, HTREEITEM hItemAfter) +{ + ATLASSERT(m_pTreeView != NULL); + TVINSERTSTRUCT ins = { 0 }; + ins.hParent = m_hTreeItem; + ins.hInsertAfter = hItemAfter; + ins.item.mask = TVIF_TEXT; + ins.item.pszText = (LPTSTR)lpstrItem; + if(nImageIndex != -1) + { + ins.item.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE; + ins.item.iImage = nImageIndex; + ins.item.iSelectedImage = nImageIndex; + } + return CTreeItemT(m_pTreeView->InsertItem(&ins), m_pTreeView); +} + +template +inline int CTreeItemT::GetImageIndex() const +{ + ATLASSERT(m_pTreeView != NULL); + TVITEM item = { 0 }; + item.mask = TVIF_HANDLE | TVIF_IMAGE; + item.hItem = m_hTreeItem; + m_pTreeView->GetItem(&item); + return item.iImage; +} + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) +template +inline BOOL CTreeItemT::SetInsertMark(BOOL bAfter) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SetInsertMark(m_hTreeItem, bAfter); +} +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0501) +template +inline UINT CTreeItemT::MapHTREEITEMToAccID() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->MapHTREEITEMToAccID(m_hTreeItem); +} +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_WINNT >= 0x0600) +template +inline void CTreeItemT::ShowInfoTip() +{ + ATLASSERT(m_pTreeView != NULL); + m_pTreeView->ShowInfoTip(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::GetPartRect(TVITEMPART partID, LPRECT lpRect) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemPartRect(m_hTreeItem, partID, lpRect); +} +#endif // (_WIN32_WINNT >= 0x0600) + + +/////////////////////////////////////////////////////////////////////////////// +// CToolBarCtrl + +template +class CToolBarCtrlT : public TBase +{ +public: +// Construction + CToolBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CToolBarCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return TOOLBARCLASSNAME; + } + + BOOL IsButtonEnabled(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONENABLED, nID, 0L); + } + + BOOL IsButtonChecked(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONCHECKED, nID, 0L); + } + + BOOL IsButtonPressed(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONPRESSED, nID, 0L); + } + + BOOL IsButtonHidden(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return(BOOL) ::SendMessage(m_hWnd, TB_ISBUTTONHIDDEN, nID, 0L); + } + + BOOL IsButtonIndeterminate(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONINDETERMINATE, nID, 0L); + } + + int GetState(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETSTATE, nID, 0L); + } + + BOOL SetState(int nID, UINT nState) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETSTATE, nID, MAKELPARAM(nState, 0)); + } + + BOOL GetButton(int nIndex, LPTBBUTTON lpButton) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETBUTTON, nIndex, (LPARAM)lpButton); + } + + int GetButtonCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_BUTTONCOUNT, 0, 0L); + } + + BOOL GetItemRect(int nIndex, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETITEMRECT, nIndex, (LPARAM)lpRect); + } + + void SetButtonStructSize(int nSize = sizeof(TBBUTTON)) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_BUTTONSTRUCTSIZE, nSize, 0L); + } + + BOOL SetButtonSize(SIZE size) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(size.cx, size.cy)); + } + + BOOL SetButtonSize(int cx, int cy) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, cy)); + } + + BOOL SetBitmapSize(SIZE size) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETBITMAPSIZE, 0, MAKELPARAM(size.cx, size.cy)); + } + + BOOL SetBitmapSize(int cx, int cy) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETBITMAPSIZE, 0, MAKELPARAM(cx, cy)); + } + +#ifndef _WIN32_WCE + CToolTipCtrl GetToolTips() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TB_GETTOOLTIPS, 0, 0L)); + } + + void SetToolTips(HWND hWndToolTip) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETTOOLTIPS, (WPARAM)hWndToolTip, 0L); + } +#endif // !_WIN32_WCE + + void SetNotifyWnd(HWND hWnd) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETPARENT, (WPARAM)hWnd, 0L); + } + + int GetRows() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETROWS, 0, 0L); + } + + void SetRows(int nRows, BOOL bLarger, LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETROWS, MAKELPARAM(nRows, bLarger), (LPARAM)lpRect); + } + + BOOL SetCmdID(int nIndex, UINT nID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETCMDID, nIndex, nID); + } + + DWORD GetBitmapFlags() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TB_GETBITMAPFLAGS, 0, 0L); + } + + int GetBitmap(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETBITMAP, nID, 0L); + } + + int GetButtonText(int nID, LPTSTR lpstrText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETBUTTONTEXT, nID, (LPARAM)lpstrText); + } + + // nIndex - IE5 or higher only + CImageList GetImageList(int nIndex = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETIMAGELIST, nIndex, 0L)); + } + + // nIndex - IE5 or higher only + CImageList SetImageList(HIMAGELIST hImageList, int nIndex = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETIMAGELIST, nIndex, (LPARAM)hImageList)); + } + + // nIndex - IE5 or higher only + CImageList GetDisabledImageList(int nIndex = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETDISABLEDIMAGELIST, nIndex, 0L)); + } + + // nIndex - IE5 or higher only + CImageList SetDisabledImageList(HIMAGELIST hImageList, int nIndex = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETDISABLEDIMAGELIST, nIndex, (LPARAM)hImageList)); + } + +#ifndef _WIN32_WCE + // nIndex - IE5 or higher only + CImageList GetHotImageList(int nIndex = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETHOTIMAGELIST, nIndex, 0L)); + } + + // nIndex - IE5 or higher only + CImageList SetHotImageList(HIMAGELIST hImageList, int nIndex = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETHOTIMAGELIST, nIndex, (LPARAM)hImageList)); + } +#endif // !_WIN32_WCE + + DWORD GetStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TB_GETSTYLE, 0, 0L); + } + + void SetStyle(DWORD dwStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETSTYLE, 0, dwStyle); + } + + DWORD GetButtonSize() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TB_GETBUTTONSIZE, 0, 0L); + } + + void GetButtonSize(SIZE& size) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_GETBUTTONSIZE, 0, 0L); + size.cx = LOWORD(dwRet); + size.cy = HIWORD(dwRet); + } + + BOOL GetRect(int nID, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETRECT, nID, (LPARAM)lpRect); + } + + int GetTextRows() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETTEXTROWS, 0, 0L); + } + + BOOL SetButtonWidth(int cxMin, int cxMax) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONWIDTH, 0, MAKELPARAM(cxMin, cxMax)); + } + + BOOL SetIndent(int nIndent) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETINDENT, nIndent, 0L); + } + + BOOL SetMaxTextRows(int nMaxTextRows) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETMAXTEXTROWS, nMaxTextRows, 0L); + } + +#if (_WIN32_IE >= 0x0400) +#ifndef _WIN32_WCE + BOOL GetAnchorHighlight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETANCHORHIGHLIGHT, 0, 0L); + } + + BOOL SetAnchorHighlight(BOOL bEnable = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETANCHORHIGHLIGHT, bEnable, 0L); + } +#endif // !_WIN32_WCE + + int GetButtonInfo(int nID, LPTBBUTTONINFO lptbbi) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETBUTTONINFO, nID, (LPARAM)lptbbi); + } + + BOOL SetButtonInfo(int nID, LPTBBUTTONINFO lptbbi) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONINFO, nID, (LPARAM)lptbbi); + } + + BOOL SetButtonInfo(int nID, DWORD dwMask, BYTE Style, BYTE State, LPCTSTR lpszItem, + int iImage, WORD cx, int iCommand, DWORD_PTR lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + TBBUTTONINFO tbbi = { 0 }; + tbbi.cbSize = sizeof(TBBUTTONINFO); + tbbi.dwMask = dwMask; + tbbi.idCommand = iCommand; + tbbi.iImage = iImage; + tbbi.fsState = State; + tbbi.fsStyle = Style; + tbbi.cx = cx; + tbbi.pszText = (LPTSTR) lpszItem; + tbbi.lParam = lParam; + return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONINFO, nID, (LPARAM)&tbbi); + } + +#ifndef _WIN32_WCE + int GetHotItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETHOTITEM, 0, 0L); + } + + int SetHotItem(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_SETHOTITEM, nItem, 0L); + } +#endif // !_WIN32_WCE + + BOOL IsButtonHighlighted(int nButtonID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONHIGHLIGHTED, nButtonID, 0L); + } + + DWORD SetDrawTextFlags(DWORD dwMask, DWORD dwFlags) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TB_SETDRAWTEXTFLAGS, dwMask, dwFlags); + } + +#ifndef _WIN32_WCE + BOOL GetColorScheme(LPCOLORSCHEME lpcs) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETCOLORSCHEME, 0, (LPARAM)lpcs); + } + + void SetColorScheme(LPCOLORSCHEME lpcs) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETCOLORSCHEME, 0, (LPARAM)lpcs); + } + + DWORD GetExtendedStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TB_GETEXTENDEDSTYLE, 0, 0L); + } + + DWORD SetExtendedStyle(DWORD dwStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, dwStyle); + } + + void GetInsertMark(LPTBINSERTMARK lptbim) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_GETINSERTMARK, 0, (LPARAM)lptbim); + } + + void SetInsertMark(LPTBINSERTMARK lptbim) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETINSERTMARK, 0, (LPARAM)lptbim); + } + + COLORREF GetInsertMarkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TB_GETINSERTMARKCOLOR, 0, 0L); + } + + COLORREF SetInsertMarkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TB_SETINSERTMARKCOLOR, 0, (LPARAM)clr); + } + + BOOL GetMaxSize(LPSIZE lpSize) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETMAXSIZE, 0, (LPARAM)lpSize); + } + + void GetPadding(LPSIZE lpSizePadding) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpSizePadding != NULL); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_GETPADDING, 0, 0L); + lpSizePadding->cx = GET_X_LPARAM(dwRet); + lpSizePadding->cy = GET_Y_LPARAM(dwRet); + } + + void SetPadding(int cx, int cy, LPSIZE lpSizePadding = NULL) + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_SETPADDING, 0, MAKELPARAM(cx, cy)); + if(lpSizePadding != NULL) + { + lpSizePadding->cx = GET_X_LPARAM(dwRet); + lpSizePadding->cy = GET_Y_LPARAM(dwRet); + } + } + + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + int GetString(int nString, LPTSTR lpstrString, int cchMaxLen) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(cchMaxLen, nString), (LPARAM)lpstrString); + } + + int GetStringBSTR(int nString, BSTR& bstrString) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrString == NULL); + int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(0, nString), NULL)); + if(nLength != -1) + { + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(nLength + 1); + if(lpstrText != NULL) + { + nLength = (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(nLength + 1, nString), (LPARAM)lpstrText); + if(nLength != -1) + bstrString = ::SysAllocString(T2OLE(lpstrText)); + } + else + { + nLength = -1; + } + } + + return nLength; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetString(int nString, _CSTRING_NS::CString& str) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(0, nString), NULL)); + if(nLength != -1) + { + LPTSTR lpstr = str.GetBufferSetLength(nLength + 1); + if(lpstr != NULL) + nLength = (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(nLength + 1, nString), (LPARAM)lpstr); + else + nLength = -1; + str.ReleaseBuffer(); + } + return nLength; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0501) + void GetMetrics(LPTBMETRICS lptbm) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_GETMETRICS, 0, (LPARAM)lptbm); + } + + void SetMetrics(LPTBMETRICS lptbm) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETMETRICS, 0, (LPARAM)lptbm); + } + + void SetWindowTheme(LPCWSTR lpstrTheme) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_WINNT >= 0x0600) + CImageList GetPressedImageList(int nIndex = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETPRESSEDIMAGELIST, nIndex, 0L)); + } + + CImageList SetPressedImageList(HIMAGELIST hImageList, int nIndex = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETPRESSEDIMAGELIST, nIndex, (LPARAM)hImageList)); + } + + void GetItemDropDownRect(int nIndex, LPRECT lpRect) const + { +#ifndef TB_GETITEMDROPDOWNRECT + const int TB_GETITEMDROPDOWNRECT = WM_USER + 103; +#endif + ATLASSERT(::IsWindow(m_hWnd)); + BOOL bRet = (BOOL)::SendMessage(m_hWnd, TB_GETITEMDROPDOWNRECT, nIndex, (LPARAM)lpRect); + bRet; // avoid level 4 warning + ATLASSERT(bRet != FALSE); + } +#endif // (_WIN32_WINNT >= 0x0600) + +// Operations + BOOL EnableButton(int nID, BOOL bEnable = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ENABLEBUTTON, nID, MAKELPARAM(bEnable, 0)); + } + + BOOL CheckButton(int nID, BOOL bCheck = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_CHECKBUTTON, nID, MAKELPARAM(bCheck, 0)); + } + + BOOL PressButton(int nID, BOOL bPress = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_PRESSBUTTON, nID, MAKELPARAM(bPress, 0)); + } + + BOOL HideButton(int nID, BOOL bHide = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_HIDEBUTTON, nID, MAKELPARAM(bHide, 0)); + } + + BOOL Indeterminate(int nID, BOOL bIndeterminate = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_INDETERMINATE, nID, MAKELPARAM(bIndeterminate, 0)); + } + + int AddBitmap(int nNumButtons, UINT nBitmapID) + { + ATLASSERT(::IsWindow(m_hWnd)); + TBADDBITMAP tbab = { 0 }; + tbab.hInst = ModuleHelper::GetResourceInstance(); + ATLASSERT(tbab.hInst != NULL); + tbab.nID = nBitmapID; + return (int)::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons, (LPARAM)&tbab); + } + + int AddBitmap(int nNumButtons, HBITMAP hBitmap) + { + ATLASSERT(::IsWindow(m_hWnd)); + TBADDBITMAP tbab = { 0 }; + tbab.hInst = NULL; + tbab.nID = (UINT_PTR)hBitmap; + return (int)::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons, (LPARAM)&tbab); + } + + BOOL AddButtons(int nNumButtons, LPTBBUTTON lpButtons) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ADDBUTTONS, nNumButtons, (LPARAM)lpButtons); + } + + BOOL InsertButton(int nIndex, LPTBBUTTON lpButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_INSERTBUTTON, nIndex, (LPARAM)lpButton); + } + + BOOL InsertButton(int nIndex, int iCommand, BYTE Style, BYTE State, int iBitmap, + INT_PTR iString, DWORD_PTR lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + TBBUTTON tbb = { 0 }; + tbb.fsStyle = Style; + tbb.fsState = State; + tbb.idCommand = iCommand; + tbb.iBitmap = iBitmap; + tbb.iString = iString; + tbb.dwData = lParam; + return (BOOL)::SendMessage(m_hWnd, TB_INSERTBUTTON, nIndex, (LPARAM)&tbb); + } + + BOOL InsertButton(int nIndex, int iCommand, BYTE Style, BYTE State, int iBitmap, + LPCTSTR lpszItem, DWORD_PTR lParam) + { + return InsertButton(nIndex, iCommand, Style, State, iBitmap, (INT_PTR)lpszItem, lParam); + } + + BOOL AddButton(LPTBBUTTON lpButton) + { + return InsertButton(-1, lpButton); + } + + BOOL AddButton(int iCommand, BYTE Style, BYTE State, int iBitmap, INT_PTR iString, DWORD_PTR lParam) + { + return InsertButton(-1, iCommand, Style, State, iBitmap, iString, lParam); + } + + BOOL AddButton(int iCommand, BYTE Style, BYTE State, int iBitmap, LPCTSTR lpszItem, DWORD_PTR lParam) + { + return InsertButton(-1, iCommand, Style, State, iBitmap, lpszItem, lParam); + } + + BOOL DeleteButton(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_DELETEBUTTON, nIndex, 0L); + } + + BOOL InsertSeparator(int nIndex, int cxWidth = 8) + { + return InsertButton(nIndex, 0, BTNS_SEP, 0, cxWidth, (INT_PTR)0, 0); + } + + BOOL AddSeparator(int cxWidth = 8) + { + return AddButton(0, BTNS_SEP, 0, cxWidth, (INT_PTR)0, 0); + } + + int CommandToIndex(UINT nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_COMMANDTOINDEX, nID, 0L); + } + +#ifndef _WIN32_WCE + void SaveState(HKEY hKeyRoot, LPCTSTR lpszSubKey, LPCTSTR lpszValueName) + { + ATLASSERT(::IsWindow(m_hWnd)); + TBSAVEPARAMS tbs = { 0 }; + tbs.hkr = hKeyRoot; + tbs.pszSubKey = lpszSubKey; + tbs.pszValueName = lpszValueName; + ::SendMessage(m_hWnd, TB_SAVERESTORE, (WPARAM)TRUE, (LPARAM)&tbs); + } + + void RestoreState(HKEY hKeyRoot, LPCTSTR lpszSubKey, LPCTSTR lpszValueName) + { + ATLASSERT(::IsWindow(m_hWnd)); + TBSAVEPARAMS tbs = { 0 }; + tbs.hkr = hKeyRoot; + tbs.pszSubKey = lpszSubKey; + tbs.pszValueName = lpszValueName; + ::SendMessage(m_hWnd, TB_SAVERESTORE, (WPARAM)FALSE, (LPARAM)&tbs); + } + + void Customize() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_CUSTOMIZE, 0, 0L); + } +#endif // !_WIN32_WCE + + int AddString(UINT nStringID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_ADDSTRING, (WPARAM)ModuleHelper::GetResourceInstance(), (LPARAM)nStringID); + } + + int AddStrings(LPCTSTR lpszStrings) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_ADDSTRING, 0, (LPARAM)lpszStrings); + } + + void AutoSize() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_AUTOSIZE, 0, 0L); + } + + BOOL ChangeBitmap(int nID, int nBitmap) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_CHANGEBITMAP, nID, MAKELPARAM(nBitmap, 0)); + } + + int LoadImages(int nBitmapID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_LOADIMAGES, nBitmapID, (LPARAM)ModuleHelper::GetResourceInstance()); + } + + int LoadStdImages(int nBitmapID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_LOADIMAGES, nBitmapID, (LPARAM)HINST_COMMCTRL); + } + + BOOL ReplaceBitmap(LPTBREPLACEBITMAP ptbrb) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_REPLACEBITMAP, 0, (LPARAM)ptbrb); + } + +#if (_WIN32_IE >= 0x0400) + int HitTest(LPPOINT lpPoint) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_HITTEST, 0, (LPARAM)lpPoint); + } + +#ifndef _WIN32_WCE + BOOL InsertMarkHitTest(LPPOINT lpPoint, LPTBINSERTMARK lptbim) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_INSERTMARKHITTEST, (WPARAM)lpPoint, (LPARAM)lptbim); + } + + BOOL InsertMarkHitTest(int x, int y, LPTBINSERTMARK lptbim) const + { + ATLASSERT(::IsWindow(m_hWnd)); + POINT pt = { x, y }; + return (BOOL)::SendMessage(m_hWnd, TB_INSERTMARKHITTEST, (WPARAM)&pt, (LPARAM)lptbim); + } + + BOOL MapAccelerator(TCHAR chAccel, int& nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_MAPACCELERATOR, (WPARAM)chAccel, (LPARAM)&nID); + } + + BOOL MarkButton(int nID, BOOL bHighlight = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_MARKBUTTON, nID, MAKELPARAM(bHighlight, 0)); + } + + BOOL MoveButton(int nOldPos, int nNewPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_MOVEBUTTON, nOldPos, nNewPos); + } + + HRESULT GetObject(REFIID iid, LPVOID* ppvObject) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HRESULT)::SendMessage(m_hWnd, TB_GETOBJECT, (WPARAM)&iid, (LPARAM)ppvObject); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) +}; + +typedef CToolBarCtrlT CToolBarCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CStatusBarCtrl + +template +class CStatusBarCtrlT : public TBase +{ +public: +// Constructors + CStatusBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CStatusBarCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Methods + static LPCTSTR GetWndClassName() + { + return STATUSCLASSNAME; + } + + int GetParts(int nParts, int* pParts) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, SB_GETPARTS, nParts, (LPARAM)pParts); + } + + BOOL SetParts(int nParts, int* pWidths) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, SB_SETPARTS, nParts, (LPARAM)pWidths); + } + + int GetTextLength(int nPane, int* pType = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L); + if (pType != NULL) + *pType = (int)(short)HIWORD(dwRet); + return (int)(short)LOWORD(dwRet); + } + + int GetText(int nPane, LPTSTR lpszText, int* pType = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, SB_GETTEXT, (WPARAM)nPane, (LPARAM)lpszText); + if(pType != NULL) + *pType = (int)(short)HIWORD(dwRet); + return (int)(short)LOWORD(dwRet); + } + +#ifndef _ATL_NO_COM + BOOL GetTextBSTR(int nPane, BSTR& bstrText, int* pType = NULL) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + ATLASSERT(bstrText == NULL); + int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L)); + if(nLength == 0) + return FALSE; + + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(nLength + 1); + if(lpstrText == NULL) + return FALSE; + + if(!GetText(nPane, lpstrText, pType)) + return FALSE; + + bstrText = ::SysAllocString(T2OLE(lpstrText)); + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetText(int nPane, _CSTRING_NS::CString& strText, int* pType = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L)); + if(nLength == 0) + return 0; + + LPTSTR lpstr = strText.GetBufferSetLength(nLength); + if(lpstr == NULL) + return 0; + return GetText(nPane, lpstr, pType); + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + BOOL SetText(int nPane, LPCTSTR lpszText, int nType = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + return (BOOL)::SendMessage(m_hWnd, SB_SETTEXT, (nPane | nType), (LPARAM)lpszText); + } + + BOOL GetRect(int nPane, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + return (BOOL)::SendMessage(m_hWnd, SB_GETRECT, nPane, (LPARAM)lpRect); + } + + BOOL GetBorders(int* pBorders) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, SB_GETBORDERS, 0, (LPARAM)pBorders); + } + + BOOL GetBorders(int& nHorz, int& nVert, int& nSpacing) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int borders[3] = { 0, 0, 0 }; + BOOL bResult = (BOOL)::SendMessage(m_hWnd, SB_GETBORDERS, 0, (LPARAM)&borders); + if(bResult) + { + nHorz = borders[0]; + nVert = borders[1]; + nSpacing = borders[2]; + } + return bResult; + } + + void SetMinHeight(int nMin) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, SB_SETMINHEIGHT, nMin, 0L); + } + + BOOL SetSimple(BOOL bSimple = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, SB_SIMPLE, bSimple, 0L); + } + + BOOL IsSimple() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, SB_ISSIMPLE, 0, 0L); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, SB_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, SB_SETUNICODEFORMAT, bUnicode, 0L); + } + + void GetTipText(int nPane, LPTSTR lpstrText, int nSize) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + ::SendMessage(m_hWnd, SB_GETTIPTEXT, MAKEWPARAM(nPane, nSize), (LPARAM)lpstrText); + } + + void SetTipText(int nPane, LPCTSTR lpstrText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + ::SendMessage(m_hWnd, SB_SETTIPTEXT, nPane, (LPARAM)lpstrText); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) + COLORREF SetBkColor(COLORREF clrBk) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, SB_SETBKCOLOR, 0, (LPARAM)clrBk); + } + + HICON GetIcon(int nPane) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + return (HICON)::SendMessage(m_hWnd, SB_GETICON, nPane, 0L); + } + + BOOL SetIcon(int nPane, HICON hIcon) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + return (BOOL)::SendMessage(m_hWnd, SB_SETICON, nPane, (LPARAM)hIcon); + } +#endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) +}; + +typedef CStatusBarCtrlT CStatusBarCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CTabCtrl + +template +class CTabCtrlT : public TBase +{ +public: +// Constructors + CTabCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CTabCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_TABCONTROL; + } + + CImageList GetImageList() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TCM_GETIMAGELIST, 0, 0L)); + } + + CImageList SetImageList(HIMAGELIST hImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TCM_SETIMAGELIST, 0, (LPARAM)hImageList)); + } + + int GetItemCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_GETITEMCOUNT, 0, 0L); + } + + BOOL GetItem(int nItem, LPTCITEM pTabCtrlItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_GETITEM, nItem, (LPARAM)pTabCtrlItem); + } + + BOOL SetItem(int nItem, LPTCITEM pTabCtrlItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_SETITEM, nItem, (LPARAM)pTabCtrlItem); + } + + int SetItem(int nItem, UINT mask, LPCTSTR lpszItem, DWORD dwState, DWORD dwStateMask, int iImage, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + TCITEM tci = { 0 }; + tci.mask = mask; + tci.pszText = (LPTSTR) lpszItem; + tci.dwState = dwState; + tci.dwStateMask = dwStateMask; + tci.iImage = iImage; + tci.lParam = lParam; + return (int)::SendMessage(m_hWnd, TCM_SETITEM, nItem, (LPARAM)&tci); + } + + BOOL GetItemRect(int nItem, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_GETITEMRECT, nItem, (LPARAM)lpRect); + } + + int GetCurSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_GETCURSEL, 0, 0L); + } + + int SetCurSel(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_SETCURSEL, nItem, 0L); + } + + SIZE SetItemSize(SIZE size) + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwSize = (DWORD)::SendMessage(m_hWnd, TCM_SETITEMSIZE, 0, MAKELPARAM(size.cx, size.cy)); + SIZE sizeRet = { GET_X_LPARAM(dwSize), GET_Y_LPARAM(dwSize) }; + return sizeRet; + } + + void SetItemSize(int cx, int cy) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_SETITEMSIZE, 0, MAKELPARAM(cx, cy)); + } + + void SetPadding(SIZE size) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_SETPADDING, 0, MAKELPARAM(size.cx, size.cy)); + } + + int GetRowCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_GETROWCOUNT, 0, 0L); + } + +#ifndef _WIN32_WCE + CToolTipCtrl GetToolTips() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TCM_GETTOOLTIPS, 0, 0L)); + } + + // this method is deprecated, please use GetToolTips + CToolTipCtrl GetTooltips() const { return GetToolTips(); } + + void SetToolTips(HWND hWndToolTip) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_SETTOOLTIPS, (WPARAM)hWndToolTip, 0L); + } + + // this method is deprecated, please use SetToolTips + void SetTooltips(HWND hWndToolTip) { SetToolTips(hWndToolTip); } + +#endif // !_WIN32_WCE + + int GetCurFocus() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_GETCURFOCUS, 0, 0L); + } + + void SetCurFocus(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_SETCURFOCUS, nItem, 0L); + } + + BOOL SetItemExtra(int cbExtra) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetItemCount() == 0); // must be empty + return (BOOL)::SendMessage(m_hWnd, TCM_SETITEMEXTRA, cbExtra, 0L); + } + + int SetMinTabWidth(int nWidth = -1) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_SETMINTABWIDTH, 0, nWidth); + } + +#if (_WIN32_IE >= 0x0400) + DWORD GetExtendedStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TCM_GETEXTENDEDSTYLE, 0, 0L); + } + + DWORD SetExtendedStyle(DWORD dwExMask, DWORD dwExStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TCM_SETEXTENDEDSTYLE, dwExMask, dwExStyle); + } + +#ifndef _WIN32_WCE + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) + +// Operations + int InsertItem(int nItem, LPTCITEM pTabCtrlItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)pTabCtrlItem); + } + + int InsertItem(int nItem, UINT mask, LPCTSTR lpszItem, int iImage, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + TCITEM tci = { 0 }; + tci.mask = mask; + tci.pszText = (LPTSTR) lpszItem; + tci.iImage = iImage; + tci.lParam = lParam; + return (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)&tci); + } + + int InsertItem(int nItem, LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + TCITEM tci = { 0 }; + tci.mask = TCIF_TEXT; + tci.pszText = (LPTSTR) lpszItem; + return (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)&tci); + } + + int AddItem(LPTCITEM pTabCtrlItem) + { + return InsertItem(GetItemCount(), pTabCtrlItem); + } + + int AddItem(UINT mask, LPCTSTR lpszItem, int iImage, LPARAM lParam) + { + return InsertItem(GetItemCount(), mask, lpszItem, iImage, lParam); + } + + int AddItem(LPCTSTR lpszItem) + { + return InsertItem(GetItemCount(), lpszItem); + } + + BOOL DeleteItem(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_DELETEITEM, nItem, 0L); + } + + BOOL DeleteAllItems() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_DELETEALLITEMS, 0, 0L); + } + + void AdjustRect(BOOL bLarger, LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_ADJUSTRECT, bLarger, (LPARAM)lpRect); + } + + void RemoveImage(int nImage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_REMOVEIMAGE, nImage, 0L); + } + + int HitTest(TC_HITTESTINFO* pHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_HITTEST, 0, (LPARAM)pHitTestInfo); + } + + void DeselectAll(BOOL bExcludeFocus = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_DESELECTALL, bExcludeFocus, 0L); + } + +#if (_WIN32_IE >= 0x0400) + BOOL HighlightItem(int nIndex, BOOL bHighlight = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_HIGHLIGHTITEM, nIndex, MAKELPARAM(bHighlight, 0)); + } +#endif // (_WIN32_IE >= 0x0400) +}; + +typedef CTabCtrlT CTabCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CTrackBarCtrl + +template +class CTrackBarCtrlT : public TBase +{ +public: +// Constructors + CTrackBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CTrackBarCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return TRACKBAR_CLASS; + } + + int GetLineSize() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETLINESIZE, 0, 0L); + } + + int SetLineSize(int nSize) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_SETLINESIZE, 0, nSize); + } + + int GetPageSize() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETPAGESIZE, 0, 0L); + } + + int SetPageSize(int nSize) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_SETPAGESIZE, 0, nSize); + } + + int GetRangeMin() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETRANGEMIN, 0, 0L); + } + + void SetRangeMin(int nMin, BOOL bRedraw = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETRANGEMIN, bRedraw, nMin); + } + + int GetRangeMax() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETRANGEMAX, 0, 0L); + } + + void SetRangeMax(int nMax, BOOL bRedraw = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETRANGEMAX, bRedraw, nMax); + } + + void GetRange(int& nMin, int& nMax) const + { + nMin = GetRangeMin(); + nMax = GetRangeMax(); + } + + void SetRange(int nMin, int nMax, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETRANGE, bRedraw, MAKELPARAM(nMin, nMax)); + } + + int GetSelStart() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETSELSTART, 0, 0L); + } + + void SetSelStart(int nMin, BOOL bRedraw = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETSELSTART, bRedraw, (LPARAM)nMin); + } + + int GetSelEnd() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETSELEND, 0, 0L); + } + + void SetSelEnd(int nMax, BOOL bRedraw = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETSELEND, bRedraw, (LPARAM)nMax); + } + + void GetSelection(int& nMin, int& nMax) const + { + nMin = GetSelStart(); + nMax = GetSelEnd(); + } + + void SetSelection(int nMin, int nMax, BOOL bRedraw = TRUE) + { + SetSelStart(nMin, FALSE); + SetSelEnd(nMax, bRedraw); + } + + void GetChannelRect(LPRECT lprc) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_GETCHANNELRECT, 0, (LPARAM)lprc); + } + + void GetThumbRect(LPRECT lprc) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_GETTHUMBRECT, 0, (LPARAM)lprc); + } + + int GetPos() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETPOS, 0, 0L); + } + + void SetPos(int nPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETPOS, TRUE, nPos); + } + + UINT GetNumTics() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, TBM_GETNUMTICS, 0, 0L); + } + + DWORD* GetTicArray() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD*)::SendMessage(m_hWnd, TBM_GETPTICS, 0, 0L); + } + + int GetTic(int nTic) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETTIC, nTic, 0L); + } + + BOOL SetTic(int nTic) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TBM_SETTIC, 0, nTic); + } + + int GetTicPos(int nTic) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETTICPOS, nTic, 0L); + } + + void SetTicFreq(int nFreq) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETTICFREQ, nFreq, 0L); + } + + int GetThumbLength() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETTHUMBLENGTH, 0, 0L); + } + + void SetThumbLength(int nLength) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETTHUMBLENGTH, nLength, 0L); + } + + void SetSel(int nStart, int nEnd, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & TBS_ENABLESELRANGE) != 0); + ::SendMessage(m_hWnd, TBM_SETSEL, bRedraw, MAKELPARAM(nStart, nEnd)); + } + + ATL::CWindow GetBuddy(BOOL bLeft = TRUE) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ATL::CWindow((HWND)::SendMessage(m_hWnd, TBM_GETBUDDY, bLeft, 0L)); + } + + ATL::CWindow SetBuddy(HWND hWndBuddy, BOOL bLeft = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ATL::CWindow((HWND)::SendMessage(m_hWnd, TBM_SETBUDDY, bLeft, (LPARAM)hWndBuddy)); + } + +#ifndef _WIN32_WCE + CToolTipCtrl GetToolTips() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TBM_GETTOOLTIPS, 0, 0L)); + } + + void SetToolTips(HWND hWndTT) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETTOOLTIPS, (WPARAM)hWndTT, 0L); + } + + int SetTipSide(int nSide) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_SETTIPSIDE, nSide, 0L); + } +#endif // !_WIN32_WCE + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TBM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TBM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +// Operations + void ClearSel(BOOL bRedraw = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_CLEARSEL, bRedraw, 0L); + } + + void VerifyPos() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETPOS, FALSE, 0L); + } + + void ClearTics(BOOL bRedraw = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_CLEARTICS, bRedraw, 0L); + } +}; + +typedef CTrackBarCtrlT CTrackBarCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CUpDownCtrl + +template +class CUpDownCtrlT : public TBase +{ +public: +// Constructors + CUpDownCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CUpDownCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return UPDOWN_CLASS; + } + + UINT GetAccel(int nAccel, UDACCEL* pAccel) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)LOWORD(::SendMessage(m_hWnd, UDM_GETACCEL, nAccel, (LPARAM)pAccel)); + } + + BOOL SetAccel(int nAccel, UDACCEL* pAccel) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)LOWORD(::SendMessage(m_hWnd, UDM_SETACCEL, nAccel, (LPARAM)pAccel)); + } + + UINT GetBase() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)LOWORD(::SendMessage(m_hWnd, UDM_GETBASE, 0, 0L)); + } + + int SetBase(int nBase) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, UDM_SETBASE, nBase, 0L); + } + + ATL::CWindow GetBuddy() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ATL::CWindow((HWND)::SendMessage(m_hWnd, UDM_GETBUDDY, 0, 0L)); + } + + ATL::CWindow SetBuddy(HWND hWndBuddy) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ATL::CWindow((HWND)::SendMessage(m_hWnd, UDM_SETBUDDY, (WPARAM)hWndBuddy, 0L)); + } + + int GetPos(LPBOOL lpbError = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, UDM_GETPOS, 0, 0L); + // Note: Seems that Windows always sets error to TRUE if + // UDS_SETBUDDYINT style is not used + if(lpbError != NULL) + *lpbError = (HIWORD(dwRet) != 0) ? TRUE : FALSE; + return (int)(short)LOWORD(dwRet); + } + + int SetPos(int nPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)(short)LOWORD(::SendMessage(m_hWnd, UDM_SETPOS, 0, MAKELPARAM(nPos, 0))); + } + + DWORD GetRange() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, UDM_GETRANGE, 0, 0L); + } + + void GetRange(int& nLower, int& nUpper) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, UDM_GETRANGE, 0, 0L); + nLower = (int)(short)HIWORD(dwRet); + nUpper = (int)(short)LOWORD(dwRet); + } + + void SetRange(int nLower, int nUpper) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, UDM_SETRANGE, 0, MAKELPARAM(nUpper, nLower)); + } + +#if (_WIN32_IE >= 0x0400) + void SetRange32(int nLower, int nUpper) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, UDM_SETRANGE32, nLower, nUpper); + } + + void GetRange32(int& nLower, int& nUpper) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, UDM_GETRANGE32, (WPARAM)&nLower, (LPARAM)&nUpper); + } + +#ifndef _WIN32_WCE + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, UDM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, UDM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + int GetPos32(LPBOOL lpbError = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + // Note: Seems that Windows always sets error to TRUE if + // UDS_SETBUDDYINT style is not used + return (int)::SendMessage(m_hWnd, UDM_GETPOS32, 0, (LPARAM)lpbError); + } + + int SetPos32(int nPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, UDM_SETPOS32, 0, (LPARAM)nPos); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +}; + +typedef CUpDownCtrlT CUpDownCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CProgressBarCtrl + +template +class CProgressBarCtrlT : public TBase +{ +public: +// Constructors + CProgressBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CProgressBarCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return PROGRESS_CLASS; + } + + DWORD SetRange(int nLower, int nUpper) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, PBM_SETRANGE, 0, MAKELPARAM(nLower, nUpper)); + } + + int SetPos(int nPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_SETPOS, nPos, 0L)); + } + + int OffsetPos(int nPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_DELTAPOS, nPos, 0L)); + } + + int SetStep(int nStep) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_SETSTEP, nStep, 0L)); + } + + UINT GetPos() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, PBM_GETPOS, 0, 0L); + } + + void GetRange(PPBRANGE pPBRange) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pPBRange != NULL); + ::SendMessage(m_hWnd, PBM_GETRANGE, TRUE, (LPARAM)pPBRange); + } + + void GetRange(int& nLower, int& nUpper) const + { + ATLASSERT(::IsWindow(m_hWnd)); + PBRANGE range = { 0 }; + ::SendMessage(m_hWnd, PBM_GETRANGE, TRUE, (LPARAM)&range); + nLower = range.iLow; + nUpper = range.iHigh; + } + + int GetRangeLimit(BOOL bLowLimit) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PBM_GETRANGE, bLowLimit, (LPARAM)NULL); + } + + DWORD SetRange32(int nMin, int nMax) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, PBM_SETRANGE32, nMin, nMax); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + COLORREF SetBarColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, PBM_SETBARCOLOR, 0, (LPARAM)clr); + } + + COLORREF SetBkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, PBM_SETBKCOLOR, 0, (LPARAM)clr); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0501) && defined(PBM_SETMARQUEE) + BOOL SetMarquee(BOOL bMarquee, UINT uUpdateTime = 0U) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PBM_SETMARQUEE, (WPARAM)bMarquee, (LPARAM)uUpdateTime); + } +#endif // (_WIN32_WINNT >= 0x0501) && defined(PBM_SETMARQUEE) + +#if (_WIN32_WINNT >= 0x0600) + int GetStep() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PBM_GETSTEP, 0, 0L); + } + + COLORREF GetBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, PBM_GETBKCOLOR, 0, 0L); + } + + COLORREF GetBarColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, PBM_GETBARCOLOR, 0, 0L); + } + + int GetState() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PBM_GETSTATE, 0, 0L); + } + + int SetState(int nState) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PBM_SETSTATE, nState, 0L); + } +#endif // (_WIN32_WINNT >= 0x0600) + +// Operations + int StepIt() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_STEPIT, 0, 0L)); + } +}; + +typedef CProgressBarCtrlT CProgressBarCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CHotKeyCtrl + +#ifndef _WIN32_WCE + +template +class CHotKeyCtrlT : public TBase +{ +public: +// Constructors + CHotKeyCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CHotKeyCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return HOTKEY_CLASS; + } + + DWORD GetHotKey() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, HKM_GETHOTKEY, 0, 0L); + } + + void GetHotKey(WORD &wVirtualKeyCode, WORD &wModifiers) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dw = (DWORD)::SendMessage(m_hWnd, HKM_GETHOTKEY, 0, 0L); + wVirtualKeyCode = LOBYTE(LOWORD(dw)); + wModifiers = HIBYTE(LOWORD(dw)); + } + + void SetHotKey(WORD wVirtualKeyCode, WORD wModifiers) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, HKM_SETHOTKEY, MAKEWORD(wVirtualKeyCode, wModifiers), 0L); + } + + void SetRules(WORD wInvalidComb, WORD wModifiers) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, HKM_SETRULES, wInvalidComb, MAKELPARAM(wModifiers, 0)); + } +}; + +typedef CHotKeyCtrlT CHotKeyCtrl; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CAnimateCtrl + +#ifndef _WIN32_WCE + +template +class CAnimateCtrlT : public TBase +{ +public: +// Constructors + CAnimateCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CAnimateCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return ANIMATE_CLASS; + } + +// Operations + BOOL Open(ATL::_U_STRINGorID FileName) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, ACM_OPEN, 0, (LPARAM)FileName.m_lpstr); + } + + BOOL Play(UINT nFrom, UINT nTo, UINT nRep) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, ACM_PLAY, nRep, MAKELPARAM(nFrom, nTo)); + } + + BOOL Stop() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, ACM_STOP, 0, 0L); + } + + BOOL Close() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, ACM_OPEN, 0, 0L); + } + + BOOL Seek(UINT nTo) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, ACM_PLAY, 0, MAKELPARAM(nTo, nTo)); + } + + // Vista only + BOOL IsPlaying() const + { +#ifndef ACM_ISPLAYING + const UINT ACM_ISPLAYING = (WM_USER+104); +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, ACM_ISPLAYING, 0, 0L); + } +}; + +typedef CAnimateCtrlT CAnimateCtrl; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CRichEditCtrl + +#ifndef _WIN32_WCE + +#if defined(_UNICODE) && (_RICHEDIT_VER == 0x0100) + #undef RICHEDIT_CLASS + #define RICHEDIT_CLASS L"RICHEDIT" +#endif + +#if !defined(_UNICODE) && (_RICHEDIT_VER >= 0x0500) + #undef MSFTEDIT_CLASS + #define MSFTEDIT_CLASS "RICHEDIT50W" +#endif + +template +class CRichEditCtrlT : public TBase +{ +public: +// Constructors + CRichEditCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CRichEditCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { +#if (_RICHEDIT_VER >= 0x0500) + return MSFTEDIT_CLASS; +#else + return RICHEDIT_CLASS; +#endif + } + + static LPCTSTR GetLibraryName() + { +#if (_RICHEDIT_VER >= 0x0500) + return _T("MSFTEDIT.DLL"); +#elif (_RICHEDIT_VER >= 0x0200) + return _T("RICHED20.DLL"); +#else + return _T("RICHED32.DLL"); +#endif + } + + int GetLineCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETLINECOUNT, 0, 0L); + } + + BOOL GetModify() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L); + } + + void SetModify(BOOL bModified = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETMODIFY, bModified, 0L); + } + + void GetRect(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_GETRECT, 0, (LPARAM)lpRect); + } + + DWORD GetOptions() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETOPTIONS, 0, 0L); + } + + DWORD SetOptions(WORD wOperation, DWORD dwOptions) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_SETOPTIONS, wOperation, dwOptions); + } + + // NOTE: first word in lpszBuffer must contain the size of the buffer! + int GetLine(int nIndex, LPTSTR lpszBuffer) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer); + } + + int GetLine(int nIndex, LPTSTR lpszBuffer, int nMaxLength) const + { + ATLASSERT(::IsWindow(m_hWnd)); + *(LPWORD)lpszBuffer = (WORD)nMaxLength; + return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer); + } + + BOOL CanUndo() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L); + } + + BOOL CanPaste(UINT nFormat = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANPASTE, nFormat, 0L); + } + + void GetSel(LONG& nStartChar, LONG& nEndChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + CHARRANGE cr = { 0, 0 }; + ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr); + nStartChar = cr.cpMin; + nEndChar = cr.cpMax; + } + + void GetSel(CHARRANGE &cr) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr); + } + + int SetSel(LONG nStartChar, LONG nEndChar) + { + ATLASSERT(::IsWindow(m_hWnd)); + CHARRANGE cr = { nStartChar, nEndChar }; + return (int)::SendMessage(m_hWnd, EM_EXSETSEL, 0, (LPARAM)&cr); + } + + int SetSel(CHARRANGE &cr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_EXSETSEL, 0, (LPARAM)&cr); + } + + int SetSelAll() + { + return SetSel(0, -1); + } + + int SetSelNone() + { + return SetSel(-1, 0); + } + + DWORD GetDefaultCharFormat(CHARFORMAT& cf) const + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT); + return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 0, (LPARAM)&cf); + } + + DWORD GetSelectionCharFormat(CHARFORMAT& cf) const + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT); + return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 1, (LPARAM)&cf); + } + + DWORD GetEventMask() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETEVENTMASK, 0, 0L); + } + + LONG GetLimitText() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_GETLIMITTEXT, 0, 0L); + } + + DWORD GetParaFormat(PARAFORMAT& pf) const + { + ATLASSERT(::IsWindow(m_hWnd)); + pf.cbSize = sizeof(PARAFORMAT); + return (DWORD)::SendMessage(m_hWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf); + } + +#if (_RICHEDIT_VER >= 0x0200) + LONG GetSelText(LPTSTR lpstrBuff) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrBuff); + } +#else // !(_RICHEDIT_VER >= 0x0200) + // RichEdit 1.0 EM_GETSELTEXT is ANSI only + LONG GetSelText(LPSTR lpstrBuff) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrBuff); + } +#endif // !(_RICHEDIT_VER >= 0x0200) + +#ifndef _ATL_NO_COM + BOOL GetSelTextBSTR(BSTR& bstrText) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrText == NULL); + + CHARRANGE cr = { 0, 0 }; + ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr); + +#if (_RICHEDIT_VER >= 0x0200) + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1); + if(lpstrText == NULL) + return FALSE; + if(::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText) == 0) + return FALSE; + + bstrText = ::SysAllocString(T2W(lpstrText)); +#else // !(_RICHEDIT_VER >= 0x0200) + CTempBuffer buff; + LPSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1); + if(lpstrText == NULL) + return FALSE; + if(::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText) == 0) + return FALSE; + + bstrText = ::SysAllocString(A2W(lpstrText)); +#endif // !(_RICHEDIT_VER >= 0x0200) + + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + LONG GetSelText(_CSTRING_NS::CString& strText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + + CHARRANGE cr = { 0, 0 }; + ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr); + +#if (_RICHEDIT_VER >= 0x0200) + LONG lLen = 0; + LPTSTR lpstrText = strText.GetBufferSetLength(cr.cpMax - cr.cpMin); + if(lpstrText != NULL) + { + lLen = (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText); + strText.ReleaseBuffer(); + } +#else // !(_RICHEDIT_VER >= 0x0200) + CTempBuffer buff; + LPSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1); + if(lpstrText == NULL) + return 0; + LONG lLen = (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText); + if(lLen == 0) + return 0; + + USES_CONVERSION; + strText = A2T(lpstrText); +#endif // !(_RICHEDIT_VER >= 0x0200) + + return lLen; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + WORD GetSelectionType() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (WORD)::SendMessage(m_hWnd, EM_SELECTIONTYPE, 0, 0L); + } + + COLORREF SetBackgroundColor(COLORREF cr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, EM_SETBKGNDCOLOR, 0, cr); + } + + COLORREF SetBackgroundColor() // sets to system background + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, EM_SETBKGNDCOLOR, 1, 0); + } + + BOOL SetCharFormat(CHARFORMAT& cf, WORD wFlags) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, (WPARAM)wFlags, (LPARAM)&cf); + } + + BOOL SetDefaultCharFormat(CHARFORMAT& cf) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf); + } + + BOOL SetSelectionCharFormat(CHARFORMAT& cf) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + + BOOL SetWordCharFormat(CHARFORMAT& cf) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION | SCF_WORD, (LPARAM)&cf); + } + + DWORD SetEventMask(DWORD dwEventMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_SETEVENTMASK, 0, dwEventMask); + } + + BOOL SetParaFormat(PARAFORMAT& pf) + { + ATLASSERT(::IsWindow(m_hWnd)); + pf.cbSize = sizeof(PARAFORMAT); + return (BOOL)::SendMessage(m_hWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf); + } + + BOOL SetTargetDevice(HDC hDC, int cxLineWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTARGETDEVICE, (WPARAM)hDC, cxLineWidth); + } + + int GetTextLength() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, WM_GETTEXTLENGTH, 0, 0L); + } + + BOOL SetReadOnly(BOOL bReadOnly = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETREADONLY, bReadOnly, 0L); + } + + int GetFirstVisibleLine() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L); + } + + int GetTextRange(TEXTRANGE* pTextRange) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)pTextRange); + } + +#if (_RICHEDIT_VER < 0x0200) + EDITWORDBREAKPROCEX GetWordBreakProcEx() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (EDITWORDBREAKPROCEX)::SendMessage(m_hWnd, EM_GETWORDBREAKPROCEX, 0, 0L); + } + + EDITWORDBREAKPROCEX SetWordBreakProcEx(EDITWORDBREAKPROCEX pfnEditWordBreakProcEx) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (EDITWORDBREAKPROCEX)::SendMessage(m_hWnd, EM_SETWORDBREAKPROCEX, 0, (LPARAM)pfnEditWordBreakProcEx); + } +#endif // (_RICHEDIT_VER < 0x0200) + +#if (_RICHEDIT_VER >= 0x0200) + int GetTextRange(LONG nStartChar, LONG nEndChar, LPTSTR lpstrText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TEXTRANGE tr = { 0 }; + tr.chrg.cpMin = nStartChar; + tr.chrg.cpMax = nEndChar; + tr.lpstrText = lpstrText; + return (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr); + } +#else // !(_RICHEDIT_VER >= 0x0200) + int GetTextRange(LONG nStartChar, LONG nEndChar, LPSTR lpstrText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TEXTRANGE tr = { 0 }; + tr.chrg.cpMin = nStartChar; + tr.chrg.cpMax = nEndChar; + tr.lpstrText = lpstrText; + return (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr); + } +#endif // !(_RICHEDIT_VER >= 0x0200) + +#if (_RICHEDIT_VER >= 0x0200) + DWORD GetDefaultCharFormat(CHARFORMAT2& cf) const + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT2); + return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 0, (LPARAM)&cf); + } + + BOOL SetCharFormat(CHARFORMAT2& cf, WORD wFlags) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT2); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, (WPARAM)wFlags, (LPARAM)&cf); + } + + BOOL SetDefaultCharFormat(CHARFORMAT2& cf) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT2); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf); + } + + DWORD GetSelectionCharFormat(CHARFORMAT2& cf) const + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT2); + return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 1, (LPARAM)&cf); + } + + BOOL SetSelectionCharFormat(CHARFORMAT2& cf) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT2); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + + BOOL SetWordCharFormat(CHARFORMAT2& cf) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT2); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION | SCF_WORD, (LPARAM)&cf); + } + + DWORD GetParaFormat(PARAFORMAT2& pf) const + { + ATLASSERT(::IsWindow(m_hWnd)); + pf.cbSize = sizeof(PARAFORMAT2); + return (DWORD)::SendMessage(m_hWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf); + } + + BOOL SetParaFormat(PARAFORMAT2& pf) + { + ATLASSERT(::IsWindow(m_hWnd)); + pf.cbSize = sizeof(PARAFORMAT2); + return (BOOL)::SendMessage(m_hWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf); + } + + TEXTMODE GetTextMode() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (TEXTMODE)::SendMessage(m_hWnd, EM_GETTEXTMODE, 0, 0L); + } + + BOOL SetTextMode(TEXTMODE enumTextMode) + { + ATLASSERT(::IsWindow(m_hWnd)); + return !(BOOL)::SendMessage(m_hWnd, EM_SETTEXTMODE, enumTextMode, 0L); + } + + UNDONAMEID GetUndoName() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UNDONAMEID)::SendMessage(m_hWnd, EM_GETUNDONAME, 0, 0L); + } + + UNDONAMEID GetRedoName() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UNDONAMEID)::SendMessage(m_hWnd, EM_GETREDONAME, 0, 0L); + } + + BOOL CanRedo() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANREDO, 0, 0L); + } + + BOOL GetAutoURLDetect() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETAUTOURLDETECT, 0, 0L); + } + + BOOL SetAutoURLDetect(BOOL bAutoDetect = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return !(BOOL)::SendMessage(m_hWnd, EM_AUTOURLDETECT, bAutoDetect, 0L); + } + + // this method is deprecated, please use SetAutoURLDetect + BOOL EnableAutoURLDetect(BOOL bEnable = TRUE) { return SetAutoURLDetect(bEnable); } + + UINT SetUndoLimit(UINT uUndoLimit) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_SETUNDOLIMIT, uUndoLimit, 0L); + } + + void SetPalette(HPALETTE hPalette) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETPALETTE, (WPARAM)hPalette, 0L); + } + + int GetTextEx(GETTEXTEX* pGetTextEx, LPTSTR lpstrText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETTEXTEX, (WPARAM)pGetTextEx, (LPARAM)lpstrText); + } + + int GetTextEx(LPTSTR lpstrText, int nTextLen, DWORD dwFlags = GT_DEFAULT, UINT uCodePage = CP_ACP, LPCSTR lpDefaultChar = NULL, LPBOOL lpUsedDefChar = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + GETTEXTEX gte = { 0 }; + gte.cb = nTextLen * sizeof(TCHAR); + gte.codepage = uCodePage; + gte.flags = dwFlags; + gte.lpDefaultChar = lpDefaultChar; + gte.lpUsedDefChar = lpUsedDefChar; + return (int)::SendMessage(m_hWnd, EM_GETTEXTEX, (WPARAM)>e, (LPARAM)lpstrText); + } + + int GetTextLengthEx(GETTEXTLENGTHEX* pGetTextLengthEx) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETTEXTLENGTHEX, (WPARAM)pGetTextLengthEx, 0L); + } + + int GetTextLengthEx(DWORD dwFlags = GTL_DEFAULT, UINT uCodePage = CP_ACP) const + { + ATLASSERT(::IsWindow(m_hWnd)); + GETTEXTLENGTHEX gtle = { 0 }; + gtle.codepage = uCodePage; + gtle.flags = dwFlags; + return (int)::SendMessage(m_hWnd, EM_GETTEXTLENGTHEX, (WPARAM)>le, 0L); + } + + EDITWORDBREAKPROC GetWordBreakProc() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (EDITWORDBREAKPROC)::SendMessage(m_hWnd, EM_GETWORDBREAKPROC, 0, 0L); + } + + void SetWordBreakProc(EDITWORDBREAKPROC ewbprc) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETWORDBREAKPROC, 0, (LPARAM)ewbprc); + } +#endif // (_RICHEDIT_VER >= 0x0200) + +#if (_RICHEDIT_VER >= 0x0300) + int SetTextEx(SETTEXTEX* pSetTextEx, LPCTSTR lpstrText) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_SETTEXTEX, (WPARAM)pSetTextEx, (LPARAM)lpstrText); + } + + int SetTextEx(LPCTSTR lpstrText, DWORD dwFlags = ST_DEFAULT, UINT uCodePage = CP_ACP) + { + ATLASSERT(::IsWindow(m_hWnd)); + SETTEXTEX ste = { 0 }; + ste.flags = dwFlags; + ste.codepage = uCodePage; + return (int)::SendMessage(m_hWnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpstrText); + } + + int GetEditStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETEDITSTYLE, 0, 0L); + } + + int SetEditStyle(int nStyle, int nMask = -1) + { + ATLASSERT(::IsWindow(m_hWnd)); + if(nMask == -1) + nMask = nStyle; // set everything specified + return (int)::SendMessage(m_hWnd, EM_SETEDITSTYLE, nStyle, nMask); + } + + BOOL SetFontSize(int nFontSizeDelta) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nFontSizeDelta >= -1637 && nFontSizeDelta <= 1638); + return (BOOL)::SendMessage(m_hWnd, EM_SETFONTSIZE, nFontSizeDelta, 0L); + } + + void GetScrollPos(LPPOINT lpPoint) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpPoint != NULL); + ::SendMessage(m_hWnd, EM_GETSCROLLPOS, 0, (LPARAM)lpPoint); + } + + void SetScrollPos(LPPOINT lpPoint) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpPoint != NULL); + ::SendMessage(m_hWnd, EM_SETSCROLLPOS, 0, (LPARAM)lpPoint); + } + + BOOL GetZoom(int& nNum, int& nDen) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETZOOM, (WPARAM)&nNum, (LPARAM)&nDen); + } + + BOOL SetZoom(int nNum, int nDen) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nNum >= 0 && nNum <= 64); + ATLASSERT(nDen >= 0 && nDen <= 64); + return (BOOL)::SendMessage(m_hWnd, EM_SETZOOM, nNum, nDen); + } + + BOOL SetZoomOff() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETZOOM, 0, 0L); + } + + void SetMargins(UINT nLeft, UINT nRight, WORD wFlags = EC_LEFTMARGIN | EC_RIGHTMARGIN) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETMARGINS, wFlags, MAKELONG(nLeft, nRight)); + } +#endif // (_RICHEDIT_VER >= 0x0300) + +// Operations + void LimitText(LONG nChars = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_EXLIMITTEXT, 0, nChars); + } + + int LineFromChar(LONG nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_EXLINEFROMCHAR, 0, nIndex); + } + + POINT PosFromChar(LONG nChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + POINT point = { 0, 0 }; + ::SendMessage(m_hWnd, EM_POSFROMCHAR, (WPARAM)&point, nChar); + return point; + } + + int CharFromPos(POINT pt) const + { + ATLASSERT(::IsWindow(m_hWnd)); + POINTL ptl = { pt.x, pt.y }; + return (int)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0, (LPARAM)&ptl); + } + + void EmptyUndoBuffer() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_EMPTYUNDOBUFFER, 0, 0L); + } + + int LineIndex(int nLine = -1) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_LINEINDEX, nLine, 0L); + } + + int LineLength(int nLine = -1) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_LINELENGTH, nLine, 0L); + } + + BOOL LineScroll(int nLines) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_LINESCROLL, 0, nLines); + } + + void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM) bCanUndo, (LPARAM)lpszNewText); + } + + void SetRect(LPCRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETRECT, 0, (LPARAM)lpRect); + } + + BOOL DisplayBand(LPRECT pDisplayRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_DISPLAYBAND, 0, (LPARAM)pDisplayRect); + } + + LONG FindText(DWORD dwFlags, FINDTEXT& ft) const + { + ATLASSERT(::IsWindow(m_hWnd)); +#if (_RICHEDIT_VER >= 0x0200) && defined(_UNICODE) + return (LONG)::SendMessage(m_hWnd, EM_FINDTEXTW, dwFlags, (LPARAM)&ft); +#else + return (LONG)::SendMessage(m_hWnd, EM_FINDTEXT, dwFlags, (LPARAM)&ft); +#endif + } + + LONG FindText(DWORD dwFlags, FINDTEXTEX& ft) const + { + ATLASSERT(::IsWindow(m_hWnd)); +#if (_RICHEDIT_VER >= 0x0200) && defined(_UNICODE) + return (LONG)::SendMessage(m_hWnd, EM_FINDTEXTEXW, dwFlags, (LPARAM)&ft); +#else + return (LONG)::SendMessage(m_hWnd, EM_FINDTEXTEX, dwFlags, (LPARAM)&ft); +#endif + } + + LONG FormatRange(FORMATRANGE& fr, BOOL bDisplay = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_FORMATRANGE, bDisplay, (LPARAM)&fr); + } + + LONG FormatRange(FORMATRANGE* pFormatRange, BOOL bDisplay = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_FORMATRANGE, bDisplay, (LPARAM)pFormatRange); + } + + void HideSelection(BOOL bHide = TRUE, BOOL bChangeStyle = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_HIDESELECTION, bHide, bChangeStyle); + } + + void PasteSpecial(UINT uClipFormat, DWORD dwAspect = 0, HMETAFILE hMF = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + REPASTESPECIAL reps = { dwAspect, (DWORD_PTR)hMF }; + ::SendMessage(m_hWnd, EM_PASTESPECIAL, uClipFormat, (LPARAM)&reps); + } + + void RequestResize() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_REQUESTRESIZE, 0, 0L); + } + + LONG StreamIn(UINT uFormat, EDITSTREAM& es) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_STREAMIN, uFormat, (LPARAM)&es); + } + + LONG StreamOut(UINT uFormat, EDITSTREAM& es) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_STREAMOUT, uFormat, (LPARAM)&es); + } + + DWORD FindWordBreak(int nCode, LONG nStartChar) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_FINDWORDBREAK, nCode, nStartChar); + } + + // Additional operations + void ScrollCaret() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L); + } + + int InsertText(long nInsertAfterChar, LPCTSTR lpstrText, BOOL bCanUndo = FALSE) + { + int nRet = SetSel(nInsertAfterChar, nInsertAfterChar); + ReplaceSel(lpstrText, bCanUndo); + return nRet; + } + + int AppendText(LPCTSTR lpstrText, BOOL bCanUndo = FALSE) + { + return InsertText(GetWindowTextLength(), lpstrText, bCanUndo); + } + + // Clipboard operations + BOOL Undo() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_UNDO, 0, 0L); + } + + void Clear() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L); + } + + void Copy() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_COPY, 0, 0L); + } + + void Cut() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CUT, 0, 0L); + } + + void Paste() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_PASTE, 0, 0L); + } + + // OLE support + IRichEditOle* GetOleInterface() const + { + ATLASSERT(::IsWindow(m_hWnd)); + IRichEditOle *pRichEditOle = NULL; + ::SendMessage(m_hWnd, EM_GETOLEINTERFACE, 0, (LPARAM)&pRichEditOle); + return pRichEditOle; + } + + BOOL SetOleCallback(IRichEditOleCallback* pCallback) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETOLECALLBACK, 0, (LPARAM)pCallback); + } + +#if (_RICHEDIT_VER >= 0x0200) + BOOL Redo() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_REDO, 0, 0L); + } + + void StopGroupTyping() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_STOPGROUPTYPING, 0, 0L); + } + + void ShowScrollBar(int nBarType, BOOL bVisible = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SHOWSCROLLBAR, nBarType, bVisible); + } +#endif // (_RICHEDIT_VER >= 0x0200) + +#if (_RICHEDIT_VER >= 0x0300) + BOOL SetTabStops(int nTabStops, LPINT rgTabStops) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops); + } + + BOOL SetTabStops() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 0, 0L); + } + + BOOL SetTabStops(const int& cxEachStop) // takes an 'int' + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop); + } +#endif // (_RICHEDIT_VER >= 0x0300) + +#if (_RICHEDIT_VER >= 0x0800) + AutoCorrectProc GetAutoCorrectProc() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (AutoCorrectProc)::SendMessage(m_hWnd, EM_GETAUTOCORRECTPROC, 0, 0L); + } + + BOOL SetAutoCorrectProc(AutoCorrectProc pfn) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETAUTOCORRECTPROC, (WPARAM)pfn, 0L); + } + + BOOL CallAutoCorrectProc(WCHAR ch) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CALLAUTOCORRECTPROC, (WPARAM)ch, 0L); + } + + DWORD GetEditStyleEx() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETEDITSTYLEEX, 0, 0L); + } + + DWORD SetEditStyleEx(DWORD dwStyleEx, DWORD dwMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_SETEDITSTYLEEX, dwStyleEx, dwMask); + } + + DWORD GetStoryType(int nStoryIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETSTORYTYPE, nStoryIndex, 0L); + } + + DWORD SetStoryType(int nStoryIndex, DWORD dwStoryType) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_SETSTORYTYPE, nStoryIndex, dwStoryType); + } + + DWORD GetEllipsisMode() const + { + ATLASSERT(::IsWindow(m_hWnd)); + + DWORD dwMode = 0; + BOOL bRet = (BOOL)::SendMessage(m_hWnd, EM_GETELLIPSISMODE, 0, (LPARAM)&dwMode); + bRet; // avoid level 4 warning + ATLASSERT(bRet != FALSE); + + return dwMode; + } + + BOOL SetEllipsisMode(DWORD dwEllipsisMode) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETELLIPSISMODE, 0, dwEllipsisMode); + } + + BOOL GetEllipsisState() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETELLIPSISSTATE, 0, 0L); + } + + BOOL GetTouchOptions(int nTouchOptions) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETTOUCHOPTIONS, nTouchOptions, 0L); + } + + void SetTouchOptions(int nTouchOptions, BOOL bEnable) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETTOUCHOPTIONS, nTouchOptions, bEnable); + } + + HRESULT InsertTable(TABLEROWPARMS* pRowParams, TABLECELLPARMS* pCellParams) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HRESULT)::SendMessage(m_hWnd, EM_INSERTTABLE, (WPARAM)pRowParams, (LPARAM)pCellParams); + } + + HRESULT GetTableParams(TABLEROWPARMS* pRowParams, TABLECELLPARMS* pCellParams) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HRESULT)::SendMessage(m_hWnd, EM_GETTABLEPARMS, (WPARAM)pRowParams, (LPARAM)pCellParams); + } + + HRESULT SetTableParams(TABLEROWPARMS* pRowParams, TABLECELLPARMS* pCellParams) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HRESULT)::SendMessage(m_hWnd, EM_SETTABLEPARMS, (WPARAM)pRowParams, (LPARAM)pCellParams); + } + + HRESULT InsertImage(RICHEDIT_IMAGE_PARAMETERS* pParams) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HRESULT)::SendMessage(m_hWnd, EM_INSERTIMAGE, 0, (LPARAM)pParams); + } + + BOOL SetUiaName(LPCTSTR lpstrName) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETUIANAME, 0, (LPARAM)lpstrName); + } +#endif // (_RICHEDIT_VER >= 0x0800) +}; + +typedef CRichEditCtrlT CRichEditCtrl; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CRichEditCommands - message handlers for standard EDIT commands + +#ifndef _WIN32_WCE + +// Chain to CRichEditCommands message map. Your class must also derive from CRichEditCtrl. +// Example: +// class CMyRichEdit : public CWindowImpl, +// public CRichEditCommands +// { +// public: +// BEGIN_MSG_MAP(CMyRichEdit) +// // your handlers... +// CHAIN_MSG_MAP_ALT(CRichEditCommands, 1) +// END_MSG_MAP() +// // other stuff... +// }; + +template +class CRichEditCommands : public CEditCommands< T > +{ +public: + BEGIN_MSG_MAP(CRichEditCommands< T >) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_EDIT_CLEAR, CEditCommands< T >::OnEditClear) + COMMAND_ID_HANDLER(ID_EDIT_CLEAR_ALL, CEditCommands< T >::OnEditClearAll) + COMMAND_ID_HANDLER(ID_EDIT_COPY, CEditCommands< T >::OnEditCopy) + COMMAND_ID_HANDLER(ID_EDIT_CUT, CEditCommands< T >::OnEditCut) + COMMAND_ID_HANDLER(ID_EDIT_PASTE, CEditCommands< T >::OnEditPaste) + COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, CEditCommands< T >::OnEditSelectAll) + COMMAND_ID_HANDLER(ID_EDIT_UNDO, CEditCommands< T >::OnEditUndo) +#if (_RICHEDIT_VER >= 0x0200) + COMMAND_ID_HANDLER(ID_EDIT_REDO, OnEditRedo) +#endif // (_RICHEDIT_VER >= 0x0200) + END_MSG_MAP() + +#if (_RICHEDIT_VER >= 0x0200) + LRESULT OnEditRedo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Redo(); + return 0; + } +#endif // (_RICHEDIT_VER >= 0x0200) + +// State (update UI) helpers + BOOL CanCut() const + { return HasSelection(); } + + BOOL CanCopy() const + { return HasSelection(); } + + BOOL CanClear() const + { return HasSelection(); } + +// Implementation + BOOL HasSelection() const + { + const T* pT = static_cast(this); + return (pT->GetSelectionType() != SEL_EMPTY); + } +}; + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CDragListBox + +#ifndef _WIN32_WCE + +template +class CDragListBoxT : public CListBoxT< TBase > +{ +public: +// Constructors + CDragListBoxT(HWND hWnd = NULL) : CListBoxT< TBase >(hWnd) + { } + + CDragListBoxT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + if(hWnd != NULL) + MakeDragList(); + return hWnd; + } + +// Operations + BOOL MakeDragList() + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0); + return ::MakeDragList(m_hWnd); + } + + int LBItemFromPt(POINT pt, BOOL bAutoScroll = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::LBItemFromPt(m_hWnd, pt, bAutoScroll); + } + + void DrawInsert(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::DrawInsert(GetParent(), m_hWnd, nItem); + } + + static UINT GetDragListMessage() + { + static UINT uDragListMessage = 0; + if(uDragListMessage == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CDragListBox::GetDragListMessage.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uDragListMessage == 0) + uDragListMessage = ::RegisterWindowMessage(DRAGLISTMSGSTRING); + + lock.Unlock(); + } + ATLASSERT(uDragListMessage != 0); + return uDragListMessage; + } +}; + +typedef CDragListBoxT CDragListBox; + +template +class CDragListNotifyImpl +{ +public: + BEGIN_MSG_MAP(CDragListNotifyImpl< T >) + MESSAGE_HANDLER(CDragListBox::GetDragListMessage(), OnDragListNotify) + END_MSG_MAP() + + LRESULT OnDragListNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + uMsg; // avoid level 4 warning + ATLASSERT(uMsg == CDragListBox::GetDragListMessage()); + T* pT = static_cast(this); + LPDRAGLISTINFO lpDragListInfo = (LPDRAGLISTINFO)lParam; + LRESULT lRet = 0; + switch(lpDragListInfo->uNotification) + { + case DL_BEGINDRAG: + lRet = (LPARAM)pT->OnBeginDrag((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor); + break; + case DL_CANCELDRAG: + pT->OnCancelDrag((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor); + break; + case DL_DRAGGING: + lRet = (LPARAM)pT->OnDragging((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor); + break; + case DL_DROPPED: + pT->OnDropped((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor); + break; + default: + ATLTRACE2(atlTraceUI, 0, _T("Unknown DragListBox notification\n")); + bHandled = FALSE; // don't handle it + break; + } + return lRet; + } + +// Overrideables + BOOL OnBeginDrag(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/) + { + return TRUE; // allow dragging + } + + void OnCancelDrag(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/) + { + // nothing to do + } + + int OnDragging(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/) + { + return 0; // don't change cursor + } + + void OnDropped(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/) + { + // nothing to do + } +}; + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CReBarCtrl + +template +class CReBarCtrlT : public TBase +{ +public: +// Constructors + CReBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CReBarCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return REBARCLASSNAME; + } + + UINT GetBandCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, RB_GETBANDCOUNT, 0, 0L); + } + + BOOL GetBandInfo(int nBand, LPREBARBANDINFO lprbbi) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_GETBANDINFO, nBand, (LPARAM)lprbbi); + } + + BOOL SetBandInfo(int nBand, LPREBARBANDINFO lprbbi) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_SETBANDINFO, nBand, (LPARAM)lprbbi); + } + + BOOL GetBarInfo(LPREBARINFO lprbi) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_GETBARINFO, 0, (LPARAM)lprbi); + } + + BOOL SetBarInfo(LPREBARINFO lprbi) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_SETBARINFO, 0, (LPARAM)lprbi); + } + + CImageList GetImageList() const + { + ATLASSERT(::IsWindow(m_hWnd)); + REBARINFO rbi = { 0 }; + rbi.cbSize = sizeof(REBARINFO); + rbi.fMask = RBIM_IMAGELIST; + BOOL bRet = (BOOL)::SendMessage(m_hWnd, RB_GETBARINFO, 0, (LPARAM)&rbi); + return CImageList((bRet != FALSE) ? rbi.himl : NULL); + } + + BOOL SetImageList(HIMAGELIST hImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + REBARINFO rbi = { 0 }; + rbi.cbSize = sizeof(REBARINFO); + rbi.fMask = RBIM_IMAGELIST; + rbi.himl = hImageList; + return (BOOL)::SendMessage(m_hWnd, RB_SETBARINFO, 0, (LPARAM)&rbi); + } + + UINT GetRowCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, RB_GETROWCOUNT, 0, 0L); + } + + UINT GetRowHeight(int nBand) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, RB_GETROWHEIGHT, nBand, 0L); + } + +#if (_WIN32_IE >= 0x0400) + COLORREF GetTextColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, RB_GETTEXTCOLOR, 0, 0L); + } + + COLORREF SetTextColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, RB_SETTEXTCOLOR, 0, (LPARAM)clr); + } + + COLORREF GetBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, RB_GETBKCOLOR, 0, 0L); + } + + COLORREF SetBkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, RB_SETBKCOLOR, 0, (LPARAM)clr); + } + + UINT GetBarHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, RB_GETBARHEIGHT, 0, 0L); + } + + BOOL GetRect(int nBand, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_GETRECT, nBand, (LPARAM)lpRect); + } + +#ifndef _WIN32_WCE + CToolTipCtrl GetToolTips() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, RB_GETTOOLTIPS, 0, 0L)); + } + + void SetToolTips(HWND hwndToolTip) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_SETTOOLTIPS, (WPARAM)hwndToolTip, 0L); + } +#endif // !_WIN32_WCE + + void GetBandBorders(int nBand, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpRect != NULL); + ::SendMessage(m_hWnd, RB_GETBANDBORDERS, nBand, (LPARAM)lpRect); + } + +#ifndef _WIN32_WCE + BOOL GetColorScheme(LPCOLORSCHEME lpColorScheme) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpColorScheme != NULL); + return (BOOL)::SendMessage(m_hWnd, RB_GETCOLORSCHEME, 0, (LPARAM)lpColorScheme); + } + + void SetColorScheme(LPCOLORSCHEME lpColorScheme) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpColorScheme != NULL); + ::SendMessage(m_hWnd, RB_SETCOLORSCHEME, 0, (LPARAM)lpColorScheme); + } + + HPALETTE GetPalette() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HPALETTE)::SendMessage(m_hWnd, RB_GETPALETTE, 0, 0L); + } + + HPALETTE SetPalette(HPALETTE hPalette) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HPALETTE)::SendMessage(m_hWnd, RB_SETPALETTE, 0, (LPARAM)hPalette); + } + + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_WINNT >= 0x0501) + // requires uxtheme.h to be included to use MARGINS struct +#ifndef _UXTHEME_H_ + typedef struct _MARGINS* PMARGINS; +#endif // !_UXTHEME_H_ + void GetBandMargins(PMARGINS pMargins) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_GETBANDMARGINS, 0, (LPARAM)pMargins); + } + + void SetWindowTheme(LPCWSTR lpstrTheme) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_IE >= 0x0600) + DWORD GetExtendedStyle() const + { +#ifndef RB_GETEXTENDEDSTYLE + const UINT RB_GETEXTENDEDSTYLE = WM_USER + 42; +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, RB_GETEXTENDEDSTYLE, 0, 0L); + } + + DWORD SetExtendedStyle(DWORD dwStyle, DWORD dwMask) + { +#ifndef RB_SETEXTENDEDSTYLE + const UINT RB_SETEXTENDEDSTYLE = WM_USER + 41; +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, RB_SETEXTENDEDSTYLE, dwMask, dwStyle); + } +#endif // (_WIN32_IE >= 0x0600) + +// Operations + BOOL InsertBand(int nBand, LPREBARBANDINFO lprbbi) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_INSERTBAND, nBand, (LPARAM)lprbbi); + } + + BOOL AddBand(LPREBARBANDINFO lprbbi) + { + return InsertBand(-1, lprbbi); + } + + BOOL DeleteBand(int nBand) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_DELETEBAND, nBand, 0L); + } + + ATL::CWindow SetNotifyWnd(HWND hWnd) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ATL::CWindow((HWND)::SendMessage(m_hWnd, RB_SETPARENT, (WPARAM)hWnd, 0L)); + } + +#if (_WIN32_IE >= 0x0400) + void BeginDrag(int nBand, DWORD dwPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_BEGINDRAG, nBand, dwPos); + } + + void BeginDrag(int nBand, int xPos, int yPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_BEGINDRAG, nBand, MAKELPARAM(xPos, yPos)); + } + + void EndDrag() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_ENDDRAG, 0, 0L); + } + + void DragMove(DWORD dwPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_DRAGMOVE, 0, dwPos); + } + + void DragMove(int xPos, int yPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_DRAGMOVE, 0, MAKELPARAM(xPos, yPos)); + } + +#ifndef _WIN32_WCE + void GetDropTarget(IDropTarget** ppDropTarget) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_GETDROPTARGET, 0, (LPARAM)ppDropTarget); + } +#endif // !_WIN32_WCE + + void MaximizeBand(int nBand, BOOL bIdeal = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_MAXIMIZEBAND, nBand, bIdeal); + } + + void MinimizeBand(int nBand) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_MINIMIZEBAND, nBand, 0L); + } + + BOOL SizeToRect(LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_SIZETORECT, 0, (LPARAM)lpRect); + } + + int IdToIndex(UINT uBandID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, RB_IDTOINDEX, uBandID, 0L); + } + + int HitTest(LPRBHITTESTINFO lprbht) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, RB_HITTEST, 0, (LPARAM)lprbht); + } + + BOOL ShowBand(int nBand, BOOL bShow) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_SHOWBAND, nBand, bShow); + } + +#ifndef _WIN32_WCE + BOOL MoveBand(int nBand, int nNewPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nNewPos >= 0 && nNewPos <= ((int)GetBandCount() - 1)); + return (BOOL)::SendMessage(m_hWnd, RB_MOVEBAND, nBand, nNewPos); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + void PushChevron(int nBand, LPARAM lAppValue) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_PUSHCHEVRON, nBand, lAppValue); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +// Extra operations +#if (_WIN32_IE >= 0x0400) + void LockBands(bool bLock) + { + int nBandCount = GetBandCount(); + for(int i =0; i < nBandCount; i++) + { + REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() }; + rbbi.fMask = RBBIM_STYLE; + BOOL bRet = GetBandInfo(i, &rbbi); + ATLASSERT(bRet); + + if((rbbi.fStyle & RBBS_GRIPPERALWAYS) == 0) + { + rbbi.fStyle |= RBBS_GRIPPERALWAYS; + bRet = SetBandInfo(i, &rbbi); + ATLASSERT(bRet); + rbbi.fStyle &= ~RBBS_GRIPPERALWAYS; + } + + if(bLock) + rbbi.fStyle |= RBBS_NOGRIPPER; + else + rbbi.fStyle &= ~RBBS_NOGRIPPER; + + bRet = SetBandInfo(i, &rbbi); + ATLASSERT(bRet); + } + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_WINNT >= 0x0600) + BOOL SetBandWidth(int nBand, int cxWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_SETBANDWIDTH, nBand, cxWidth); + } +#endif // (_WIN32_WINNT >= 0x0600) +}; + +typedef CReBarCtrlT CReBarCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CComboBoxEx + +#ifndef _WIN32_WCE + +template +class CComboBoxExT : public CComboBoxT< TBase > +{ +public: +// Constructors + CComboBoxExT(HWND hWnd = NULL) : CComboBoxT< TBase >(hWnd) + { } + + CComboBoxExT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_COMBOBOXEX; + } + + CImageList GetImageList() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, CBEM_GETIMAGELIST, 0, 0L)); + } + + CImageList SetImageList(HIMAGELIST hImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, CBEM_SETIMAGELIST, 0, (LPARAM)hImageList)); + } + +#if (_WIN32_IE >= 0x0400) + DWORD GetExtendedStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, CBEM_GETEXTENDEDSTYLE, 0, 0L); + } + + DWORD SetExtendedStyle(DWORD dwExMask, DWORD dwExStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, CBEM_SETEXTENDEDSTYLE, dwExMask, dwExStyle); + } + + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CBEM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CBEM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_WINNT >= 0x0501) + void SetWindowTheme(LPCWSTR lpstrTheme) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, CBEM_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme); + } +#endif // (_WIN32_WINNT >= 0x0501) + +// Operations + int InsertItem(const COMBOBOXEXITEM* lpcCBItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)lpcCBItem); + } + + int InsertItem(UINT nMask, int nIndex, LPCTSTR lpszItem, int nImage, int nSelImage, + int iIndent, int iOverlay, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + COMBOBOXEXITEM cbex = { 0 }; + cbex.mask = nMask; + cbex.iItem = nIndex; + cbex.pszText = (LPTSTR) lpszItem; + cbex.iImage = nImage; + cbex.iSelectedImage = nSelImage; + cbex.iIndent = iIndent; + cbex.iOverlay = iOverlay; + cbex.lParam = lParam; + return (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)&cbex); + } + + int InsertItem(int nIndex, LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, LPARAM lParam = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + COMBOBOXEXITEM cbex = { 0 }; + cbex.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_INDENT | CBEIF_LPARAM; + cbex.iItem = nIndex; + cbex.pszText = (LPTSTR) lpszItem; + cbex.iImage = nImage; + cbex.iSelectedImage = nSelImage; + cbex.iIndent = iIndent; + cbex.lParam = lParam; + return (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)&cbex); + } + + int AddItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, int iOverlay, LPARAM lParam) + { + return InsertItem(nMask, -1, lpszItem, nImage, nSelImage, iIndent, iOverlay, lParam); + } + + int AddItem(LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, LPARAM lParam = 0) + { + return InsertItem(-1, lpszItem, nImage, nSelImage, iIndent, lParam); + } + + int DeleteItem(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CBEM_DELETEITEM, nIndex, 0L); + } + + BOOL GetItem(PCOMBOBOXEXITEM pCBItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)pCBItem); + } + + BOOL SetItem(const COMBOBOXEXITEM* lpcCBItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CBEM_SETITEM, 0, (LPARAM)lpcCBItem); + } + + int SetItem(int nIndex, UINT nMask, LPCTSTR lpszItem, int nImage, int nSelImage, + int iIndent, int iOverlay, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + COMBOBOXEXITEM cbex = { 0 }; + cbex.mask = nMask; + cbex.iItem = nIndex; + cbex.pszText = (LPTSTR) lpszItem; + cbex.iImage = nImage; + cbex.iSelectedImage = nSelImage; + cbex.iIndent = iIndent; + cbex.iOverlay = iOverlay; + cbex.lParam = lParam; + return (int)::SendMessage(m_hWnd, CBEM_SETITEM, 0, (LPARAM)&cbex); + } + + BOOL GetItemText(int nIndex, LPTSTR lpszItem, int nLen) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpszItem != NULL); + + COMBOBOXEXITEM cbex = { 0 }; + cbex.mask = CBEIF_TEXT; + cbex.iItem = nIndex; + cbex.pszText = lpszItem; + cbex.cchTextMax = nLen; + + return (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex); + } + +#ifndef _ATL_NO_COM + BOOL GetItemText(int nIndex, BSTR& bstrText) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrText == NULL); + + COMBOBOXEXITEM cbex = { 0 }; + cbex.mask = CBEIF_TEXT; + cbex.iItem = nIndex; + + LPTSTR lpstrText = NULL; + BOOL bRet = FALSE; + for(int nLen = 256; ; nLen *= 2) + { + ATLTRY(lpstrText = new TCHAR[nLen]); + if(lpstrText == NULL) + break; + lpstrText[0] = NULL; + cbex.pszText = lpstrText; + cbex.cchTextMax = nLen; + bRet = (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex); + if(!bRet || (lstrlen(cbex.pszText) < nLen - 1)) + break; + delete [] lpstrText; + lpstrText = NULL; + } + + if(lpstrText != NULL) + { + if(bRet) + bstrText = ::SysAllocString(T2OLE(lpstrText)); + delete [] lpstrText; + } + + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + BOOL GetItemText(int nIndex, _CSTRING_NS::CString& strText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + + COMBOBOXEXITEM cbex = { 0 }; + cbex.mask = CBEIF_TEXT; + cbex.iItem = nIndex; + + strText.Empty(); + BOOL bRet = FALSE; + for(int nLen = 256; ; nLen *= 2) + { + cbex.pszText = strText.GetBufferSetLength(nLen); + if(cbex.pszText == NULL) + { + bRet = FALSE; + break; + } + cbex.cchTextMax = nLen; + bRet = (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex); + if(!bRet || (lstrlen(cbex.pszText) < nLen - 1)) + break; + } + strText.ReleaseBuffer(); + return bRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + BOOL SetItemText(int nIndex, LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(nIndex, CBEIF_TEXT, lpszItem, 0, 0, 0, 0, 0); + } + + CComboBox GetComboCtrl() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CComboBox((HWND)::SendMessage(m_hWnd, CBEM_GETCOMBOCONTROL, 0, 0L)); + } + + CEdit GetEditCtrl() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CEdit((HWND)::SendMessage(m_hWnd, CBEM_GETEDITCONTROL, 0, 0L)); + } + + BOOL HasEditChanged() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CBEM_HASEDITCHANGED, 0, 0L); + } + +// Non-functional + int AddString(LPCTSTR /*lpszItem*/) + { + ATLASSERT(FALSE); // Not available in CComboBoxEx; use InsertItem + return 0; + } + + int InsertString(int /*nIndex*/, LPCTSTR /*lpszString*/) + { + ATLASSERT(FALSE); // Not available in CComboBoxEx; use InsertItem + return 0; + } + + int Dir(UINT /*attr*/, LPCTSTR /*lpszWildCard*/) + { + ATLASSERT(FALSE); // Not available in CComboBoxEx + return 0; + } + + int FindString(int /*nStartAfter*/, LPCTSTR /*lpszString*/) const + { + ATLASSERT(FALSE); // Not available in CComboBoxEx; try FindStringExact + return 0; + } +}; + +typedef CComboBoxExT CComboBoxEx; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMonthCalendarCtrl + +template +class CMonthCalendarCtrlT : public TBase +{ +public: +// Constructors + CMonthCalendarCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CMonthCalendarCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return MONTHCAL_CLASS; + } + + COLORREF GetColor(int nColorType) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, MCM_GETCOLOR, nColorType, 0L); + } + + COLORREF SetColor(int nColorType, COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, MCM_SETCOLOR, nColorType, clr); + } + + BOOL GetCurSel(LPSYSTEMTIME lpSysTime) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_GETCURSEL, 0, (LPARAM)lpSysTime); + } + + BOOL SetCurSel(LPSYSTEMTIME lpSysTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETCURSEL, 0, (LPARAM)lpSysTime); + } + + int GetFirstDayOfWeek(BOOL* pbLocaleVal = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, MCM_GETFIRSTDAYOFWEEK, 0, 0L); + if(pbLocaleVal != NULL) + *pbLocaleVal = (BOOL)HIWORD(dwRet); + return (int)(short)LOWORD(dwRet); + } + + int SetFirstDayOfWeek(int nDay, BOOL* pbLocaleVal = NULL) + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, MCM_SETFIRSTDAYOFWEEK, 0, nDay); + if(pbLocaleVal != NULL) + *pbLocaleVal = (BOOL)HIWORD(dwRet); + return (int)(short)LOWORD(dwRet); + } + + int GetMaxSelCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, MCM_GETMAXSELCOUNT, 0, 0L); + } + + BOOL SetMaxSelCount(int nMax) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETMAXSELCOUNT, nMax, 0L); + } + + int GetMonthDelta() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, MCM_GETMONTHDELTA, 0, 0L); + } + + int SetMonthDelta(int nDelta) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, MCM_SETMONTHDELTA, nDelta, 0L); + } + + DWORD GetRange(LPSYSTEMTIME lprgSysTimeArray) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, MCM_GETRANGE, 0, (LPARAM)lprgSysTimeArray); + } + + BOOL SetRange(DWORD dwFlags, LPSYSTEMTIME lprgSysTimeArray) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETRANGE, dwFlags, (LPARAM)lprgSysTimeArray); + } + + BOOL GetSelRange(LPSYSTEMTIME lprgSysTimeArray) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_GETSELRANGE, 0, (LPARAM)lprgSysTimeArray); + } + + BOOL SetSelRange(LPSYSTEMTIME lprgSysTimeArray) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETSELRANGE, 0, (LPARAM)lprgSysTimeArray); + } + + BOOL GetToday(LPSYSTEMTIME lpSysTime) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_GETTODAY, 0, (LPARAM)lpSysTime); + } + + void SetToday(LPSYSTEMTIME lpSysTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, MCM_SETTODAY, 0, (LPARAM)lpSysTime); + } + + BOOL GetMinReqRect(LPRECT lpRectInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_GETMINREQRECT, 0, (LPARAM)lpRectInfo); + } + + int GetMaxTodayWidth() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, MCM_GETMAXTODAYWIDTH, 0, 0L); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + DWORD GetCurrentView() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, MCM_GETCURRENTVIEW, 0, 0L); + } + + BOOL SetCurrentView(DWORD dwView) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETCURRENTVIEW, 0, dwView); + } + + DWORD GetCalendarCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, MCM_GETCALENDARCOUNT, 0, 0L); + } + + BOOL GetCalendarGridInfo(PMCGRIDINFO pGridInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_GETCALENDARGRIDINFO, 0, (LPARAM)pGridInfo); + } + + CALID GetCALID() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (CALID)::SendMessage(m_hWnd, MCM_GETCALID, 0, 0L); + } + + void SetCALID(CALID calid) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, MCM_SETCALID, (LPARAM)calid, 0L); + } + + int GetCalendarBorder() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, MCM_GETCALENDARBORDER, 0, 0L); + } + + void SetCalendarBorder(int cxyBorder, BOOL bSet = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, MCM_SETCALENDARBORDER, (WPARAM)bSet, (LPARAM)cxyBorder); + } +#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + +// Operations + int GetMonthRange(DWORD dwFlags, LPSYSTEMTIME lprgSysTimeArray) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, MCM_GETMONTHRANGE, dwFlags, (LPARAM)lprgSysTimeArray); + } + + BOOL SetDayState(int nMonths, LPMONTHDAYSTATE lpDayStateArray) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETDAYSTATE, nMonths, (LPARAM)lpDayStateArray); + } + + DWORD HitTest(PMCHITTESTINFO pMCHitTest) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, MCM_HITTEST, 0, (LPARAM)pMCHitTest); + } + +#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + void SizeRectToMin(LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, MCM_SIZERECTTOMIN, 0, (LPARAM)lpRect); + } +#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) +}; + +typedef CMonthCalendarCtrlT CMonthCalendarCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CDateTimePickerCtrl + +template +class CDateTimePickerCtrlT : public TBase +{ +public: +// Constructors + CDateTimePickerCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CDateTimePickerCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Operations + static LPCTSTR GetWndClassName() + { + return DATETIMEPICK_CLASS; + } + + BOOL SetFormat(LPCTSTR lpszFormat) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DTM_SETFORMAT, 0, (LPARAM)lpszFormat); + } + + COLORREF GetMonthCalColor(int nColorType) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, DTM_GETMCCOLOR, nColorType, 0L); + } + + COLORREF SetMonthCalColor(int nColorType, COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, DTM_SETMCCOLOR, nColorType, clr); + } + + DWORD GetRange(LPSYSTEMTIME lpSysTimeArray) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, DTM_GETRANGE, 0, (LPARAM)lpSysTimeArray); + } + + BOOL SetRange(DWORD dwFlags, LPSYSTEMTIME lpSysTimeArray) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DTM_SETRANGE, dwFlags, (LPARAM)lpSysTimeArray); + } + + DWORD GetSystemTime(LPSYSTEMTIME lpSysTime) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)lpSysTime); + } + + BOOL SetSystemTime(DWORD dwFlags, LPSYSTEMTIME lpSysTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DTM_SETSYSTEMTIME, dwFlags, (LPARAM)lpSysTime); + } + + CMonthCalendarCtrl GetMonthCal() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CMonthCalendarCtrl((HWND)::SendMessage(m_hWnd, DTM_GETMONTHCAL, 0, 0L)); + } + +#if (_WIN32_IE >= 0x0400) + CFontHandle GetMonthCalFont() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CFontHandle((HFONT)::SendMessage(m_hWnd, DTM_GETMCFONT, 0, 0L)); + } + + void SetMonthCalFont(HFONT hFont, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_SETMCFONT, (WPARAM)hFont, MAKELPARAM(bRedraw, 0)); + } +#endif // (_WIN32_IE >= 0x0400) + +#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + DWORD GetMonthCalStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, DTM_GETMCSTYLE, 0, 0L); + } + + DWORD SetMonthCalStyle(DWORD dwStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, DTM_SETMCSTYLE, 0, (LPARAM)dwStyle); + } + + void GetDateTimePickerInfo(LPDATETIMEPICKERINFO lpPickerInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_GETDATETIMEPICKERINFO, 0, (LPARAM)lpPickerInfo); + } + + BOOL GetIdealSize(LPSIZE lpSize) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DTM_GETIDEALSIZE, 0, (LPARAM)lpSize); + } + + void CloseMonthCal() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_CLOSEMONTHCAL, 0, 0L); + } +#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) +}; + +typedef CDateTimePickerCtrlT CDateTimePickerCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CFlatScrollBarImpl - support for flat scroll bars + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +template +class CFlatScrollBarImpl +{ +public: +// Initialization + BOOL FlatSB_Initialize() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::InitializeFlatSB(pT->m_hWnd); + } + + HRESULT FlatSB_Uninitialize() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::UninitializeFlatSB(pT->m_hWnd); + } + +// Flat scroll bar properties + BOOL FlatSB_GetScrollProp(UINT uIndex, LPINT lpnValue) const + { + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_GetScrollProp(pT->m_hWnd, uIndex, lpnValue); + } + + BOOL FlatSB_SetScrollProp(UINT uIndex, int nValue, BOOL bRedraw = TRUE) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_SetScrollProp(pT->m_hWnd, uIndex, nValue, bRedraw); + } + +// Attributes + int FlatSB_GetScrollPos(int nBar) const + { + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_GetScrollPos(pT->m_hWnd, nBar); + } + + int FlatSB_SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_SetScrollPos(pT->m_hWnd, nBar, nPos, bRedraw); + } + + BOOL FlatSB_GetScrollRange(int nBar, LPINT lpMinPos, LPINT lpMaxPos) const + { + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_GetScrollRange(pT->m_hWnd, nBar, lpMinPos, lpMaxPos); + } + + BOOL FlatSB_SetScrollRange(int nBar, int nMinPos, int nMaxPos, BOOL bRedraw = TRUE) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_SetScrollRange(pT->m_hWnd, nBar, nMinPos, nMaxPos, bRedraw); + } + + BOOL FlatSB_GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo) const + { + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_GetScrollInfo(pT->m_hWnd, nBar, lpScrollInfo); + } + + int FlatSB_SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_SetScrollInfo(pT->m_hWnd, nBar, lpScrollInfo, bRedraw); + } + +// Operations + BOOL FlatSB_ShowScrollBar(UINT nBar, BOOL bShow = TRUE) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_ShowScrollBar(pT->m_hWnd, nBar, bShow); + } + + BOOL FlatSB_EnableScrollBar(UINT uSBFlags, UINT uArrowFlags = ESB_ENABLE_BOTH) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_EnableScrollBar(pT->m_hWnd, uSBFlags, uArrowFlags); + } +}; + +template +class CFlatScrollBarT : public TBase, public CFlatScrollBarImpl > +{ +public: + CFlatScrollBarT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CFlatScrollBarT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } +}; + +typedef CFlatScrollBarT CFlatScrollBar; + +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CIPAddressCtrl + +#if (_WIN32_IE >= 0x0400) + +template +class CIPAddressCtrlT : public TBase +{ +public: +// Constructors + CIPAddressCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CIPAddressCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Atteributes + static LPCTSTR GetWndClassName() + { + return WC_IPADDRESS; + } + + BOOL IsBlank() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, IPM_ISBLANK, 0, 0L); + } + + int GetAddress(LPDWORD lpdwAddress) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, IPM_GETADDRESS, 0, (LPARAM)lpdwAddress); + } + + void SetAddress(DWORD dwAddress) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IPM_SETADDRESS, 0, dwAddress); + } + + void ClearAddress() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IPM_CLEARADDRESS, 0, 0L); + } + + void SetRange(int nField, WORD wRange) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IPM_SETRANGE, nField, wRange); + } + + void SetRange(int nField, BYTE nMin, BYTE nMax) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IPM_SETRANGE, nField, MAKEIPRANGE(nMin, nMax)); + } + + void SetFocus(int nField) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IPM_SETFOCUS, nField, 0L); + } +}; + +typedef CIPAddressCtrlT CIPAddressCtrl; + +#endif // (_WIN32_IE >= 0x0400) + + +/////////////////////////////////////////////////////////////////////////////// +// CPagerCtrl + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +template +class CPagerCtrlT : public TBase +{ +public: +// Constructors + CPagerCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CPagerCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_PAGESCROLLER; + } + + int GetButtonSize() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PGM_GETBUTTONSIZE, 0, 0L); + } + + int SetButtonSize(int nButtonSize) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PGM_SETBUTTONSIZE, 0, nButtonSize); + } + + DWORD GetButtonState(int nButton) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nButton == PGB_TOPORLEFT || nButton == PGB_BOTTOMORRIGHT); + return (DWORD)::SendMessage(m_hWnd, PGM_GETBUTTONSTATE, 0, nButton); + } + + COLORREF GetBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, PGM_GETBKCOLOR, 0, 0L); + } + + COLORREF SetBkColor(COLORREF clrBk) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, PGM_SETBKCOLOR, 0, (LPARAM)clrBk); + } + + int GetBorder() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PGM_GETBORDER, 0, 0L); + } + + int SetBorder(int nBorderSize) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PGM_SETBORDER, 0, nBorderSize); + } + + int GetPos() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PGM_GETPOS, 0, 0L); + } + + int SetPos(int nPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PGM_SETPOS, 0, nPos); + } + +// Operations + void SetChild(HWND hWndChild) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PGM_SETCHILD, 0, (LPARAM)hWndChild); + } + + void ForwardMouse(BOOL bForward = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PGM_FORWARDMOUSE, bForward, 0L); + } + + void RecalcSize() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PGM_RECALCSIZE, 0, 0L); + } + + void GetDropTarget(IDropTarget** ppDropTarget) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(ppDropTarget != NULL); + ::SendMessage(m_hWnd, PGM_GETDROPTARGET, 0, (LPARAM)ppDropTarget); + } +}; + +typedef CPagerCtrlT CPagerCtrl; + +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CLinkCtrl - Windows SYSLINK control + +#if (_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE) + +template +class CLinkCtrlT : public TBase +{ +public: +// Constructors + CLinkCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CLinkCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { +#ifdef _UNICODE + return WC_LINK; +#else // !_UNICODE + return "SysLink"; +#endif // !_UNICODE + } + + int GetIdealHeight(int cxMaxWidth = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LM_GETIDEALHEIGHT, cxMaxWidth, 0L); + } + + BOOL GetItem(PLITEM pLItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LM_GETITEM, 0, (LPARAM)pLItem); + } + + BOOL SetItem(PLITEM pLItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LM_SETITEM, 0, (LPARAM)pLItem); + } + + // Vista only + int GetIdealSize(SIZE& size, int cxMaxWidth = 0) const + { +#ifndef LM_GETIDEALSIZE + const UINT LM_GETIDEALSIZE = LM_GETIDEALHEIGHT; +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LM_GETIDEALSIZE, cxMaxWidth, (LPARAM)&size); + } + +// Operations + BOOL HitTest(PLHITTESTINFO pLHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LM_HITTEST, 0, (LPARAM)pLHitTestInfo); + } +}; + +typedef CLinkCtrlT CLinkCtrl; + +#endif // (_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CCustomDraw - MI class for custom-draw support + +template +class CCustomDraw +{ +public: +#if (_ATL_VER < 0x0700) + BOOL m_bHandledCD; + + BOOL IsMsgHandled() const + { + return m_bHandledCD; + } + + void SetMsgHandled(BOOL bHandled) + { + m_bHandledCD = bHandled; + } +#endif // !(_ATL_VER < 0x0700) + +// Message map and handlers + BEGIN_MSG_MAP(CCustomDraw< T >) + NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw) + ALT_MSG_MAP(1) + REFLECTED_NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw) + END_MSG_MAP() + +// message handler + LRESULT OnCustomDraw(int idCtrl, LPNMHDR pnmh, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + LPNMCUSTOMDRAW lpNMCustomDraw = (LPNMCUSTOMDRAW)pnmh; + DWORD dwRet = 0; + switch(lpNMCustomDraw->dwDrawStage) + { + case CDDS_PREPAINT: + dwRet = pT->OnPrePaint(idCtrl, lpNMCustomDraw); + break; + case CDDS_POSTPAINT: + dwRet = pT->OnPostPaint(idCtrl, lpNMCustomDraw); + break; + case CDDS_PREERASE: + dwRet = pT->OnPreErase(idCtrl, lpNMCustomDraw); + break; + case CDDS_POSTERASE: + dwRet = pT->OnPostErase(idCtrl, lpNMCustomDraw); + break; + case CDDS_ITEMPREPAINT: + dwRet = pT->OnItemPrePaint(idCtrl, lpNMCustomDraw); + break; + case CDDS_ITEMPOSTPAINT: + dwRet = pT->OnItemPostPaint(idCtrl, lpNMCustomDraw); + break; + case CDDS_ITEMPREERASE: + dwRet = pT->OnItemPreErase(idCtrl, lpNMCustomDraw); + break; + case CDDS_ITEMPOSTERASE: + dwRet = pT->OnItemPostErase(idCtrl, lpNMCustomDraw); + break; +#if (_WIN32_IE >= 0x0400) + case (CDDS_ITEMPREPAINT | CDDS_SUBITEM): + dwRet = pT->OnSubItemPrePaint(idCtrl, lpNMCustomDraw); + break; +#endif // (_WIN32_IE >= 0x0400) + default: + pT->SetMsgHandled(FALSE); + break; + } + bHandled = pT->IsMsgHandled(); + return dwRet; + } + +// Overrideables + DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnPreErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnPostErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnItemPreErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnItemPostErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + +#if (_WIN32_IE >= 0x0400) + DWORD OnSubItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } +#endif // (_WIN32_IE >= 0x0400) +}; + + +// --- Windows CE common controls --- + +#ifdef _WIN32_WCE + +/////////////////////////////////////////////////////////////////////////////// +// CCECommandBarCtrl + +template +class CCECommandBarCtrlT : public TBase +{ +public: +// Constructors + CCECommandBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } + + CCECommandBarCtrlT< TBase >& operator=(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Attributes + BOOL IsVisible() const + { + return IsWindowVisible(); + } + + int GetHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_Height(m_hWnd); + } + + HMENU GetMenu(WORD wButton) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_GetMenu(m_hWnd, wButton); + } + +// Operations + HWND Create(HWND hWndParent, int nCmdBarID) + { + m_hWnd = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), hWndParent, nCmdBarID); + ATLASSERT(::IsWindow(m_hWnd)); + return m_hWnd; + } + + void Destroy() + { + DestroyWindow(); + } + + BOOL Show(BOOL bShow = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_Show(m_hWnd, bShow); + } + + BOOL DrawMenuBar(WORD wButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_DrawMenuBar(m_hWnd, wButton); + } + + BOOL AddAdornments(DWORD dwFlags = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_AddAdornments(m_hWnd, dwFlags, 0); + } + + int AddBitmap(int nBitmapID, int nNumImages) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_AddBitmap(m_hWnd, ModuleHelper::GetResourceInstance(), nBitmapID, nNumImages, 16, 16); + } + + BOOL AddButtons(UINT uNumButtons, LPTBBUTTON lpButtons) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CommandBar_AddButtons(m_hWnd, uNumButtons, lpButtons); + } + + BOOL AddToolTips(UINT uNumToolTips, LPTSTR lpToolTips) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CommandBar_AddToolTips(m_hWnd, uNumToolTips, lpToolTips); + } + + BOOL InsertButton(int nButton, LPTBBUTTON lpButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CommandBar_InsertButton(m_hWnd, nButton, lpButton); + } + + HWND InsertComboBox(int nWidth, UINT dwStyle, WORD wComboBoxID, WORD wButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_InsertComboBox(m_hWnd, ModuleHelper::GetModuleInstance(), nWidth, dwStyle, wComboBoxID, wButton); + } + + BOOL InsertMenubar(WORD wMenuID, WORD wButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_InsertMenubar(m_hWnd, ModuleHelper::GetResourceInstance(), wMenuID, wButton); + } + + BOOL InsertMenubarEx(ATL::_U_STRINGorID menu, WORD wButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_InsertMenubarEx(m_hWnd, ModuleHelper::GetResourceInstance(), (LPTSTR)menu.m_lpstr, wButton); + } + + BOOL IsCommandBarMessage(LPMSG lpMsg) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::IsCommandBarMessage(m_hWnd, lpMsg); + } +}; + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC MenuBar + typedef CCECommandBarCtrlT CMenuBarCtrl; +#else + typedef CCECommandBarCtrlT CCECommandBarCtrl; +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + +/////////////////////////////////////////////////////////////////////////////// +// CCECommandBandsCtrl + +template +class CCECommandBandsCtrlT : public TBase +{ +public: +// Constructors + CCECommandBandsCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } + + CCECommandBandsCtrlT< TBase >& operator=(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Attributes + BOOL IsVisible() const + { + return IsWindowVisible(); + } + +#if (_WIN32_IE >= 0x0400) + UINT GetHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CommandBands_Height(m_hWnd); + } +#endif // (_WIN32_IE >= 0x0400) + + HWND GetCommandBar(UINT uBand) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBands_GetCommandBar(m_hWnd, uBand); + } + + BOOL GetRestoreInformation(UINT uBand, LPCOMMANDBANDSRESTOREINFO pcbr) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBands_GetRestoreInformation(m_hWnd, uBand, pcbr); + } + +// Operations + HWND Create(HWND hWndParent, UINT wID, DWORD dwStyles, HIMAGELIST hImageList = NULL) + { + m_hWnd = ::CommandBands_Create(ModuleHelper::GetModuleInstance(), hWndParent, wID, dwStyles, hImageList); + ATLASSERT(::IsWindow(m_hWnd)); + return m_hWnd; + } + + BOOL AddAdornments(DWORD dwFlags = 0, LPREBARBANDINFO prbbi = NULL) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBands_AddAdornments(m_hWnd, ModuleHelper::GetModuleInstance(), dwFlags, prbbi); + } + + BOOL AddBands(UINT uBandCount, LPREBARBANDINFO prbbi) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBands_AddBands(m_hWnd, ModuleHelper::GetModuleInstance(), uBandCount, prbbi); + } + + BOOL Show(BOOL bShow = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBands_Show(m_hWnd, bShow); + } +}; + +typedef CCECommandBandsCtrlT CCECommandBandsCtrl; + +#endif // _WIN32_WCE + +}; // namespace WTL + +#endif // __ATLCTRLS_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlctrlw.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlctrlw.h new file mode 100644 index 0000000000000000000000000000000000000000..0984551fed49c69a126b59fa8981df7190c358ec --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlctrlw.h @@ -0,0 +1,4211 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLCTRLW_H__ +#define __ATLCTRLW_H__ + +#pragma once + +#ifdef _WIN32_WCE + #error atlctrlw.h is not supported on Windows CE +#endif + +#ifndef __ATLAPP_H__ + #error atlctrlw.h requires atlapp.h to be included first +#endif + +#ifndef __ATLCTRLS_H__ + #error atlctrlw.h requires atlctrls.h to be included first +#endif + +#if (_WIN32_IE < 0x0400) + #error atlctrlw.h requires _WIN32_IE >= 0x0400 +#endif + +// Define _WTL_CMDBAR_VISTA_MENUS as 0 to exclude Vista menus support +#if !defined(_WTL_CMDBAR_VISTA_MENUS) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501) + #define _WTL_CMDBAR_VISTA_MENUS 1 +#endif + +#if _WTL_CMDBAR_VISTA_MENUS + #if !((_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)) + #error _WTL_CMDBAR_VISTA_MENUS requires (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501) + #endif +#endif + +// Note: Define _WTL_CMDBAR_VISTA_STD_MENUBAR to use Vista standard menubar look with Vista menus + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CCommandBarCtrlImpl +// CCommandBarCtrl +// CMDICommandBarCtrlImpl +// CMDICommandBarCtrl + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// Command Bars + +// Window Styles: +#define CBRWS_TOP CCS_TOP +#define CBRWS_BOTTOM CCS_BOTTOM +#define CBRWS_NORESIZE CCS_NORESIZE +#define CBRWS_NOPARENTALIGN CCS_NOPARENTALIGN +#define CBRWS_NODIVIDER CCS_NODIVIDER + +// Extended styles +#define CBR_EX_TRANSPARENT 0x00000001L +#define CBR_EX_SHAREMENU 0x00000002L +#define CBR_EX_ALTFOCUSMODE 0x00000004L +#define CBR_EX_TRACKALWAYS 0x00000008L +#define CBR_EX_NOVISTAMENUS 0x00000010L + +// standard command bar styles +#define ATL_SIMPLE_CMDBAR_PANE_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CBRWS_NODIVIDER | CBRWS_NORESIZE | CBRWS_NOPARENTALIGN) + +// Messages - support chevrons for frame windows +#define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND +#define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu +#define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu + +typedef struct tagCBRPOPUPMENU +{ + int cbSize; + HMENU hMenu; // popup menu do display + UINT uFlags; // TPM_* flags for ::TrackPopupMenuEx + int x; + int y; + LPTPMPARAMS lptpm; // ptr to TPMPARAMS for ::TrackPopupMenuEx +} CBRPOPUPMENU, *LPCBRPOPUPMENU; + +// helper class +template +class CSimpleStack : public ATL::CSimpleArray< T > +{ +public: + BOOL Push(T t) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - STACK-PUSH (%8.8X) size = %i\n"), t, GetSize()); +#endif + return Add(t); + } + + T Pop() + { + int nLast = GetSize() - 1; + if(nLast < 0) + return NULL; // must be able to convert to NULL + T t = m_aT[nLast]; +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - STACK-POP (%8.8X) size = %i\n"), t, GetSize()); +#endif + if(!RemoveAt(nLast)) + return NULL; + return t; + } + + T GetCurrent() + { + int nLast = GetSize() - 1; + if(nLast < 0) + return NULL; // must be able to convert to NULL + return m_aT[nLast]; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CCommandBarCtrlBase - base class for the Command Bar implementation + +class CCommandBarCtrlBase : public CToolBarCtrl +{ +public: + struct _MsgHookData + { + HHOOK hMsgHook; + DWORD dwUsage; + + _MsgHookData() : hMsgHook(NULL), dwUsage(0) + { } + }; + + typedef ATL::CSimpleMap CMsgHookMap; + static CMsgHookMap* s_pmapMsgHook; + + static HHOOK s_hCreateHook; + static bool s_bW2K; // For animation flag + static CCommandBarCtrlBase* s_pCurrentBar; + static bool s_bStaticInit; + + CSimpleStack m_stackMenuWnd; + CSimpleStack m_stackMenuHandle; + + HWND m_hWndHook; + DWORD m_dwMagic; + + + CCommandBarCtrlBase() : m_hWndHook(NULL), m_dwMagic(1314) + { + // init static variables + if(!s_bStaticInit) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlBase::CCommandBarCtrlBase.\n")); + ATLASSERT(FALSE); + return; + } + + if(!s_bStaticInit) + { + // Just in case... + AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES); + // Animation on Win2000 only + s_bW2K = !AtlIsOldWindows(); + // done + s_bStaticInit = true; + } + + lock.Unlock(); + } + } + + bool IsCommandBarBase() const { return m_dwMagic == 1314; } +}; + +__declspec(selectany) CCommandBarCtrlBase::CMsgHookMap* CCommandBarCtrlBase::s_pmapMsgHook = NULL; +__declspec(selectany) HHOOK CCommandBarCtrlBase::s_hCreateHook = NULL; +__declspec(selectany) CCommandBarCtrlBase* CCommandBarCtrlBase::s_pCurrentBar = NULL; +__declspec(selectany) bool CCommandBarCtrlBase::s_bW2K = false; +__declspec(selectany) bool CCommandBarCtrlBase::s_bStaticInit = false; + + +/////////////////////////////////////////////////////////////////////////////// +// CCommandBarCtrl - ATL implementation of Command Bars + +template +class ATL_NO_VTABLE CCommandBarCtrlImpl : public ATL::CWindowImpl< T, TBase, TWinTraits > +{ +public: + DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) + +// Declarations + struct _MenuItemData // menu item data + { + DWORD dwMagic; + LPTSTR lpstrText; + UINT fType; + UINT fState; + int iButton; + + _MenuItemData() { dwMagic = 0x1313; } + bool IsCmdBarMenuItem() { return (dwMagic == 0x1313); } + }; + + struct _ToolBarData // toolbar resource data + { + WORD wVersion; + WORD wWidth; + WORD wHeight; + WORD wItemCount; + //WORD aItems[wItemCount] + + WORD* items() + { return (WORD*)(this+1); } + }; + +// Constants + enum _CmdBarDrawConstants + { + s_kcxGap = 1, + s_kcxTextMargin = 2, + s_kcxButtonMargin = 3, + s_kcyButtonMargin = 3 + }; + + enum + { + _nMaxMenuItemTextLength = 100, + _chChevronShortcut = _T('/') + }; + +#ifndef DT_HIDEPREFIX + enum { DT_HIDEPREFIX = 0x00100000 }; +#endif // !DT_HIDEPREFIX + +// Data members + HMENU m_hMenu; + HIMAGELIST m_hImageList; + ATL::CSimpleValArray m_arrCommand; + + DWORD m_dwExtendedStyle; // Command Bar specific extended styles + + ATL::CContainedWindow m_wndParent; + + bool m_bMenuActive:1; + bool m_bAttachedMenu:1; + bool m_bImagesVisible:1; + bool m_bPopupItem:1; + bool m_bContextMenu:1; + bool m_bEscapePressed:1; + bool m_bSkipMsg:1; + bool m_bParentActive:1; + bool m_bFlatMenus:1; + bool m_bUseKeyboardCues:1; + bool m_bShowKeyboardCues:1; + bool m_bAllowKeyboardCues:1; + bool m_bKeyboardInput:1; + bool m_bAlphaImages:1; + bool m_bLayoutRTL:1; + bool m_bSkipPostDown:1; + bool m_bVistaMenus:1; + + int m_nPopBtn; + int m_nNextPopBtn; + + SIZE m_szBitmap; + SIZE m_szButton; + + COLORREF m_clrMask; + CFont m_fontMenu; // used internally, only to measure text + + UINT m_uSysKey; + + HWND m_hWndFocus; // Alternate focus mode + + int m_cxExtraSpacing; + +#if _WTL_CMDBAR_VISTA_MENUS + ATL::CSimpleValArray m_arrVistaBitmap; // Bitmaps for Vista menus +#endif // _WTL_CMDBAR_VISTA_MENUS + +// Constructor/destructor + CCommandBarCtrlImpl() : + m_hMenu(NULL), + m_hImageList(NULL), + m_wndParent(this, 1), + m_bMenuActive(false), + m_bAttachedMenu(false), + m_nPopBtn(-1), + m_nNextPopBtn(-1), + m_bPopupItem(false), + m_bImagesVisible(true), + m_bSkipMsg(false), + m_uSysKey(0), + m_hWndFocus(NULL), + m_bContextMenu(false), + m_bEscapePressed(false), + m_clrMask(RGB(192, 192, 192)), + m_dwExtendedStyle(CBR_EX_TRANSPARENT | CBR_EX_SHAREMENU | CBR_EX_TRACKALWAYS), + m_bParentActive(true), + m_bFlatMenus(false), + m_bUseKeyboardCues(false), + m_bShowKeyboardCues(false), + m_bAllowKeyboardCues(true), + m_bKeyboardInput(false), + m_cxExtraSpacing(0), + m_bAlphaImages(false), + m_bLayoutRTL(false), + m_bSkipPostDown(false), + m_bVistaMenus(false) + { + SetImageSize(16, 15); // default + } + + ~CCommandBarCtrlImpl() + { + if(m_wndParent.IsWindow()) +/*scary!*/ m_wndParent.UnsubclassWindow(); + + if(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0) + ::DestroyMenu(m_hMenu); + + if(m_hImageList != NULL) + ::ImageList_Destroy(m_hImageList); + } + +// Attributes + DWORD GetCommandBarExtendedStyle() const + { + return m_dwExtendedStyle; + } + + DWORD SetCommandBarExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + return dwPrevStyle; + } + + CMenuHandle GetMenu() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return m_hMenu; + } + + COLORREF GetImageMaskColor() const + { + return m_clrMask; + } + + COLORREF SetImageMaskColor(COLORREF clrMask) + { + COLORREF clrOld = m_clrMask; + m_clrMask = clrMask; + return clrOld; + } + + bool GetImagesVisible() const + { + return m_bImagesVisible; + } + + bool SetImagesVisible(bool bVisible) + { + bool bOld = m_bImagesVisible; + m_bImagesVisible = bVisible; + return bOld; + } + + void GetImageSize(SIZE& size) const + { + size = m_szBitmap; + } + + bool SetImageSize(SIZE& size) + { + return SetImageSize(size.cx, size.cy); + } + + bool SetImageSize(int cx, int cy) + { + if(m_hImageList != NULL) + { + if(::ImageList_GetImageCount(m_hImageList) == 0) // empty + { + ::ImageList_Destroy(m_hImageList); + m_hImageList = NULL; + } + else + { + return false; // can't set, image list exists + } + } + + if(cx == 0 || cy == 0) + return false; + + m_szBitmap.cx = cx; + m_szBitmap.cy = cy; + m_szButton.cx = m_szBitmap.cx + 2 * s_kcxButtonMargin; + m_szButton.cy = m_szBitmap.cy + 2 * s_kcyButtonMargin; + + return true; + } + + bool GetAlphaImages() const + { + return m_bAlphaImages; + } + + bool SetAlphaImages(bool bAlphaImages) + { + if(m_hImageList != NULL) + { + if(::ImageList_GetImageCount(m_hImageList) == 0) // empty + { + ::ImageList_Destroy(m_hImageList); + m_hImageList = NULL; + } + else + { + return false; // can't set, image list exists + } + } + + m_bAlphaImages = bAlphaImages; + return true; + } + + HWND GetCmdBar() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L); + } + +// Methods + HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + UINT nID = 0, LPVOID lpCreateParam = NULL) + { + // These styles are required for command bars + dwStyle |= TBSTYLE_LIST | TBSTYLE_FLAT; +#if (_MSC_VER >= 1300) + return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + return _baseClass::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam); +#endif // !(_MSC_VER >= 1300) + } + + BOOL AttachToWindow(HWND hWnd) + { + ATLASSERT(m_hWnd == NULL); + ATLASSERT(::IsWindow(hWnd)); + BOOL bRet = SubclassWindow(hWnd); + if(bRet) + { + m_bAttachedMenu = true; + T* pT = static_cast(this); + pT->GetSystemSettings(); + } + return bRet; + } + + BOOL LoadMenu(ATL::_U_STRINGorID menu) + { + ATLASSERT(::IsWindow(m_hWnd)); + + if(m_bAttachedMenu) // doesn't work in this mode + return FALSE; + if(menu.m_lpstr == NULL) + return FALSE; + + HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr); + if(hMenu == NULL) + return FALSE; + + return AttachMenu(hMenu); + } + + BOOL AttachMenu(HMENU hMenu) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hMenu == NULL || ::IsMenu(hMenu)); + if(hMenu != NULL && !::IsMenu(hMenu)) + return FALSE; + +#if _WTL_CMDBAR_VISTA_MENUS + // remove Vista bitmaps if used + if(m_bVistaMenus && (m_hMenu != NULL)) + { + T* pT = static_cast(this); + pT->_RemoveVistaBitmapsFromMenu(); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + + // destroy old menu, if needed, and set new one + if(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0) + ::DestroyMenu(m_hMenu); + + m_hMenu = hMenu; + + if(m_bAttachedMenu) // Nothing else in this mode + return TRUE; + + // Build buttons according to menu + SetRedraw(FALSE); + + // Clear all buttons + int nCount = GetButtonCount(); + for(int i = 0; i < nCount; i++) + ATLVERIFY(DeleteButton(0) != FALSE); + + // Add buttons for each menu item + if(m_hMenu != NULL) + { + int nItems = ::GetMenuItemCount(m_hMenu); + + T* pT = static_cast(this); + pT; // avoid level 4 warning + TCHAR szString[pT->_nMaxMenuItemTextLength] = { 0 }; + for(int i = 0; i < nItems; i++) + { + CMenuItemInfo mii; + mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU; + mii.fType = MFT_STRING; + mii.dwTypeData = szString; + mii.cch = pT->_nMaxMenuItemTextLength; + BOOL bRet = ::GetMenuItemInfo(m_hMenu, i, TRUE, &mii); + ATLASSERT(bRet); + // If we have more than the buffer, we assume we have bitmaps bits + if(lstrlen(szString) > pT->_nMaxMenuItemTextLength - 1) + { + mii.fType = MFT_BITMAP; + ::SetMenuItemInfo(m_hMenu, i, TRUE, &mii); + szString[0] = 0; + } + + // NOTE: Command Bar currently supports only drop-down menu items + ATLASSERT(mii.hSubMenu != NULL); + + TBBUTTON btn = { 0 }; + btn.iBitmap = 0; + btn.idCommand = i; + btn.fsState = (BYTE)(((mii.fState & MFS_DISABLED) == 0) ? TBSTATE_ENABLED : 0); + btn.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_DROPDOWN; + btn.dwData = 0; + btn.iString = 0; + + bRet = InsertButton(-1, &btn); + ATLASSERT(bRet); + + TBBUTTONINFO bi = { 0 }; + bi.cbSize = sizeof(TBBUTTONINFO); + bi.dwMask = TBIF_TEXT; + bi.pszText = szString; + + bRet = SetButtonInfo(i, &bi); + ATLASSERT(bRet); + } + } + + SetRedraw(TRUE); + Invalidate(); + UpdateWindow(); + + return TRUE; + } + + BOOL LoadImages(ATL::_U_STRINGorID image) + { + return _LoadImagesHelper(image, false); + } + + BOOL LoadMappedImages(UINT nIDImage, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0) + { + return _LoadImagesHelper(nIDImage, true, nFlags , lpColorMap, nMapSize); + } + + BOOL _LoadImagesHelper(ATL::_U_STRINGorID image, bool bMapped, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + HINSTANCE hInstance = ModuleHelper::GetResourceInstance(); + + HRSRC hRsrc = ::FindResource(hInstance, image.m_lpstr, (LPTSTR)RT_TOOLBAR); + if(hRsrc == NULL) + return FALSE; + + HGLOBAL hGlobal = ::LoadResource(hInstance, hRsrc); + if(hGlobal == NULL) + return FALSE; + + _ToolBarData* pData = (_ToolBarData*)::LockResource(hGlobal); + if(pData == NULL) + return FALSE; + ATLASSERT(pData->wVersion == 1); + + WORD* pItems = pData->items(); + int nItems = pData->wItemCount; + + // Set internal data + SetImageSize(pData->wWidth, pData->wHeight); + + // Create image list if needed + if(m_hImageList == NULL) + { + // Check if the bitmap is 32-bit (alpha channel) bitmap (valid for Windows XP only) + T* pT = static_cast(this); + m_bAlphaImages = AtlIsAlphaBitmapResource(image); + + if(!pT->CreateInternalImageList(pData->wItemCount)) + return FALSE; + } + +#if _WTL_CMDBAR_VISTA_MENUS + int nOldImageCount = ::ImageList_GetImageCount(m_hImageList); +#endif // _WTL_CMDBAR_VISTA_MENUS + + // Add bitmap to our image list + CBitmap bmp; + if(bMapped) + { + ATLASSERT(HIWORD(PtrToUlong(image.m_lpstr)) == 0); // if mapped, must be a numeric ID + int nIDImage = (int)(short)LOWORD(PtrToUlong(image.m_lpstr)); + bmp.LoadMappedBitmap(nIDImage, (WORD)nFlags, lpColorMap, nMapSize); + } + else + { + if(m_bAlphaImages) + bmp = (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), image.m_lpstr, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE); + else + bmp.LoadBitmap(image.m_lpstr); + } + ATLASSERT(bmp.m_hBitmap != NULL); + if(bmp.m_hBitmap == NULL) + return FALSE; + if(::ImageList_AddMasked(m_hImageList, bmp, m_clrMask) == -1) + return FALSE; + + // Fill the array with command IDs + for(int i = 0; i < nItems; i++) + { + if(pItems[i] != 0) + m_arrCommand.Add(pItems[i]); + } + + int nImageCount = ::ImageList_GetImageCount(m_hImageList); + ATLASSERT(nImageCount == m_arrCommand.GetSize()); + if(nImageCount != m_arrCommand.GetSize()) + return FALSE; + +#if _WTL_CMDBAR_VISTA_MENUS + if(RunTimeHelper::IsVista()) + { + T* pT = static_cast(this); + pT->_AddVistaBitmapsFromImageList(nOldImageCount, nImageCount - nOldImageCount); + ATLASSERT(nImageCount == m_arrVistaBitmap.GetSize()); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + + return TRUE; + } + + BOOL AddBitmap(ATL::_U_STRINGorID bitmap, int nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + CBitmap bmp; + bmp.LoadBitmap(bitmap.m_lpstr); + if(bmp.m_hBitmap == NULL) + return FALSE; + return AddBitmap(bmp, nCommandID); + } + + BOOL AddBitmap(HBITMAP hBitmap, UINT nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + // Create image list if it doesn't exist + if(m_hImageList == NULL) + { + if(!pT->CreateInternalImageList(1)) + return FALSE; + } + // check bitmap size + CBitmapHandle bmp = hBitmap; + SIZE size = { 0, 0 }; + bmp.GetSize(size); + if(size.cx != m_szBitmap.cx || size.cy != m_szBitmap.cy) + { + ATLASSERT(FALSE); // must match size! + return FALSE; + } + // add bitmap + int nRet = ::ImageList_AddMasked(m_hImageList, hBitmap, m_clrMask); + if(nRet == -1) + return FALSE; + BOOL bRet = m_arrCommand.Add((WORD)nCommandID); + ATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize()); +#if _WTL_CMDBAR_VISTA_MENUS + if(RunTimeHelper::IsVista()) + { + pT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1); + ATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize()); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + return bRet; + } + + BOOL AddIcon(ATL::_U_STRINGorID icon, UINT nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + HICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr); + if(hIcon == NULL) + return FALSE; + return AddIcon(hIcon, nCommandID); + } + + BOOL AddIcon(HICON hIcon, UINT nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + // create image list if it doesn't exist + if(m_hImageList == NULL) + { + if(!pT->CreateInternalImageList(1)) + return FALSE; + } + + int nRet = ::ImageList_AddIcon(m_hImageList, hIcon); + if(nRet == -1) + return FALSE; + BOOL bRet = m_arrCommand.Add((WORD)nCommandID); + ATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize()); +#if _WTL_CMDBAR_VISTA_MENUS + if(RunTimeHelper::IsVista()) + { + pT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1); + ATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize()); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + return bRet; + } + + BOOL ReplaceBitmap(ATL::_U_STRINGorID bitmap, int nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + CBitmap bmp; + bmp.LoadBitmap(bitmap.m_lpstr); + if(bmp.m_hBitmap == NULL) + return FALSE; + return ReplaceBitmap(bmp, nCommandID); + } + + BOOL ReplaceBitmap(HBITMAP hBitmap, UINT nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + BOOL bRet = FALSE; + for(int i = 0; i < m_arrCommand.GetSize(); i++) + { + if(m_arrCommand[i] == nCommandID) + { + bRet = ::ImageList_Remove(m_hImageList, i); + if(bRet) + { + m_arrCommand.RemoveAt(i); +#if _WTL_CMDBAR_VISTA_MENUS + if(RunTimeHelper::IsVista()) + { + if(m_arrVistaBitmap[i] != NULL) + ::DeleteObject(m_arrVistaBitmap[i]); + m_arrVistaBitmap.RemoveAt(i); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + } + break; + } + } + if(bRet) + bRet = AddBitmap(hBitmap, nCommandID); + return bRet; + } + + BOOL ReplaceIcon(ATL::_U_STRINGorID icon, UINT nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + HICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr); + if(hIcon == NULL) + return FALSE; + return ReplaceIcon(hIcon, nCommandID); + } + + BOOL ReplaceIcon(HICON hIcon, UINT nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + BOOL bRet = FALSE; + for(int i = 0; i < m_arrCommand.GetSize(); i++) + { + if(m_arrCommand[i] == nCommandID) + { + bRet = (::ImageList_ReplaceIcon(m_hImageList, i, hIcon) != -1); +#if _WTL_CMDBAR_VISTA_MENUS + if(RunTimeHelper::IsVista() && bRet != FALSE) + { + T* pT = static_cast(this); + pT->_ReplaceVistaBitmapFromImageList(i); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + break; + } + } + return bRet; + } + + BOOL RemoveImage(int nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + + BOOL bRet = FALSE; + for(int i = 0; i < m_arrCommand.GetSize(); i++) + { + if(m_arrCommand[i] == nCommandID) + { + bRet = ::ImageList_Remove(m_hImageList, i); + if(bRet) + { + m_arrCommand.RemoveAt(i); +#if _WTL_CMDBAR_VISTA_MENUS + if(RunTimeHelper::IsVista()) + { + if(m_arrVistaBitmap[i] != NULL) + ::DeleteObject(m_arrVistaBitmap[i]); + m_arrVistaBitmap.RemoveAt(i); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + } + break; + } + } + return bRet; + } + + BOOL RemoveAllImages() + { + ATLASSERT(::IsWindow(m_hWnd)); + + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Removing all images\n")); + BOOL bRet = ::ImageList_RemoveAll(m_hImageList); + if(bRet) + { + m_arrCommand.RemoveAll(); +#if _WTL_CMDBAR_VISTA_MENUS + for(int i = 0; i < m_arrVistaBitmap.GetSize(); i++) + { + if(m_arrVistaBitmap[i] != NULL) + ::DeleteObject(m_arrVistaBitmap[i]); + } + m_arrVistaBitmap.RemoveAll(); +#endif // _WTL_CMDBAR_VISTA_MENUS + } + return bRet; + } + + BOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(::IsMenu(hMenu)); + if(!::IsMenu(hMenu)) + return FALSE; + m_bContextMenu = true; + if(m_bUseKeyboardCues) + m_bShowKeyboardCues = m_bKeyboardInput; + T* pT = static_cast(this); + return pT->DoTrackPopupMenu(hMenu, uFlags, x, y, lpParams); + } + + BOOL SetMDIClient(HWND /*hWndMDIClient*/) + { + // Use CMDICommandBarCtrl for MDI support + ATLASSERT(FALSE); + return FALSE; + } + +// Message map and handlers + BEGIN_MSG_MAP(CCommandBarCtrlImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_INITMENU, OnInitMenu) + MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) + MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) + MESSAGE_HANDLER(GetAutoPopupMessage(), OnInternalAutoPopup) + MESSAGE_HANDLER(GetGetBarMessage(), OnInternalGetBar) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) + MESSAGE_HANDLER(WM_MENUCHAR, OnMenuChar) + MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus) + + MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) + MESSAGE_HANDLER(WM_KEYUP, OnKeyUp) + MESSAGE_HANDLER(WM_CHAR, OnChar) + MESSAGE_HANDLER(WM_SYSKEYDOWN, OnSysKeyDown) + MESSAGE_HANDLER(WM_SYSKEYUP, OnSysKeyUp) + MESSAGE_HANDLER(WM_SYSCHAR, OnSysChar) +// public API handlers - these stay to support chevrons in atlframe.h + MESSAGE_HANDLER(CBRM_GETMENU, OnAPIGetMenu) + MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnAPITrackPopupMenu) + MESSAGE_HANDLER(CBRM_GETCMDBAR, OnAPIGetCmdBar) + + MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem) + MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem) + + MESSAGE_HANDLER(WM_FORWARDMSG, OnForwardMsg) + ALT_MSG_MAP(1) // Parent window messages + NOTIFY_CODE_HANDLER(TBN_HOTITEMCHANGE, OnParentHotItemChange) + NOTIFY_CODE_HANDLER(TBN_DROPDOWN, OnParentDropDown) + MESSAGE_HANDLER(WM_INITMENUPOPUP, OnParentInitMenuPopup) + MESSAGE_HANDLER(GetGetBarMessage(), OnParentInternalGetBar) + MESSAGE_HANDLER(WM_SYSCOMMAND, OnParentSysCommand) + MESSAGE_HANDLER(CBRM_GETMENU, OnParentAPIGetMenu) + MESSAGE_HANDLER(WM_MENUCHAR, OnParentMenuChar) + MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnParentAPITrackPopupMenu) + MESSAGE_HANDLER(CBRM_GETCMDBAR, OnParentAPIGetCmdBar) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnParentSettingChange) + + MESSAGE_HANDLER(WM_DRAWITEM, OnParentDrawItem) + MESSAGE_HANDLER(WM_MEASUREITEM, OnParentMeasureItem) + + MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate) + NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnParentCustomDraw) + ALT_MSG_MAP(2) // MDI client window messages + // Use CMDICommandBarCtrl for MDI support + ALT_MSG_MAP(3) // Message hook messages + MESSAGE_HANDLER(WM_MOUSEMOVE, OnHookMouseMove) + MESSAGE_HANDLER(WM_SYSKEYDOWN, OnHookSysKeyDown) + MESSAGE_HANDLER(WM_SYSKEYUP, OnHookSysKeyUp) + MESSAGE_HANDLER(WM_SYSCHAR, OnHookSysChar) + MESSAGE_HANDLER(WM_KEYDOWN, OnHookKeyDown) + MESSAGE_HANDLER(WM_NEXTMENU, OnHookNextMenu) + MESSAGE_HANDLER(WM_CHAR, OnHookChar) + END_MSG_MAP() + + LRESULT OnForwardMsg(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + LPMSG pMsg = (LPMSG)lParam; + if(pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST) + m_bKeyboardInput = false; + else if(pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) + m_bKeyboardInput = true; + LRESULT lRet = 0; + ProcessWindowMessage(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam, lRet, 3); + return lRet; + } + + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + // Let the toolbar initialize itself + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + // get and use system settings + T* pT = static_cast(this); + pT->GetSystemSettings(); + // Parent init + ATL::CWindow wndParent = GetParent(); + ATL::CWindow wndTopLevelParent = wndParent.GetTopLevelParent(); + m_wndParent.SubclassWindow(wndTopLevelParent); + // Toolbar Init + SetButtonStructSize(); + SetImageList(NULL); + + // Create message hook if needed + CWindowCreateCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnCreate.\n")); + ATLASSERT(FALSE); + return -1; + } + + if(s_pmapMsgHook == NULL) + { + ATLTRY(s_pmapMsgHook = new CMsgHookMap); + ATLASSERT(s_pmapMsgHook != NULL); + } + + if(s_pmapMsgHook != NULL) + { + DWORD dwThreadID = ::GetCurrentThreadId(); + _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID); + if(pData == NULL) + { + ATLTRY(pData = new _MsgHookData); + ATLASSERT(pData != NULL); + HHOOK hMsgHook = ::SetWindowsHookEx(WH_GETMESSAGE, MessageHookProc, ModuleHelper::GetModuleInstance(), dwThreadID); + ATLASSERT(hMsgHook != NULL); + if(pData != NULL && hMsgHook != NULL) + { + pData->hMsgHook = hMsgHook; + pData->dwUsage = 1; + BOOL bRet = s_pmapMsgHook->Add(dwThreadID, pData); + bRet; + ATLASSERT(bRet); + } + } + else + { + (pData->dwUsage)++; + } + } + lock.Unlock(); + + // Get layout +#if (WINVER >= 0x0500) + m_bLayoutRTL = ((GetExStyle() & WS_EX_LAYOUTRTL) != 0); +#endif // (WINVER >= 0x0500) + + return lRet; + } + + LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + +#if _WTL_CMDBAR_VISTA_MENUS + if(m_bVistaMenus && (m_hMenu != NULL)) + { + T* pT = static_cast(this); + pT->_RemoveVistaBitmapsFromMenu(); + } + + for(int i = 0; i < m_arrVistaBitmap.GetSize(); i++) + { + if(m_arrVistaBitmap[i] != NULL) + ::DeleteObject(m_arrVistaBitmap[i]); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + + if(m_bAttachedMenu) // nothing to do in this mode + return lRet; + + CWindowCreateCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnDestroy.\n")); + ATLASSERT(FALSE); + return lRet; + } + + if(s_pmapMsgHook != NULL) + { + DWORD dwThreadID = ::GetCurrentThreadId(); + _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID); + if(pData != NULL) + { + (pData->dwUsage)--; + if(pData->dwUsage == 0) + { + BOOL bRet = ::UnhookWindowsHookEx(pData->hMsgHook); + ATLASSERT(bRet); + bRet = s_pmapMsgHook->Remove(dwThreadID); + ATLASSERT(bRet); + if(bRet) + delete pData; + } + + if(s_pmapMsgHook->GetSize() == 0) + { + delete s_pmapMsgHook; + s_pmapMsgHook = NULL; + } + } + } + + lock.Unlock(); + + return lRet; + } + + LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnKeyDown\n")); +#endif + if(m_bAttachedMenu) // nothing to do in this mode + { + bHandled = FALSE; + return 1; + } + + bHandled = FALSE; + // Simulate Alt+Space for the parent + if(wParam == VK_SPACE) + { + m_wndParent.PostMessage(WM_SYSKEYDOWN, wParam, lParam | (1 << 29)); + bHandled = TRUE; + } +#if (_WIN32_IE >= 0x0500) + else if(wParam == VK_LEFT || wParam == VK_RIGHT) + { + WPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT; + + if(!m_bMenuActive) + { + T* pT = static_cast(this); + int nBtn = GetHotItem(); + int nNextBtn = (wParam == wpNext) ? pT->GetNextMenuItem(nBtn) : pT->GetPreviousMenuItem(nBtn); + if(nNextBtn == -2) + { + SetHotItem(-1); + if(pT->DisplayChevronMenu()) + bHandled = TRUE; + } + } + } +#endif // (_WIN32_IE >= 0x0500) + return 0; + } + + LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnKeyUp\n")); +#endif + if(m_bAttachedMenu) // nothing to do in this mode + { + bHandled = FALSE; + return 1; + } + + if(wParam != VK_SPACE) + bHandled = FALSE; + + return 0; + } + + LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnChar\n")); +#endif + if(m_bAttachedMenu) // nothing to do in this mode + { + bHandled = FALSE; + return 1; + } + + if(wParam != VK_SPACE) + bHandled = FALSE; + else + return 0; + // Security + if(!m_wndParent.IsWindowEnabled() || ::GetFocus() != m_hWnd) + return 0; + + // Handle mnemonic press when we have focus + int nBtn = 0; + if(wParam != VK_RETURN && !MapAccelerator((TCHAR)LOWORD(wParam), nBtn)) + { +#if (_WIN32_IE >= 0x0500) + if((TCHAR)LOWORD(wParam) != _chChevronShortcut) +#endif // (_WIN32_IE >= 0x0500) + ::MessageBeep(0); + } + else + { +#if (_WIN32_IE >= 0x0500) + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + RECT rcBtn = { 0 }; + GetItemRect(nBtn, &rcBtn); + TBBUTTON tbb = { 0 }; + GetButton(nBtn, &tbb); + if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right) + { +#endif // (_WIN32_IE >= 0x0500) + PostMessage(WM_KEYDOWN, VK_DOWN, 0L); + if(wParam != VK_RETURN) + SetHotItem(nBtn); +#if (_WIN32_IE >= 0x0500) + } + else + { + ::MessageBeep(0); + bHandled = TRUE; + } +#endif // (_WIN32_IE >= 0x0500) + } + return 0; + } + + LRESULT OnSysKeyDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysKeyDown\n")); +#endif + bHandled = FALSE; + return 0; + } + + LRESULT OnSysKeyUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysKeyUp\n")); +#endif + bHandled = FALSE; + return 0; + } + + LRESULT OnSysChar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysChar\n")); +#endif + bHandled = FALSE; + return 0; + } + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_bAttachedMenu || (m_dwExtendedStyle & CBR_EX_TRANSPARENT)) + { + bHandled = FALSE; + return 0; + } + + CDCHandle dc = (HDC)wParam; + RECT rect = { 0 }; + GetClientRect(&rect); + dc.FillRect(&rect, COLOR_MENU); + + return 1; // don't do the default erase + } + + LRESULT OnInitMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + int nIndex = GetHotItem(); + SendMessage(WM_MENUSELECT, MAKEWPARAM(nIndex, MF_POPUP|MF_HILITE), (LPARAM)m_hMenu); + bHandled = FALSE; + return 1; + } + + LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if((BOOL)HIWORD(lParam)) // System menu, do nothing + { + bHandled = FALSE; + return 1; + } + + if(!(m_bAttachedMenu || m_bMenuActive)) // Not attached or ours, do nothing + { + bHandled = FALSE; + return 1; + } + +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnInitMenuPopup\n")); +#endif + // forward to the parent or subclassed window, so it can handle update UI + LRESULT lRet = 0; + if(m_bAttachedMenu) + lRet = DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem()); + else + lRet = m_wndParent.DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem()); + +#if _WTL_CMDBAR_VISTA_MENUS + // If Vista menus are active, just set bitmaps and return + if(m_bVistaMenus) + { + CMenuHandle menu = (HMENU)wParam; + ATLASSERT(menu.m_hMenu != NULL); + + for(int i = 0; i < menu.GetMenuItemCount(); i++) + { + WORD nID = (WORD)menu.GetMenuItemID(i); + int nIndex = m_arrCommand.Find(nID); + + CMenuItemInfo mii; + mii.fMask = MIIM_BITMAP; + mii.hbmpItem = (m_bImagesVisible && (nIndex != -1)) ? m_arrVistaBitmap[nIndex] : NULL; + menu.SetMenuItemInfo(i, TRUE, &mii); + } + + return lRet; + } +#endif // _WTL_CMDBAR_VISTA_MENUS + + // Convert menu items to ownerdraw, add our data + if(m_bImagesVisible) + { + CMenuHandle menuPopup = (HMENU)wParam; + ATLASSERT(menuPopup.m_hMenu != NULL); + + T* pT = static_cast(this); + pT; // avoid level 4 warning + TCHAR szString[pT->_nMaxMenuItemTextLength] = { 0 }; + BOOL bRet = FALSE; + for(int i = 0; i < menuPopup.GetMenuItemCount(); i++) + { + CMenuItemInfo mii; + mii.cch = pT->_nMaxMenuItemTextLength; + mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE; + mii.dwTypeData = szString; + bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + + if(!(mii.fType & MFT_OWNERDRAW)) // Not already an ownerdraw item + { + mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE; + _MenuItemData* pMI = NULL; + ATLTRY(pMI = new _MenuItemData); + ATLASSERT(pMI != NULL); + if(pMI != NULL) + { + pMI->fType = mii.fType; + pMI->fState = mii.fState; + mii.fType |= MFT_OWNERDRAW; + pMI->iButton = -1; + for(int j = 0; j < m_arrCommand.GetSize(); j++) + { + if(m_arrCommand[j] == mii.wID) + { + pMI->iButton = j; + break; + } + } + int cchLen = lstrlen(szString) + 1; + pMI->lpstrText = NULL; + ATLTRY(pMI->lpstrText = new TCHAR[cchLen]); + ATLASSERT(pMI->lpstrText != NULL); + if(pMI->lpstrText != NULL) + SecureHelper::strcpy_x(pMI->lpstrText, cchLen, szString); + mii.dwItemData = (ULONG_PTR)pMI; + bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + } + } + } + + // Add it to the list + m_stackMenuHandle.Push(menuPopup.m_hMenu); + } + + return lRet; + } + + LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if(!m_bAttachedMenu) // Not attached, do nothing, forward to parent + { + m_bPopupItem = (lParam != NULL) && ((HMENU)lParam != m_hMenu) && (HIWORD(wParam) & MF_POPUP); + if(m_wndParent.IsWindow()) + m_wndParent.SendMessage(uMsg, wParam, lParam); + bHandled = FALSE; + return 1; + } + + // Check if a menu is closing, do a cleanup + if(HIWORD(wParam) == 0xFFFF && lParam == NULL) // Menu closing + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnMenuSelect - CLOSING!!!!\n")); +#endif + ATLASSERT(m_stackMenuWnd.GetSize() == 0); + // Restore the menu items to the previous state for all menus that were converted + if(m_bImagesVisible) + { + HMENU hMenu = NULL; + while((hMenu = m_stackMenuHandle.Pop()) != NULL) + { + CMenuHandle menuPopup = hMenu; + ATLASSERT(menuPopup.m_hMenu != NULL); + // Restore state and delete menu item data + BOOL bRet = FALSE; + for(int i = 0; i < menuPopup.GetMenuItemCount(); i++) + { + CMenuItemInfo mii; + mii.fMask = MIIM_DATA | MIIM_TYPE; + bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + + _MenuItemData* pMI = (_MenuItemData*)mii.dwItemData; + if(pMI != NULL && pMI->IsCmdBarMenuItem()) + { + mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE; + mii.fType = pMI->fType; + mii.dwTypeData = pMI->lpstrText; + mii.cch = lstrlen(pMI->lpstrText); + mii.dwItemData = NULL; + + bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + + delete [] pMI->lpstrText; + pMI->dwMagic = 0x6666; + delete pMI; + } + } + } + } + } + + bHandled = FALSE; + return 1; + } + + LRESULT OnInternalAutoPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + int nIndex = (int)wParam; + T* pT = static_cast(this); + pT->DoPopupMenu(nIndex, false); + return 0; + } + + LRESULT OnInternalGetBar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + // Let's make sure we're not embedded in another process + if((LPVOID)wParam != NULL) + *((DWORD*)wParam) = GetCurrentProcessId(); + if(IsWindowVisible()) + return (LRESULT)static_cast(this); + else + return NULL; + } + + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { +#ifndef SPI_SETKEYBOARDCUES + const UINT SPI_SETKEYBOARDCUES = 0x100B; +#endif // !SPI_SETKEYBOARDCUES +#ifndef SPI_GETFLATMENU + const UINT SPI_SETFLATMENU = 0x1023; +#endif // !SPI_GETFLATMENU + + if(wParam == SPI_SETNONCLIENTMETRICS || wParam == SPI_SETKEYBOARDCUES || wParam == SPI_SETFLATMENU) + { + T* pT = static_cast(this); + pT->GetSystemSettings(); + } + + return 0; + } + + LRESULT OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + + LPWINDOWPOS lpWP = (LPWINDOWPOS)lParam; + int cyMin = ::GetSystemMetrics(SM_CYMENU); + if(lpWP->cy < cyMin) + lpWP->cy = cyMin; + + return lRet; + } + + LRESULT OnMenuChar(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnMenuChar\n")); +#endif + bHandled = TRUE; + T* pT = static_cast(this); + + LRESULT lRet; + if(m_bMenuActive && LOWORD(wParam) != 0x0D) + lRet = 0; + else + lRet = MAKELRESULT(1, 1); + + if(m_bMenuActive && HIWORD(wParam) == MF_POPUP) + { + // Convert character to lower/uppercase and possibly Unicode, using current keyboard layout + TCHAR ch = (TCHAR)LOWORD(wParam); + CMenuHandle menu = (HMENU)lParam; + int nCount = ::GetMenuItemCount(menu); + int nRetCode = MNC_EXECUTE; + BOOL bRet = FALSE; + TCHAR szString[pT->_nMaxMenuItemTextLength] = { 0 }; + WORD wMnem = 0; + bool bFound = false; + for(int i = 0; i < nCount; i++) + { + CMenuItemInfo mii; + mii.cch = pT->_nMaxMenuItemTextLength; + mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE; + mii.dwTypeData = szString; + bRet = menu.GetMenuItemInfo(i, TRUE, &mii); + if(!bRet || (mii.fType & MFT_SEPARATOR)) + continue; + _MenuItemData* pmd = (_MenuItemData*)mii.dwItemData; + if(pmd != NULL && pmd->IsCmdBarMenuItem()) + { + LPTSTR p = pmd->lpstrText; + + if(p != NULL) + { + while(*p && *p != _T('&')) + p = ::CharNext(p); + if(p != NULL && *p) + { + DWORD dwP = MAKELONG(*(++p), 0); + DWORD dwC = MAKELONG(ch, 0); + if(::CharLower((LPTSTR)ULongToPtr(dwP)) == ::CharLower((LPTSTR)ULongToPtr(dwC))) + { + if(!bFound) + { + wMnem = (WORD)i; + bFound = true; + } + else + { + nRetCode = MNC_SELECT; + break; + } + } + } + } + } + } + if(bFound) + { + if(nRetCode == MNC_EXECUTE) + { + PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); + pT->GiveFocusBack(); + } + bHandled = TRUE; + lRet = MAKELRESULT(wMnem, nRetCode); + } + } + else if(!m_bMenuActive) + { + int nBtn = 0; + if(!MapAccelerator((TCHAR)LOWORD(wParam), nBtn)) + { + bHandled = FALSE; + PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); + pT->GiveFocusBack(); + +#if (_WIN32_IE >= 0x0500) + // check if we should display chevron menu + if((TCHAR)LOWORD(wParam) == pT->_chChevronShortcut) + { + if(pT->DisplayChevronMenu()) + bHandled = TRUE; + } +#endif // (_WIN32_IE >= 0x0500) + } + else if(m_wndParent.IsWindowEnabled()) + { +#if (_WIN32_IE >= 0x0500) + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + RECT rcBtn = { 0 }; + GetItemRect(nBtn, &rcBtn); + TBBUTTON tbb = { 0 }; + GetButton(nBtn, &tbb); + if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right) + { +#endif // (_WIN32_IE >= 0x0500) + if(m_bUseKeyboardCues && !m_bShowKeyboardCues) + { + m_bAllowKeyboardCues = true; + ShowKeyboardCues(true); + } + pT->TakeFocus(); + PostMessage(WM_KEYDOWN, VK_DOWN, 0L); + SetHotItem(nBtn); +#if (_WIN32_IE >= 0x0500) + } + else + { + ::MessageBeep(0); + } +#endif // (_WIN32_IE >= 0x0500) + } + } + + return lRet; + } + + LRESULT OnKillFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_bUseKeyboardCues && m_bShowKeyboardCues) + ShowKeyboardCues(false); + + bHandled = FALSE; + return 1; + } + + LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + LPDRAWITEMSTRUCT lpDrawItemStruct = (LPDRAWITEMSTRUCT)lParam; + _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData; + if(lpDrawItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem()) + { + T* pT = static_cast(this); + pT->DrawItem(lpDrawItemStruct); + } + else + { + bHandled = FALSE; + } + return (LRESULT)TRUE; + } + + LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + LPMEASUREITEMSTRUCT lpMeasureItemStruct = (LPMEASUREITEMSTRUCT)lParam; + _MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData; + if(lpMeasureItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem()) + { + T* pT = static_cast(this); + pT->MeasureItem(lpMeasureItemStruct); + } + else + { + bHandled = FALSE; + } + return (LRESULT)TRUE; + } + +// API message handlers + LRESULT OnAPIGetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return (LRESULT)m_hMenu; + } + + LRESULT OnAPITrackPopupMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + if(lParam == NULL) + return FALSE; + LPCBRPOPUPMENU lpCBRPopupMenu = (LPCBRPOPUPMENU)lParam; + if(lpCBRPopupMenu->cbSize != sizeof(CBRPOPUPMENU)) + return FALSE; + + T* pT = static_cast(this); + return pT->TrackPopupMenu(lpCBRPopupMenu->hMenu, lpCBRPopupMenu->uFlags, lpCBRPopupMenu->x, lpCBRPopupMenu->y, lpCBRPopupMenu->lptpm); + } + + LRESULT OnAPIGetCmdBar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return (LRESULT)m_hWnd; + } + +// Parent window message handlers + LRESULT OnParentHotItemChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + LPNMTBHOTITEM lpNMHT = (LPNMTBHOTITEM)pnmh; + + // Check if this comes from us + if(pnmh->hwndFrom != m_hWnd) + { + bHandled = FALSE; + return 0; + } + + bool bBlockTracking = false; + if((m_dwExtendedStyle & CBR_EX_TRACKALWAYS) == 0) + { + DWORD dwProcessID; + ::GetWindowThreadProcessId(::GetActiveWindow(), &dwProcessID); + bBlockTracking = (::GetCurrentProcessId() != dwProcessID); + } + + if((!m_wndParent.IsWindowEnabled() || bBlockTracking) && (lpNMHT->dwFlags & HICF_MOUSE)) + { + return 1; + } + else + { +#ifndef HICF_LMOUSE + const DWORD HICF_LMOUSE = 0x00000080; // left mouse button selected +#endif + bHandled = FALSE; + + // Send WM_MENUSELECT to the app if it needs to display a status text + if(!(lpNMHT->dwFlags & HICF_MOUSE) + && !(lpNMHT->dwFlags & HICF_ACCELERATOR) + && !(lpNMHT->dwFlags & HICF_LMOUSE)) + { + if(lpNMHT->dwFlags & HICF_ENTERING) + m_wndParent.SendMessage(WM_MENUSELECT, 0, (LPARAM)m_hMenu); + if(lpNMHT->dwFlags & HICF_LEAVING) + m_wndParent.SendMessage(WM_MENUSELECT, MAKEWPARAM(0, 0xFFFF), NULL); + } + + return 0; + } + } + + LRESULT OnParentDropDown(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + // Check if this comes from us + if(pnmh->hwndFrom != m_hWnd) + { + bHandled = FALSE; + return 1; + } + + T* pT = static_cast(this); + if(::GetFocus() != m_hWnd) + pT->TakeFocus(); + LPNMTOOLBAR pNMToolBar = (LPNMTOOLBAR)pnmh; + int nIndex = CommandToIndex(pNMToolBar->iItem); + m_bContextMenu = false; + m_bEscapePressed = false; + pT->DoPopupMenu(nIndex, true); + + return TBDDRET_DEFAULT; + } + + LRESULT OnParentInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnInitMenuPopup(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentInternalGetBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnInternalGetBar(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; + if((m_uSysKey == VK_MENU + || (m_uSysKey == VK_F10 && !(::GetKeyState(VK_SHIFT) & 0x80)) + || m_uSysKey == VK_SPACE) + && wParam == SC_KEYMENU) + { + T* pT = static_cast(this); + if(::GetFocus() == m_hWnd) + { + pT->GiveFocusBack(); // exit menu "loop" + PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); + } + else if(m_uSysKey != VK_SPACE && !m_bSkipMsg) + { + if(m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues) + ShowKeyboardCues(true); + + pT->TakeFocus(); // enter menu "loop" + bHandled = TRUE; + } + else if(m_uSysKey != VK_SPACE) + { + bHandled = TRUE; + } + } + m_bSkipMsg = false; + return 0; + } + + LRESULT OnParentAPIGetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnAPIGetMenu(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentMenuChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnMenuChar(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentAPITrackPopupMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnAPITrackPopupMenu(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentAPIGetCmdBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnAPIGetCmdBar(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + OnSettingChange(uMsg, wParam, lParam, bHandled); + bHandled = FALSE; + return 1; + } + + LRESULT OnParentDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnDrawItem(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentMeasureItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnMeasureItem(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + m_bParentActive = (LOWORD(wParam) != WA_INACTIVE); + if(!m_bParentActive && m_bUseKeyboardCues && m_bShowKeyboardCues) + { + ShowKeyboardCues(false); // this will repaint our window + } + else + { + Invalidate(); + UpdateWindow(); + } + bHandled = FALSE; + return 1; + } + + LRESULT OnParentCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + LRESULT lRet = CDRF_DODEFAULT; + bHandled = FALSE; + if(pnmh->hwndFrom == m_hWnd) + { + LPNMTBCUSTOMDRAW lpTBCustomDraw = (LPNMTBCUSTOMDRAW)pnmh; + if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT) + { + lRet = CDRF_NOTIFYITEMDRAW; + bHandled = TRUE; + } + else if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) + { +#if _WTL_CMDBAR_VISTA_MENUS && defined(_WTL_CMDBAR_VISTA_STD_MENUBAR) + if(m_bVistaMenus) + { + ::SetRectEmpty(&lpTBCustomDraw->rcText); + lRet = CDRF_NOTIFYPOSTPAINT; + bHandled = TRUE; + } + else +#endif // _WTL_CMDBAR_VISTA_MENUS && defined(_WTL_CMDBAR_VISTA_STD_MENUBAR) + { + if(m_bFlatMenus) + { +#ifndef COLOR_MENUHILIGHT + const int COLOR_MENUHILIGHT = 29; +#endif // !COLOR_MENUHILIGHT + bool bDisabled = ((lpTBCustomDraw->nmcd.uItemState & CDIS_DISABLED) == CDIS_DISABLED); + if(!bDisabled && ((lpTBCustomDraw->nmcd.uItemState & CDIS_HOT) == CDIS_HOT || + (lpTBCustomDraw->nmcd.uItemState & CDIS_SELECTED) == CDIS_SELECTED)) + { + ::FillRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_MENUHILIGHT)); + ::FrameRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_HIGHLIGHT)); + lpTBCustomDraw->clrText = ::GetSysColor(m_bParentActive ? COLOR_HIGHLIGHTTEXT : COLOR_GRAYTEXT); + } + else if(bDisabled || !m_bParentActive) + { + lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT); + } + + _ParentCustomDrawHelper(lpTBCustomDraw); + + lRet = CDRF_SKIPDEFAULT; + bHandled = TRUE; + } + else if(!m_bParentActive) + { + lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT); + bHandled = TRUE; + } + } + } +#if _WTL_CMDBAR_VISTA_MENUS && defined(_WTL_CMDBAR_VISTA_STD_MENUBAR) + else if (lpTBCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPOSTPAINT) + { + bool bDisabled = ((lpTBCustomDraw->nmcd.uItemState & CDIS_DISABLED) == CDIS_DISABLED); + if(bDisabled || !m_bParentActive) + lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT); + + _ParentCustomDrawHelper(lpTBCustomDraw); + + lRet = CDRF_SKIPDEFAULT; + bHandled = TRUE; + } +#endif // _WTL_CMDBAR_VISTA_MENUS && defined(_WTL_CMDBAR_VISTA_STD_MENUBAR) + } + return lRet; + } + + void _ParentCustomDrawHelper(LPNMTBCUSTOMDRAW lpTBCustomDraw) + { + CDCHandle dc = lpTBCustomDraw->nmcd.hdc; + dc.SetTextColor(lpTBCustomDraw->clrText); + dc.SetBkMode(lpTBCustomDraw->nStringBkMode); + + HFONT hFont = GetFont(); + HFONT hFontOld = NULL; + if(hFont != NULL) + hFontOld = dc.SelectFont(hFont); + + const int cchText = 200; + TCHAR szText[cchText] = { 0 }; + TBBUTTONINFO tbbi = { 0 }; + tbbi.cbSize = sizeof(TBBUTTONINFO); + tbbi.dwMask = TBIF_TEXT; + tbbi.pszText = szText; + tbbi.cchText = cchText; + GetButtonInfo((int)lpTBCustomDraw->nmcd.dwItemSpec, &tbbi); + + dc.DrawText(szText, -1, &lpTBCustomDraw->nmcd.rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX)); + + if(hFont != NULL) + dc.SelectFont(hFontOld); + } + +// Message hook handlers + LRESULT OnHookMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + static POINT s_point = { -1, -1 }; + DWORD dwPoint = ::GetMessagePos(); + POINT point = { GET_X_LPARAM(dwPoint), GET_Y_LPARAM(dwPoint) }; + + bHandled = FALSE; + if(m_bMenuActive) + { + if(::WindowFromPoint(point) == m_hWnd) + { + ScreenToClient(&point); + int nHit = HitTest(&point); + + if((point.x != s_point.x || point.y != s_point.y) && nHit >= 0 && nHit < ::GetMenuItemCount(m_hMenu) && nHit != m_nPopBtn && m_nPopBtn != -1) + { + TBBUTTON tbb = { 0 }; + GetButton(nHit, &tbb); + if((tbb.fsState & TBSTATE_ENABLED) != 0) + { + m_nNextPopBtn = nHit | 0xFFFF0000; + HWND hWndMenu = m_stackMenuWnd.GetCurrent(); + ATLASSERT(hWndMenu != NULL); + + // this one is needed to close a menu if mouse button was down + ::PostMessage(hWndMenu, WM_LBUTTONUP, 0, MAKELPARAM(point.x, point.y)); + // this one closes a popup menu + ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L); + + bHandled = TRUE; + } + } + } + } + else + { + ScreenToClient(&point); + } + + s_point = point; + return 0; + } + + LRESULT OnHookSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSKEYDOWN (0x%2.2X)\n"), wParam); +#endif + + if(wParam == VK_MENU && m_bParentActive && m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues) + ShowKeyboardCues(true); + + if(wParam != VK_SPACE && !m_bMenuActive && ::GetFocus() == m_hWnd) + { + m_bAllowKeyboardCues = false; + PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); + T* pT = static_cast(this); + pT->GiveFocusBack(); + m_bSkipMsg = true; + } + else + { + if(wParam == VK_SPACE && m_bUseKeyboardCues && m_bShowKeyboardCues) + { + m_bAllowKeyboardCues = true; + ShowKeyboardCues(false); + } + m_uSysKey = (UINT)wParam; + } + return 0; + } + + LRESULT OnHookSysKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(!m_bAllowKeyboardCues) + m_bAllowKeyboardCues = true; + bHandled = FALSE; + wParam; +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSKEYUP (0x%2.2X)\n"), wParam); +#endif + return 0; + } + + LRESULT OnHookSysChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSCHAR (0x%2.2X)\n"), wParam); +#endif + + if(!m_bMenuActive && m_hWndHook != m_hWnd && wParam != VK_SPACE) + bHandled = TRUE; + return 0; + } + + LRESULT OnHookKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_KEYDOWN (0x%2.2X)\n"), wParam); +#endif + bHandled = FALSE; + T* pT = static_cast(this); + + if(wParam == VK_ESCAPE && m_stackMenuWnd.GetSize() <= 1) + { + if(m_bMenuActive && !m_bContextMenu) + { + int nHot = GetHotItem(); + if(nHot == -1) + nHot = m_nPopBtn; + if(nHot == -1) + nHot = 0; + SetHotItem(nHot); + bHandled = TRUE; + pT->TakeFocus(); + m_bEscapePressed = true; // To keep focus + m_bSkipPostDown = false; + } + else if(::GetFocus() == m_hWnd && m_wndParent.IsWindow()) + { + SetHotItem(-1); + pT->GiveFocusBack(); + bHandled = TRUE; + } + } + else if(wParam == VK_RETURN || wParam == VK_UP || wParam == VK_DOWN) + { + if(!m_bMenuActive && ::GetFocus() == m_hWnd && m_wndParent.IsWindow()) + { + int nHot = GetHotItem(); + if(nHot != -1) + { + if(wParam != VK_RETURN) + { + if(!m_bSkipPostDown) + { +// IE4 only: WM_KEYDOWN doesn't generate TBN_DROPDOWN, we need to simulate a mouse click +#if (_WIN32_IE < 0x0500) + DWORD dwMajor = 0, dwMinor = 0; + ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor); + if(dwMajor <= 4 || (dwMajor == 5 && dwMinor < 80)) + { + RECT rect = { 0 }; + GetItemRect(nHot, &rect); + PostMessage(WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(rect.left, rect.top)); + } +#endif // (_WIN32_IE < 0x0500) + PostMessage(WM_KEYDOWN, VK_DOWN, 0L); + m_bSkipPostDown = true; + } + else + { + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - skipping posting another VK_DOWN\n")); + m_bSkipPostDown = false; + } + } + } + else + { + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Can't find hot button\n")); + } + } + if(wParam == VK_RETURN && m_bMenuActive) + { + PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); + m_nNextPopBtn = -1; + pT->GiveFocusBack(); + } + } + else if(wParam == VK_LEFT || wParam == VK_RIGHT) + { + WPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT; + WPARAM wpPrev = m_bLayoutRTL ? VK_RIGHT : VK_LEFT; + + if(m_bMenuActive && !m_bContextMenu && !(wParam == wpNext && m_bPopupItem)) + { + bool bAction = false; + if(wParam == wpPrev && s_pCurrentBar->m_stackMenuWnd.GetSize() == 1) + { + m_nNextPopBtn = pT->GetPreviousMenuItem(m_nPopBtn); + if(m_nNextPopBtn != -1) + bAction = true; + } + else if(wParam == wpNext) + { + m_nNextPopBtn = pT->GetNextMenuItem(m_nPopBtn); + if(m_nNextPopBtn != -1) + bAction = true; + } + HWND hWndMenu = m_stackMenuWnd.GetCurrent(); + ATLASSERT(hWndMenu != NULL); + + // Close the popup menu + if(bAction) + { + ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L); + if(wParam == wpNext) + { + int cItem = m_stackMenuWnd.GetSize() - 1; + while(cItem >= 0) + { + hWndMenu = m_stackMenuWnd[cItem]; + if(hWndMenu != NULL) + ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L); + cItem--; + } + } +#if (_WIN32_IE >= 0x0500) + if(m_nNextPopBtn == -2) + { + m_nNextPopBtn = -1; + pT->DisplayChevronMenu(); + } +#endif // (_WIN32_IE >= 0x0500) + bHandled = TRUE; + } + } + } + return 0; + } + + LRESULT OnHookNextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_NEXTMENU\n")); +#endif + bHandled = FALSE; + return 1; + } + + LRESULT OnHookChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_CHAR (0x%2.2X)\n"), wParam); +#endif + bHandled = (wParam == VK_ESCAPE); + return 0; + } + +// Implementation - ownerdraw overrideables and helpers + void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) + { + T* pT = static_cast(this); + if(m_bFlatMenus) + pT->DrawItemFlat(lpDrawItemStruct); + else + pT->DrawItem3D(lpDrawItemStruct); + + } + + void DrawItem3D(LPDRAWITEMSTRUCT lpDrawItemStruct) + { + _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData; + CDCHandle dc = lpDrawItemStruct->hDC; + const RECT& rcItem = lpDrawItemStruct->rcItem; + T* pT = static_cast(this); + + if(pmd->fType & MFT_SEPARATOR) + { + // draw separator + RECT rc = rcItem; + rc.top += (rc.bottom - rc.top) / 2; // vertical center + dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // draw separator line + } + else // not a separator + { + BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED; + BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED; + BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED; + BOOL bHasImage = FALSE; + + if(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1) + bSelected = FALSE; + RECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy }; // button rect + ::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2); // center vertically + + int iButton = pmd->iButton; + if(iButton >= 0) + { + bHasImage = TRUE; + + // calc drawing point + SIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy }; + sz.cx /= 2; + sz.cy /= 2; + POINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy }; + + // fill background depending on state + if(!bChecked || (bSelected && !bDisabled)) + { + if(!bDisabled) + dc.FillRect(&rcButn, (bChecked && !bSelected) ? COLOR_3DLIGHT : COLOR_MENU); + else + dc.FillRect(&rcButn, COLOR_MENU); + } + else + { + COLORREF crTxt = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE)); + COLORREF crBk = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT)); + CBrush hbr(CDCHandle::GetHalftoneBrush()); + dc.SetBrushOrg(rcButn.left, rcButn.top); + dc.FillRect(&rcButn, hbr); + dc.SetTextColor(crTxt); + dc.SetBkColor(crBk); + } + + // draw disabled or normal + if(!bDisabled) + { + // draw pushed-in or popped-out edge + if(bSelected || bChecked) + { + RECT rc2 = rcButn; + dc.DrawEdge(&rc2, bChecked ? BDR_SUNKENOUTER : BDR_RAISEDINNER, BF_RECT); + } + // draw the image + ::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT); + } + else + { + HBRUSH hBrushBackground = bChecked ? NULL : ::GetSysColorBrush(COLOR_MENU); + pT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground); + } + } + else + { + // no image - look for custom checked/unchecked bitmaps + CMenuItemInfo info; + info.fMask = MIIM_CHECKMARKS | MIIM_TYPE; + ::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info); + if(bChecked || info.hbmpUnchecked != NULL) + { + BOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0); + bHasImage = pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked); + } + } + + // draw item text + int cxButn = m_szButton.cx; + COLORREF colorBG = ::GetSysColor(bSelected ? COLOR_HIGHLIGHT : COLOR_MENU); + if(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT) + { + RECT rcBG = rcItem; + if(bHasImage) + rcBG.left += cxButn + s_kcxGap; + dc.FillRect(&rcBG, bSelected ? COLOR_HIGHLIGHT : COLOR_MENU); + } + + // calc text rectangle and colors + RECT rcText = rcItem; + rcText.left += cxButn + s_kcxGap + s_kcxTextMargin; + rcText.right -= cxButn; + dc.SetBkMode(TRANSPARENT); + COLORREF colorText = ::GetSysColor(bDisabled ? (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)); + + // font already selected by Windows + if(bDisabled && (!bSelected || colorText == colorBG)) + { + // disabled - draw shadow text shifted down and right 1 pixel (unles selected) + RECT rcDisabled = rcText; + ::OffsetRect(&rcDisabled, 1, 1); + pT->DrawMenuText(dc, rcDisabled, pmd->lpstrText, ::GetSysColor(COLOR_3DHILIGHT)); + } + pT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally! + } + } + + void DrawItemFlat(LPDRAWITEMSTRUCT lpDrawItemStruct) + { + _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData; + CDCHandle dc = lpDrawItemStruct->hDC; + const RECT& rcItem = lpDrawItemStruct->rcItem; + T* pT = static_cast(this); + +#ifndef COLOR_MENUHILIGHT + const int COLOR_MENUHILIGHT = 29; +#endif // !COLOR_MENUHILIGHT + + BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED; + BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED; + BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED; + + // paint background + if(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT) + { + if(bSelected) + { + dc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENUHILIGHT)); + dc.FrameRect(&rcItem, ::GetSysColorBrush(COLOR_HIGHLIGHT)); + } + else + { + dc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENU)); + } + } + + if(pmd->fType & MFT_SEPARATOR) + { + // draw separator + RECT rc = rcItem; + rc.top += (rc.bottom - rc.top) / 2; // vertical center + dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // draw separator line + } + else // not a separator + { + if(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1) + bSelected = FALSE; + RECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy }; // button rect + ::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2); // center vertically + + // draw background and border for checked items + if(bChecked) + { + RECT rcCheck = rcButn; + ::InflateRect(&rcCheck, -1, -1); + if(bSelected) + dc.FillRect(&rcCheck, ::GetSysColorBrush(COLOR_MENU)); + dc.FrameRect(&rcCheck, ::GetSysColorBrush(COLOR_HIGHLIGHT)); + } + + int iButton = pmd->iButton; + if(iButton >= 0) + { + // calc drawing point + SIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy }; + sz.cx /= 2; + sz.cy /= 2; + POINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy }; + + // draw disabled or normal + if(!bDisabled) + { + ::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT); + } + else + { + HBRUSH hBrushBackground = ::GetSysColorBrush((bSelected && !(bDisabled && bChecked)) ? COLOR_MENUHILIGHT : COLOR_MENU); + HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW); + pT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground, hBrushBackground, hBrushDisabledImage); + } + } + else + { + // no image - look for custom checked/unchecked bitmaps + CMenuItemInfo info; + info.fMask = MIIM_CHECKMARKS | MIIM_TYPE; + ::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info); + if(bChecked || info.hbmpUnchecked != NULL) + { + BOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0); + pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked); + } + } + + // draw item text + int cxButn = m_szButton.cx; + // calc text rectangle and colors + RECT rcText = rcItem; + rcText.left += cxButn + s_kcxGap + s_kcxTextMargin; + rcText.right -= cxButn; + dc.SetBkMode(TRANSPARENT); + COLORREF colorText = ::GetSysColor(bDisabled ? (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)); + + pT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally! + } + } + + void DrawMenuText(CDCHandle& dc, RECT& rc, LPCTSTR lpstrText, COLORREF color) + { + int nTab = -1; + const int nLen = lstrlen(lpstrText); + for(int i = 0; i < nLen; i++) + { + if(lpstrText[i] == _T('\t')) + { + nTab = i; + break; + } + } + dc.SetTextColor(color); + dc.DrawText(lpstrText, nTab, &rc, DT_SINGLELINE | DT_LEFT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX)); + if(nTab != -1) + dc.DrawText(&lpstrText[nTab + 1], -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX)); + } + + void DrawBitmapDisabled(CDCHandle& dc, int nImage, POINT point, + HBRUSH hBrushBackground = ::GetSysColorBrush(COLOR_3DFACE), + HBRUSH hBrush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT), + HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW)) + { +#if (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501) + if(m_bAlphaImages) + { + IMAGELISTDRAWPARAMS ildp = { 0 }; + ildp.cbSize = sizeof(IMAGELISTDRAWPARAMS); + ildp.himl = m_hImageList; + ildp.i = nImage; + ildp.hdcDst = dc; + ildp.x = point.x; + ildp.y = point.y; + ildp.cx = 0; + ildp.cy = 0; + ildp.xBitmap = 0; + ildp.yBitmap = 0; + ildp.fStyle = ILD_TRANSPARENT; + ildp.fState = ILS_SATURATE; + ildp.Frame = 0; + ::ImageList_DrawIndirect(&ildp); + } + else +#endif // (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501) + { + // create memory DC + CDC dcMem; + dcMem.CreateCompatibleDC(dc); + // create mono or color bitmap + CBitmap bmp; + bmp.CreateCompatibleBitmap(dc, m_szBitmap.cx, m_szBitmap.cy); + ATLASSERT(bmp.m_hBitmap != NULL); + // draw image into memory DC--fill BG white first + HBITMAP hBmpOld = dcMem.SelectBitmap(bmp); + dcMem.PatBlt(0, 0, m_szBitmap.cx, m_szBitmap.cy, WHITENESS); + // If white is the text color, we can't use the normal painting since + // it would blend with the WHITENESS, but the mask is OK + UINT uDrawStyle = (::GetSysColor(COLOR_BTNTEXT) == RGB(255, 255, 255)) ? ILD_MASK : ILD_NORMAL; + ::ImageList_Draw(m_hImageList, nImage, dcMem, 0, 0, uDrawStyle); + dc.DitherBlt(point.x, point.y, m_szBitmap.cx, m_szBitmap.cy, dcMem, NULL, 0, 0, hBrushBackground, hBrush3DEffect, hBrushDisabledImage); + dcMem.SelectBitmap(hBmpOld); // restore + } + } + + // old name + BOOL Draw3DCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck) + { + return DrawCheckmark(dc, rc, bSelected, bDisabled, bRadio, hBmpCheck); + } + + BOOL DrawCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck) + { + // get checkmark bitmap, if none, use Windows standard + SIZE size = { 0, 0 }; + CBitmapHandle bmp = hBmpCheck; + if(hBmpCheck != NULL) + { + bmp.GetSize(size); + } + else + { + size.cx = ::GetSystemMetrics(SM_CXMENUCHECK); + size.cy = ::GetSystemMetrics(SM_CYMENUCHECK); + bmp.CreateCompatibleBitmap(dc, size.cx, size.cy); + ATLASSERT(bmp.m_hBitmap != NULL); + } + // center bitmap in caller's rectangle + RECT rcDest = rc; + if((rc.right - rc.left) > size.cx) + { + rcDest.left = rc.left + (rc.right - rc.left - size.cx) / 2; + rcDest.right = rcDest.left + size.cx; + } + if((rc.bottom - rc.top) > size.cy) + { + rcDest.top = rc.top + (rc.bottom - rc.top - size.cy) / 2; + rcDest.bottom = rcDest.top + size.cy; + } + // paint background + if(!m_bFlatMenus) + { + if(bSelected && !bDisabled) + { + dc.FillRect(&rcDest, COLOR_MENU); + } + else + { + COLORREF clrTextOld = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE)); + COLORREF clrBkOld = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT)); + CBrush hbr(CDCHandle::GetHalftoneBrush()); + dc.SetBrushOrg(rcDest.left, rcDest.top); + dc.FillRect(&rcDest, hbr); + dc.SetTextColor(clrTextOld); + dc.SetBkColor(clrBkOld); + } + } + + // create source image + CDC dcSource; + dcSource.CreateCompatibleDC(dc); + HBITMAP hBmpOld = dcSource.SelectBitmap(bmp); + // set colors + const COLORREF clrBlack = RGB(0, 0, 0); + const COLORREF clrWhite = RGB(255, 255, 255); + COLORREF clrTextOld = dc.SetTextColor(clrBlack); + COLORREF clrBkOld = dc.SetBkColor(clrWhite); + // create mask + CDC dcMask; + dcMask.CreateCompatibleDC(dc); + CBitmap bmpMask; + bmpMask.CreateBitmap(size.cx, size.cy, 1, 1, NULL); + HBITMAP hBmpOld1 = dcMask.SelectBitmap(bmpMask); + + // draw the checkmark transparently + int cx = rcDest.right - rcDest.left; + int cy = rcDest.bottom - rcDest.top; + if(hBmpCheck != NULL) + { + // build mask based on transparent color + dcSource.SetBkColor(m_clrMask); + dcMask.SetBkColor(clrBlack); + dcMask.SetTextColor(clrWhite); + dcMask.BitBlt(0, 0, size.cx, size.cy, dcSource, 0, 0, SRCCOPY); + // draw bitmap using the mask + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT); + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, SRCAND); + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT); + } + else + { + const DWORD ROP_DSno = 0x00BB0226L; + const DWORD ROP_DSa = 0x008800C6L; + const DWORD ROP_DSo = 0x00EE0086L; + const DWORD ROP_DSna = 0x00220326L; + + // draw mask + RECT rcSource = { 0, 0, __min(size.cx, rc.right - rc.left), __min(size.cy, rc.bottom - rc.top) }; + dcMask.DrawFrameControl(&rcSource, DFC_MENU, bRadio ? DFCS_MENUBULLET : DFCS_MENUCHECK); + + // draw shadow if disabled + if(!m_bFlatMenus && bDisabled) + { + // offset by one pixel + int x = rcDest.left + 1; + int y = rcDest.top + 1; + // paint source bitmap + const int nColor = COLOR_3DHILIGHT; + dcSource.FillRect(&rcSource, nColor); + // draw checkmark - special case black and white colors + COLORREF clrCheck = ::GetSysColor(nColor); + if(clrCheck == clrWhite) + { + dc.BitBlt(x, y, cx, cy, dcMask, 0, 0, ROP_DSno); + dc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSa); + } + else + { + if(clrCheck != clrBlack) + { + ATLASSERT(dcSource.GetTextColor() == clrBlack); + ATLASSERT(dcSource.GetBkColor() == clrWhite); + dcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna); + } + dc.BitBlt(x, y, cx, cy, dcMask, 0, 0, ROP_DSa); + dc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSo); + } + } + + // paint source bitmap + const int nColor = bDisabled ? COLOR_BTNSHADOW : COLOR_MENUTEXT; + dcSource.FillRect(&rcSource, nColor); + // draw checkmark - special case black and white colors + COLORREF clrCheck = ::GetSysColor(nColor); + if(clrCheck == clrWhite) + { + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, ROP_DSno); + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSa); + } + else + { + if(clrCheck != clrBlack) + { + ATLASSERT(dcSource.GetTextColor() == clrBlack); + ATLASSERT(dcSource.GetBkColor() == clrWhite); + dcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna); + } + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, ROP_DSa); + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSo); + } + } + // restore all + dc.SetTextColor(clrTextOld); + dc.SetBkColor(clrBkOld); + dcSource.SelectBitmap(hBmpOld); + dcMask.SelectBitmap(hBmpOld1); + if(hBmpCheck == NULL) + bmp.DeleteObject(); + // draw pushed-in hilight + if(!m_bFlatMenus && !bDisabled) + { + if(rc.right - rc.left > size.cx) + ::InflateRect(&rcDest, 1,1); // inflate checkmark by one pixel all around + dc.DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT); + } + + return TRUE; + } + + void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) + { + _MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData; + + if(pmd->fType & MFT_SEPARATOR) // separator - use half system height and zero width + { + lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU) / 2; + lpMeasureItemStruct->itemWidth = 0; + } + else + { + // compute size of text - use DrawText with DT_CALCRECT + CWindowDC dc(NULL); + CFont fontBold; + HFONT hOldFont = NULL; + if(pmd->fState & MFS_DEFAULT) + { + // need bold version of font + LOGFONT lf = { 0 }; + m_fontMenu.GetLogFont(lf); + lf.lfWeight += 200; + fontBold.CreateFontIndirect(&lf); + ATLASSERT(fontBold.m_hFont != NULL); + hOldFont = dc.SelectFont(fontBold); + } + else + { + hOldFont = dc.SelectFont(m_fontMenu); + } + + RECT rcText = { 0 }; + dc.DrawText(pmd->lpstrText, -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT); + int cx = rcText.right - rcText.left; + dc.SelectFont(hOldFont); + + LOGFONT lf = { 0 }; + m_fontMenu.GetLogFont(lf); + int cy = lf.lfHeight; + if(cy < 0) + cy = -cy; + const int cyMargin = 8; + cy += cyMargin; + + // height of item is the bigger of these two + lpMeasureItemStruct->itemHeight = __max(cy, (int)m_szButton.cy); + + // width is width of text plus a bunch of stuff + cx += 2 * s_kcxTextMargin; // L/R margin for readability + cx += s_kcxGap; // space between button and menu text + cx += 2 * m_szButton.cx; // button width (L=button; R=empty margin) + cx += m_cxExtraSpacing; // extra between item text and accelerator keys + + // Windows adds 1 to returned value + cx -= ::GetSystemMetrics(SM_CXMENUCHECK) - 1; + lpMeasureItemStruct->itemWidth = cx; // done deal + } + } + +// Implementation - Hook procs + static LRESULT CALLBACK CreateHookProc(int nCode, WPARAM wParam, LPARAM lParam) + { + const int cchClassName = 7; + TCHAR szClassName[cchClassName] = { 0 }; + + if(nCode == HCBT_CREATEWND) + { + HWND hWndMenu = (HWND)wParam; +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - HCBT_CREATEWND (HWND = %8.8X)\n"), hWndMenu); +#endif + + ::GetClassName(hWndMenu, szClassName, cchClassName); + if(!lstrcmp(_T("#32768"), szClassName)) + s_pCurrentBar->m_stackMenuWnd.Push(hWndMenu); + } + else if(nCode == HCBT_DESTROYWND) + { + HWND hWndMenu = (HWND)wParam; +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - HCBT_DESTROYWND (HWND = %8.8X)\n"), hWndMenu); +#endif + + ::GetClassName(hWndMenu, szClassName, cchClassName); + if(!lstrcmp(_T("#32768"), szClassName)) + { + ATLASSERT(hWndMenu == s_pCurrentBar->m_stackMenuWnd.GetCurrent()); + s_pCurrentBar->m_stackMenuWnd.Pop(); + } + } + + return ::CallNextHookEx(s_hCreateHook, nCode, wParam, lParam); + } + + static LRESULT CALLBACK MessageHookProc(int nCode, WPARAM wParam, LPARAM lParam) + { + LPMSG pMsg = (LPMSG)lParam; + + if(nCode == HC_ACTION && wParam == PM_REMOVE && pMsg->message != GetGetBarMessage() && pMsg->message != WM_FORWARDMSG) + { + CCommandBarCtrlBase* pCmdBar = NULL; + HWND hWnd = pMsg->hwnd; + DWORD dwPID = 0; + while(pCmdBar == NULL && hWnd != NULL) + { + pCmdBar = (CCommandBarCtrlBase*)::SendMessage(hWnd, GetGetBarMessage(), (WPARAM)&dwPID, 0L); + hWnd = ::GetParent(hWnd); + } + + if(pCmdBar != NULL && dwPID == GetCurrentProcessId()) + { + pCmdBar->m_hWndHook = pMsg->hwnd; + ATLASSERT(pCmdBar->IsCommandBarBase()); + + if(::IsWindow(pCmdBar->m_hWnd)) + pCmdBar->SendMessage(WM_FORWARDMSG, 0, (LPARAM)pMsg); + else + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook skipping message, can't find command bar!\n")); + } + } + + LRESULT lRet = 0; + ATLASSERT(s_pmapMsgHook != NULL); + if(s_pmapMsgHook != NULL) + { + DWORD dwThreadID = ::GetCurrentThreadId(); + _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID); + if(pData != NULL) + { + lRet = ::CallNextHookEx(pData->hMsgHook, nCode, wParam, lParam); + } + } + return lRet; + } + +// Implementation + void DoPopupMenu(int nIndex, bool bAnimate) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - DoPopupMenu, bAnimate = %s\n"), bAnimate ? "true" : "false"); +#endif + + // Menu animation flags +#ifndef TPM_VERPOSANIMATION + const UINT TPM_VERPOSANIMATION = 0x1000L; +#endif +#ifndef TPM_NOANIMATION + const UINT TPM_NOANIMATION = 0x4000L; +#endif + T* pT = static_cast(this); + + // get popup menu and it's position + RECT rect = { 0 }; + GetItemRect(nIndex, &rect); + POINT pt = { rect.left, rect.bottom }; + MapWindowPoints(NULL, &pt, 1); + MapWindowPoints(NULL, &rect); + TPMPARAMS TPMParams = { 0 }; + TPMParams.cbSize = sizeof(TPMPARAMS); + TPMParams.rcExclude = rect; + HMENU hMenuPopup = ::GetSubMenu(m_hMenu, nIndex); + ATLASSERT(hMenuPopup != NULL); + + // get button ID + TBBUTTON tbb = { 0 }; + GetButton(nIndex, &tbb); + int nCmdID = tbb.idCommand; + + m_nPopBtn = nIndex; // remember current button's index + + // press button and display popup menu + PressButton(nCmdID, TRUE); + SetHotItem(nCmdID); + pT->DoTrackPopupMenu(hMenuPopup, TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | + (s_bW2K ? (bAnimate ? TPM_VERPOSANIMATION : TPM_NOANIMATION) : 0), pt.x, pt.y, &TPMParams); + PressButton(nCmdID, FALSE); + if(::GetFocus() != m_hWnd) + SetHotItem(-1); + + m_nPopBtn = -1; // restore + + // eat next message if click is on the same button + MSG msg = { 0 }; + if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rect, msg.pt)) + ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE); + + // check if another popup menu should be displayed + if(m_nNextPopBtn != -1) + { + PostMessage(GetAutoPopupMessage(), m_nNextPopBtn & 0xFFFF); + if(!(m_nNextPopBtn & 0xFFFF0000) && !m_bPopupItem) + PostMessage(WM_KEYDOWN, VK_DOWN, 0); + m_nNextPopBtn = -1; + } + else + { + m_bContextMenu = false; + // If user didn't hit escape, give focus back + if(!m_bEscapePressed) + { + if(m_bUseKeyboardCues && m_bShowKeyboardCues) + m_bAllowKeyboardCues = false; + pT->GiveFocusBack(); + } + else + { + SetHotItem(nCmdID); + SetAnchorHighlight(TRUE); + } + } + } + + BOOL DoTrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL) + { + CMenuHandle menuPopup = hMenu; + + CWindowCreateCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::DoTrackPopupMenu.\n")); + ATLASSERT(FALSE); + return FALSE; + } + + ATLASSERT(s_hCreateHook == NULL); + + s_pCurrentBar = static_cast(this); + + s_hCreateHook = ::SetWindowsHookEx(WH_CBT, CreateHookProc, ModuleHelper::GetModuleInstance(), GetCurrentThreadId()); + ATLASSERT(s_hCreateHook != NULL); + + m_bPopupItem = false; + m_bMenuActive = true; + + BOOL bTrackRet = menuPopup.TrackPopupMenuEx(uFlags, x, y, m_hWnd, lpParams); + m_bMenuActive = false; + + ::UnhookWindowsHookEx(s_hCreateHook); + + s_hCreateHook = NULL; + s_pCurrentBar = NULL; + + lock.Unlock(); + + // cleanup - convert menus back to original state +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - TrackPopupMenu - cleanup\n")); +#endif + + ATLASSERT(m_stackMenuWnd.GetSize() == 0); + + UpdateWindow(); + ATL::CWindow wndTL = GetTopLevelParent(); + wndTL.UpdateWindow(); + + // restore the menu items to the previous state for all menus that were converted + if(m_bImagesVisible) + { + HMENU hMenuSav = NULL; + while((hMenuSav = m_stackMenuHandle.Pop()) != NULL) + { + menuPopup = hMenuSav; + BOOL bRet = FALSE; + // restore state and delete menu item data + for(int i = 0; i < menuPopup.GetMenuItemCount(); i++) + { + CMenuItemInfo mii; + mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID; + bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + + _MenuItemData* pMI = (_MenuItemData*)mii.dwItemData; + if(pMI != NULL && pMI->IsCmdBarMenuItem()) + { + mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE; + mii.fType = pMI->fType; + mii.fState = pMI->fState; + mii.dwTypeData = pMI->lpstrText; + mii.cch = lstrlen(pMI->lpstrText); + mii.dwItemData = NULL; + + bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii); + // this one triggers WM_MEASUREITEM + menuPopup.ModifyMenu(i, MF_BYPOSITION | mii.fType | mii.fState, mii.wID, pMI->lpstrText); + ATLASSERT(bRet); + + delete [] pMI->lpstrText; + delete pMI; + } + } + } + } + return bTrackRet; + } + + int GetPreviousMenuItem(int nBtn) const + { + if(nBtn == -1) + return -1; +#if (_WIN32_IE >= 0x0500) + RECT rcClient = { 0 }; + GetClientRect(&rcClient); +#endif // (_WIN32_IE >= 0x0500) + int nNextBtn; + for(nNextBtn = nBtn - 1; nNextBtn != nBtn; nNextBtn--) + { + if(nNextBtn < 0) + nNextBtn = ::GetMenuItemCount(m_hMenu) - 1; + TBBUTTON tbb = { 0 }; + GetButton(nNextBtn, &tbb); +#if (_WIN32_IE >= 0x0500) + RECT rcBtn = { 0 }; + GetItemRect(nNextBtn, &rcBtn); + if(rcBtn.right > rcClient.right) + { + nNextBtn = -2; // chevron + break; + } +#endif // (_WIN32_IE >= 0x0500) + if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0) + break; + } + return (nNextBtn != nBtn) ? nNextBtn : -1; + } + + int GetNextMenuItem(int nBtn) const + { + if(nBtn == -1) + return -1; +#if (_WIN32_IE >= 0x0500) + RECT rcClient = { 0 }; + GetClientRect(&rcClient); +#endif // (_WIN32_IE >= 0x0500) + int nNextBtn = 0; + int nCount = ::GetMenuItemCount(m_hMenu); + for(nNextBtn = nBtn + 1; nNextBtn != nBtn; nNextBtn++) + { + if(nNextBtn >= nCount) + nNextBtn = 0; + TBBUTTON tbb = { 0 }; + GetButton(nNextBtn, &tbb); +#if (_WIN32_IE >= 0x0500) + RECT rcBtn = { 0 }; + GetItemRect(nNextBtn, &rcBtn); + if(rcBtn.right > rcClient.right) + { + nNextBtn = -2; // chevron + break; + } +#endif // (_WIN32_IE >= 0x0500) + if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0) + break; + } + return (nNextBtn != nBtn) ? nNextBtn : -1; + } + +#if (_WIN32_IE >= 0x0500) + bool DisplayChevronMenu() + { + // assume we are in a rebar + HWND hWndReBar = GetParent(); + int nCount = (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L); + bool bRet = false; + for(int i = 0; i < nCount; i++) + { + REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_STYLE }; + BOOL bRetBandInfo = (BOOL)::SendMessage(hWndReBar, RB_GETBANDINFO, i, (LPARAM)&rbbi); + if(bRetBandInfo && rbbi.hwndChild == m_hWnd) + { + if((rbbi.fStyle & RBBS_USECHEVRON) != 0) + { + ::PostMessage(hWndReBar, RB_PUSHCHEVRON, i, 0L); + PostMessage(WM_KEYDOWN, VK_DOWN, 0L); + bRet = true; + } + break; + } + } + return bRet; + } +#endif // (_WIN32_IE >= 0x0500) + + void GetSystemSettings() + { + // refresh our font + NONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; + BOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0); + ATLASSERT(bRet); + if(bRet) + { + LOGFONT logfont = { 0 }; + if(m_fontMenu.m_hFont != NULL) + m_fontMenu.GetLogFont(logfont); + if(logfont.lfHeight != info.lfMenuFont.lfHeight || + logfont.lfWidth != info.lfMenuFont.lfWidth || + logfont.lfEscapement != info.lfMenuFont.lfEscapement || + logfont.lfOrientation != info.lfMenuFont.lfOrientation || + logfont.lfWeight != info.lfMenuFont.lfWeight || + logfont.lfItalic != info.lfMenuFont.lfItalic || + logfont.lfUnderline != info.lfMenuFont.lfUnderline || + logfont.lfStrikeOut != info.lfMenuFont.lfStrikeOut || + logfont.lfCharSet != info.lfMenuFont.lfCharSet || + logfont.lfOutPrecision != info.lfMenuFont.lfOutPrecision || + logfont.lfClipPrecision != info.lfMenuFont.lfClipPrecision || + logfont.lfQuality != info.lfMenuFont.lfQuality || + logfont.lfPitchAndFamily != info.lfMenuFont.lfPitchAndFamily || + lstrcmp(logfont.lfFaceName, info.lfMenuFont.lfFaceName) != 0) + { + HFONT hFontMenu = ::CreateFontIndirect(&info.lfMenuFont); + ATLASSERT(hFontMenu != NULL); + if(hFontMenu != NULL) + { + if(m_fontMenu.m_hFont != NULL) + m_fontMenu.DeleteObject(); + m_fontMenu.Attach(hFontMenu); + SetFont(m_fontMenu); + AddStrings(_T("NS\0")); // for proper item height + AutoSize(); + } + } + } + + // check if we need extra spacing for menu item text + CWindowDC dc(m_hWnd); + HFONT hFontOld = dc.SelectFont(m_fontMenu); + RECT rcText = { 0 }; + dc.DrawText(_T("\t"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT); + if((rcText.right - rcText.left) < 4) + { + ::SetRectEmpty(&rcText); + dc.DrawText(_T("x"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT); + m_cxExtraSpacing = rcText.right - rcText.left; + } + else + { + m_cxExtraSpacing = 0; + } + dc.SelectFont(hFontOld); + + // get Windows version +#ifndef _versionhelpers_H_INCLUDED_ + OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; + ::GetVersionEx(&ovi); +#endif // !_versionhelpers_H_INCLUDED_ + + // query keyboard cues mode (Windows 2000 or later) +#ifdef _versionhelpers_H_INCLUDED_ + if(::IsWindowsVersionOrGreater(5, 0, 0)) +#else // !_versionhelpers_H_INCLUDED_ + if (ovi.dwMajorVersion >= 5) +#endif // _versionhelpers_H_INCLUDED_ + { +#ifndef SPI_GETKEYBOARDCUES + const UINT SPI_GETKEYBOARDCUES = 0x100A; +#endif // !SPI_GETKEYBOARDCUES + BOOL bRetVal = TRUE; + bRet = ::SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &bRetVal, 0); + m_bUseKeyboardCues = (bRet && !bRetVal); + m_bAllowKeyboardCues = true; + ShowKeyboardCues(!m_bUseKeyboardCues); + } + + // query flat menu mode (Windows XP or later) +#ifdef _versionhelpers_H_INCLUDED_ + if(::IsWindowsXPOrGreater()) +#else // !_versionhelpers_H_INCLUDED_ + if ((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5)) +#endif // _versionhelpers_H_INCLUDED_ + { +#ifndef SPI_GETFLATMENU + const UINT SPI_GETFLATMENU = 0x1022; +#endif // !SPI_GETFLATMENU + BOOL bRetVal = FALSE; + bRet = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &bRetVal, 0); + m_bFlatMenus = (bRet && bRetVal); + } + +#if _WTL_CMDBAR_VISTA_MENUS + // check if we should use Vista menus + bool bVistaMenus = (((m_dwExtendedStyle & CBR_EX_NOVISTAMENUS) == 0) && RunTimeHelper::IsVista() && RunTimeHelper::IsThemeAvailable()); + if(!bVistaMenus && m_bVistaMenus && (m_hMenu != NULL) && (m_arrCommand.GetSize() > 0)) + { + T* pT = static_cast(this); + pT->_RemoveVistaBitmapsFromMenu(); + } + + m_bVistaMenus = bVistaMenus; +#endif // _WTL_CMDBAR_VISTA_MENUS + +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - GetSystemSettings:\n m_bFlatMenus = %s\n m_bUseKeyboardCues = %s m_bVistaMenus = %s\n"), + m_bFlatMenus ? "true" : "false", m_bUseKeyboardCues ? "true" : "false", m_bVistaMenus ? "true" : "false"); +#endif + } + +// Implementation - alternate focus mode support + void TakeFocus() + { + if((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_hWndFocus == NULL) + m_hWndFocus = ::GetFocus(); + SetFocus(); + } + + void GiveFocusBack() + { + if(m_bParentActive) + { + if((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && ::IsWindow(m_hWndFocus)) + ::SetFocus(m_hWndFocus); + else if(!(m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_wndParent.IsWindow()) + m_wndParent.SetFocus(); + } + m_hWndFocus = NULL; + SetAnchorHighlight(FALSE); + if(m_bUseKeyboardCues && m_bShowKeyboardCues) + ShowKeyboardCues(false); + m_bSkipPostDown = false; + } + + void ShowKeyboardCues(bool bShow) + { + m_bShowKeyboardCues = bShow; + SetDrawTextFlags(DT_HIDEPREFIX, m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX); + Invalidate(); + UpdateWindow(); + } + +// Implementation - internal message helpers + static UINT GetAutoPopupMessage() + { + static UINT uAutoPopupMessage = 0; + if(uAutoPopupMessage == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetAutoPopupMessage.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uAutoPopupMessage == 0) + uAutoPopupMessage = ::RegisterWindowMessage(_T("WTL_CmdBar_InternalAutoPopupMsg")); + + lock.Unlock(); + } + ATLASSERT(uAutoPopupMessage != 0); + return uAutoPopupMessage; + } + + static UINT GetGetBarMessage() + { + static UINT uGetBarMessage = 0; + if(uGetBarMessage == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetGetBarMessage.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uGetBarMessage == 0) + uGetBarMessage = ::RegisterWindowMessage(_T("WTL_CmdBar_InternalGetBarMsg")); + + lock.Unlock(); + } + ATLASSERT(uGetBarMessage != 0); + return uGetBarMessage; + } + +// Implementation + bool CreateInternalImageList(int cImages) + { + UINT uFlags = (m_bAlphaImages ? ILC_COLOR32 : ILC_COLOR24) | ILC_MASK; + m_hImageList = ::ImageList_Create(m_szBitmap.cx, m_szBitmap.cy, uFlags, cImages, 1); + ATLASSERT(m_hImageList != NULL); + return (m_hImageList != NULL); + } + +// Implementation - support for Vista menus +#if _WTL_CMDBAR_VISTA_MENUS + void _AddVistaBitmapsFromImageList(int nStartIndex, int nCount) + { + // Create display compatible memory DC + CClientDC dc(NULL); + CDC dcMem; + dcMem.CreateCompatibleDC(dc); + HBITMAP hBitmapSave = dcMem.GetCurrentBitmap(); + + T* pT = static_cast(this); + // Create bitmaps for all menu items + for(int i = 0; i < nCount; i++) + { + HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nStartIndex + i, dc, dcMem); + dcMem.SelectBitmap(hBitmapSave); + m_arrVistaBitmap.Add(hBitmap); + } + } + + void _AddVistaBitmapFromImageList(int nIndex) + { + // Create display compatible memory DC + CClientDC dc(NULL); + CDC dcMem; + dcMem.CreateCompatibleDC(dc); + HBITMAP hBitmapSave = dcMem.GetCurrentBitmap(); + + // Create bitmap for menu item + T* pT = static_cast(this); + HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, dc, dcMem); + + // Select saved bitmap back and add bitmap to the array + dcMem.SelectBitmap(hBitmapSave); + m_arrVistaBitmap.Add(hBitmap); + } + + void _ReplaceVistaBitmapFromImageList(int nIndex) + { + // Delete existing bitmap + if(m_arrVistaBitmap[nIndex] != NULL) + ::DeleteObject(m_arrVistaBitmap[nIndex]); + + // Create display compatible memory DC + CClientDC dc(NULL); + CDC dcMem; + dcMem.CreateCompatibleDC(dc); + HBITMAP hBitmapSave = dcMem.GetCurrentBitmap(); + + // Create bitmap for menu item + T* pT = static_cast(this); + HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, dc, dcMem); + + // Select saved bitmap back and replace bitmap in the array + dcMem.SelectBitmap(hBitmapSave); + m_arrVistaBitmap.SetAtIndex(nIndex, hBitmap); + } + + HBITMAP _CreateVistaBitmapHelper(int nIndex, HDC hDCSource, HDC hDCTarget) + { + // Create 32-bit bitmap + BITMAPINFO bi = { 0 }; + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = m_szBitmap.cx; + bi.bmiHeader.biHeight = m_szBitmap.cy; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = BI_RGB; + bi.bmiHeader.biSizeImage = 0; + bi.bmiHeader.biXPelsPerMeter = 0; + bi.bmiHeader.biYPelsPerMeter = 0; + bi.bmiHeader.biClrUsed = 0; + bi.bmiHeader.biClrImportant = 0; + HBITMAP hBitmap = ::CreateDIBSection(hDCSource, &bi, DIB_RGB_COLORS, NULL, NULL, 0); + ATLASSERT(hBitmap != NULL); + + // Select bitmap into target DC and draw from image list to it + if(hBitmap != NULL) + { + ::SelectObject(hDCTarget, hBitmap); + + IMAGELISTDRAWPARAMS ildp = { 0 }; + ildp.cbSize = sizeof(IMAGELISTDRAWPARAMS); + ildp.himl = m_hImageList; + ildp.i = nIndex; + ildp.hdcDst = hDCTarget; + ildp.x = 0; + ildp.y = 0; + ildp.cx = 0; + ildp.cy = 0; + ildp.xBitmap = 0; + ildp.yBitmap = 0; + ildp.fStyle = ILD_TRANSPARENT; + ildp.fState = ILS_ALPHA; + ildp.Frame = 255; + ::ImageList_DrawIndirect(&ildp); + } + + return hBitmap; + } + + void _RemoveVistaBitmapsFromMenu() + { + CMenuHandle menu = m_hMenu; + for(int i = 0; i < m_arrCommand.GetSize(); i++) + { + CMenuItemInfo mii; + mii.fMask = MIIM_BITMAP; + mii.hbmpItem = NULL; + menu.SetMenuItemInfo(m_arrCommand[i], FALSE, &mii); + } + } +#endif // _WTL_CMDBAR_VISTA_MENUS +}; + + +class CCommandBarCtrl : public CCommandBarCtrlImpl +{ +public: + DECLARE_WND_SUPERCLASS(_T("WTL_CommandBar"), GetWndClassName()) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CMDICommandBarCtrl - ATL implementation of Command Bars for MDI apps + +template +class ATL_NO_VTABLE CMDICommandBarCtrlImpl : public CCommandBarCtrlImpl< T, TBase, TWinTraits> +{ +public: +// Data members + ATL::CContainedWindow m_wndMDIClient; + bool m_bChildMaximized; + HWND m_hWndChildMaximized; + HICON m_hIconChildMaximized; + int m_nBtnPressed; + int m_nBtnWasPressed; + + int m_cxyOffset; // offset between nonclient elements + int m_cxIconWidth; // small icon width + int m_cyIconHeight; // small icon height + int m_cxBtnWidth; // nonclient button width + int m_cyBtnHeight; // nonclient button height + int m_cxLeft; // left nonclient area width + int m_cxRight; // right nonclient area width + +// Theme declarations and data members +#ifndef _WTL_NO_AUTO_THEME +#ifndef _UXTHEME_H_ + typedef HANDLE HTHEME; +#endif // !_UXTHEME_H_ + typedef HTHEME (STDAPICALLTYPE *PFN_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList); + typedef HRESULT (STDAPICALLTYPE *PFN_CloseThemeData)(HTHEME hTheme); + typedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect); + typedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeParentBackground)(HWND hwnd, HDC hdc, OPTIONAL RECT* prc); + + HMODULE m_hThemeDLL; + HTHEME m_hTheme; + PFN_DrawThemeBackground m_pfnDrawThemeBackground; + PFN_DrawThemeParentBackground m_pfnDrawThemeParentBackground; +#endif // !_WTL_NO_AUTO_THEME + +// Constructor/destructor + CMDICommandBarCtrlImpl() : + m_wndMDIClient(this, 2), m_bChildMaximized(false), + m_hWndChildMaximized(NULL), m_hIconChildMaximized(NULL), + m_nBtnPressed(-1), m_nBtnWasPressed(-1), +#ifndef _WTL_NO_AUTO_THEME + m_hThemeDLL(NULL), m_hTheme(NULL), m_pfnDrawThemeBackground(NULL), m_pfnDrawThemeParentBackground(NULL), +#endif // !_WTL_NO_AUTO_THEME + m_cxyOffset(2), + m_cxIconWidth(16), m_cyIconHeight(16), + m_cxBtnWidth(16), m_cyBtnHeight(14), + m_cxLeft(20), m_cxRight(55) + { } + + ~CMDICommandBarCtrlImpl() + { + if(m_wndMDIClient.IsWindow()) +/*scary!*/ m_wndMDIClient.UnsubclassWindow(); + } + +// Operations + BOOL SetMDIClient(HWND hWndMDIClient) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(::IsWindow(hWndMDIClient)); + if(!::IsWindow(hWndMDIClient)) + return FALSE; + +#ifdef _DEBUG + // BLOCK: Test if the passed window is MDICLIENT + { + LPCTSTR lpszMDIClientClass = _T("MDICLIENT"); + const int nNameLen = 9 + 1; // "MDICLIENT" + NULL + TCHAR szClassName[nNameLen] = { 0 }; + ::GetClassName(hWndMDIClient, szClassName, nNameLen); + ATLASSERT(lstrcmpi(szClassName, lpszMDIClientClass) == 0); + } +#endif // _DEBUG + + if(m_wndMDIClient.IsWindow()) +/*scary!*/ m_wndMDIClient.UnsubclassWindow(); + + return m_wndMDIClient.SubclassWindow(hWndMDIClient); + } + +// Message maps + typedef CCommandBarCtrlImpl< T, TBase, TWinTraits > _baseClass; + BEGIN_MSG_MAP(CMDICommandBarCtrlImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) +#ifndef _WTL_NO_AUTO_THEME + MESSAGE_HANDLER(_GetThemeChangedMsg(), OnThemeChanged) +#endif // !_WTL_NO_AUTO_THEME + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize) + MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint) + MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) + MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDown) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) + MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClk) + MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) + CHAIN_MSG_MAP(_baseClass) + ALT_MSG_MAP(1) // Parent window messages + MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate) + CHAIN_MSG_MAP_ALT(_baseClass, 1) + ALT_MSG_MAP(2) // MDI client window messages + MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu) + // no chaining needed since this was moved from the base class here + ALT_MSG_MAP(3) // Message hook messages + MESSAGE_RANGE_HANDLER(0, 0xFFFF, OnAllHookMessages) + CHAIN_MSG_MAP_ALT(_baseClass, 3) + END_MSG_MAP() + +// Additional MDI message handlers + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT lRet = _baseClass::OnCreate(uMsg, wParam, lParam, bHandled); + if(lRet == (LRESULT)-1) + return lRet; + +#ifndef _WTL_NO_AUTO_THEME + // this will fail if theming is not supported + m_hThemeDLL = ::LoadLibrary(_T("uxtheme.dll")); + if(m_hThemeDLL != NULL) + { + m_pfnDrawThemeBackground = (PFN_DrawThemeBackground)::GetProcAddress(m_hThemeDLL, "DrawThemeBackground"); + ATLASSERT(m_pfnDrawThemeBackground != NULL); + if(m_pfnDrawThemeBackground != NULL) + { + T* pT = static_cast(this); + pT->_OpenThemeData(); + } + else + { + ::FreeLibrary(m_hThemeDLL); + m_hThemeDLL = NULL; + } + m_pfnDrawThemeParentBackground = (PFN_DrawThemeParentBackground)::GetProcAddress(m_hThemeDLL, "DrawThemeParentBackground"); + ATLASSERT(m_pfnDrawThemeParentBackground != NULL); + } +#endif // !_WTL_NO_AUTO_THEME + + return lRet; + } + + LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT lRet = _baseClass::OnDestroy(uMsg, wParam, lParam, bHandled); + +#ifndef _WTL_NO_AUTO_THEME + if(m_hThemeDLL != NULL) + { + T* pT = static_cast(this); + pT->_CloseThemeData(); + ::FreeLibrary(m_hThemeDLL); + m_hThemeDLL = NULL; + } +#endif // !_WTL_NO_AUTO_THEME + + return lRet; + } + +#ifndef _WTL_NO_AUTO_THEME + LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(m_hThemeDLL != NULL) + { + T* pT = static_cast(this); + pT->_CloseThemeData(); + pT->_OpenThemeData(); + } + return 0; + } +#endif // !_WTL_NO_AUTO_THEME + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + T* pT = static_cast(this); + pT->_AdjustBtnSize(GET_Y_LPARAM(lParam)); + return lRet; + } + + LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + + if(m_bChildMaximized && (BOOL)wParam) + { + LPNCCALCSIZE_PARAMS lpParams = (LPNCCALCSIZE_PARAMS)lParam; + if(m_bLayoutRTL) + { + lpParams->rgrc[0].left += m_cxRight; + lpParams->rgrc[0].right -= m_cxLeft; + } + else + { + lpParams->rgrc[0].left += m_cxLeft; + lpParams->rgrc[0].right -= m_cxRight; + } + } + + return lRet; + } + + LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + + if(!m_bChildMaximized) + return lRet; + + ATLASSERT(m_hWndChildMaximized != NULL && m_hIconChildMaximized != NULL); + + // get DC and window rectangle + CWindowDC dc(m_hWnd); + RECT rect = { 0 }; + GetWindowRect(&rect); + int cxWidth = rect.right - rect.left; + int cyHeight = rect.bottom - rect.top; + + // paint left side nonclient background and draw icon + ::SetRect(&rect, 0, 0, m_cxLeft, cyHeight); +#ifndef _WTL_NO_AUTO_THEME + if(m_hTheme != NULL) + { + if(m_pfnDrawThemeParentBackground != NULL) + m_pfnDrawThemeParentBackground(m_hWnd, dc, &rect); + else + dc.FillRect(&rect, COLOR_WINDOW); + } + else +#endif // !_WTL_NO_AUTO_THEME + { + if((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0) + dc.FillRect(&rect, COLOR_3DFACE); + else + dc.FillRect(&rect, COLOR_MENU); + } + + RECT rcIcon = { 0 }; + T* pT = static_cast(this); + pT->_CalcIconRect(cxWidth, cyHeight, rcIcon); + dc.DrawIconEx(rcIcon.left, rcIcon.top, m_hIconChildMaximized, m_cxIconWidth, m_cyIconHeight); + + // paint right side nonclient background + ::SetRect(&rect, cxWidth - m_cxRight, 0, cxWidth, cyHeight); +#ifndef _WTL_NO_AUTO_THEME + if(m_hTheme != NULL) + { + if(m_pfnDrawThemeParentBackground != NULL) + { + // this is to account for the left non-client area + POINT ptOrg = { 0, 0 }; + dc.GetViewportOrg(&ptOrg); + dc.SetViewportOrg(ptOrg.x + m_cxLeft, ptOrg.y); + ::OffsetRect(&rect, -m_cxLeft, 0); + + m_pfnDrawThemeParentBackground(m_hWnd, dc, &rect); + + // restore + dc.SetViewportOrg(ptOrg); + ::OffsetRect(&rect, m_cxLeft, 0); + } + else + { + dc.FillRect(&rect, COLOR_3DFACE); + } + } + else +#endif // !_WTL_NO_AUTO_THEME + { + if((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0) + dc.FillRect(&rect, COLOR_3DFACE); + else + dc.FillRect(&rect, COLOR_MENU); + } + + // draw buttons + RECT arrRect[3] = { 0 }; + pT->_CalcBtnRects(cxWidth, cyHeight, arrRect); + pT->_DrawMDIButton(dc, arrRect, -1); // draw all buttons + + return lRet; + } + + LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + if(m_bChildMaximized) + { + RECT rect = { 0 }; + GetWindowRect(&rect); + POINT pt = { GET_X_LPARAM(lParam) - rect.left, GET_Y_LPARAM(lParam) - rect.top }; + if(m_bLayoutRTL) + { + if((pt.x < m_cxRight) || (pt.x > ((rect.right - rect.left) - m_cxLeft))) + lRet = HTBORDER; + } + else + { + if((pt.x < m_cxLeft) || (pt.x > ((rect.right - rect.left) - m_cxRight))) + lRet = HTBORDER; + } + } + return lRet; + } + + LRESULT OnNcLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(!m_bChildMaximized) + { + bHandled = FALSE; + return 1; + } + + ATLASSERT(_DebugCheckChild()); + + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + RECT rect = { 0 }; + GetWindowRect(&rect); + pt.x -= rect.left; + pt.y -= rect.top; + + RECT rcIcon = { 0 }; + T* pT = static_cast(this); + pT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL); + RECT arrRect[3] = { 0 }; + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL); + + if(::PtInRect(&rcIcon, pt)) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: icon\n")); +#endif +#ifndef TPM_VERPOSANIMATION + const UINT TPM_VERPOSANIMATION = 0x1000L; // Menu animation flag +#endif + CMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE); + UINT uRet = (UINT)menu.TrackPopupMenu(TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | + (s_bW2K ? TPM_VERPOSANIMATION : 0), m_bLayoutRTL ? rect.right : rect.left, rect.bottom, m_hWndChildMaximized); + + // eat next message if click is on the same button + ::OffsetRect(&rcIcon, rect.left, rect.top); + MSG msg = { 0 }; + if(::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rcIcon, msg.pt)) + ::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_REMOVE); + + if(uRet != 0) + ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uRet, 0L); + } + else if(::PtInRect(&arrRect[0], pt)) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: close button\n")); +#endif + m_nBtnWasPressed = m_nBtnPressed = 0; + } + else if(::PtInRect(&arrRect[1], pt)) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: restore button\n")); +#endif + m_nBtnWasPressed = m_nBtnPressed = 1; + } + else if(::PtInRect(&arrRect[2], pt)) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: minimize button\n")); +#endif + m_nBtnWasPressed = m_nBtnPressed = 2; + } + else + { + bHandled = FALSE; + } + + // draw the button state if it was pressed + if(m_nBtnPressed != -1) + { + SetCapture(); + CWindowDC dc(m_hWnd); + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect); + pT->_DrawMDIButton(dc, arrRect, m_nBtnPressed); + } + + return 0; + } + + LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1) + { + bHandled = FALSE; + return 1; + } + + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + ClientToScreen(&pt); + RECT rect = { 0 }; + GetWindowRect(&rect); + pt.x -= rect.left; + pt.y -= rect.top; + RECT arrRect[3] = { 0 }; + T* pT = static_cast(this); + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL); + int nOldBtnPressed = m_nBtnPressed; + m_nBtnPressed = ::PtInRect(&arrRect[m_nBtnWasPressed], pt) ? m_nBtnWasPressed : -1; + if(nOldBtnPressed != m_nBtnPressed) + { + CWindowDC dc(m_hWnd); + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect); + pT->_DrawMDIButton(dc, arrRect, (m_nBtnPressed != -1) ? m_nBtnPressed : nOldBtnPressed); + } + + return 0; + } + + LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1) + { + bHandled = FALSE; + return 1; + } + + ATLASSERT(_DebugCheckChild()); + + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + ClientToScreen(&pt); + RECT rect = { 0 }; + GetWindowRect(&rect); + pt.x -= rect.left; + pt.y -= rect.top; + + int nBtn = m_nBtnWasPressed; + ReleaseCapture(); + + RECT arrRect[3] = { 0 }; + T* pT = static_cast(this); + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL); + if(::PtInRect(&arrRect[nBtn], pt)) + { + switch(nBtn) + { + case 0: // close +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: close button\n")); +#endif + ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_CLOSE, 0L); + break; + case 1: // restore +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: restore button\n")); +#endif + ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_RESTORE, 0L); + break; + case 2: // minimize +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: minimize button\n")); +#endif + ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_MINIMIZE, 0L); + break; + default: + break; + } + } + + return 0; + } + + LRESULT OnNcLButtonDblClk(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(!m_bChildMaximized || m_nBtnWasPressed != -1) + { + bHandled = FALSE; + return 1; + } + + ATLASSERT(_DebugCheckChild()); + + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + RECT rect = { 0 }; + GetWindowRect(&rect); + pt.x -= rect.left; + pt.y -= rect.top; + + RECT rcIcon = { 0 }; + T* pT = static_cast(this); + pT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL); + RECT arrRect[3] = { 0 }; + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL); + + if(::PtInRect(&rcIcon, pt)) + { + CMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE); + UINT uDefID = menu.GetMenuDefaultItem(); + if(uDefID == (UINT)-1) + uDefID = SC_CLOSE; + ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uDefID, 0L); + } + + return 0; + } + + LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_bChildMaximized) + { + if(m_nBtnPressed != -1) + { + ATLASSERT(m_nBtnPressed == m_nBtnWasPressed); // must be + m_nBtnPressed = -1; + RECT rect = { 0 }; + GetWindowRect(&rect); + RECT arrRect[3] = { 0 }; + T* pT = static_cast(this); + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect); + CWindowDC dc(m_hWnd); + pT->_DrawMDIButton(dc, arrRect, m_nBtnWasPressed); + } + m_nBtnWasPressed = -1; + } + else + { + bHandled = FALSE; + } + return 0; + } + +// Parent window message handlers + LRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + m_bParentActive = (LOWORD(wParam) != WA_INACTIVE); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW); + bHandled = FALSE; + return 1; + } + +// MDI client window message handlers + LRESULT OnMDISetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + m_wndMDIClient.DefWindowProc(uMsg, NULL, lParam); + HMENU hOldMenu = GetMenu(); + BOOL bRet = AttachMenu((HMENU)wParam); + bRet; // avoid level 4 warning + ATLASSERT(bRet); + +#if (_WIN32_IE >= 0x0400) + T* pT = static_cast(this); + pT->UpdateRebarBandIdealSize(); +#endif // (_WIN32_IE >= 0x0400) + + return (LRESULT)hOldMenu; + } + +// All messages from the message hook + LRESULT OnAllHookMessages(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->_ProcessAllHookMessages(uMsg, wParam, lParam); + + bHandled = FALSE; + return 1; + } + +// Overrideables + // override this to provide different ideal size + void UpdateRebarBandIdealSize() + { + // assuming we are in a rebar, change ideal size to our size + // we hope that if we are not in a rebar, nCount will be 0 + int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L); + for(int i = 0; i < nCount; i++) + { + REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE }; + ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi); + if(rbi.hwndChild == m_hWnd) + { + rbi.fMask = RBBIM_IDEALSIZE; + rbi.cxIdeal = m_bChildMaximized ? m_cxLeft + m_cxRight : 0; + int nBtnCount = GetButtonCount(); + if(nBtnCount > 0) + { + RECT rect = { 0 }; + GetItemRect(nBtnCount - 1, &rect); + rbi.cxIdeal += rect.right; + } + ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi); + break; + } + } + } + + // all hook messages - check for the maximized MDI child window change + void _ProcessAllHookMessages(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/) + { + if(uMsg == WM_MDIGETACTIVE || uMsg == WM_MDISETMENU) + return; + + BOOL bMaximized = FALSE; + HWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); + bool bMaxOld = m_bChildMaximized; + m_bChildMaximized = (hWndChild != NULL && bMaximized); + HICON hIconOld = m_hIconChildMaximized; + + if(m_bChildMaximized) + { + if(m_hWndChildMaximized != hWndChild) + { + ATL::CWindow wnd = m_hWndChildMaximized = hWndChild; + m_hIconChildMaximized = wnd.GetIcon(FALSE); + if(m_hIconChildMaximized == NULL) + { + m_hIconChildMaximized = wnd.GetIcon(TRUE); + if(m_hIconChildMaximized == NULL) + { + // no icon set with WM_SETICON, get the class one +// need conditional code because types don't match in winuser.h +#ifdef _WIN64 + m_hIconChildMaximized = (HICON)::GetClassLongPtr(wnd, GCLP_HICONSM); +#else + m_hIconChildMaximized = (HICON)LongToHandle(::GetClassLongPtr(wnd, GCLP_HICONSM)); +#endif + } + } + } + } + else + { + m_hWndChildMaximized = NULL; + m_hIconChildMaximized = NULL; + } + + if(bMaxOld != m_bChildMaximized) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - All messages hook change: m_bChildMaximized = %s\n"), m_bChildMaximized ? "true" : "false"); +#endif + // assuming we are in a rebar, change our size to accomodate new state + // we hope that if we are not in a rebar, nCount will be 0 + int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L); + int cxDiff = (m_bChildMaximized ? 1 : -1) * (m_cxLeft + m_cxRight); + for(int i = 0; i < nCount; i++) + { +#if (_WIN32_IE >= 0x0500) + REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_STYLE }; + ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi); + if(rbi.hwndChild == m_hWnd) + { + if((rbi.fStyle & RBBS_USECHEVRON) != 0) + { + rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE; + rbi.cxMinChild += cxDiff; + rbi.cxIdeal += cxDiff; + ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi); + } + break; + } +#elif (_WIN32_IE >= 0x0400) + REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE }; + ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi); + if(rbi.hwndChild == m_hWnd) + { + rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE; + rbi.cxMinChild += cxDiff; + rbi.cxIdeal += cxDiff; + ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi); + break; + } +#else // (_WIN32_IE < 0x0400) + REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE }; + ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi); + if(rbi.hwndChild == m_hWnd) + { + rbi.fMask = RBBIM_CHILDSIZE; + rbi.cxMinChild += cxDiff; + ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi); + break; + } +#endif // (_WIN32_IE < 0x0400) + } + } + + if(bMaxOld != m_bChildMaximized || hIconOld != m_hIconChildMaximized) + { + // force size change and redraw everything + RECT rect = { 0 }; + GetWindowRect(&rect); + ::MapWindowPoints(NULL, GetParent(), (LPPOINT)&rect, 2); + SetRedraw(FALSE); + SetWindowPos(NULL, 0, 0, 1, 1, SWP_NOZORDER | SWP_NOMOVE); + SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE); + SetRedraw(TRUE); + RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW); + } + } + +// Implementation + void GetSystemSettings() + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - GetSystemSettings\n")); +#endif + _baseClass::GetSystemSettings(); + + NONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; + BOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0); + ATLASSERT(bRet); + if(bRet) + { + m_cxIconWidth = ::GetSystemMetrics(SM_CXSMICON); + m_cyIconHeight = ::GetSystemMetrics(SM_CYSMICON); + m_cxLeft = m_cxIconWidth; + +#ifndef _WTL_NO_AUTO_THEME + if(m_hTheme != NULL) + { + m_cxBtnWidth = info.iCaptionWidth - 2 * m_cxyOffset; + m_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset; + m_cxRight = 3 * m_cxBtnWidth; + } + else +#endif // !_WTL_NO_AUTO_THEME + { + m_cxBtnWidth = info.iCaptionWidth - m_cxyOffset; + m_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset; + m_cxRight = 3 * m_cxBtnWidth + m_cxyOffset; + } + } + + RECT rect = { 0 }; + GetClientRect(&rect); + T* pT = static_cast(this); + pT->_AdjustBtnSize(rect.bottom); + } + + void _AdjustBtnSize(int cyHeight) + { + if(cyHeight > 1 && m_cyBtnHeight > cyHeight) + { +#ifndef _WTL_NO_AUTO_THEME + if(m_hTheme != NULL) + { + m_cyBtnHeight = cyHeight; + m_cxBtnWidth = cyHeight; + m_cxRight = 3 * m_cxBtnWidth; + } + else +#endif // !_WTL_NO_AUTO_THEME + { + m_cyBtnHeight = cyHeight; + m_cxBtnWidth = cyHeight + m_cxyOffset; + m_cxRight = 3 * m_cxBtnWidth + m_cxyOffset; + } + } + } + + void _CalcIconRect(int cxWidth, int cyHeight, RECT& rect, bool bInvertX = false) const + { + int xStart = (m_cxLeft - m_cxIconWidth) / 2; + if(xStart < 0) + xStart = 0; + int yStart = (cyHeight - m_cyIconHeight) / 2; + if(yStart < 0) + yStart = 0; + + if(bInvertX) + ::SetRect(&rect, cxWidth - (xStart + m_cxBtnWidth), yStart, cxWidth - xStart, yStart + m_cyBtnHeight); + else + ::SetRect(&rect, xStart, yStart, xStart + m_cxBtnWidth, yStart + m_cyBtnHeight); + } + + void _CalcBtnRects(int cxWidth, int cyHeight, RECT arrRect[3], bool bInvertX = false) const + { + int yStart = (cyHeight - m_cyBtnHeight) / 2; + if(yStart < 0) + yStart = 0; + + RECT rcBtn = { cxWidth - m_cxBtnWidth, yStart, cxWidth, yStart + m_cyBtnHeight }; + int nDirection = -1; + if(bInvertX) + { + ::SetRect(&rcBtn, 0, yStart, m_cxBtnWidth, yStart + m_cyBtnHeight); + nDirection = 1; + } + + arrRect[0] = rcBtn; +#ifndef _WTL_NO_AUTO_THEME + if(m_hTheme != NULL) + ::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0); + else +#endif // !_WTL_NO_AUTO_THEME + ::OffsetRect(&rcBtn, nDirection * (m_cxBtnWidth + m_cxyOffset), 0); + arrRect[1] = rcBtn; + ::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0); + arrRect[2] = rcBtn; + } + + void _DrawMDIButton(CWindowDC& dc, LPRECT pRects, int nBtn) + { +#ifndef _WTL_NO_AUTO_THEME + if(m_hTheme != NULL) + { +#if !defined(TMSCHEMA_H) && !defined(__VSSYM32_H__) + const int WP_MDICLOSEBUTTON = 20; + const int CBS_NORMAL = 1; + const int CBS_PUSHED = 3; + const int CBS_DISABLED = 4; + const int WP_MDIRESTOREBUTTON = 22; + const int RBS_NORMAL = 1; + const int RBS_PUSHED = 3; + const int RBS_DISABLED = 4; + const int WP_MDIMINBUTTON = 16; + const int MINBS_NORMAL = 1; + const int MINBS_PUSHED = 3; + const int MINBS_DISABLED = 4; +#endif // !defined(TMSCHEMA_H) && !defined(__VSSYM32_H__) + if(nBtn == -1 || nBtn == 0) + m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDICLOSEBUTTON, m_bParentActive ? ((m_nBtnPressed == 0) ? CBS_PUSHED : CBS_NORMAL) : CBS_DISABLED, &pRects[0], NULL); + if(nBtn == -1 || nBtn == 1) + m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIRESTOREBUTTON, m_bParentActive ? ((m_nBtnPressed == 1) ? RBS_PUSHED : RBS_NORMAL) : RBS_DISABLED, &pRects[1], NULL); + if(nBtn == -1 || nBtn == 2) + m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIMINBUTTON, m_bParentActive ? ((m_nBtnPressed == 2) ? MINBS_PUSHED : MINBS_NORMAL) : MINBS_DISABLED, &pRects[2], NULL); + } + else +#endif // !_WTL_NO_AUTO_THEME + { + if(nBtn == -1 || nBtn == 0) + dc.DrawFrameControl(&pRects[0], DFC_CAPTION, DFCS_CAPTIONCLOSE | ((m_nBtnPressed == 0) ? DFCS_PUSHED : 0)); + if(nBtn == -1 || nBtn == 1) + dc.DrawFrameControl(&pRects[1], DFC_CAPTION, DFCS_CAPTIONRESTORE | ((m_nBtnPressed == 1) ? DFCS_PUSHED : 0)); + if(nBtn == -1 || nBtn == 2) + dc.DrawFrameControl(&pRects[2], DFC_CAPTION, DFCS_CAPTIONMIN | ((m_nBtnPressed == 2) ? DFCS_PUSHED : 0)); + } + } + +#ifndef _WTL_NO_AUTO_THEME + static UINT _GetThemeChangedMsg() + { +#ifndef WM_THEMECHANGED + static const UINT WM_THEMECHANGED = 0x031A; +#endif // !WM_THEMECHANGED + return WM_THEMECHANGED; + } + + void _OpenThemeData() + { + ATLASSERT(m_hThemeDLL != NULL); + + PFN_OpenThemeData pfnOpenThemeData = (PFN_OpenThemeData)::GetProcAddress(m_hThemeDLL, "OpenThemeData"); + ATLASSERT(pfnOpenThemeData != NULL); + if(pfnOpenThemeData != NULL) + m_hTheme = pfnOpenThemeData(m_hWnd, L"Window"); + } + + void _CloseThemeData() + { + ATLASSERT(m_hThemeDLL != NULL); + + if(m_hTheme == NULL) + return; // nothing to do + + PFN_CloseThemeData pfnCloseThemeData = (PFN_CloseThemeData)::GetProcAddress(m_hThemeDLL, "CloseThemeData"); + ATLASSERT(pfnCloseThemeData != NULL); + if(pfnCloseThemeData != NULL) + { + pfnCloseThemeData(m_hTheme); + m_hTheme = NULL; + } + } +#endif // !_WTL_NO_AUTO_THEME + + bool _DebugCheckChild() + { +#ifdef _DEBUG + BOOL bMaximized = FALSE; + HWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); + return (bMaximized && hWndChild == m_hWndChildMaximized); +#else // !_DEBUG + return true; +#endif // !_DEBUG + } +}; + +class CMDICommandBarCtrl : public CMDICommandBarCtrlImpl +{ +public: + DECLARE_WND_SUPERCLASS(_T("WTL_MDICommandBar"), GetWndClassName()) +}; + +}; // namespace WTL + +#endif // __ATLCTRLW_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlctrlx.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlctrlx.h new file mode 100644 index 0000000000000000000000000000000000000000..c0ad456388d50ab178677d2701a1d405ec43dae4 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlctrlx.h @@ -0,0 +1,5120 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLCTRLX_H__ +#define __ATLCTRLX_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atlctrlx.h requires atlapp.h to be included first +#endif + +#ifndef __ATLCTRLS_H__ + #error atlctrlx.h requires atlctrls.h to be included first +#endif + +#ifndef WM_UPDATEUISTATE + #define WM_UPDATEUISTATE 0x0128 +#endif // !WM_UPDATEUISTATE + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CBitmapButtonImpl +// CBitmapButton +// CCheckListViewCtrlImpl +// CCheckListViewCtrl +// CHyperLinkImpl +// CHyperLink +// CWaitCursor +// CCustomWaitCursor +// CMultiPaneStatusBarCtrlImpl +// CMultiPaneStatusBarCtrl +// CPaneContainerImpl +// CPaneContainer +// CSortListViewImpl +// CSortListViewCtrlImpl +// CSortListViewCtrl +// CTabViewImpl +// CTabView + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CBitmapButton - bitmap button implementation + +#ifndef _WIN32_WCE + +// bitmap button extended styles +#define BMPBTN_HOVER 0x00000001 +#define BMPBTN_AUTO3D_SINGLE 0x00000002 +#define BMPBTN_AUTO3D_DOUBLE 0x00000004 +#define BMPBTN_AUTOSIZE 0x00000008 +#define BMPBTN_SHAREIMAGELISTS 0x00000010 +#define BMPBTN_AUTOFIRE 0x00000020 +#define BMPBTN_CHECK 0x00000040 +#define BMPBTN_AUTOCHECK 0x00000080 + +// Note: BMPBTN_CHECK/BMPBTN_AUTOCHECK disables BN_DOUBLECLICKED, +// BMPBTN_AUTOFIRE doesn't work with BMPBTN_CHECK/BMPBTN_AUTOCHECK + +template +class ATL_NO_VTABLE CBitmapButtonImpl : public ATL::CWindowImpl< T, TBase, TWinTraits > +{ +public: + DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) + + enum + { + _nImageNormal = 0, + _nImagePushed, + _nImageFocusOrHover, + _nImageDisabled, + + _nImageCount = 4, + }; + + enum + { + ID_TIMER_FIRST = 1000, + ID_TIMER_REPEAT = 1001 + }; + + // Bitmap button specific extended styles + DWORD m_dwExtendedStyle; + + CImageList m_ImageList; + int m_nImage[_nImageCount]; + + CToolTipCtrl m_tip; + LPTSTR m_lpstrToolTipText; + + // Internal states + unsigned m_fMouseOver:1; + unsigned m_fFocus:1; + unsigned m_fPressed:1; + unsigned m_fChecked:1; + + +// Constructor/Destructor + CBitmapButtonImpl(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) : + m_dwExtendedStyle(dwExtendedStyle), m_ImageList(hImageList), + m_lpstrToolTipText(NULL), + m_fMouseOver(0), m_fFocus(0), m_fPressed(0), m_fChecked(0) + { + m_nImage[_nImageNormal] = -1; + m_nImage[_nImagePushed] = -1; + m_nImage[_nImageFocusOrHover] = -1; + m_nImage[_nImageDisabled] = -1; + +#ifdef _DEBUG + if(((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) && IsCheckMode()) + ATLTRACE2(atlTraceUI, 0, _T("CBitmapButtonImpl - Check mode and BMPBTN_AUTOFIRE cannot be used together, BMPBTN_AUTOFIRE will be ignored.\n")); +#endif // _DEBUG + } + + ~CBitmapButtonImpl() + { + if((m_dwExtendedStyle & BMPBTN_SHAREIMAGELISTS) == 0) + m_ImageList.Destroy(); + delete [] m_lpstrToolTipText; + } + + // overridden to provide proper initialization + BOOL SubclassWindow(HWND hWnd) + { +#if (_MSC_VER >= 1300) + BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + BOOL bRet = _baseClass::SubclassWindow(hWnd); +#endif // !(_MSC_VER >= 1300) + if(bRet != FALSE) + { + T* pT = static_cast(this); + pT->Init(); + } + + return bRet; + } + +// Attributes + DWORD GetBitmapButtonExtendedStyle() const + { + return m_dwExtendedStyle; + } + + DWORD SetBitmapButtonExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + +#ifdef _DEBUG + if(((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) && IsCheckMode()) + ATLTRACE2(atlTraceUI, 0, _T("CBitmapButtonImpl - Check mode and BMPBTN_AUTOFIRE cannot be used together, BMPBTN_AUTOFIRE will be ignored.\n")); +#endif // _DEBUG + + return dwPrevStyle; + } + + HIMAGELIST GetImageList() const + { + return m_ImageList; + } + + HIMAGELIST SetImageList(HIMAGELIST hImageList) + { + HIMAGELIST hImageListPrev = m_ImageList; + m_ImageList = hImageList; + if((m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0 && ::IsWindow(m_hWnd)) + SizeToImage(); + + return hImageListPrev; + } + + int GetToolTipTextLength() const + { + return (m_lpstrToolTipText == NULL) ? -1 : lstrlen(m_lpstrToolTipText); + } + + bool GetToolTipText(LPTSTR lpstrText, int nLength) const + { + ATLASSERT(lpstrText != NULL); + if(m_lpstrToolTipText == NULL) + return false; + + errno_t nRet = SecureHelper::strncpy_x(lpstrText, nLength, m_lpstrToolTipText, _TRUNCATE); + + return (nRet == 0 || nRet == STRUNCATE); + } + + bool SetToolTipText(LPCTSTR lpstrText) + { + if(m_lpstrToolTipText != NULL) + { + delete [] m_lpstrToolTipText; + m_lpstrToolTipText = NULL; + } + + if(lpstrText == NULL) + { + if(m_tip.IsWindow()) + m_tip.Activate(FALSE); + return true; + } + + int cchLen = lstrlen(lpstrText) + 1; + ATLTRY(m_lpstrToolTipText = new TCHAR[cchLen]); + if(m_lpstrToolTipText == NULL) + return false; + + SecureHelper::strcpy_x(m_lpstrToolTipText, cchLen, lpstrText); + if(m_tip.IsWindow()) + { + m_tip.Activate(TRUE); + m_tip.AddTool(m_hWnd, m_lpstrToolTipText); + } + + return true; + } + + bool GetCheck() const + { + return (m_fChecked == 1); + } + + void SetCheck(bool bCheck, bool bUpdate = true) + { + m_fChecked = bCheck ? 1 : 0; + + if(bUpdate) + { + Invalidate(); + UpdateWindow(); + } + } + +// Operations + void SetImages(int nNormal, int nPushed = -1, int nFocusOrHover = -1, int nDisabled = -1) + { + if(nNormal != -1) + m_nImage[_nImageNormal] = nNormal; + if(nPushed != -1) + m_nImage[_nImagePushed] = nPushed; + if(nFocusOrHover != -1) + m_nImage[_nImageFocusOrHover] = nFocusOrHover; + if(nDisabled != -1) + m_nImage[_nImageDisabled] = nDisabled; + } + + BOOL SizeToImage() + { + ATLASSERT(::IsWindow(m_hWnd) && m_ImageList.m_hImageList != NULL); + int cx = 0; + int cy = 0; + if(!m_ImageList.GetIconSize(cx, cy)) + return FALSE; + return ResizeClient(cx, cy); + } + +// Overrideables + void DoPaint(CDCHandle dc) + { + ATLASSERT(m_ImageList.m_hImageList != NULL); // image list must be set + ATLASSERT(m_nImage[0] != -1); // main bitmap must be set + + // set bitmap according to the current button state + bool bHover = IsHoverMode(); + bool bPressed = (m_fPressed == 1) || (IsCheckMode() && (m_fChecked == 1)); + int nImage = -1; + if(!IsWindowEnabled()) + nImage = m_nImage[_nImageDisabled]; + else if(bPressed) + nImage = m_nImage[_nImagePushed]; + else if((!bHover && (m_fFocus == 1)) || (bHover && (m_fMouseOver == 1))) + nImage = m_nImage[_nImageFocusOrHover]; + + // if none is set, use default one + if(nImage == -1) + nImage = m_nImage[_nImageNormal]; + + // draw the button image + bool bAuto3D = (m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0; + int xyPos = (bPressed && bAuto3D && (m_nImage[_nImagePushed] == -1)) ? 1 : 0; + m_ImageList.Draw(dc, nImage, xyPos, xyPos, ILD_NORMAL); + + // draw 3D border if required + if(bAuto3D) + { + RECT rect = { 0 }; + GetClientRect(&rect); + + if(bPressed) + dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_SUNKENOUTER : EDGE_SUNKEN, BF_RECT); + else if(!bHover || (m_fMouseOver == 1)) + dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_RAISEDINNER : EDGE_RAISED, BF_RECT); + + if(!bHover && (m_fFocus == 1)) + { + ::InflateRect(&rect, -2 * ::GetSystemMetrics(SM_CXEDGE), -2 * ::GetSystemMetrics(SM_CYEDGE)); + dc.DrawFocusRect(&rect); + } + } + } + +// Message map and handlers + BEGIN_MSG_MAP(CBitmapButtonImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + MESSAGE_HANDLER(WM_SETFOCUS, OnFocus) + MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus) + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) + MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk) + MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) + MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) + MESSAGE_HANDLER(WM_ENABLE, OnEnable) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) + MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) + MESSAGE_HANDLER(WM_KEYUP, OnKeyUp) + MESSAGE_HANDLER(WM_TIMER, OnTimer) + MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->Init(); + + bHandled = FALSE; + return 1; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_tip.IsWindow()) + { + m_tip.DestroyWindow(); + m_tip.m_hWnd = NULL; + } + bHandled = FALSE; + return 1; + } + + LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + MSG msg = { m_hWnd, uMsg, wParam, lParam }; + if(m_tip.IsWindow()) + m_tip.RelayEvent(&msg); + bHandled = FALSE; + return 1; + } + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background needed + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + if(wParam != NULL) + { + pT->DoPaint((HDC)wParam); + } + else + { + CPaintDC dc(m_hWnd); + pT->DoPaint(dc.m_hDC); + } + return 0; + } + + LRESULT OnFocus(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + m_fFocus = (uMsg == WM_SETFOCUS) ? 1 : 0; + Invalidate(); + UpdateWindow(); + bHandled = FALSE; + return 1; + } + + LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = 0; + if(IsHoverMode()) + SetCapture(); + else + lRet = DefWindowProc(uMsg, wParam, lParam); + if(::GetCapture() == m_hWnd) + { + m_fPressed = 1; + Invalidate(); + UpdateWindow(); + } + if(((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) && !IsCheckMode()) + { + int nElapse = 250; + int nDelay = 0; + if(::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &nDelay, 0)) + nElapse += nDelay * 250; // all milli-seconds + SetTimer(ID_TIMER_FIRST, nElapse); + } + return lRet; + } + + LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = 0; + if(!IsHoverMode() && !IsCheckMode()) + lRet = DefWindowProc(uMsg, wParam, lParam); + if(::GetCapture() != m_hWnd) + SetCapture(); + if(m_fPressed == 0) + { + m_fPressed = 1; + Invalidate(); + UpdateWindow(); + } + return lRet; + } + + LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + if(((m_dwExtendedStyle & BMPBTN_AUTOCHECK) != 0) && (m_fPressed == 1)) + SetCheck(!GetCheck(), false); + + LRESULT lRet = 0; + if(!IsHoverMode() && !IsCheckMode()) + lRet = DefWindowProc(uMsg, wParam, lParam); + if(::GetCapture() == m_hWnd) + { + if((IsHoverMode() || IsCheckMode()) && (m_fPressed == 1)) + ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); + ::ReleaseCapture(); + } + return lRet; + } + + LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_fPressed == 1) + { + m_fPressed = 0; + Invalidate(); + UpdateWindow(); + } + bHandled = FALSE; + return 1; + } + + LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + Invalidate(); + UpdateWindow(); + bHandled = FALSE; + return 1; + } + + LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(::GetCapture() == m_hWnd) + { + POINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + ClientToScreen(&ptCursor); + RECT rect = { 0 }; + GetWindowRect(&rect); + unsigned int uPressed = ::PtInRect(&rect, ptCursor) ? 1 : 0; + if(m_fPressed != uPressed) + { + m_fPressed = uPressed; + Invalidate(); + UpdateWindow(); + } + } + else if(IsHoverMode() && m_fMouseOver == 0) + { + m_fMouseOver = 1; + Invalidate(); + UpdateWindow(); + StartTrackMouseLeave(); + } + bHandled = FALSE; + return 1; + } + + LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(m_fMouseOver == 1) + { + m_fMouseOver = 0; + Invalidate(); + UpdateWindow(); + } + return 0; + } + + LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam == VK_SPACE && IsHoverMode()) + return 0; // ignore if in hover mode + if(wParam == VK_SPACE && m_fPressed == 0) + { + m_fPressed = 1; + Invalidate(); + UpdateWindow(); + } + bHandled = FALSE; + return 1; + } + + LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam == VK_SPACE && IsHoverMode()) + return 0; // ignore if in hover mode + if(wParam == VK_SPACE && m_fPressed == 1) + { + m_fPressed = 0; + if((m_dwExtendedStyle & BMPBTN_AUTOCHECK) != 0) + SetCheck(!GetCheck(), false); + Invalidate(); + UpdateWindow(); + } + bHandled = FALSE; + return 1; + } + + LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + ATLASSERT((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0); + switch(wParam) // timer ID + { + case ID_TIMER_FIRST: + KillTimer(ID_TIMER_FIRST); + if(m_fPressed == 1) + { + ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); + int nElapse = 250; + int nRepeat = 40; + if(::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &nRepeat, 0)) + nElapse = 10000 / (10 * nRepeat + 25); // milli-seconds, approximated + SetTimer(ID_TIMER_REPEAT, nElapse); + } + break; + case ID_TIMER_REPEAT: + if(m_fPressed == 1) + ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); + else if(::GetCapture() != m_hWnd) + KillTimer(ID_TIMER_REPEAT); + break; + default: // not our timer + break; + } + return 0; + } + + LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + // If the control is subclassed or superclassed, this message can cause + // repainting without WM_PAINT. We don't use this state, so just do nothing. + return 0; + } + +// Implementation + void Init() + { + // We need this style to prevent Windows from painting the button + ModifyStyle(0, BS_OWNERDRAW); + + // create a tool tip + m_tip.Create(m_hWnd); + ATLASSERT(m_tip.IsWindow()); + if(m_tip.IsWindow() && m_lpstrToolTipText != NULL) + { + m_tip.Activate(TRUE); + m_tip.AddTool(m_hWnd, m_lpstrToolTipText); + } + + if(m_ImageList.m_hImageList != NULL && (m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0) + SizeToImage(); + } + + BOOL StartTrackMouseLeave() + { + TRACKMOUSEEVENT tme = { 0 }; + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = m_hWnd; + return _TrackMouseEvent(&tme); + } + + bool IsHoverMode() const + { + return ((m_dwExtendedStyle & BMPBTN_HOVER) != 0); + } + + bool IsCheckMode() const + { + return ((m_dwExtendedStyle & (BMPBTN_CHECK | BMPBTN_AUTOCHECK)) != 0); + } +}; + +class CBitmapButton : public CBitmapButtonImpl +{ +public: + DECLARE_WND_SUPERCLASS(_T("WTL_BitmapButton"), GetWndClassName()) + + CBitmapButton(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) : + CBitmapButtonImpl(dwExtendedStyle, hImageList) + { } +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CCheckListCtrlView - list view control with check boxes + +template +class CCheckListViewCtrlImplTraits +{ +public: + static DWORD GetWndStyle(DWORD dwStyle) + { + return (dwStyle == 0) ? t_dwStyle : dwStyle; + } + + static DWORD GetWndExStyle(DWORD dwExStyle) + { + return (dwExStyle == 0) ? t_dwExStyle : dwExStyle; + } + + static DWORD GetExtendedLVStyle() + { + return t_dwExListViewStyle; + } +}; + +typedef CCheckListViewCtrlImplTraits CCheckListViewCtrlTraits; + +template +class ATL_NO_VTABLE CCheckListViewCtrlImpl : public ATL::CWindowImpl +{ +public: + DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) + +// Attributes + static DWORD GetExtendedLVStyle() + { + return TWinTraits::GetExtendedLVStyle(); + } + +// Operations + BOOL SubclassWindow(HWND hWnd) + { +#if (_MSC_VER >= 1300) + BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + BOOL bRet = _baseClass::SubclassWindow(hWnd); +#endif // !(_MSC_VER >= 1300) + if(bRet != FALSE) + { + T* pT = static_cast(this); + pT->Init(); + } + + return bRet; + } + + void CheckSelectedItems(int nCurrItem) + { + // first check if this item is selected + LVITEM lvi = { 0 }; + lvi.iItem = nCurrItem; + lvi.iSubItem = 0; + lvi.mask = LVIF_STATE; + lvi.stateMask = LVIS_SELECTED; + GetItem(&lvi); + // if item is not selected, don't do anything + if(!(lvi.state & LVIS_SELECTED)) + return; + // new check state will be reverse of the current state, + BOOL bCheck = !GetCheckState(nCurrItem); + int nItem = -1; + int nOldItem = -1; + while((nItem = GetNextItem(nOldItem, LVNI_SELECTED)) != -1) + { + if(nItem != nCurrItem) + SetCheckState(nItem, bCheck); + nOldItem = nItem; + } + } + +// Implementation + void Init() + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0); + SetExtendedListViewStyle(pT->GetExtendedLVStyle()); + } + +// Message map and handlers + BEGIN_MSG_MAP(CCheckListViewCtrlImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) + MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDown) + MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) + END_MSG_MAP() + + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + // first let list view control initialize everything + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + if(lRet == 0) + { + T* pT = static_cast(this); + pT->Init(); + } + + return lRet; + } + + LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + POINT ptMsg = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + LVHITTESTINFO lvh = { 0 }; + lvh.pt = ptMsg; + if(HitTest(&lvh) != -1 && lvh.flags == LVHT_ONITEMSTATEICON && ::GetKeyState(VK_CONTROL) >= 0) + { + T* pT = static_cast(this); + pT->CheckSelectedItems(lvh.iItem); + } + bHandled = FALSE; + return 1; + } + + LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam == VK_SPACE) + { + int nCurrItem = GetNextItem(-1, LVNI_FOCUSED); + if(nCurrItem != -1 && ::GetKeyState(VK_CONTROL) >= 0) + { + T* pT = static_cast(this); + pT->CheckSelectedItems(nCurrItem); + } + } + bHandled = FALSE; + return 1; + } +}; + +class CCheckListViewCtrl : public CCheckListViewCtrlImpl +{ +public: + DECLARE_WND_SUPERCLASS(_T("WTL_CheckListView"), GetWndClassName()) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CHyperLink - hyper link control implementation + +#if (WINVER < 0x0500) && !defined(_WIN32_WCE) +__declspec(selectany) struct +{ + enum { cxWidth = 32, cyHeight = 32 }; + int xHotSpot; + int yHotSpot; + unsigned char arrANDPlane[cxWidth * cyHeight / 8]; + unsigned char arrXORPlane[cxWidth * cyHeight / 8]; +} _AtlHyperLink_CursorData = +{ + 5, 0, + { + 0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, + 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, + 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, + 0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, + 0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }, + { + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x06, 0xD8, 0x00, 0x00, + 0x06, 0xDA, 0x00, 0x00, 0x06, 0xDB, 0x00, 0x00, 0x67, 0xFB, 0x00, 0x00, 0x77, 0xFF, 0x00, 0x00, + 0x37, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00, + 0x0F, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, + 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + } +}; +#endif // (WINVER < 0x0500) && !defined(_WIN32_WCE) + +#define HLINK_UNDERLINED 0x00000000 +#define HLINK_NOTUNDERLINED 0x00000001 +#define HLINK_UNDERLINEHOVER 0x00000002 +#define HLINK_COMMANDBUTTON 0x00000004 +#define HLINK_NOTIFYBUTTON 0x0000000C +#define HLINK_USETAGS 0x00000010 +#define HLINK_USETAGSBOLD 0x00000030 +#define HLINK_NOTOOLTIP 0x00000040 +#define HLINK_AUTOCREATELINKFONT 0x00000080 +#define HLINK_SINGLELINE 0x00000100 + +// Notes: +// - HLINK_USETAGS and HLINK_USETAGSBOLD are always left-aligned +// - When HLINK_USETAGSBOLD is used, the underlined styles will be ignored + +template +class ATL_NO_VTABLE CHyperLinkImpl : public ATL::CWindowImpl< T, TBase, TWinTraits > +{ +public: + LPTSTR m_lpstrLabel; + LPTSTR m_lpstrHyperLink; + + HCURSOR m_hCursor; + HFONT m_hFontLink; + HFONT m_hFontNormal; + + RECT m_rcLink; +#ifndef _WIN32_WCE + CToolTipCtrl m_tip; +#endif // !_WIN32_WCE + + COLORREF m_clrLink; + COLORREF m_clrVisited; + + DWORD m_dwExtendedStyle; // Hyper Link specific extended styles + + bool m_bPaintLabel:1; + bool m_bVisited:1; + bool m_bHover:1; + bool m_bInternalLinkFont:1; + bool m_bInternalNormalFont:1; + + +// Constructor/Destructor + CHyperLinkImpl(DWORD dwExtendedStyle = HLINK_UNDERLINED) : + m_lpstrLabel(NULL), m_lpstrHyperLink(NULL), + m_hCursor(NULL), m_hFontLink(NULL), m_hFontNormal(NULL), + m_clrLink(RGB(0, 0, 255)), m_clrVisited(RGB(128, 0, 128)), + m_dwExtendedStyle(dwExtendedStyle), + m_bPaintLabel(true), m_bVisited(false), + m_bHover(false), m_bInternalLinkFont(false), m_bInternalNormalFont(false) + { + ::SetRectEmpty(&m_rcLink); + } + + ~CHyperLinkImpl() + { + delete [] m_lpstrLabel; + delete [] m_lpstrHyperLink; +#if (WINVER < 0x0500) && !defined(_WIN32_WCE) + // It was created, not loaded, so we have to destroy it + if(m_hCursor != NULL) + ::DestroyCursor(m_hCursor); +#endif // (WINVER < 0x0500) && !defined(_WIN32_WCE) + } + +// Attributes + DWORD GetHyperLinkExtendedStyle() const + { + return m_dwExtendedStyle; + } + + DWORD SetHyperLinkExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + return dwPrevStyle; + } + + bool GetLabel(LPTSTR lpstrBuffer, int nLength) const + { + if(m_lpstrLabel == NULL) + return false; + ATLASSERT(lpstrBuffer != NULL); + if(nLength <= lstrlen(m_lpstrLabel)) + return false; + + SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrLabel); + + return true; + } + + bool SetLabel(LPCTSTR lpstrLabel) + { + delete [] m_lpstrLabel; + m_lpstrLabel = NULL; + int cchLen = lstrlen(lpstrLabel) + 1; + ATLTRY(m_lpstrLabel = new TCHAR[cchLen]); + if(m_lpstrLabel == NULL) + return false; + + SecureHelper::strcpy_x(m_lpstrLabel, cchLen, lpstrLabel); + T* pT = static_cast(this); + pT->CalcLabelRect(); + + if(m_hWnd != NULL) + SetWindowText(lpstrLabel); // Set this for accessibility + + return true; + } + + bool GetHyperLink(LPTSTR lpstrBuffer, int nLength) const + { + if(m_lpstrHyperLink == NULL) + return false; + ATLASSERT(lpstrBuffer != NULL); + if(nLength <= lstrlen(m_lpstrHyperLink)) + return false; + + SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrHyperLink); + + return true; + } + + bool SetHyperLink(LPCTSTR lpstrLink) + { + delete [] m_lpstrHyperLink; + m_lpstrHyperLink = NULL; + int cchLen = lstrlen(lpstrLink) + 1; + ATLTRY(m_lpstrHyperLink = new TCHAR[cchLen]); + if(m_lpstrHyperLink == NULL) + return false; + + SecureHelper::strcpy_x(m_lpstrHyperLink, cchLen, lpstrLink); + if(m_lpstrLabel == NULL) + { + T* pT = static_cast(this); + pT->CalcLabelRect(); + } +#ifndef _WIN32_WCE + if(m_tip.IsWindow()) + { + m_tip.Activate(TRUE); + m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1); + } +#endif // !_WIN32_WCE + return true; + } + + HFONT GetLinkFont() const + { + return m_hFontLink; + } + + void SetLinkFont(HFONT hFont) + { + if(m_bInternalLinkFont) + { + ::DeleteObject(m_hFontLink); + m_bInternalLinkFont = false; + } + + m_hFontLink = hFont; + + T* pT = static_cast(this); + pT->CalcLabelRect(); + } + + int GetIdealHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) + return -1; + if(!m_bPaintLabel) + return -1; + + UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + + CClientDC dc(m_hWnd); + RECT rect = { 0 }; + GetClientRect(&rect); + HFONT hFontOld = dc.SelectFont(m_hFontNormal); + RECT rcText = rect; + dc.DrawText(_T("NS"), -1, &rcText, DT_LEFT | uFormat | DT_CALCRECT); + dc.SelectFont(m_hFontLink); + RECT rcLink = rect; + dc.DrawText(_T("NS"), -1, &rcLink, DT_LEFT | uFormat | DT_CALCRECT); + dc.SelectFont(hFontOld); + return __max(rcText.bottom - rcText.top, rcLink.bottom - rcLink.top); + } + + bool GetIdealSize(SIZE& size) const + { + int cx = 0, cy = 0; + bool bRet = GetIdealSize(cx, cy); + if(bRet) + { + size.cx = cx; + size.cy = cy; + } + return bRet; + } + + bool GetIdealSize(int& cx, int& cy) const + { + ATLASSERT(::IsWindow(m_hWnd)); + if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) + return false; + if(!m_bPaintLabel) + return false; + + CClientDC dc(m_hWnd); + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + RECT rcAll = rcClient; + + if(IsUsingTags()) + { + // find tags and label parts + LPTSTR lpstrLeft = NULL; + int cchLeft = 0; + LPTSTR lpstrLink = NULL; + int cchLink = 0; + LPTSTR lpstrRight = NULL; + int cchRight = 0; + + const T* pT = static_cast(this); + pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight); + + // get label part rects + UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + + HFONT hFontOld = dc.SelectFont(m_hFontNormal); + RECT rcLeft = rcClient; + dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT); + + dc.SelectFont(m_hFontLink); + RECT rcLink = { rcLeft.right, rcLeft.top, rcClient.right, rcClient.bottom }; + dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT); + + dc.SelectFont(m_hFontNormal); + RECT rcRight = { rcLink.right, rcLink.top, rcClient.right, rcClient.bottom }; + dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat | DT_CALCRECT); + + dc.SelectFont(hFontOld); + + int cyMax = __max(rcLeft.bottom, __max(rcLink.bottom, rcRight.bottom)); + ::SetRect(&rcAll, rcLeft.left, rcLeft.top, rcRight.right, cyMax); + } + else + { + HFONT hOldFont = NULL; + if(m_hFontLink != NULL) + hOldFont = dc.SelectFont(m_hFontLink); + LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; + DWORD dwStyle = GetStyle(); + UINT uFormat = DT_LEFT; + if (dwStyle & SS_CENTER) + uFormat = DT_CENTER; + else if (dwStyle & SS_RIGHT) + uFormat = DT_RIGHT; + uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + dc.DrawText(lpstrText, -1, &rcAll, uFormat | DT_CALCRECT); + if(m_hFontLink != NULL) + dc.SelectFont(hOldFont); + if (dwStyle & SS_CENTER) + { + int dx = (rcClient.right - rcAll.right) / 2; + ::OffsetRect(&rcAll, dx, 0); + } + else if (dwStyle & SS_RIGHT) + { + int dx = rcClient.right - rcAll.right; + ::OffsetRect(&rcAll, dx, 0); + } + } + + cx = rcAll.right - rcAll.left; + cy = rcAll.bottom - rcAll.top; + + return true; + } + + // for command buttons only + bool GetToolTipText(LPTSTR lpstrBuffer, int nLength) const + { + ATLASSERT(IsCommandButton()); + return GetHyperLink(lpstrBuffer, nLength); + } + + bool SetToolTipText(LPCTSTR lpstrToolTipText) + { + ATLASSERT(IsCommandButton()); + return SetHyperLink(lpstrToolTipText); + } + +// Operations + BOOL SubclassWindow(HWND hWnd) + { + ATLASSERT(m_hWnd == NULL); + ATLASSERT(::IsWindow(hWnd)); + if(m_hFontNormal == NULL) + m_hFontNormal = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L); + +#if (_MSC_VER >= 1300) + BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + BOOL bRet = _baseClass::SubclassWindow(hWnd); +#endif // !(_MSC_VER >= 1300) + if(bRet != FALSE) + { + T* pT = static_cast(this); + pT->Init(); + } + + return bRet; + } + + bool Navigate() + { + ATLASSERT(::IsWindow(m_hWnd)); + bool bRet = true; + if(IsNotifyButton()) + { + NMHDR nmhdr = { m_hWnd, (UINT_PTR)GetDlgCtrlID(), NM_CLICK }; + ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr); + } + else if(IsCommandButton()) + { + ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); + } + else + { + ATLASSERT(m_lpstrHyperLink != NULL); +#ifndef _WIN32_WCE + DWORD_PTR dwRet = (DWORD_PTR)::ShellExecute(0, _T("open"), m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL); + bRet = (dwRet > 32); +#else // CE specific + SHELLEXECUTEINFO shExeInfo = { sizeof(SHELLEXECUTEINFO), 0, 0, L"open", m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL, 0, 0, 0, 0, 0, 0, 0 }; + ::ShellExecuteEx(&shExeInfo); + DWORD_PTR dwRet = (DWORD_PTR)shExeInfo.hInstApp; + bRet = (dwRet == 0) || (dwRet > 32); +#endif // _WIN32_WCE + ATLASSERT(bRet); + if(bRet) + { + m_bVisited = true; + Invalidate(); + } + } + return bRet; + } + + void CreateLinkFontFromNormal() + { + if(m_bInternalLinkFont) + { + ::DeleteObject(m_hFontLink); + m_bInternalLinkFont = false; + } + + CFontHandle font = (m_hFontNormal != NULL) ? m_hFontNormal : (HFONT)::GetStockObject(SYSTEM_FONT); + LOGFONT lf = { 0 }; + font.GetLogFont(&lf); + + if(IsUsingTagsBold()) + lf.lfWeight = FW_BOLD; + else if(!IsNotUnderlined()) + lf.lfUnderline = TRUE; + + m_hFontLink = ::CreateFontIndirect(&lf); + m_bInternalLinkFont = true; + ATLASSERT(m_hFontLink != NULL); + } + +// Message map and handlers + BEGIN_MSG_MAP(CHyperLinkImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_SETFOCUS, OnFocus) + MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) + MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) + MESSAGE_HANDLER(WM_CHAR, OnChar) + MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode) + MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) + MESSAGE_HANDLER(WM_ENABLE, OnEnable) + MESSAGE_HANDLER(WM_GETFONT, OnGetFont) + MESSAGE_HANDLER(WM_SETFONT, OnSetFont) + MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState) + MESSAGE_HANDLER(WM_SIZE, OnSize) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Init(); + return 0; + } + +#ifndef _WIN32_WCE + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_tip.IsWindow()) + { + m_tip.DestroyWindow(); + m_tip.m_hWnd = NULL; + } + + if(m_bInternalLinkFont) + { + ::DeleteObject(m_hFontLink); + m_hFontLink = NULL; + m_bInternalLinkFont = false; + } + + if(m_bInternalNormalFont) + { + ::DeleteObject(m_hFontNormal); + m_hFontNormal = NULL; + m_bInternalNormalFont = false; + } + + bHandled = FALSE; + return 1; + } + + LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + MSG msg = { m_hWnd, uMsg, wParam, lParam }; + if(m_tip.IsWindow() && IsUsingToolTip()) + m_tip.RelayEvent(&msg); + bHandled = FALSE; + return 1; + } +#endif // !_WIN32_WCE + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background painting needed (we do it all during WM_PAINT) + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(!m_bPaintLabel) + { + bHandled = FALSE; + return 1; + } + + T* pT = static_cast(this); + if(wParam != NULL) + { + pT->DoEraseBackground((HDC)wParam); + pT->DoPaint((HDC)wParam); + } + else + { + CPaintDC dc(m_hWnd); + pT->DoEraseBackground(dc.m_hDC); + pT->DoPaint(dc.m_hDC); + } + + return 0; + } + + LRESULT OnFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_bPaintLabel) + Invalidate(); + else + bHandled = FALSE; + return 0; + } + + LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRect(&m_rcLink, pt)) + { + ::SetCursor(m_hCursor); + if(IsUnderlineHover()) + { + if(!m_bHover) + { + m_bHover = true; + InvalidateRect(&m_rcLink); + UpdateWindow(); +#ifndef _WIN32_WCE + StartTrackMouseLeave(); +#endif // !_WIN32_WCE + } + } + } + else + { + if(IsUnderlineHover()) + { + if(m_bHover) + { + m_bHover = false; + InvalidateRect(&m_rcLink); + UpdateWindow(); + } + } + bHandled = FALSE; + } + return 0; + } + +#ifndef _WIN32_WCE + LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(IsUnderlineHover() && m_bHover) + { + m_bHover = false; + InvalidateRect(&m_rcLink); + UpdateWindow(); + } + return 0; + } +#endif // !_WIN32_WCE + + LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + if(::PtInRect(&m_rcLink, pt)) + { + SetFocus(); + SetCapture(); + } + return 0; + } + + LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + if(GetCapture() == m_hWnd) + { + ReleaseCapture(); + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + if(::PtInRect(&m_rcLink, pt)) + { + T* pT = static_cast(this); + pT->Navigate(); + } + } + return 0; + } + + LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(wParam == VK_RETURN || wParam == VK_SPACE) + { + T* pT = static_cast(this); + pT->Navigate(); + } + return 0; + } + + LRESULT OnGetDlgCode(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return DLGC_WANTCHARS; + } + + LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + POINT pt = { 0, 0 }; + GetCursorPos(&pt); + ScreenToClient(&pt); + if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRect(&m_rcLink, pt)) + { + return TRUE; + } + bHandled = FALSE; + return FALSE; + } + + LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + Invalidate(); + UpdateWindow(); + return 0; + } + + LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return (LRESULT)m_hFontNormal; + } + + LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + if(m_bInternalNormalFont) + { + ::DeleteObject(m_hFontNormal); + m_bInternalNormalFont = false; + } + + bool bCreateLinkFont = m_bInternalLinkFont; + + m_hFontNormal = (HFONT)wParam; + + if(bCreateLinkFont || IsAutoCreateLinkFont()) + CreateLinkFontFromNormal(); + + T* pT = static_cast(this); + pT->CalcLabelRect(); + + if((BOOL)lParam) + { + Invalidate(); + UpdateWindow(); + } + + return 0; + } + + LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + // If the control is subclassed or superclassed, this message can cause + // repainting without WM_PAINT. We don't use this state, so just do nothing. + return 0; + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->CalcLabelRect(); + pT->Invalidate(); + return 0; + } + +// Implementation + void Init() + { + ATLASSERT(::IsWindow(m_hWnd)); + + // Check if we should paint a label + const int cchBuff = 8; + TCHAR szBuffer[cchBuff] = { 0 }; + if(::GetClassName(m_hWnd, szBuffer, cchBuff)) + { + if(lstrcmpi(szBuffer, _T("static")) == 0) + { + ModifyStyle(0, SS_NOTIFY); // we need this + DWORD dwStyle = GetStyle() & 0x000000FF; +#ifndef _WIN32_WCE + if(dwStyle == SS_ICON || dwStyle == SS_BLACKRECT || dwStyle == SS_GRAYRECT || + dwStyle == SS_WHITERECT || dwStyle == SS_BLACKFRAME || dwStyle == SS_GRAYFRAME || + dwStyle == SS_WHITEFRAME || dwStyle == SS_OWNERDRAW || + dwStyle == SS_BITMAP || dwStyle == SS_ENHMETAFILE) +#else // CE specific + if(dwStyle == SS_ICON || dwStyle == SS_BITMAP) +#endif // _WIN32_WCE + m_bPaintLabel = false; + } + } + + // create or load a cursor +#if (WINVER >= 0x0500) || defined(_WIN32_WCE) + m_hCursor = ::LoadCursor(NULL, IDC_HAND); +#else + m_hCursor = ::CreateCursor(ModuleHelper::GetModuleInstance(), _AtlHyperLink_CursorData.xHotSpot, _AtlHyperLink_CursorData.yHotSpot, _AtlHyperLink_CursorData.cxWidth, _AtlHyperLink_CursorData.cyHeight, _AtlHyperLink_CursorData.arrANDPlane, _AtlHyperLink_CursorData.arrXORPlane); +#endif + ATLASSERT(m_hCursor != NULL); + + // set fonts + if(m_bPaintLabel) + { + if(m_hFontNormal == NULL) + { + m_hFontNormal = AtlCreateControlFont(); + m_bInternalNormalFont = true; + } + + if(m_hFontLink == NULL) + CreateLinkFontFromNormal(); + } + +#ifndef _WIN32_WCE + // create a tool tip + m_tip.Create(m_hWnd); + ATLASSERT(m_tip.IsWindow()); +#endif // !_WIN32_WCE + + // set label (defaults to window text) + if(m_lpstrLabel == NULL) + { + int nLen = GetWindowTextLength(); + if(nLen > 0) + { + ATLTRY(m_lpstrLabel = new TCHAR[nLen + 1]); + if(m_lpstrLabel != NULL) + ATLVERIFY(GetWindowText(m_lpstrLabel, nLen + 1) > 0); + } + } + + T* pT = static_cast(this); + pT->CalcLabelRect(); + + // set hyperlink (defaults to label), or just activate tool tip if already set + if(m_lpstrHyperLink == NULL && !IsCommandButton()) + { + if(m_lpstrLabel != NULL) + SetHyperLink(m_lpstrLabel); + } +#ifndef _WIN32_WCE + else + { + m_tip.Activate(TRUE); + m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1); + } +#endif // !_WIN32_WCE + + // set link colors + if(m_bPaintLabel) + { + CRegKeyEx rk; + LONG lRet = rk.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Internet Explorer\\Settings")); + if(lRet == ERROR_SUCCESS) + { + const int cchValue = 12; + TCHAR szValue[cchValue] = { 0 }; + ULONG ulCount = cchValue; + lRet = rk.QueryStringValue(_T("Anchor Color"), szValue, &ulCount); + if(lRet == ERROR_SUCCESS) + { + COLORREF clr = pT->_ParseColorString(szValue); + ATLASSERT(clr != CLR_INVALID); + if(clr != CLR_INVALID) + m_clrLink = clr; + } + + ulCount = cchValue; + lRet = rk.QueryStringValue(_T("Anchor Color Visited"), szValue, &ulCount); + if(lRet == ERROR_SUCCESS) + { + COLORREF clr = pT->_ParseColorString(szValue); + ATLASSERT(clr != CLR_INVALID); + if(clr != CLR_INVALID) + m_clrVisited = clr; + } + } + } + } + + static COLORREF _ParseColorString(LPTSTR lpstr) + { + int c[3] = { -1, -1, -1 }; + LPTSTR p = NULL; + for(int i = 0; i < 2; i++) + { + for(p = lpstr; *p != _T('\0'); p = ::CharNext(p)) + { + if(*p == _T(',')) + { + *p = _T('\0'); + c[i] = MinCrtHelper::_atoi(lpstr); + lpstr = &p[1]; + break; + } + } + if(c[i] == -1) + return CLR_INVALID; + } + if(*lpstr == _T('\0')) + return CLR_INVALID; + c[2] = MinCrtHelper::_atoi(lpstr); + + return RGB(c[0], c[1], c[2]); + } + + bool CalcLabelRect() + { + if(!::IsWindow(m_hWnd)) + return false; + if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) + return false; + + CClientDC dc(m_hWnd); + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + m_rcLink = rcClient; + if(!m_bPaintLabel) + return true; + + if(IsUsingTags()) + { + // find tags and label parts + LPTSTR lpstrLeft = NULL; + int cchLeft = 0; + LPTSTR lpstrLink = NULL; + int cchLink = 0; + LPTSTR lpstrRight = NULL; + int cchRight = 0; + + T* pT = static_cast(this); + pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight); + ATLASSERT(lpstrLink != NULL); + ATLASSERT(cchLink > 0); + + // get label part rects + HFONT hFontOld = dc.SelectFont(m_hFontNormal); + + UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + + RECT rcLeft = rcClient; + if(lpstrLeft != NULL) + dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT); + + dc.SelectFont(m_hFontLink); + RECT rcLink = rcClient; + if(lpstrLeft != NULL) + rcLink.left = rcLeft.right; + dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT); + + dc.SelectFont(hFontOld); + + m_rcLink = rcLink; + } + else + { + HFONT hOldFont = NULL; + if(m_hFontLink != NULL) + hOldFont = dc.SelectFont(m_hFontLink); + LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; + DWORD dwStyle = GetStyle(); + UINT uFormat = DT_LEFT; + if (dwStyle & SS_CENTER) + uFormat = DT_CENTER; + else if (dwStyle & SS_RIGHT) + uFormat = DT_RIGHT; + uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + dc.DrawText(lpstrText, -1, &m_rcLink, uFormat | DT_CALCRECT); + if(m_hFontLink != NULL) + dc.SelectFont(hOldFont); + if (dwStyle & SS_CENTER) + { + int dx = (rcClient.right - m_rcLink.right) / 2; + ::OffsetRect(&m_rcLink, dx, 0); + } + else if (dwStyle & SS_RIGHT) + { + int dx = rcClient.right - m_rcLink.right; + ::OffsetRect(&m_rcLink, dx, 0); + } + } + + return true; + } + + void CalcLabelParts(LPTSTR& lpstrLeft, int& cchLeft, LPTSTR& lpstrLink, int& cchLink, LPTSTR& lpstrRight, int& cchRight) const + { + lpstrLeft = NULL; + cchLeft = 0; + lpstrLink = NULL; + cchLink = 0; + lpstrRight = NULL; + cchRight = 0; + + LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; + int cchText = lstrlen(lpstrText); + bool bOutsideLink = true; + for(int i = 0; i < cchText; i++) + { + if(lpstrText[i] != _T('<')) + continue; + + if(bOutsideLink) + { + if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 3, _T(""), 3) == CSTR_EQUAL) + { + if(i > 0) + { + lpstrLeft = lpstrText; + cchLeft = i; + } + lpstrLink = &lpstrText[i + 3]; + bOutsideLink = false; + } + } + else + { + if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 4, _T(""), 4) == CSTR_EQUAL) + { + cchLink = i - 3 - cchLeft; + if(lpstrText[i + 4] != 0) + { + lpstrRight = &lpstrText[i + 4]; + cchRight = cchText - (i + 4); + break; + } + } + } + } + + } + + void DoEraseBackground(CDCHandle dc) + { + HBRUSH hBrush = (HBRUSH)::SendMessage(GetParent(), WM_CTLCOLORSTATIC, (WPARAM)dc.m_hDC, (LPARAM)m_hWnd); + if(hBrush != NULL) + { + RECT rect = { 0 }; + GetClientRect(&rect); + dc.FillRect(&rect, hBrush); + } + } + + void DoPaint(CDCHandle dc) + { + if(IsUsingTags()) + { + // find tags and label parts + LPTSTR lpstrLeft = NULL; + int cchLeft = 0; + LPTSTR lpstrLink = NULL; + int cchLink = 0; + LPTSTR lpstrRight = NULL; + int cchRight = 0; + + T* pT = static_cast(this); + pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight); + + // get label part rects + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + + dc.SetBkMode(TRANSPARENT); + HFONT hFontOld = dc.SelectFont(m_hFontNormal); + + UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + + if(lpstrLeft != NULL) + dc.DrawText(lpstrLeft, cchLeft, &rcClient, DT_LEFT | uFormat); + + COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT))); + if(m_hFontLink != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover))) + dc.SelectFont(m_hFontLink); + else + dc.SelectFont(m_hFontNormal); + + dc.DrawText(lpstrLink, cchLink, &m_rcLink, DT_LEFT | uFormat); + + dc.SetTextColor(clrOld); + dc.SelectFont(m_hFontNormal); + if(lpstrRight != NULL) + { + RECT rcRight = { m_rcLink.right, m_rcLink.top, rcClient.right, rcClient.bottom }; + dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat); + } + + if(GetFocus() == m_hWnd) + dc.DrawFocusRect(&m_rcLink); + + dc.SelectFont(hFontOld); + } + else + { + dc.SetBkMode(TRANSPARENT); + COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT))); + + HFONT hFontOld = NULL; + if(m_hFontLink != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover))) + hFontOld = dc.SelectFont(m_hFontLink); + else + hFontOld = dc.SelectFont(m_hFontNormal); + + LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; + + DWORD dwStyle = GetStyle(); + UINT uFormat = DT_LEFT; + if (dwStyle & SS_CENTER) + uFormat = DT_CENTER; + else if (dwStyle & SS_RIGHT) + uFormat = DT_RIGHT; + uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; + + dc.DrawText(lpstrText, -1, &m_rcLink, uFormat); + + if(GetFocus() == m_hWnd) + dc.DrawFocusRect(&m_rcLink); + + dc.SetTextColor(clrOld); + dc.SelectFont(hFontOld); + } + } + +#ifndef _WIN32_WCE + BOOL StartTrackMouseLeave() + { + TRACKMOUSEEVENT tme = { 0 }; + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = m_hWnd; + return _TrackMouseEvent(&tme); + } +#endif // !_WIN32_WCE + +// Implementation helpers + bool IsUnderlined() const + { + return ((m_dwExtendedStyle & (HLINK_NOTUNDERLINED | HLINK_UNDERLINEHOVER)) == 0); + } + + bool IsNotUnderlined() const + { + return ((m_dwExtendedStyle & HLINK_NOTUNDERLINED) != 0); + } + + bool IsUnderlineHover() const + { + return ((m_dwExtendedStyle & HLINK_UNDERLINEHOVER) != 0); + } + + bool IsCommandButton() const + { + return ((m_dwExtendedStyle & HLINK_COMMANDBUTTON) != 0); + } + + bool IsNotifyButton() const + { + return ((m_dwExtendedStyle & HLINK_NOTIFYBUTTON) == HLINK_NOTIFYBUTTON); + } + + bool IsUsingTags() const + { + return ((m_dwExtendedStyle & HLINK_USETAGS) != 0); + } + + bool IsUsingTagsBold() const + { + return ((m_dwExtendedStyle & HLINK_USETAGSBOLD) == HLINK_USETAGSBOLD); + } + + bool IsUsingToolTip() const + { + return ((m_dwExtendedStyle & HLINK_NOTOOLTIP) == 0); + } + + bool IsAutoCreateLinkFont() const + { + return ((m_dwExtendedStyle & HLINK_AUTOCREATELINKFONT) == HLINK_AUTOCREATELINKFONT); + } + + bool IsSingleLine() const + { + return ((m_dwExtendedStyle & HLINK_SINGLELINE) == HLINK_SINGLELINE); + } +}; + +class CHyperLink : public CHyperLinkImpl +{ +public: + DECLARE_WND_CLASS(_T("WTL_HyperLink")) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CWaitCursor - displays a wait cursor + +class CWaitCursor +{ +public: +// Data + HCURSOR m_hWaitCursor; + HCURSOR m_hOldCursor; + bool m_bInUse; + +// Constructor/destructor + CWaitCursor(bool bSet = true, LPCTSTR lpstrCursor = IDC_WAIT, bool bSys = true) : m_hOldCursor(NULL), m_bInUse(false) + { + HINSTANCE hInstance = bSys ? NULL : ModuleHelper::GetResourceInstance(); + m_hWaitCursor = ::LoadCursor(hInstance, lpstrCursor); + ATLASSERT(m_hWaitCursor != NULL); + + if(bSet) + Set(); + } + + ~CWaitCursor() + { + Restore(); + } + +// Methods + bool Set() + { + if(m_bInUse) + return false; + m_hOldCursor = ::SetCursor(m_hWaitCursor); + m_bInUse = true; + return true; + } + + bool Restore() + { + if(!m_bInUse) + return false; + ::SetCursor(m_hOldCursor); + m_bInUse = false; + return true; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CCustomWaitCursor - for custom and animated cursors + +class CCustomWaitCursor : public CWaitCursor +{ +public: +// Constructor/destructor + CCustomWaitCursor(ATL::_U_STRINGorID cursor, bool bSet = true, HINSTANCE hInstance = NULL) : + CWaitCursor(false, IDC_WAIT, true) + { + if(hInstance == NULL) + hInstance = ModuleHelper::GetResourceInstance(); + m_hWaitCursor = (HCURSOR)::LoadImage(hInstance, cursor.m_lpstr, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE); + + if(bSet) + Set(); + } + + ~CCustomWaitCursor() + { + Restore(); +#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) + ::DestroyCursor(m_hWaitCursor); +#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CMultiPaneStatusBarCtrl - Status Bar with multiple panes + +template +class ATL_NO_VTABLE CMultiPaneStatusBarCtrlImpl : public ATL::CWindowImpl< T, TBase > +{ +public: + DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) + +// Data + enum { m_cxPaneMargin = 3 }; + + int m_nPanes; + int* m_pPane; + +// Constructor/destructor + CMultiPaneStatusBarCtrlImpl() : m_nPanes(0), m_pPane(NULL) + { } + + ~CMultiPaneStatusBarCtrlImpl() + { + delete [] m_pPane; + } + +// Methods + HWND Create(HWND hWndParent, LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) + { +#if (_MSC_VER >= 1300) + return ATL::CWindowImpl< T, TBase >::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase > _baseClass; + return _baseClass::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID); +#endif // !(_MSC_VER >= 1300) + } + + HWND Create(HWND hWndParent, UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) + { + const int cchMax = 128; // max text length is 127 for status bars (+1 for null) + TCHAR szText[cchMax] = { 0 }; + ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax); + return Create(hWndParent, szText, dwStyle, nID); + } + + BOOL SetPanes(int* pPanes, int nPanes, bool bSetText = true) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPanes > 0); + + m_nPanes = nPanes; + delete [] m_pPane; + m_pPane = NULL; + + ATLTRY(m_pPane = new int[nPanes]); + ATLASSERT(m_pPane != NULL); + if(m_pPane == NULL) + return FALSE; + + CTempBuffer buff; + int* pPanesPos = buff.Allocate(nPanes); + ATLASSERT(pPanesPos != NULL); + if(pPanesPos == NULL) + return FALSE; + + SecureHelper::memcpy_x(m_pPane, nPanes * sizeof(int), pPanes, nPanes * sizeof(int)); + + // get status bar DC and set font + CClientDC dc(m_hWnd); + HFONT hOldFont = dc.SelectFont(GetFont()); + + // get status bar borders + int arrBorders[3] = { 0 }; + GetBorders(arrBorders); + + const int cchBuff = 128; + TCHAR szBuff[cchBuff] = { 0 }; + SIZE size = { 0, 0 }; + int cxLeft = arrBorders[0]; + + // calculate right edge of each part + for(int i = 0; i < nPanes; i++) + { + if(pPanes[i] == ID_DEFAULT_PANE) + { + // make very large, will be resized later + pPanesPos[i] = INT_MAX / 2; + } + else + { + ::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff); + dc.GetTextExtent(szBuff, lstrlen(szBuff), &size); + T* pT = static_cast(this); + pT; + pPanesPos[i] = cxLeft + size.cx + arrBorders[2] + 2 * pT->m_cxPaneMargin; + } + cxLeft = pPanesPos[i]; + } + + BOOL bRet = SetParts(nPanes, pPanesPos); + + if(bRet && bSetText) + { + for(int i = 0; i < nPanes; i++) + { + if(pPanes[i] != ID_DEFAULT_PANE) + { + ::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff); + SetPaneText(m_pPane[i], szBuff); + } + } + } + + dc.SelectFont(hOldFont); + return bRet; + } + + bool GetPaneTextLength(int nPaneID, int* pcchLength = NULL, int* pnType = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return false; + + int nLength = GetTextLength(nIndex, pnType); + if(pcchLength != NULL) + *pcchLength = nLength; + + return true; + } + + BOOL GetPaneText(int nPaneID, LPTSTR lpstrText, int* pcchLength = NULL, int* pnType = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + int nLength = GetText(nIndex, lpstrText, pnType); + if(pcchLength != NULL) + *pcchLength = nLength; + + return TRUE; + } + + BOOL SetPaneText(int nPaneID, LPCTSTR lpstrText, int nType = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + return SetText(nIndex, lpstrText, nType); + } + + BOOL GetPaneRect(int nPaneID, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + return GetRect(nIndex, lpRect); + } + + BOOL SetPaneWidth(int nPaneID, int cxWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPaneID != ID_DEFAULT_PANE); // Can't resize this one + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + // get pane positions + CTempBuffer buff; + int* pPanesPos = buff.Allocate(m_nPanes); + if(pPanesPos == NULL) + return FALSE; + GetParts(m_nPanes, pPanesPos); + // calculate offset + int cxPaneWidth = pPanesPos[nIndex] - ((nIndex == 0) ? 0 : pPanesPos[nIndex - 1]); + int cxOff = cxWidth - cxPaneWidth; + // find variable width pane + int nDef = m_nPanes; + for(int i = 0; i < m_nPanes; i++) + { + if(m_pPane[i] == ID_DEFAULT_PANE) + { + nDef = i; + break; + } + } + // resize + if(nIndex < nDef) // before default pane + { + for(int i = nIndex; i < nDef; i++) + pPanesPos[i] += cxOff; + + } + else // after default one + { + for(int i = nDef; i < nIndex; i++) + pPanesPos[i] -= cxOff; + } + // set pane postions + return SetParts(m_nPanes, pPanesPos); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL GetPaneTipText(int nPaneID, LPTSTR lpstrText, int nSize) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + GetTipText(nIndex, lpstrText, nSize); + return TRUE; + } + + BOOL SetPaneTipText(int nPaneID, LPCTSTR lpstrText) + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + SetTipText(nIndex, lpstrText); + return TRUE; + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) + BOOL GetPaneIcon(int nPaneID, HICON& hIcon) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + hIcon = GetIcon(nIndex); + return TRUE; + } + + BOOL SetPaneIcon(int nPaneID, HICON hIcon) + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + return SetIcon(nIndex, hIcon); + } +#endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) + +// Message map and handlers + BEGIN_MSG_MAP(CMultiPaneStatusBarCtrlImpl< T >) + MESSAGE_HANDLER(WM_SIZE, OnSize) + END_MSG_MAP() + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + if(wParam != SIZE_MINIMIZED && m_nPanes > 0) + { + T* pT = static_cast(this); + pT->UpdatePanesLayout(); + } + return lRet; + } + +// Implementation + BOOL UpdatePanesLayout() + { + // get pane positions + CTempBuffer buff; + int* pPanesPos = buff.Allocate(m_nPanes); + ATLASSERT(pPanesPos != NULL); + if(pPanesPos == NULL) + return FALSE; + int nRet = GetParts(m_nPanes, pPanesPos); + ATLASSERT(nRet == m_nPanes); + if(nRet != m_nPanes) + return FALSE; + // calculate offset + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + int cxOff = rcClient.right - pPanesPos[m_nPanes - 1]; +#ifndef _WIN32_WCE + // Move panes left if size grip box is present + if((GetStyle() & SBARS_SIZEGRIP) != 0) + cxOff -= ::GetSystemMetrics(SM_CXVSCROLL) + ::GetSystemMetrics(SM_CXEDGE); +#endif // !_WIN32_WCE + // find variable width pane + int i; + for(i = 0; i < m_nPanes; i++) + { + if(m_pPane[i] == ID_DEFAULT_PANE) + break; + } + // resize all panes from the variable one to the right + if((i < m_nPanes) && (pPanesPos[i] + cxOff) > ((i == 0) ? 0 : pPanesPos[i - 1])) + { + for(; i < m_nPanes; i++) + pPanesPos[i] += cxOff; + } + // set pane postions + return SetParts(m_nPanes, pPanesPos); + } + + int GetPaneIndexFromID(int nPaneID) const + { + for(int i = 0; i < m_nPanes; i++) + { + if(m_pPane[i] == nPaneID) + return i; + } + + return -1; // not found + } +}; + +class CMultiPaneStatusBarCtrl : public CMultiPaneStatusBarCtrlImpl +{ +public: + DECLARE_WND_SUPERCLASS(_T("WTL_MultiPaneStatusBar"), GetWndClassName()) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPaneContainer - provides header with title and close button for panes + +// pane container extended styles +#define PANECNT_NOCLOSEBUTTON 0x00000001 +#define PANECNT_VERTICAL 0x00000002 +#define PANECNT_FLATBORDER 0x00000004 +#define PANECNT_NOBORDER 0x00000008 +#define PANECNT_DIVIDER 0x00000010 +#define PANECNT_GRADIENT 0x00000020 + +// Note: PANECNT_GRADIENT doesn't work with _ATL_NO_MSIMG + +template +class ATL_NO_VTABLE CPaneContainerImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CCustomDraw< T > +{ +public: + DECLARE_WND_CLASS_EX(NULL, 0, -1) + +// Constants + enum + { + m_cxyBorder = 2, + m_cxyTextOffset = 4, + m_cxyBtnOffset = 1, + + m_cchTitle = 80, + + m_cxImageTB = 13, + m_cyImageTB = 11, + m_cxyBtnAddTB = 7, + + m_cxToolBar = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + m_cxyBtnOffset, + + m_xBtnImageLeft = 6, + m_yBtnImageTop = 5, + m_xBtnImageRight = 12, + m_yBtnImageBottom = 11, + + m_nCloseBtnID = ID_PANE_CLOSE + }; + +// Data members + CToolBarCtrl m_tb; + ATL::CWindow m_wndClient; + int m_cxyHeader; + TCHAR m_szTitle[m_cchTitle]; + DWORD m_dwExtendedStyle; // Pane container specific extended styles + HFONT m_hFont; + bool m_bInternalFont; + + +// Constructor + CPaneContainerImpl() : m_cxyHeader(0), m_dwExtendedStyle(0), m_hFont(NULL), m_bInternalFont(false) + { + m_szTitle[0] = 0; + } + +// Attributes + DWORD GetPaneContainerExtendedStyle() const + { + return m_dwExtendedStyle; + } + + DWORD SetPaneContainerExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + if(m_hWnd != NULL) + { + T* pT = static_cast(this); + bool bUpdate = false; + + if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) != 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)) // add close button + { + pT->CreateCloseButton(); + bUpdate = true; + } + else if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) == 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) != 0)) // remove close button + { + pT->DestroyCloseButton(); + bUpdate = true; + } + + if((dwPrevStyle & PANECNT_VERTICAL) != (m_dwExtendedStyle & PANECNT_VERTICAL)) // change orientation + { + pT->CalcSize(); + bUpdate = true; + } + + if((dwPrevStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER)) != + (m_dwExtendedStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER))) // change border + { + bUpdate = true; + } + +#if (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420) + if((dwPrevStyle & PANECNT_GRADIENT) != (m_dwExtendedStyle & PANECNT_GRADIENT)) // change background + { + bUpdate = true; + } +#endif // (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420) + + if(bUpdate) + pT->UpdateLayout(); + } + return dwPrevStyle; + } + + HWND GetClient() const + { + return m_wndClient; + } + + HWND SetClient(HWND hWndClient) + { + HWND hWndOldClient = m_wndClient; + m_wndClient = hWndClient; + if(m_hWnd != NULL) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + return hWndOldClient; + } + + BOOL GetTitle(LPTSTR lpstrTitle, int cchLength) const + { + ATLASSERT(lpstrTitle != NULL); + + errno_t nRet = SecureHelper::strncpy_x(lpstrTitle, cchLength, m_szTitle, _TRUNCATE); + + return (nRet == 0 || nRet == STRUNCATE); + } + + BOOL SetTitle(LPCTSTR lpstrTitle) + { + ATLASSERT(lpstrTitle != NULL); + + errno_t nRet = SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE); + bool bRet = (nRet == 0 || nRet == STRUNCATE); + if(bRet && m_hWnd != NULL) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + + return bRet; + } + + int GetTitleLength() const + { + return lstrlen(m_szTitle); + } + +// Methods + HWND Create(HWND hWndParent, LPCTSTR lpstrTitle = NULL, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL) + { + if(lpstrTitle != NULL) + SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE); +#if (_MSC_VER >= 1300) + return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + return _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); +#endif // !(_MSC_VER >= 1300) + } + + HWND Create(HWND hWndParent, UINT uTitleID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL) + { + if(uTitleID != 0U) + ::LoadString(ModuleHelper::GetResourceInstance(), uTitleID, m_szTitle, m_cchTitle); +#if (_MSC_VER >= 1300) + return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + return _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); +#endif // !(_MSC_VER >= 1300) + } + + BOOL SubclassWindow(HWND hWnd) + { +#if (_MSC_VER >= 1300) + BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + BOOL bRet = _baseClass::SubclassWindow(hWnd); +#endif // !(_MSC_VER >= 1300) + if(bRet != FALSE) + { + T* pT = static_cast(this); + pT->Init(); + + RECT rect = { 0 }; + GetClientRect(&rect); + pT->UpdateLayout(rect.right, rect.bottom); + } + + return bRet; + } + + BOOL EnableCloseButton(BOOL bEnable) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + pT; // avoid level 4 warning + return (m_tb.m_hWnd != NULL) ? m_tb.EnableButton(pT->m_nCloseBtnID, bEnable) : FALSE; + } + + void UpdateLayout() + { + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + T* pT = static_cast(this); + pT->UpdateLayout(rcClient.right, rcClient.bottom); + } + +// Message map and handlers + BEGIN_MSG_MAP(CPaneContainerImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_GETFONT, OnGetFont) + MESSAGE_HANDLER(WM_SETFONT, OnSetFont) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_NOTIFY, OnNotify) + MESSAGE_HANDLER(WM_COMMAND, OnCommand) + FORWARD_NOTIFICATIONS() + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Init(); + + return 0; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(m_bInternalFont) + { + ::DeleteObject(m_hFont); + m_hFont = NULL; + m_bInternalFont = false; + } + + return 0; + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + return 0; + } + + LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(m_wndClient.m_hWnd != NULL) + m_wndClient.SetFocus(); + return 0; + } + + LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return (LRESULT)m_hFont; + } + + LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + if(m_bInternalFont) + { + ::DeleteObject(m_hFont); + m_bInternalFont = false; + } + + m_hFont = (HFONT)wParam; + + T* pT = static_cast(this); + pT->CalcSize(); + + if((BOOL)lParam != FALSE) + pT->UpdateLayout(); + + return 0; + } + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->DrawPaneTitleBackground((HDC)wParam); + + return 1; + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + if(wParam != NULL) + { + pT->DrawPaneTitle((HDC)wParam); + + if(m_wndClient.m_hWnd == NULL) // no client window + pT->DrawPane((HDC)wParam); + } + else + { + CPaintDC dc(m_hWnd); + pT->DrawPaneTitle(dc.m_hDC); + + if(m_wndClient.m_hWnd == NULL) // no client window + pT->DrawPane(dc.m_hDC); + } + + return 0; + } + + LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(m_tb.m_hWnd == NULL) + { + bHandled = FALSE; + return 1; + } + + T* pT = static_cast(this); + pT; + LPNMHDR lpnmh = (LPNMHDR)lParam; + LRESULT lRet = 0; + + // pass toolbar custom draw notifications to the base class + if(lpnmh->code == NM_CUSTOMDRAW && lpnmh->hwndFrom == m_tb.m_hWnd) + lRet = CCustomDraw< T >::OnCustomDraw(0, lpnmh, bHandled); +#ifndef _WIN32_WCE + // tooltip notifications come with the tooltip window handle and button ID, + // pass them to the parent if we don't handle them + else if(lpnmh->code == TTN_GETDISPINFO && lpnmh->idFrom == pT->m_nCloseBtnID) + bHandled = pT->GetToolTipText(lpnmh); +#endif // !_WIN32_WCE + // only let notifications not from the toolbar go to the parent + else if(lpnmh->hwndFrom != m_tb.m_hWnd && lpnmh->idFrom != pT->m_nCloseBtnID) + bHandled = FALSE; + + return lRet; + } + + LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + // if command comes from the close button, substitute HWND of the pane container instead + if(m_tb.m_hWnd != NULL && (HWND)lParam == m_tb.m_hWnd) + return ::SendMessage(GetParent(), WM_COMMAND, wParam, (LPARAM)m_hWnd); + + bHandled = FALSE; + return 1; + } + +// Custom draw overrides + DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_NOTIFYITEMDRAW; // we need per-item notifications + } + + DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_NOTIFYPOSTPAINT; + } + + DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw) + { + CDCHandle dc = lpNMCustomDraw->hdc; +#if (_WIN32_IE >= 0x0400) + RECT& rc = lpNMCustomDraw->rc; +#else // !(_WIN32_IE >= 0x0400) + RECT rc = { 0 }; + m_tb.GetItemRect(0, &rc); +#endif // !(_WIN32_IE >= 0x0400) + + RECT rcImage = { m_xBtnImageLeft, m_yBtnImageTop, m_xBtnImageRight + 1, m_yBtnImageBottom + 1 }; + ::OffsetRect(&rcImage, rc.left, rc.top); + T* pT = static_cast(this); + + if((lpNMCustomDraw->uItemState & CDIS_DISABLED) != 0) + { + RECT rcShadow = rcImage; + ::OffsetRect(&rcShadow, 1, 1); + CPen pen1; + pen1.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DHILIGHT)); + pT->DrawButtonImage(dc, rcShadow, pen1); + CPen pen2; + pen2.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DSHADOW)); + pT->DrawButtonImage(dc, rcImage, pen2); + } + else + { + if((lpNMCustomDraw->uItemState & CDIS_SELECTED) != 0) + ::OffsetRect(&rcImage, 1, 1); + CPen pen; + pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNTEXT)); + pT->DrawButtonImage(dc, rcImage, pen); + } + + return CDRF_DODEFAULT; // continue with the default item painting + } + +// Implementation - overrideable methods + void Init() + { + if(m_hFont == NULL) + { + // The same as AtlCreateControlFont() for horizontal pane +#ifndef _WIN32_WCE + LOGFONT lf = { 0 }; + ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE); + if(IsVertical()) + lf.lfEscapement = 900; // 90 degrees + m_hFont = ::CreateFontIndirect(&lf); +#else // CE specific + m_hFont = (HFONT)::GetStockObject(SYSTEM_FONT); + if(IsVertical()) + { + CLogFont lf(m_hFont); + lf.lfEscapement = 900; // 90 degrees + m_hFont = ::CreateFontIndirect(&lf); + } +#endif // _WIN32_WCE + m_bInternalFont = true; + } + + T* pT = static_cast(this); + pT->CalcSize(); + + if((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0) + pT->CreateCloseButton(); + } + + void UpdateLayout(int cxWidth, int cyHeight) + { + ATLASSERT(::IsWindow(m_hWnd)); + RECT rect = { 0 }; + + if(IsVertical()) + { + ::SetRect(&rect, 0, 0, m_cxyHeader, cyHeight); + if(m_tb.m_hWnd != NULL) + m_tb.SetWindowPos(NULL, m_cxyBorder, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + + if(m_wndClient.m_hWnd != NULL) + m_wndClient.SetWindowPos(NULL, m_cxyHeader, 0, cxWidth - m_cxyHeader, cyHeight, SWP_NOZORDER); + else + rect.right = cxWidth; + } + else + { + ::SetRect(&rect, 0, 0, cxWidth, m_cxyHeader); + if(m_tb.m_hWnd != NULL) + m_tb.SetWindowPos(NULL, rect.right - m_cxToolBar, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + + if(m_wndClient.m_hWnd != NULL) + m_wndClient.SetWindowPos(NULL, 0, m_cxyHeader, cxWidth, cyHeight - m_cxyHeader, SWP_NOZORDER); + else + rect.bottom = cyHeight; + } + + InvalidateRect(&rect); + } + + void CreateCloseButton() + { + ATLASSERT(m_tb.m_hWnd == NULL); + // create toolbar for the "x" button + m_tb.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NOMOVEY | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT, 0); + ATLASSERT(m_tb.IsWindow()); + + if(m_tb.m_hWnd != NULL) + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + + m_tb.SetButtonStructSize(); + + TBBUTTON tbbtn = { 0 }; + tbbtn.idCommand = pT->m_nCloseBtnID; + tbbtn.fsState = TBSTATE_ENABLED; + tbbtn.fsStyle = BTNS_BUTTON; + m_tb.AddButtons(1, &tbbtn); + + m_tb.SetBitmapSize(m_cxImageTB, m_cyImageTB); + m_tb.SetButtonSize(m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB); + + if(IsVertical()) + m_tb.SetWindowPos(NULL, m_cxyBorder + m_cxyBtnOffset, m_cxyBorder + m_cxyBtnOffset, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB + 1, SWP_NOZORDER | SWP_NOACTIVATE); + else + m_tb.SetWindowPos(NULL, 0, 0, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB + 1, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + } + } + + void DestroyCloseButton() + { + if(m_tb.m_hWnd != NULL) + m_tb.DestroyWindow(); + } + + void CalcSize() + { + T* pT = static_cast(this); + CFontHandle font = pT->GetTitleFont(); + if(font.IsNull()) + font = (HFONT)::GetStockObject(SYSTEM_FONT); + LOGFONT lf = { 0 }; + font.GetLogFont(lf); + if(IsVertical()) + { + m_cxyHeader = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + 1; + } + else + { + int cyFont = abs(lf.lfHeight) + m_cxyBorder + 2 * m_cxyTextOffset; + int cyBtn = m_cyImageTB + m_cxyBtnAddTB + m_cxyBorder + 2 * m_cxyBtnOffset + 1; + m_cxyHeader = __max(cyFont, cyBtn); + } + } + + HFONT GetTitleFont() const + { + return m_hFont; + } + +#ifndef _WIN32_WCE + BOOL GetToolTipText(LPNMHDR /*lpnmh*/) + { + return FALSE; + } +#endif // !_WIN32_WCE + + void DrawPaneTitle(CDCHandle dc) + { + RECT rect = { 0 }; + GetClientRect(&rect); + + UINT uBorder = BF_LEFT | BF_TOP | BF_ADJUST; + if(IsVertical()) + { + rect.right = rect.left + m_cxyHeader; + uBorder |= BF_BOTTOM; + } + else + { + rect.bottom = rect.top + m_cxyHeader; + uBorder |= BF_RIGHT; + } + + if((m_dwExtendedStyle & PANECNT_NOBORDER) == 0) + { + if((m_dwExtendedStyle & PANECNT_FLATBORDER) != 0) + uBorder |= BF_FLAT; + dc.DrawEdge(&rect, EDGE_ETCHED, uBorder); + } + + if((m_dwExtendedStyle & PANECNT_DIVIDER) != 0) + { + uBorder = BF_FLAT | BF_ADJUST | (IsVertical() ? BF_RIGHT : BF_BOTTOM); + dc.DrawEdge(&rect, BDR_SUNKENOUTER, uBorder); + } + + // draw title text + dc.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)); + dc.SetBkMode(TRANSPARENT); + T* pT = static_cast(this); + HFONT hFontOld = dc.SelectFont(pT->GetTitleFont()); +#if defined(_WIN32_WCE) && !defined(DT_END_ELLIPSIS) + const UINT DT_END_ELLIPSIS = 0; +#endif // defined(_WIN32_WCE) && !defined(DT_END_ELLIPSIS) + + if(IsVertical()) + { + rect.top += m_cxyTextOffset; + rect.bottom -= m_cxyTextOffset; + if(m_tb.m_hWnd != NULL) + rect.top += m_cxToolBar;; + + RECT rcCalc = { rect.left, rect.bottom, rect.right, rect.top }; + int cxFont = dc.DrawText(m_szTitle, -1, &rcCalc, DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS | DT_CALCRECT); + RECT rcText = { 0 }; + rcText.left = (rect.right - rect.left - cxFont) / 2; + rcText.right = rcText.left + (rect.bottom - rect.top); + rcText.top = rect.bottom; + rcText.bottom = rect.top; + dc.DrawText(m_szTitle, -1, &rcText, DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS); + } + else + { + rect.left += m_cxyTextOffset; + rect.right -= m_cxyTextOffset; + if(m_tb.m_hWnd != NULL) + rect.right -= m_cxToolBar;; + + dc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS); + } + + dc.SelectFont(hFontOld); + } + + void DrawPaneTitleBackground(CDCHandle dc) + { + RECT rect = { 0 }; + GetClientRect(&rect); + if(IsVertical()) + rect.right = m_cxyHeader; + else + rect.bottom = m_cxyHeader; + +#if (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420) + if((m_dwExtendedStyle & PANECNT_GRADIENT) != 0) + dc.GradientFillRect(rect, ::GetSysColor(COLOR_WINDOW), ::GetSysColor(COLOR_3DFACE), IsVertical()); + else +#endif // (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420) + dc.FillRect(&rect, COLOR_3DFACE); + } + + // called only if pane is empty + void DrawPane(CDCHandle dc) + { + RECT rect = { 0 }; + GetClientRect(&rect); + if(IsVertical()) + rect.left += m_cxyHeader; + else + rect.top += m_cxyHeader; + if((GetExStyle() & WS_EX_CLIENTEDGE) == 0) + dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + dc.FillRect(&rect, COLOR_APPWORKSPACE); + } + + // drawing helper - draws "x" button image + void DrawButtonImage(CDCHandle dc, RECT& rcImage, HPEN hPen) + { +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + HPEN hPenOld = dc.SelectPen(hPen); + + dc.MoveTo(rcImage.left, rcImage.top); + dc.LineTo(rcImage.right, rcImage.bottom); + dc.MoveTo(rcImage.left + 1, rcImage.top); + dc.LineTo(rcImage.right + 1, rcImage.bottom); + + dc.MoveTo(rcImage.left, rcImage.bottom - 1); + dc.LineTo(rcImage.right, rcImage.top - 1); + dc.MoveTo(rcImage.left + 1, rcImage.bottom - 1); + dc.LineTo(rcImage.right + 1, rcImage.top - 1); + + dc.SelectPen(hPenOld); +#else // (_WIN32_WCE < 400) + rcImage; + hPen; + // no support for the "x" button image +#endif // (_WIN32_WCE < 400) + } + + bool IsVertical() const + { + return ((m_dwExtendedStyle & PANECNT_VERTICAL) != 0); + } +}; + +class CPaneContainer : public CPaneContainerImpl +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_PaneContainer"), 0, -1) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CSortListViewCtrl - implements sorting for a listview control + +// sort listview extended styles +#define SORTLV_USESHELLBITMAPS 0x00000001 + +// Notification sent to parent when sort column is changed by user clicking header. +#define SLVN_SORTCHANGED LVN_LAST + +// A LPNMSORTLISTVIEW is sent with the SLVN_SORTCHANGED notification +typedef struct tagNMSORTLISTVIEW +{ + NMHDR hdr; + int iNewSortColumn; + int iOldSortColumn; +} NMSORTLISTVIEW, *LPNMSORTLISTVIEW; + +// Column sort types. Can be set on a per-column basis with the SetColumnSortType method. +enum +{ + LVCOLSORT_NONE, + LVCOLSORT_TEXT, // default + LVCOLSORT_TEXTNOCASE, + LVCOLSORT_LONG, + LVCOLSORT_DOUBLE, + LVCOLSORT_DECIMAL, + LVCOLSORT_DATETIME, + LVCOLSORT_DATE, + LVCOLSORT_TIME, + LVCOLSORT_CUSTOM, + LVCOLSORT_LAST = LVCOLSORT_CUSTOM +}; + + +template +class CSortListViewImpl +{ +public: + enum + { + m_cchCmpTextMax = 32, // overrideable + m_cxSortImage = 16, + m_cySortImage = 15, + m_cxSortArrow = 11, + m_cySortArrow = 6, + m_iSortUp = 0, // index of sort bitmaps + m_iSortDown = 1, + m_nShellSortUpID = 133 + }; + + // passed to LVCompare functions as lParam1 and lParam2 + struct LVCompareParam + { + int iItem; + DWORD_PTR dwItemData; + union + { + long lValue; + double dblValue; + DECIMAL decValue; + LPCTSTR pszValue; + }; + }; + + // passed to LVCompare functions as the lParamSort parameter + struct LVSortInfo + { + T* pT; + int iSortCol; + bool bDescending; + }; + + bool m_bSortDescending; + bool m_bCommCtrl6; + int m_iSortColumn; + CBitmap m_bmSort[2]; + int m_fmtOldSortCol; + HBITMAP m_hbmOldSortCol; + DWORD m_dwSortLVExtendedStyle; + ATL::CSimpleArray m_arrColSortType; + bool m_bUseWaitCursor; + + CSortListViewImpl() : + m_bSortDescending(false), + m_bCommCtrl6(false), + m_iSortColumn(-1), + m_fmtOldSortCol(0), + m_hbmOldSortCol(NULL), + m_dwSortLVExtendedStyle(SORTLV_USESHELLBITMAPS), + m_bUseWaitCursor(true) + { +#ifndef _WIN32_WCE + DWORD dwMajor = 0; + DWORD dwMinor = 0; + HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor); + m_bCommCtrl6 = SUCCEEDED(hRet) && dwMajor >= 6; +#endif // !_WIN32_WCE + } + +// Attributes + void SetSortColumn(int iCol) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + CHeaderCtrl header = pT->GetHeader(); + ATLASSERT(header.m_hWnd != NULL); + ATLASSERT(iCol >= -1 && iCol < m_arrColSortType.GetSize()); + + int iOldSortCol = m_iSortColumn; + m_iSortColumn = iCol; + if(m_bCommCtrl6) + { +#ifndef HDF_SORTUP + const int HDF_SORTUP = 0x0400; +#endif // HDF_SORTUP +#ifndef HDF_SORTDOWN + const int HDF_SORTDOWN = 0x0200; +#endif // HDF_SORTDOWN + const int nMask = HDF_SORTUP | HDF_SORTDOWN; + HDITEM hditem = { HDI_FORMAT }; + if(iOldSortCol != iCol && iOldSortCol >= 0 && header.GetItem(iOldSortCol, &hditem)) + { + hditem.fmt &= ~nMask; + header.SetItem(iOldSortCol, &hditem); + } + if(iCol >= 0 && header.GetItem(iCol, &hditem)) + { + hditem.fmt &= ~nMask; + hditem.fmt |= m_bSortDescending ? HDF_SORTDOWN : HDF_SORTUP; + header.SetItem(iCol, &hditem); + } + return; + } + + if(m_bmSort[m_iSortUp].IsNull()) + pT->CreateSortBitmaps(); + + // restore previous sort column's bitmap, if any, and format + HDITEM hditem = { HDI_BITMAP | HDI_FORMAT }; + if(iOldSortCol != iCol && iOldSortCol >= 0) + { + hditem.hbm = m_hbmOldSortCol; + hditem.fmt = m_fmtOldSortCol; + header.SetItem(iOldSortCol, &hditem); + } + + // save new sort column's bitmap and format, and add our sort bitmap + if(iCol >= 0 && header.GetItem(iCol, &hditem)) + { + if(iOldSortCol != iCol) + { + m_fmtOldSortCol = hditem.fmt; + m_hbmOldSortCol = hditem.hbm; + } + hditem.fmt &= ~HDF_IMAGE; + hditem.fmt |= HDF_BITMAP | HDF_BITMAP_ON_RIGHT; + int i = m_bSortDescending ? m_iSortDown : m_iSortUp; + hditem.hbm = m_bmSort[i]; + header.SetItem(iCol, &hditem); + } + } + + int GetSortColumn() const + { + return m_iSortColumn; + } + + void SetColumnSortType(int iCol, WORD wType) + { + ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize()); + ATLASSERT(wType >= LVCOLSORT_NONE && wType <= LVCOLSORT_LAST); + m_arrColSortType[iCol] = wType; + } + + WORD GetColumnSortType(int iCol) const + { + ATLASSERT((iCol >= 0) && iCol < m_arrColSortType.GetSize()); + return m_arrColSortType[iCol]; + } + + int GetColumnCount() const + { + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + CHeaderCtrl header = pT->GetHeader(); + return header.m_hWnd != NULL ? header.GetItemCount() : 0; + } + + bool IsSortDescending() const + { + return m_bSortDescending; + } + + DWORD GetSortListViewExtendedStyle() const + { + return m_dwSortLVExtendedStyle; + } + + DWORD SetSortListViewExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwSortLVExtendedStyle; + if(dwMask == 0) + m_dwSortLVExtendedStyle = dwExtendedStyle; + else + m_dwSortLVExtendedStyle = (m_dwSortLVExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + return dwPrevStyle; + } + +// Operations + bool DoSortItems(int iCol, bool bDescending = false) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize()); + + WORD wType = m_arrColSortType[iCol]; + if(wType == LVCOLSORT_NONE) + return false; + + int nCount = pT->GetItemCount(); + if(nCount < 2) + { + m_bSortDescending = bDescending; + SetSortColumn(iCol); + return true; + } + + CWaitCursor waitCursor(false); + if(m_bUseWaitCursor) + waitCursor.Set(); + + LVCompareParam* pParam = NULL; + ATLTRY(pParam = new LVCompareParam[nCount]); + PFNLVCOMPARE pFunc = NULL; + TCHAR pszTemp[pT->m_cchCmpTextMax] = { 0 }; + bool bStrValue = false; + + switch(wType) + { + case LVCOLSORT_TEXT: + pFunc = (PFNLVCOMPARE)pT->LVCompareText; + case LVCOLSORT_TEXTNOCASE: + if(pFunc == NULL) + pFunc = (PFNLVCOMPARE)pT->LVCompareTextNoCase; + case LVCOLSORT_CUSTOM: + { + if(pFunc == NULL) + pFunc = (PFNLVCOMPARE)pT->LVCompareCustom; + + for(int i = 0; i < nCount; i++) + { + pParam[i].iItem = i; + pParam[i].dwItemData = pT->GetItemData(i); + pParam[i].pszValue = new TCHAR[pT->m_cchCmpTextMax]; + pT->GetItemText(i, iCol, (LPTSTR)pParam[i].pszValue, pT->m_cchCmpTextMax); + pT->SetItemData(i, (DWORD_PTR)&pParam[i]); + } + bStrValue = true; + } + break; + case LVCOLSORT_LONG: + { + pFunc = (PFNLVCOMPARE)pT->LVCompareLong; + for(int i = 0; i < nCount; i++) + { + pParam[i].iItem = i; + pParam[i].dwItemData = pT->GetItemData(i); + pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); + pParam[i].lValue = pT->StrToLong(pszTemp); + pT->SetItemData(i, (DWORD_PTR)&pParam[i]); + } + } + break; + case LVCOLSORT_DOUBLE: + { + pFunc = (PFNLVCOMPARE)pT->LVCompareDouble; + for(int i = 0; i < nCount; i++) + { + pParam[i].iItem = i; + pParam[i].dwItemData = pT->GetItemData(i); + pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); + pParam[i].dblValue = pT->StrToDouble(pszTemp); + pT->SetItemData(i, (DWORD_PTR)&pParam[i]); + } + } + break; + case LVCOLSORT_DECIMAL: + { + pFunc = (PFNLVCOMPARE)pT->LVCompareDecimal; + for(int i = 0; i < nCount; i++) + { + pParam[i].iItem = i; + pParam[i].dwItemData = pT->GetItemData(i); + pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); + pT->StrToDecimal(pszTemp, &pParam[i].decValue); + pT->SetItemData(i, (DWORD_PTR)&pParam[i]); + } + } + break; + case LVCOLSORT_DATETIME: + case LVCOLSORT_DATE: + case LVCOLSORT_TIME: + { + pFunc = (PFNLVCOMPARE)pT->LVCompareDouble; + DWORD dwFlags = LOCALE_NOUSEROVERRIDE; + if(wType == LVCOLSORT_DATE) + dwFlags |= VAR_DATEVALUEONLY; + else if(wType == LVCOLSORT_TIME) + dwFlags |= VAR_TIMEVALUEONLY; + for(int i = 0; i < nCount; i++) + { + pParam[i].iItem = i; + pParam[i].dwItemData = pT->GetItemData(i); + pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); + pParam[i].dblValue = pT->DateStrToDouble(pszTemp, dwFlags); + pT->SetItemData(i, (DWORD_PTR)&pParam[i]); + } + } + break; + default: + ATLTRACE2(atlTraceUI, 0, _T("Unknown value for sort type in CSortListViewImpl::DoSortItems()\n")); + break; + } // switch(wType) + + ATLASSERT(pFunc != NULL); + LVSortInfo lvsi = { pT, iCol, bDescending }; + bool bRet = ((BOOL)pT->DefWindowProc(LVM_SORTITEMS, (WPARAM)&lvsi, (LPARAM)pFunc) != FALSE); + for(int i = 0; i < nCount; i++) + { + DWORD_PTR dwItemData = pT->GetItemData(i); + LVCompareParam* p = (LVCompareParam*)dwItemData; + ATLASSERT(p != NULL); + if(bStrValue) + delete [] (TCHAR*)p->pszValue; + pT->SetItemData(i, p->dwItemData); + } + delete [] pParam; + + if(bRet) + { + m_bSortDescending = bDescending; + SetSortColumn(iCol); + } + + if(m_bUseWaitCursor) + waitCursor.Restore(); + + return bRet; + } + + void CreateSortBitmaps() + { + if((m_dwSortLVExtendedStyle & SORTLV_USESHELLBITMAPS) != 0) + { + bool bFree = false; + LPCTSTR pszModule = _T("shell32.dll"); + HINSTANCE hShell = ::GetModuleHandle(pszModule); + + if (hShell == NULL) + { + hShell = ::LoadLibrary(pszModule); + bFree = true; + } + + if (hShell != NULL) + { + bool bSuccess = true; + for(int i = m_iSortUp; i <= m_iSortDown; i++) + { + if(!m_bmSort[i].IsNull()) + m_bmSort[i].DeleteObject(); + m_bmSort[i] = (HBITMAP)::LoadImage(hShell, MAKEINTRESOURCE(m_nShellSortUpID + i), +#ifndef _WIN32_WCE + IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); +#else // CE specific + IMAGE_BITMAP, 0, 0, 0); +#endif // _WIN32_WCE + if(m_bmSort[i].IsNull()) + { + bSuccess = false; + break; + } + } + if(bFree) + ::FreeLibrary(hShell); + if(bSuccess) + return; + } + } + + T* pT = static_cast(this); + for(int i = m_iSortUp; i <= m_iSortDown; i++) + { + if(!m_bmSort[i].IsNull()) + m_bmSort[i].DeleteObject(); + + CDC dcMem; + CClientDC dc(::GetDesktopWindow()); + dcMem.CreateCompatibleDC(dc.m_hDC); + m_bmSort[i].CreateCompatibleBitmap(dc.m_hDC, m_cxSortImage, m_cySortImage); + HBITMAP hbmOld = dcMem.SelectBitmap(m_bmSort[i]); + RECT rc = { 0, 0, m_cxSortImage, m_cySortImage }; + pT->DrawSortBitmap(dcMem.m_hDC, i, &rc); + dcMem.SelectBitmap(hbmOld); + dcMem.DeleteDC(); + } + } + + void NotifyParentSortChanged(int iNewSortCol, int iOldSortCol) + { + T* pT = static_cast(this); + int nID = pT->GetDlgCtrlID(); + NMSORTLISTVIEW nm = { { pT->m_hWnd, (UINT_PTR)nID, SLVN_SORTCHANGED }, iNewSortCol, iOldSortCol }; + ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nm); + } + +// Overrideables + int CompareItemsCustom(LVCompareParam* /*pItem1*/, LVCompareParam* /*pItem2*/, int /*iSortCol*/) + { + // pItem1 and pItem2 contain valid iItem, dwItemData, and pszValue members. + // If item1 > item2 return 1, if item1 < item2 return -1, else return 0. + return 0; + } + + void DrawSortBitmap(CDCHandle dc, int iBitmap, LPRECT prc) + { + dc.FillRect(prc, ::GetSysColorBrush(COLOR_BTNFACE)); + HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW)); + CPen pen; + pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNSHADOW)); + HPEN hpenOld = dc.SelectPen(pen); + POINT ptOrg = { (m_cxSortImage - m_cxSortArrow) / 2, (m_cySortImage - m_cySortArrow) / 2 }; + if(iBitmap == m_iSortUp) + { + POINT pts[3] = + { + { ptOrg.x + m_cxSortArrow / 2, ptOrg.y }, + { ptOrg.x, ptOrg.y + m_cySortArrow - 1 }, + { ptOrg.x + m_cxSortArrow - 1, ptOrg.y + m_cySortArrow - 1 } + }; + dc.Polygon(pts, 3); + } + else + { + POINT pts[3] = + { + { ptOrg.x, ptOrg.y }, + { ptOrg.x + m_cxSortArrow / 2, ptOrg.y + m_cySortArrow - 1 }, + { ptOrg.x + m_cxSortArrow - 1, ptOrg.y } + }; + dc.Polygon(pts, 3); + } + dc.SelectBrush(hbrOld); + dc.SelectPen(hpenOld); + } + + double DateStrToDouble(LPCTSTR lpstr, DWORD dwFlags) + { + ATLASSERT(lpstr != NULL); + if(lpstr == NULL || lpstr[0] == _T('\0')) + return 0; + + USES_CONVERSION; + HRESULT hRet = E_FAIL; + DATE dRet = 0; + if (FAILED(hRet = ::VarDateFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, dwFlags, &dRet))) + { + ATLTRACE2(atlTraceUI, 0, _T("VarDateFromStr failed with result of 0x%8.8X\n"), hRet); + dRet = 0; + } + return dRet; + } + + long StrToLong(LPCTSTR lpstr) + { + ATLASSERT(lpstr != NULL); + if(lpstr == NULL || lpstr[0] == _T('\0')) + return 0; + + USES_CONVERSION; + HRESULT hRet = E_FAIL; + long lRet = 0; + if (FAILED(hRet = ::VarI4FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &lRet))) + { + ATLTRACE2(atlTraceUI, 0, _T("VarI4FromStr failed with result of 0x%8.8X\n"), hRet); + lRet = 0; + } + return lRet; + } + + double StrToDouble(LPCTSTR lpstr) + { + ATLASSERT(lpstr != NULL); + if(lpstr == NULL || lpstr[0] == _T('\0')) + return 0; + + USES_CONVERSION; + HRESULT hRet = E_FAIL; + double dblRet = 0; + if (FAILED(hRet = ::VarR8FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &dblRet))) + { + ATLTRACE2(atlTraceUI, 0, _T("VarR8FromStr failed with result of 0x%8.8X\n"), hRet); + dblRet = 0; + } + return dblRet; + } + + bool StrToDecimal(LPCTSTR lpstr, DECIMAL* pDecimal) + { + ATLASSERT(lpstr != NULL); + ATLASSERT(pDecimal != NULL); + if(lpstr == NULL || pDecimal == NULL) + return false; + + USES_CONVERSION; + HRESULT hRet = E_FAIL; + if (FAILED(hRet = ::VarDecFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, pDecimal))) + { + ATLTRACE2(atlTraceUI, 0, _T("VarDecFromStr failed with result of 0x%8.8X\n"), hRet); + pDecimal->Lo64 = 0; + pDecimal->Hi32 = 0; + pDecimal->signscale = 0; + return false; + } + return true; + } + +// Overrideable PFNLVCOMPARE functions + static int CALLBACK LVCompareText(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = lstrcmp(pParam1->pszValue, pParam2->pszValue); + return pInfo->bDescending ? -nRet : nRet; + } + + static int CALLBACK LVCompareTextNoCase(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = lstrcmpi(pParam1->pszValue, pParam2->pszValue); + return pInfo->bDescending ? -nRet : nRet; + } + + static int CALLBACK LVCompareLong(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = 0; + if(pParam1->lValue > pParam2->lValue) + nRet = 1; + else if(pParam1->lValue < pParam2->lValue) + nRet = -1; + return pInfo->bDescending ? -nRet : nRet; + } + + static int CALLBACK LVCompareDouble(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = 0; + if(pParam1->dblValue > pParam2->dblValue) + nRet = 1; + else if(pParam1->dblValue < pParam2->dblValue) + nRet = -1; + return pInfo->bDescending ? -nRet : nRet; + } + + static int CALLBACK LVCompareCustom(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = pInfo->pT->CompareItemsCustom(pParam1, pParam2, pInfo->iSortCol); + return pInfo->bDescending ? -nRet : nRet; + } + +#ifndef _WIN32_WCE + static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = (int)::VarDecCmp(&pParam1->decValue, &pParam2->decValue); + nRet--; + return pInfo->bDescending ? -nRet : nRet; + } +#else + // Compare mantissas, ignore sign and scale + static int CompareMantissas(const DECIMAL& decLeft, const DECIMAL& decRight) + { + if (decLeft.Hi32 < decRight.Hi32) + { + return -1; + } + if (decLeft.Hi32 > decRight.Hi32) + { + return 1; + } + // Here, decLeft.Hi32 == decRight.Hi32 + if (decLeft.Lo64 < decRight.Lo64) + { + return -1; + } + if (decLeft.Lo64 > decRight.Lo64) + { + return 1; + } + return 0; + } + + // return values: VARCMP_LT, VARCMP_EQ, VARCMP_GT, VARCMP_NULL + static HRESULT VarDecCmp(const DECIMAL* pdecLeft, const DECIMAL* pdecRight) + { + static const ULONG powersOfTen[] = + { + 10ul, + 100ul, + 1000ul, + 10000ul, + 100000ul, + 1000000ul, + 10000000ul, + 100000000ul, + 1000000000ul + }; + static const int largestPower = sizeof(powersOfTen) / sizeof(powersOfTen[0]); + if (!pdecLeft || !pdecRight) + { + return VARCMP_NULL; + } + + // Degenerate case - at least one comparand is of the form + // [+-]0*10^N (denormalized zero) + bool bLeftZero = (!pdecLeft->Lo64 && !pdecLeft->Hi32); + bool bRightZero = (!pdecRight->Lo64 && !pdecRight->Hi32); + if (bLeftZero && bRightZero) + { + return VARCMP_EQ; + } + bool bLeftNeg = ((pdecLeft->sign & DECIMAL_NEG) != 0); + bool bRightNeg = ((pdecRight->sign & DECIMAL_NEG) != 0); + if (bLeftZero) + { + return (bRightNeg ? VARCMP_GT : VARCMP_LT); + } + // This also covers the case where the comparands have different signs + if (bRightZero || bLeftNeg != bRightNeg) + { + return (bLeftNeg ? VARCMP_LT : VARCMP_GT); + } + + // Here both comparands have the same sign and need to be compared + // on mantissa and scale. The result is obvious when + // 1. Scales are equal (then compare mantissas) + // 2. A number with smaller scale is also the one with larger mantissa + // (then this number is obviously larger) + // In the remaining case, we would multiply the number with smaller + // scale by 10 and simultaneously increment its scale (which amounts to + // adding trailing zeros after decimal point), until the numbers fall under + // one of the two cases above + DECIMAL temp; + bool bInvert = bLeftNeg; // the final result needs to be inverted + if (pdecLeft->scale < pdecRight->scale) + { + temp = *pdecLeft; + } + else + { + temp = *pdecRight; + pdecRight = pdecLeft; + bInvert = !bInvert; + } + + // Now temp is the number with smaller (or equal) scale, and + // we can modify it freely without touching original parameters + int comp; + while ((comp = CompareMantissas(temp, *pdecRight)) < 0 && + temp.scale < pdecRight->scale) + { + // Multiply by an appropriate power of 10 + int scaleDiff = pdecRight->scale - temp.scale; + if (scaleDiff > largestPower) + { + // Keep the multiplier representable in 32bit + scaleDiff = largestPower; + } + DWORDLONG power = powersOfTen[scaleDiff - 1]; + // Multiply temp's mantissa by power + DWORDLONG product = temp.Lo32 * power; + ULONG carry = static_cast(product >> 32); + temp.Lo32 = static_cast(product); + product = temp.Mid32 * power + carry; + carry = static_cast(product >> 32); + temp.Mid32 = static_cast(product); + product = temp.Hi32 * power + carry; + if (static_cast(product >> 32)) + { + // Multiplication overflowed - pdecLeft is clearly larger + break; + } + temp.Hi32 = static_cast(product); + temp.scale = (BYTE)(temp.scale + scaleDiff); + } + if (temp.scale < pdecRight->scale) + { + comp = 1; + } + if (bInvert) + { + comp = -comp; + } + return (comp > 0 ? VARCMP_GT : comp < 0 ? VARCMP_LT : VARCMP_EQ); + } + + static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = (int)VarDecCmp(&pParam1->decValue, &pParam2->decValue); + nRet--; + return pInfo->bDescending ? -nRet : nRet; + } +#endif // !_WIN32_WCE + + BEGIN_MSG_MAP(CSortListViewImpl) + MESSAGE_HANDLER(LVM_INSERTCOLUMN, OnInsertColumn) + MESSAGE_HANDLER(LVM_DELETECOLUMN, OnDeleteColumn) + NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, OnHeaderItemClick) + NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, OnHeaderItemClick) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) + END_MSG_MAP() + + LRESULT OnInsertColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); + if(lRet == -1) + return -1; + + WORD wType = 0; + m_arrColSortType.Add(wType); + int nCount = m_arrColSortType.GetSize(); + ATLASSERT(nCount == GetColumnCount()); + + for(int i = nCount - 1; i > lRet; i--) + m_arrColSortType[i] = m_arrColSortType[i - 1]; + m_arrColSortType[(int)lRet] = LVCOLSORT_TEXT; + + if(lRet <= m_iSortColumn) + m_iSortColumn++; + + return lRet; + } + + LRESULT OnDeleteColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); + if(lRet == 0) + return 0; + + int iCol = (int)wParam; + if(m_iSortColumn == iCol) + m_iSortColumn = -1; + else if(m_iSortColumn > iCol) + m_iSortColumn--; + m_arrColSortType.RemoveAt(iCol); + + return lRet; + } + + LRESULT OnHeaderItemClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + LPNMHEADER p = (LPNMHEADER)pnmh; + if(p->iButton == 0) + { + int iOld = m_iSortColumn; + bool bDescending = (m_iSortColumn == p->iItem) ? !m_bSortDescending : false; + if(DoSortItems(p->iItem, bDescending)) + NotifyParentSortChanged(p->iItem, iOld); + } + bHandled = FALSE; + return 0; + } + + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifndef _WIN32_WCE + if(wParam == SPI_SETNONCLIENTMETRICS) + GetSystemSettings(); +#else // CE specific + wParam; // avoid level 4 warning + GetSystemSettings(); +#endif // _WIN32_WCE + bHandled = FALSE; + return 0; + } + + void GetSystemSettings() + { + if(!m_bCommCtrl6 && !m_bmSort[m_iSortUp].IsNull()) + { + T* pT = static_cast(this); + pT->CreateSortBitmaps(); + if(m_iSortColumn != -1) + SetSortColumn(m_iSortColumn); + } + } + +}; + + +typedef ATL::CWinTraits CSortListViewCtrlTraits; + +template +class ATL_NO_VTABLE CSortListViewCtrlImpl: public ATL::CWindowImpl, public CSortListViewImpl +{ +public: + DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) + + bool SortItems(int iCol, bool bDescending = false) + { + return DoSortItems(iCol, bDescending); + } + + BEGIN_MSG_MAP(CSortListViewCtrlImpl) + MESSAGE_HANDLER(LVM_INSERTCOLUMN, CSortListViewImpl::OnInsertColumn) + MESSAGE_HANDLER(LVM_DELETECOLUMN, CSortListViewImpl::OnDeleteColumn) + NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, CSortListViewImpl::OnHeaderItemClick) + NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, CSortListViewImpl::OnHeaderItemClick) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CSortListViewImpl::OnSettingChange) + END_MSG_MAP() +}; + +class CSortListViewCtrl : public CSortListViewCtrlImpl +{ +public: + DECLARE_WND_SUPERCLASS(_T("WTL_SortListViewCtrl"), GetWndClassName()) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CTabView - implements tab view window + +// TabView Notifications +#define TBVN_PAGEACTIVATED (0U-741) +#define TBVN_CONTEXTMENU (0U-742) + +// Notification data for TBVN_CONTEXTMENU +struct TBVCONTEXTMENUINFO +{ + NMHDR hdr; + POINT pt; +}; + +typedef TBVCONTEXTMENUINFO* LPTBVCONTEXTMENUINFO; + + +template +class ATL_NO_VTABLE CTabViewImpl : public ATL::CWindowImpl< T, TBase, TWinTraits > +{ +public: + DECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE) + +// Declarations and enums + struct TABVIEWPAGE + { + HWND hWnd; + LPTSTR lpstrTitle; + LPVOID pData; + }; + + struct TCITEMEXTRA + { + TCITEMHEADER tciheader; + TABVIEWPAGE tvpage; + + operator LPTCITEM() { return (LPTCITEM)this; } + }; + + enum + { + m_nTabID = 1313, + m_cxMoveMark = 6, + m_cyMoveMark = 3, + m_nMenuItemsMax = (ID_WINDOW_TABLAST - ID_WINDOW_TABFIRST + 1) + }; + +// Data members + ATL::CContainedWindowT m_tab; + int m_cyTabHeight; + + int m_nActivePage; + + int m_nInsertItem; + POINT m_ptStartDrag; + + CMenuHandle m_menu; + + int m_cchTabTextLength; + + int m_nMenuItemsCount; + + ATL::CWindow m_wndTitleBar; + LPTSTR m_lpstrTitleBarBase; + int m_cchTitleBarLength; + + CImageList m_ilDrag; + + bool m_bDestroyPageOnRemove:1; + bool m_bDestroyImageList:1; + bool m_bActivePageMenuItem:1; + bool m_bActiveAsDefaultMenuItem:1; + bool m_bEmptyMenuItem:1; + bool m_bWindowsMenuItem:1; + bool m_bNoTabDrag:1; + // internal + bool m_bTabCapture:1; + bool m_bTabDrag:1; + bool m_bInternalFont:1; + +// Constructor/destructor + CTabViewImpl() : + m_nActivePage(-1), + m_cyTabHeight(0), + m_tab(this, 1), + m_nInsertItem(-1), + m_cchTabTextLength(30), + m_nMenuItemsCount(10), + m_lpstrTitleBarBase(NULL), + m_cchTitleBarLength(100), + m_bDestroyPageOnRemove(true), + m_bDestroyImageList(true), + m_bActivePageMenuItem(true), + m_bActiveAsDefaultMenuItem(false), + m_bEmptyMenuItem(false), + m_bWindowsMenuItem(false), + m_bNoTabDrag(false), + m_bTabCapture(false), + m_bTabDrag(false), + m_bInternalFont(false) + { + m_ptStartDrag.x = 0; + m_ptStartDrag.y = 0; + } + + ~CTabViewImpl() + { + delete [] m_lpstrTitleBarBase; + } + +// Message filter function - to be called from PreTranslateMessage of the main window + BOOL PreTranslateMessage(MSG* pMsg) + { + if(IsWindow() == FALSE) + return FALSE; + + BOOL bRet = FALSE; + + // Check for TabView built-in accelerators (Ctrl+Tab/Ctrl+Shift+Tab - next/previous page) + int nCount = GetPageCount(); + if(nCount > 0) + { + bool bControl = (::GetKeyState(VK_CONTROL) < 0); + if((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_TAB) && bControl) + { + if(nCount > 1) + { + int nPage = m_nActivePage; + bool bShift = (::GetKeyState(VK_SHIFT) < 0); + if(bShift) + nPage = (nPage > 0) ? (nPage - 1) : (nCount - 1); + else + nPage = ((nPage >= 0) && (nPage < (nCount - 1))) ? (nPage + 1) : 0; + + SetActivePage(nPage); + T* pT = static_cast(this); + pT->OnPageActivated(m_nActivePage); + } + + bRet = TRUE; + } + } + + // If we are doing drag-drop, check for Escape key that cancels it + if(bRet == FALSE) + { + if(m_bTabCapture && pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) + { + ::ReleaseCapture(); + bRet = TRUE; + } + } + + // Pass the message to the active page + if(bRet == FALSE) + { + if(m_nActivePage != -1) + bRet = (BOOL)::SendMessage(GetPageHWND(m_nActivePage), WM_FORWARDMSG, 0, (LPARAM)pMsg); + } + + return bRet; + } + +// Attributes + int GetPageCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return m_tab.GetItemCount(); + } + + int GetActivePage() const + { + return m_nActivePage; + } + + void SetActivePage(int nPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + T* pT = static_cast(this); + + SetRedraw(FALSE); + + if(m_nActivePage != -1) + ::ShowWindow(GetPageHWND(m_nActivePage), FALSE); + m_nActivePage = nPage; + m_tab.SetCurSel(m_nActivePage); + ::ShowWindow(GetPageHWND(m_nActivePage), TRUE); + + pT->UpdateLayout(); + + SetRedraw(TRUE); + RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + + if(::GetFocus() != m_tab.m_hWnd) + ::SetFocus(GetPageHWND(m_nActivePage)); + + pT->UpdateTitleBar(); + pT->UpdateMenu(); + } + + HIMAGELIST GetImageList() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return m_tab.GetImageList(); + } + + HIMAGELIST SetImageList(HIMAGELIST hImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return m_tab.SetImageList(hImageList); + } + + void SetWindowMenu(HMENU hMenu) + { + ATLASSERT(::IsWindow(m_hWnd)); + + m_menu = hMenu; + + T* pT = static_cast(this); + pT->UpdateMenu(); + } + + void SetTitleBarWindow(HWND hWnd) + { + ATLASSERT(::IsWindow(m_hWnd)); + + delete [] m_lpstrTitleBarBase; + m_lpstrTitleBarBase = NULL; + + m_wndTitleBar = hWnd; + if(hWnd == NULL) + return; + + int cchLen = m_wndTitleBar.GetWindowTextLength() + 1; + ATLTRY(m_lpstrTitleBarBase = new TCHAR[cchLen]); + if(m_lpstrTitleBarBase != NULL) + { + m_wndTitleBar.GetWindowText(m_lpstrTitleBarBase, cchLen); + T* pT = static_cast(this); + pT->UpdateTitleBar(); + } + } + +// Page attributes + HWND GetPageHWND(int nPage) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_PARAM; + m_tab.GetItem(nPage, tcix); + + return tcix.tvpage.hWnd; + } + + LPCTSTR GetPageTitle(int nPage) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_PARAM; + if(m_tab.GetItem(nPage, tcix) == FALSE) + return NULL; + + return tcix.tvpage.lpstrTitle; + } + + bool SetPageTitle(int nPage, LPCTSTR lpstrTitle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + T* pT = static_cast(this); + + int cchBuff = lstrlen(lpstrTitle) + 1; + LPTSTR lpstrBuff = NULL; + ATLTRY(lpstrBuff = new TCHAR[cchBuff]); + if(lpstrBuff == NULL) + return false; + + SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle); + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_PARAM; + if(m_tab.GetItem(nPage, tcix) == FALSE) + return false; + + CTempBuffer buff; + LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1); + if(lpstrTabText == NULL) + return false; + + delete [] tcix.tvpage.lpstrTitle; + + pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1); + + tcix.tciheader.mask = TCIF_TEXT | TCIF_PARAM; + tcix.tciheader.pszText = lpstrTabText; + tcix.tvpage.lpstrTitle = lpstrBuff; + if(m_tab.SetItem(nPage, tcix) == FALSE) + return false; + + pT->UpdateTitleBar(); + pT->UpdateMenu(); + + return true; + } + + LPVOID GetPageData(int nPage) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_PARAM; + m_tab.GetItem(nPage, tcix); + + return tcix.tvpage.pData; + } + + LPVOID SetPageData(int nPage, LPVOID pData) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_PARAM; + m_tab.GetItem(nPage, tcix); + LPVOID pDataOld = tcix.tvpage.pData; + + tcix.tvpage.pData = pData; + m_tab.SetItem(nPage, tcix); + + return pDataOld; + } + + int GetPageImage(int nPage) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_IMAGE; + m_tab.GetItem(nPage, tcix); + + return tcix.tciheader.iImage; + } + + int SetPageImage(int nPage, int nImage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_IMAGE; + m_tab.GetItem(nPage, tcix); + int nImageOld = tcix.tciheader.iImage; + + tcix.tciheader.iImage = nImage; + m_tab.SetItem(nPage, tcix); + + return nImageOld; + } + +// Operations + bool AddPage(HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL) + { + return InsertPage(GetPageCount(), hWndView, lpstrTitle, nImage, pData); + } + + bool InsertPage(int nPage, HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPage == GetPageCount() || IsValidPageIndex(nPage)); + + T* pT = static_cast(this); + + int cchBuff = lstrlen(lpstrTitle) + 1; + LPTSTR lpstrBuff = NULL; + ATLTRY(lpstrBuff = new TCHAR[cchBuff]); + if(lpstrBuff == NULL) + return false; + + SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle); + + CTempBuffer buff; + LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1); + if(lpstrTabText == NULL) + return false; + + pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1); + + SetRedraw(FALSE); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM; + tcix.tciheader.pszText = lpstrTabText; + tcix.tciheader.iImage = nImage; + tcix.tvpage.hWnd = hWndView; + tcix.tvpage.lpstrTitle = lpstrBuff; + tcix.tvpage.pData = pData; + int nItem = m_tab.InsertItem(nPage, tcix); + if(nItem == -1) + { + delete [] lpstrBuff; + SetRedraw(TRUE); + return false; + } + + // adjust active page index, if inserted before it + if(nPage <= m_nActivePage) + m_nActivePage++; + + SetActivePage(nItem); + pT->OnPageActivated(m_nActivePage); + + if(GetPageCount() == 1) + pT->ShowTabControl(true); + + pT->UpdateLayout(); + + SetRedraw(TRUE); + RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + + return true; + } + + void RemovePage(int nPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + T* pT = static_cast(this); + + SetRedraw(FALSE); + + if(GetPageCount() == 1) + pT->ShowTabControl(false); + + if(m_bDestroyPageOnRemove) + ::DestroyWindow(GetPageHWND(nPage)); + else + ::ShowWindow(GetPageHWND(nPage), FALSE); + LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(nPage); + delete [] lpstrTitle; + + ATLVERIFY(m_tab.DeleteItem(nPage) != FALSE); + + if(m_nActivePage == nPage) + { + m_nActivePage = -1; + + if(nPage > 0) + { + SetActivePage(nPage - 1); + } + else if(GetPageCount() > 0) + { + SetActivePage(nPage); + } + else + { + SetRedraw(TRUE); + Invalidate(); + UpdateWindow(); + pT->UpdateTitleBar(); + pT->UpdateMenu(); + } + } + else + { + nPage = (nPage < m_nActivePage) ? (m_nActivePage - 1) : m_nActivePage; + m_nActivePage = -1; + SetActivePage(nPage); + } + + pT->OnPageActivated(m_nActivePage); + } + + void RemoveAllPages() + { + ATLASSERT(::IsWindow(m_hWnd)); + + if(GetPageCount() == 0) + return; + + T* pT = static_cast(this); + + SetRedraw(FALSE); + + pT->ShowTabControl(false); + + for(int i = 0; i < GetPageCount(); i++) + { + if(m_bDestroyPageOnRemove) + ::DestroyWindow(GetPageHWND(i)); + else + ::ShowWindow(GetPageHWND(i), FALSE); + LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(i); + delete [] lpstrTitle; + } + m_tab.DeleteAllItems(); + + m_nActivePage = -1; + pT->OnPageActivated(m_nActivePage); + + SetRedraw(TRUE); + Invalidate(); + UpdateWindow(); + + pT->UpdateTitleBar(); + pT->UpdateMenu(); + } + + int PageIndexFromHwnd(HWND hWnd) const + { + int nIndex = -1; + + for(int i = 0; i < GetPageCount(); i++) + { + if(GetPageHWND(i) == hWnd) + { + nIndex = i; + break; + } + } + + return nIndex; + } + + void BuildWindowMenu(HMENU hMenu, int nMenuItemsCount = 10, bool bEmptyMenuItem = true, bool bWindowsMenuItem = true, bool bActivePageMenuItem = true, bool bActiveAsDefaultMenuItem = false) + { + ATLASSERT(::IsWindow(m_hWnd)); + + CMenuHandle menu = hMenu; + T* pT = static_cast(this); + pT; // avoid level 4 warning + int nFirstPos = 0; + + // Find first menu item in our range +#ifndef _WIN32_WCE + for(nFirstPos = 0; nFirstPos < menu.GetMenuItemCount(); nFirstPos++) + { + UINT nID = menu.GetMenuItemID(nFirstPos); + if((nID >= ID_WINDOW_TABFIRST && nID <= ID_WINDOW_TABLAST) || nID == ID_WINDOW_SHOWTABLIST) + break; + } +#else // CE specific + for(nFirstPos = 0; ; nFirstPos++) + { + CMenuItemInfo mii; + mii.fMask = MIIM_ID; + BOOL bRet = menu.GetMenuItemInfo(nFirstPos, TRUE, &mii); + if(bRet == FALSE) + break; + if((mii.wID >= ID_WINDOW_TABFIRST && mii.wID <= ID_WINDOW_TABLAST) || mii.wID == ID_WINDOW_SHOWTABLIST) + break; + } +#endif // _WIN32_WCE + + // Remove all menu items for tab pages + BOOL bRet = TRUE; + while(bRet != FALSE) + bRet = menu.DeleteMenu(nFirstPos, MF_BYPOSITION); + + // Add separator if it's not already there + int nPageCount = GetPageCount(); + if((bWindowsMenuItem || (nPageCount > 0)) && (nFirstPos > 0)) + { + CMenuItemInfo mii; + mii.fMask = MIIM_TYPE; + menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii); + if((nFirstPos <= 0) || ((mii.fType & MFT_SEPARATOR) == 0)) + { + menu.AppendMenu(MF_SEPARATOR); + nFirstPos++; + } + } + + // Add menu items for all pages + if(nPageCount > 0) + { + // Append menu items for all pages + const int cchPrefix = 3; // 2 digits + space + nMenuItemsCount = __min(__min(nPageCount, nMenuItemsCount), (int)m_nMenuItemsMax); + ATLASSERT(nMenuItemsCount < 100); // 2 digits only + if(nMenuItemsCount >= 100) + nMenuItemsCount = 99; + + for(int i = 0; i < nMenuItemsCount; i++) + { + LPCTSTR lpstrTitle = GetPageTitle(i); + int nLen = lstrlen(lpstrTitle); + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(cchPrefix + nLen + 1); + ATLASSERT(lpstrText != NULL); + if(lpstrText != NULL) + { + LPCTSTR lpstrFormat = (i < 9) ? _T("&%i %s") : _T("%i %s"); + SecureHelper::wsprintf_x(lpstrText, cchPrefix + nLen + 1, lpstrFormat, i + 1, lpstrTitle); + menu.AppendMenu(MF_STRING, ID_WINDOW_TABFIRST + i, lpstrText); + } + } + + // Mark active page + if(bActivePageMenuItem && (m_nActivePage != -1)) + { +#ifndef _WIN32_WCE + if(bActiveAsDefaultMenuItem) + { + menu.SetMenuDefaultItem((UINT)-1, TRUE); + menu.SetMenuDefaultItem(nFirstPos + m_nActivePage, TRUE); + } + else +#else // CE specific + bActiveAsDefaultMenuItem; // avoid level 4 warning +#endif // _WIN32_WCE + { + menu.CheckMenuRadioItem(nFirstPos, nFirstPos + nMenuItemsCount, nFirstPos + m_nActivePage, MF_BYPOSITION); + } + } + } + else + { + if(bEmptyMenuItem) + { + menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_TABFIRST, pT->GetEmptyListText()); + menu.EnableMenuItem(ID_WINDOW_TABFIRST, MF_GRAYED); + } + + // Remove separator if nothing else is there + if(!bEmptyMenuItem && !bWindowsMenuItem && (nFirstPos > 0)) + { + CMenuItemInfo mii; + mii.fMask = MIIM_TYPE; + menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii); + if((mii.fType & MFT_SEPARATOR) != 0) + menu.DeleteMenu(nFirstPos - 1, MF_BYPOSITION); + } + } + + // Add "Windows..." menu item + if(bWindowsMenuItem) + menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_SHOWTABLIST, pT->GetWindowsMenuItemText()); + } + + BOOL SubclassWindow(HWND hWnd) + { +#if (_MSC_VER >= 1300) + BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + BOOL bRet = _baseClass::SubclassWindow(hWnd); +#endif // !(_MSC_VER >= 1300) + if(bRet != FALSE) + { + T* pT = static_cast(this); + pT->CreateTabControl(); + pT->UpdateLayout(); + } + + return bRet; + } + +// Message map and handlers + BEGIN_MSG_MAP(CTabViewImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_GETFONT, OnGetFont) + MESSAGE_HANDLER(WM_SETFONT, OnSetFont) + NOTIFY_HANDLER(m_nTabID, TCN_SELCHANGE, OnTabChanged) + NOTIFY_ID_HANDLER(m_nTabID, OnTabNotification) +#ifndef _WIN32_WCE + NOTIFY_CODE_HANDLER(TTN_GETDISPINFO, OnTabGetDispInfo) +#endif // !_WIN32_WCE + FORWARD_NOTIFICATIONS() + ALT_MSG_MAP(1) // tab control + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnTabLButtonDown) + MESSAGE_HANDLER(WM_LBUTTONUP, OnTabLButtonUp) + MESSAGE_HANDLER(WM_CAPTURECHANGED, OnTabCaptureChanged) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnTabMouseMove) + MESSAGE_HANDLER(WM_RBUTTONUP, OnTabRButtonUp) + MESSAGE_HANDLER(WM_SYSKEYDOWN, OnTabSysKeyDown) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->CreateTabControl(); + + return 0; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + RemoveAllPages(); + + if(m_bDestroyImageList) + { + CImageList il = m_tab.SetImageList(NULL); + if(il.m_hImageList != NULL) + il.Destroy(); + } + + if(m_bInternalFont) + { + HFONT hFont = m_tab.GetFont(); + m_tab.SetFont(NULL, FALSE); + ::DeleteObject(hFont); + m_bInternalFont = false; + } + + return 0; + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + return 0; + } + + LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(m_nActivePage != -1) + ::SetFocus(GetPageHWND(m_nActivePage)); + return 0; + } + + LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return m_tab.SendMessage(WM_GETFONT); + } + + LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + if(m_bInternalFont) + { + HFONT hFont = m_tab.GetFont(); + m_tab.SetFont(NULL, FALSE); + ::DeleteObject(hFont); + m_bInternalFont = false; + } + + m_tab.SendMessage(WM_SETFONT, wParam, lParam); + + T* pT = static_cast(this); + m_cyTabHeight = pT->CalcTabHeight(); + + if((BOOL)lParam != FALSE) + pT->UpdateLayout(); + + return 0; + } + + LRESULT OnTabChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + SetActivePage(m_tab.GetCurSel()); + T* pT = static_cast(this); + pT->OnPageActivated(m_nActivePage); + + return 0; + } + + LRESULT OnTabNotification(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + // nothing to do - this just blocks all tab control + // notifications from being propagated further + return 0; + } + +#ifndef _WIN32_WCE + LRESULT OnTabGetDispInfo(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + LPNMTTDISPINFO pTTDI = (LPNMTTDISPINFO)pnmh; + if(pTTDI->hdr.hwndFrom == m_tab.GetTooltips()) + { + T* pT = static_cast(this); + pT->UpdateTooltipText(pTTDI); + } + else + { + bHandled = FALSE; + } + + return 0; + } +#endif // !_WIN32_WCE + +// Tab control message handlers + LRESULT OnTabLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(!m_bNoTabDrag && (m_tab.GetItemCount() > 1)) + { + m_bTabCapture = true; + m_tab.SetCapture(); + + m_ptStartDrag.x = GET_X_LPARAM(lParam); + m_ptStartDrag.y = GET_Y_LPARAM(lParam); + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnTabLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(m_bTabCapture) + { + if(m_bTabDrag) + { + TCHITTESTINFO hti = { 0 }; + hti.pt.x = GET_X_LPARAM(lParam); + hti.pt.y = GET_Y_LPARAM(lParam); + int nItem = m_tab.HitTest(&hti); + if(nItem != -1) + MovePage(m_nActivePage, nItem); + } + + ::ReleaseCapture(); + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnTabCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_bTabCapture) + { + m_bTabCapture = false; + + if(m_bTabDrag) + { + m_bTabDrag = false; + T* pT = static_cast(this); + pT->DrawMoveMark(-1); + +#ifndef _WIN32_WCE + m_ilDrag.DragLeave(GetDesktopWindow()); +#endif // !_WIN32_WCE + m_ilDrag.EndDrag(); + + m_ilDrag.Destroy(); + m_ilDrag.m_hImageList = NULL; + } + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnTabMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + bHandled = FALSE; + + if(m_bTabCapture) + { + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + + if(!m_bTabDrag) + { +#ifndef _WIN32_WCE + if(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CXDRAG) || + abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CYDRAG)) +#else // CE specific + if(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= 4 || + abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= 4) +#endif // _WIN32_WCE + { + T* pT = static_cast(this); + pT->GenerateDragImage(m_nActivePage); + + int cxCursor = ::GetSystemMetrics(SM_CXCURSOR); + int cyCursor = ::GetSystemMetrics(SM_CYCURSOR); + m_ilDrag.BeginDrag(0, -(cxCursor / 2), -(cyCursor / 2)); +#ifndef _WIN32_WCE + POINT ptEnter = m_ptStartDrag; + m_tab.ClientToScreen(&ptEnter); + m_ilDrag.DragEnter(GetDesktopWindow(), ptEnter); +#endif // !_WIN32_WCE + + m_bTabDrag = true; + } + } + + if(m_bTabDrag) + { + TCHITTESTINFO hti = { 0 }; + hti.pt = pt; + int nItem = m_tab.HitTest(&hti); + + T* pT = static_cast(this); + pT->SetMoveCursor(nItem != -1); + + if(m_nInsertItem != nItem) + pT->DrawMoveMark(nItem); + + m_ilDrag.DragShowNolock((nItem != -1) ? TRUE : FALSE); + m_tab.ClientToScreen(&pt); + m_ilDrag.DragMove(pt); + + bHandled = TRUE; + } + } + + return 0; + } + + LRESULT OnTabRButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + TCHITTESTINFO hti = { 0 }; + hti.pt.x = GET_X_LPARAM(lParam); + hti.pt.y = GET_Y_LPARAM(lParam); + int nItem = m_tab.HitTest(&hti); + if(nItem != -1) + { + T* pT = static_cast(this); + pT->OnContextMenu(nItem, hti.pt); + } + + return 0; + } + + LRESULT OnTabSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bool bShift = (::GetKeyState(VK_SHIFT) < 0); + if(wParam == VK_F10 && bShift) + { + if(m_nActivePage != -1) + { + RECT rect = { 0 }; + m_tab.GetItemRect(m_nActivePage, &rect); + POINT pt = { rect.left, rect.bottom }; + T* pT = static_cast(this); + pT->OnContextMenu(m_nActivePage, pt); + } + } + else + { + bHandled = FALSE; + } + + return 0; + } + +// Implementation helpers + bool IsValidPageIndex(int nPage) const + { + return (nPage >= 0 && nPage < GetPageCount()); + } + + bool MovePage(int nMovePage, int nInsertBeforePage) + { + ATLASSERT(IsValidPageIndex(nMovePage)); + ATLASSERT(IsValidPageIndex(nInsertBeforePage)); + + if(!IsValidPageIndex(nMovePage) || !IsValidPageIndex(nInsertBeforePage)) + return false; + + if(nMovePage == nInsertBeforePage) + return true; // nothing to do + + CTempBuffer buff; + LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1); + if(lpstrTabText == NULL) + return false; + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM; + tcix.tciheader.pszText = lpstrTabText; + tcix.tciheader.cchTextMax = m_cchTabTextLength + 1; + BOOL bRet = m_tab.GetItem(nMovePage, tcix); + ATLASSERT(bRet != FALSE); + if(bRet == FALSE) + return false; + + int nInsertItem = (nInsertBeforePage > nMovePage) ? nInsertBeforePage + 1 : nInsertBeforePage; + int nNewItem = m_tab.InsertItem(nInsertItem, tcix); + ATLASSERT(nNewItem == nInsertItem); + if(nNewItem != nInsertItem) + { + ATLVERIFY(m_tab.DeleteItem(nNewItem)); + return false; + } + + if(nMovePage > nInsertBeforePage) + ATLVERIFY(m_tab.DeleteItem(nMovePage + 1) != FALSE); + else if(nMovePage < nInsertBeforePage) + ATLVERIFY(m_tab.DeleteItem(nMovePage) != FALSE); + + SetActivePage(nInsertBeforePage); + T* pT = static_cast(this); + pT->OnPageActivated(m_nActivePage); + + return true; + } + +// Implementation overrideables + bool CreateTabControl() + { +#ifndef _WIN32_WCE + m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_TOOLTIPS, 0, m_nTabID); +#else // CE specific + m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, m_nTabID); +#endif // _WIN32_WCE + ATLASSERT(m_tab.m_hWnd != NULL); + if(m_tab.m_hWnd == NULL) + return false; + + m_tab.SetFont(AtlCreateControlFont()); + m_bInternalFont = true; + + m_tab.SetItemExtra(sizeof(TABVIEWPAGE)); + + T* pT = static_cast(this); + m_cyTabHeight = pT->CalcTabHeight(); + + return true; + } + + int CalcTabHeight() + { + int nCount = m_tab.GetItemCount(); + TCHAR szText[] = _T("NS"); + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_TEXT; + tcix.tciheader.pszText = szText; + int nIndex = m_tab.InsertItem(nCount, tcix); + + RECT rect = { 0, 0, 1000, 1000 }; + m_tab.AdjustRect(FALSE, &rect); + + RECT rcWnd = { 0, 0, 1000, rect.top }; + ::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetExStyle()); + + int nHeight = rcWnd.bottom - rcWnd.top; + + m_tab.DeleteItem(nIndex); + + return nHeight; + } + + void ShowTabControl(bool bShow) + { + m_tab.ShowWindow(bShow ? SW_SHOWNOACTIVATE : SW_HIDE); + T* pT = static_cast(this); + pT->UpdateLayout(); + } + + void UpdateLayout() + { + RECT rect = { 0 }; + GetClientRect(&rect); + + int cyOffset = 0; + if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0)) + { + m_tab.SetWindowPos(NULL, 0, 0, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER); + cyOffset = m_cyTabHeight; + } + + if(m_nActivePage != -1) + ::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, cyOffset, rect.right - rect.left, rect.bottom - rect.top - cyOffset, SWP_NOZORDER); + } + + void UpdateMenu() + { + if(m_menu.m_hMenu != NULL) + BuildWindowMenu(m_menu, m_nMenuItemsCount, m_bEmptyMenuItem, m_bWindowsMenuItem, m_bActivePageMenuItem, m_bActiveAsDefaultMenuItem); + } + + void UpdateTitleBar() + { + if(!m_wndTitleBar.IsWindow() || m_lpstrTitleBarBase == NULL) + return; // nothing to do + + if(m_nActivePage != -1) + { + T* pT = static_cast(this); + LPCTSTR lpstrTitle = pT->GetPageTitle(m_nActivePage); + LPCTSTR lpstrDivider = pT->GetTitleDividerText(); + int cchBuffer = m_cchTitleBarLength + lstrlen(lpstrDivider) + lstrlen(m_lpstrTitleBarBase) + 1; + CTempBuffer buff; + LPTSTR lpstrPageTitle = buff.Allocate(cchBuffer); + ATLASSERT(lpstrPageTitle != NULL); + if(lpstrPageTitle != NULL) + { + pT->ShortenTitle(lpstrTitle, lpstrPageTitle, m_cchTitleBarLength + 1); + SecureHelper::strcat_x(lpstrPageTitle, cchBuffer, lpstrDivider); + SecureHelper::strcat_x(lpstrPageTitle, cchBuffer, m_lpstrTitleBarBase); + } + else + { + lpstrPageTitle = m_lpstrTitleBarBase; + } + + m_wndTitleBar.SetWindowText(lpstrPageTitle); + } + else + { + m_wndTitleBar.SetWindowText(m_lpstrTitleBarBase); + } + } + + void DrawMoveMark(int nItem) + { + T* pT = static_cast(this); + + if(m_nInsertItem != -1) + { + RECT rect = { 0 }; + pT->GetMoveMarkRect(rect); + m_tab.InvalidateRect(&rect); + } + + m_nInsertItem = nItem; + + if(m_nInsertItem != -1) + { + CClientDC dc(m_tab.m_hWnd); + + RECT rect = { 0 }; + pT->GetMoveMarkRect(rect); + + CPen pen; + pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_WINDOWTEXT)); + CBrush brush; + brush.CreateSolidBrush(::GetSysColor(COLOR_WINDOWTEXT)); + + HPEN hPenOld = dc.SelectPen(pen); + HBRUSH hBrushOld = dc.SelectBrush(brush); + + int x = rect.left; + int y = rect.top; + POINT ptsTop[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y + m_cyMoveMark } }; + dc.Polygon(ptsTop, 3); + + y = rect.bottom - 1; + POINT ptsBottom[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y - m_cyMoveMark } }; + dc.Polygon(ptsBottom, 3); + + dc.SelectPen(hPenOld); + dc.SelectBrush(hBrushOld); + } + } + + void GetMoveMarkRect(RECT& rect) const + { + m_tab.GetClientRect(&rect); + + RECT rcItem = { 0 }; + m_tab.GetItemRect(m_nInsertItem, &rcItem); + + if(m_nInsertItem <= m_nActivePage) + { + rect.left = rcItem.left - m_cxMoveMark / 2 - 1; + rect.right = rcItem.left + m_cxMoveMark / 2; + } + else + { + rect.left = rcItem.right - m_cxMoveMark / 2 - 1; + rect.right = rcItem.right + m_cxMoveMark / 2; + } + } + + void SetMoveCursor(bool bCanMove) + { + ::SetCursor(::LoadCursor(NULL, bCanMove ? IDC_ARROW : IDC_NO)); + } + + void GenerateDragImage(int nItem) + { + ATLASSERT(IsValidPageIndex(nItem)); + +#ifndef _WIN32_WCE + RECT rcItem = { 0 }; + m_tab.GetItemRect(nItem, &rcItem); + ::InflateRect(&rcItem, 2, 2); // make bigger to cover selected item +#else // CE specific + nItem; // avoid level 4 warning + RECT rcItem = { 0, 0, 40, 20 }; +#endif // _WIN32_WCE + + ATLASSERT(m_ilDrag.m_hImageList == NULL); + m_ilDrag.Create(rcItem.right - rcItem.left, rcItem.bottom - rcItem.top, ILC_COLORDDB | ILC_MASK, 1, 1); + + CClientDC dc(m_hWnd); + CDC dcMem; + dcMem.CreateCompatibleDC(dc); + ATLASSERT(dcMem.m_hDC != NULL); + dcMem.SetViewportOrg(-rcItem.left, -rcItem.top); + + CBitmap bmp; + bmp.CreateCompatibleBitmap(dc, rcItem.right - rcItem.left, rcItem.bottom - rcItem.top); + ATLASSERT(bmp.m_hBitmap != NULL); + + HBITMAP hBmpOld = dcMem.SelectBitmap(bmp); +#ifndef _WIN32_WCE + m_tab.SendMessage(WM_PRINTCLIENT, (WPARAM)dcMem.m_hDC); +#else // CE specific + dcMem.Rectangle(&rcItem); +#endif // _WIN32_WCE + dcMem.SelectBitmap(hBmpOld); + + ATLVERIFY(m_ilDrag.Add(bmp.m_hBitmap, RGB(255, 0, 255)) != -1); + } + + void ShortenTitle(LPCTSTR lpstrTitle, LPTSTR lpstrShortTitle, int cchShortTitle) + { + if(lstrlen(lpstrTitle) >= cchShortTitle) + { + LPCTSTR lpstrEllipsis = _T("..."); + int cchEllipsis = lstrlen(lpstrEllipsis); + SecureHelper::strncpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle, cchShortTitle - cchEllipsis - 1); + SecureHelper::strcat_x(lpstrShortTitle, cchShortTitle, lpstrEllipsis); + } + else + { + SecureHelper::strcpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle); + } + } + +#ifndef _WIN32_WCE + void UpdateTooltipText(LPNMTTDISPINFO pTTDI) + { + ATLASSERT(pTTDI != NULL); + pTTDI->lpszText = (LPTSTR)GetPageTitle((int)pTTDI->hdr.idFrom); + } +#endif // !_WIN32_WCE + +// Text for menu items and title bar - override to provide different strings + static LPCTSTR GetEmptyListText() + { + return _T("(Empty)"); + } + + static LPCTSTR GetWindowsMenuItemText() + { + return _T("&Windows..."); + } + + static LPCTSTR GetTitleDividerText() + { + return _T(" - "); + } + +// Notifications - override to provide different behavior + void OnPageActivated(int nPage) + { + NMHDR nmhdr = { 0 }; + nmhdr.hwndFrom = m_hWnd; + nmhdr.idFrom = nPage; + nmhdr.code = TBVN_PAGEACTIVATED; + ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr); + } + + void OnContextMenu(int nPage, POINT pt) + { + m_tab.ClientToScreen(&pt); + + TBVCONTEXTMENUINFO cmi = { 0 }; + cmi.hdr.hwndFrom = m_hWnd; + cmi.hdr.idFrom = nPage; + cmi.hdr.code = TBVN_CONTEXTMENU; + cmi.pt = pt; + ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&cmi); + } +}; + +class CTabView : public CTabViewImpl +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_TabView"), 0, COLOR_APPWORKSPACE) +}; + +}; // namespace WTL + +#endif // __ATLCTRLX_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlddx.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlddx.h new file mode 100644 index 0000000000000000000000000000000000000000..aa12bbb0cc7557bd229d91f79c80ca3b195763c2 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlddx.h @@ -0,0 +1,684 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLDDX_H__ +#define __ATLDDX_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atlddx.h requires atlapp.h to be included first +#endif + +#if defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT) + #error Cannot use floating point DDX with _ATL_MIN_CRT defined +#endif // defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT) + +#ifdef _ATL_USE_DDX_FLOAT + #include +#endif // _ATL_USE_DDX_FLOAT + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CWinDataExchange + + +namespace WTL +{ + +// Constants +#define DDX_LOAD FALSE +#define DDX_SAVE TRUE + +// DDX map macros +#define BEGIN_DDX_MAP(thisClass) \ + BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) \ + { \ + (bSaveAndValidate); \ + (nCtlID); + +#define DDX_TEXT(nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \ + return FALSE; \ + } + +#define DDX_TEXT_LEN(nID, var, len) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate, TRUE, len)) \ + return FALSE; \ + } + +#define DDX_INT(nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Int(nID, var, TRUE, bSaveAndValidate)) \ + return FALSE; \ + } + +#define DDX_INT_RANGE(nID, var, min, max) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Int(nID, var, TRUE, bSaveAndValidate, TRUE, min, max)) \ + return FALSE; \ + } + +#define DDX_UINT(nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Int(nID, var, FALSE, bSaveAndValidate)) \ + return FALSE; \ + } + +#define DDX_UINT_RANGE(nID, var, min, max) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Int(nID, var, FALSE, bSaveAndValidate, TRUE, min, max)) \ + return FALSE; \ + } + +#ifdef _ATL_USE_DDX_FLOAT +#define DDX_FLOAT(nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Float(nID, var, bSaveAndValidate)) \ + return FALSE; \ + } + +#define DDX_FLOAT_RANGE(nID, var, min, max) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max)) \ + return FALSE; \ + } +#define DDX_FLOAT_P(nID, var, precision) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Float(nID, var, bSaveAndValidate, FALSE, 0, 0, precision)) \ + return FALSE; \ + } + +#define DDX_FLOAT_P_RANGE(nID, var, min, max, precision) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max, precision)) \ + return FALSE; \ + } +#endif // _ATL_USE_DDX_FLOAT + +#define DDX_CONTROL(nID, obj) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + DDX_Control(nID, obj, bSaveAndValidate); + +#define DDX_CONTROL_HANDLE(nID, obj) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + DDX_Control_Handle(nID, obj, bSaveAndValidate); + +#define DDX_CHECK(nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + DDX_Check(nID, var, bSaveAndValidate); + +#define DDX_RADIO(nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + DDX_Radio(nID, var, bSaveAndValidate); + +#define END_DDX_MAP() \ + return TRUE; \ + } + +// DDX support for Tab, Combo, ListBox and ListView selection index +// Note: Specialized versions require atlctrls.h to be included first +#if (_MSC_VER >= 1300) + +#define DDX_INDEX(CtrlClass, nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + DDX_Index(nID, var, bSaveAndValidate); + +#ifdef __ATLCTRLS_H__ + #define DDX_TAB_INDEX(nID, var) DDX_INDEX(WTL::CTabCtrl, nID, var) + #ifndef WIN32_PLATFORM_WFSP // No COMBOBOX on SmartPhones + #define DDX_COMBO_INDEX(nID, var) DDX_INDEX(WTL::CComboBox, nID, var) + #endif + #define DDX_LISTBOX_INDEX(nID, var) DDX_INDEX(WTL::CListBox, nID, var) + #define DDX_LISTVIEW_INDEX(nID, var) DDX_INDEX(WTL::CListViewCtrl, nID, var) +#endif // __ATLCTRLS_H__ + +#endif // (_MSC_VER >= 1300) + + +/////////////////////////////////////////////////////////////////////////////// +// CWinDataExchange - provides support for DDX + +template +class CWinDataExchange +{ +public: +// Data exchange method - override in your derived class + BOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT /*nCtlID*/ = (UINT)-1) + { + // this one should never be called, override it in + // your derived class by implementing DDX map + ATLASSERT(FALSE); + return FALSE; + } + +// Helpers for validation error reporting + enum _XDataType + { + ddxDataNull = 0, + ddxDataText = 1, + ddxDataInt = 2, + ddxDataFloat = 3, + ddxDataDouble = 4 + }; + + struct _XTextData + { + int nLength; + int nMaxLength; + }; + + struct _XIntData + { + long nVal; + long nMin; + long nMax; + }; + + struct _XFloatData + { + double nVal; + double nMin; + double nMax; + }; + + struct _XData + { + _XDataType nDataType; + union + { + _XTextData textData; + _XIntData intData; + _XFloatData floatData; + }; + }; + +// Text exchange + BOOL DDX_Text(UINT nID, LPTSTR lpstrText, int cbSize, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + + if(bSave) + { + HWND hWndCtrl = pT->GetDlgItem(nID); + int nRetLen = ::GetWindowText(hWndCtrl, lpstrText, cbSize / sizeof(TCHAR)); + if(nRetLen < ::GetWindowTextLength(hWndCtrl)) + bSuccess = FALSE; + } + else + { + ATLASSERT(!bValidate || (lstrlen(lpstrText) <= nLength)); + bSuccess = pT->SetDlgItemText(nID, lpstrText); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nLength > 0); + if(lstrlen(lpstrText) > nLength) + { + _XData data = { ddxDataText }; + data.textData.nLength = lstrlen(lpstrText); + data.textData.nMaxLength = nLength; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } + + BOOL DDX_Text(UINT nID, BSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + + if(bSave) + { + bSuccess = pT->GetDlgItemText(nID, bstrText); + } + else + { + USES_CONVERSION; + LPTSTR lpstrText = OLE2T(bstrText); + ATLASSERT(!bValidate || (lstrlen(lpstrText) <= nLength)); + bSuccess = pT->SetDlgItemText(nID, lpstrText); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nLength > 0); + if((int)::SysStringLen(bstrText) > nLength) + { + _XData data = { ddxDataText }; + data.textData.nLength = (int)::SysStringLen(bstrText); + data.textData.nMaxLength = nLength; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } + + BOOL DDX_Text(UINT nID, ATL::CComBSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + + if(bSave) + { + bSuccess = pT->GetDlgItemText(nID, (BSTR&)bstrText); + } + else + { + USES_CONVERSION; + LPTSTR lpstrText = OLE2T(bstrText); + ATLASSERT(!bValidate || (lstrlen(lpstrText) <= nLength)); + bSuccess = pT->SetDlgItemText(nID, lpstrText); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nLength > 0); + if((int)bstrText.Length() > nLength) + { + _XData data = { ddxDataText }; + data.textData.nLength = (int)bstrText.Length(); + data.textData.nMaxLength = nLength; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + BOOL DDX_Text(UINT nID, _CSTRING_NS::CString& strText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + + if(bSave) + { + HWND hWndCtrl = pT->GetDlgItem(nID); + int nLen = ::GetWindowTextLength(hWndCtrl); + int nRetLen = -1; + LPTSTR lpstr = strText.GetBufferSetLength(nLen); + if(lpstr != NULL) + { + nRetLen = ::GetWindowText(hWndCtrl, lpstr, nLen + 1); + strText.ReleaseBuffer(); + } + if(nRetLen < nLen) + bSuccess = FALSE; + } + else + { + bSuccess = pT->SetDlgItemText(nID, strText); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nLength > 0); + if(strText.GetLength() > nLength) + { + _XData data = { ddxDataText }; + data.textData.nLength = strText.GetLength(); + data.textData.nMaxLength = nLength; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + +// Numeric exchange + template + BOOL DDX_Int(UINT nID, Type& nVal, BOOL bSigned, BOOL bSave, BOOL bValidate = FALSE, Type nMin = 0, Type nMax = 0) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + + if(bSave) + { + nVal = (Type)pT->GetDlgItemInt(nID, &bSuccess, bSigned); + } + else + { + ATLASSERT(!bValidate || (nVal >= nMin && nVal <= nMax)); + bSuccess = pT->SetDlgItemInt(nID, nVal, bSigned); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nMin != nMax); + if(nVal < nMin || nVal > nMax) + { + _XData data = { ddxDataInt }; + data.intData.nVal = (long)nVal; + data.intData.nMin = (long)nMin; + data.intData.nMax = (long)nMax; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } + +// Float exchange +#ifdef _ATL_USE_DDX_FLOAT + static BOOL _AtlSimpleFloatParse(LPCTSTR lpszText, double& d) + { + ATLASSERT(lpszText != NULL); + while (*lpszText == _T(' ') || *lpszText == _T('\t')) + lpszText++; + + TCHAR chFirst = lpszText[0]; + d = _tcstod(lpszText, (LPTSTR*)&lpszText); + if (d == 0.0 && chFirst != _T('0')) + return FALSE; // could not convert + while (*lpszText == _T(' ') || *lpszText == _T('\t')) + lpszText++; + + if (*lpszText != _T('\0')) + return FALSE; // not terminated properly + + return TRUE; + } + + BOOL DDX_Float(UINT nID, float& nVal, BOOL bSave, BOOL bValidate = FALSE, float nMin = 0.F, float nMax = 0.F, int nPrecision = FLT_DIG) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + const int cchBuff = 32; + TCHAR szBuff[cchBuff] = { 0 }; + + if(bSave) + { + pT->GetDlgItemText(nID, szBuff, cchBuff); + double d = 0; + if(_AtlSimpleFloatParse(szBuff, d)) + nVal = (float)d; + else + bSuccess = FALSE; + } + else + { + ATLASSERT(!bValidate || (nVal >= nMin && nVal <= nMax)); + SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal); + bSuccess = pT->SetDlgItemText(nID, szBuff); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nMin != nMax); + if(nVal < nMin || nVal > nMax) + { + _XData data = { ddxDataFloat }; + data.floatData.nVal = (double)nVal; + data.floatData.nMin = (double)nMin; + data.floatData.nMax = (double)nMax; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } + + BOOL DDX_Float(UINT nID, double& nVal, BOOL bSave, BOOL bValidate = FALSE, double nMin = 0., double nMax = 0., int nPrecision = DBL_DIG) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + const int cchBuff = 32; + TCHAR szBuff[cchBuff] = { 0 }; + + if(bSave) + { + pT->GetDlgItemText(nID, szBuff, cchBuff); + double d = 0; + if(_AtlSimpleFloatParse(szBuff, d)) + nVal = d; + else + bSuccess = FALSE; + } + else + { + ATLASSERT(!bValidate || (nVal >= nMin && nVal <= nMax)); + SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal); + bSuccess = pT->SetDlgItemText(nID, szBuff); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nMin != nMax); + if(nVal < nMin || nVal > nMax) + { + _XData data = { ddxDataFloat }; + data.floatData.nVal = nVal; + data.floatData.nMin = nMin; + data.floatData.nMax = nMax; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } +#endif // _ATL_USE_DDX_FLOAT + +// Full control subclassing (for CWindowImpl derived controls) + template + void DDX_Control(UINT nID, TControl& ctrl, BOOL bSave) + { + if(!bSave && ctrl.m_hWnd == NULL) + { + T* pT = static_cast(this); + ctrl.SubclassWindow(pT->GetDlgItem(nID)); + } + } + +// Simple control attaching (for HWND wrapper controls) + template + void DDX_Control_Handle(UINT nID, TControl& ctrl, BOOL bSave) + { + if(!bSave && ctrl.m_hWnd == NULL) + { + T* pT = static_cast(this); + ctrl = pT->GetDlgItem(nID); + } + } + +// Control state + void DDX_Check(UINT nID, int& nValue, BOOL bSave) + { + T* pT = static_cast(this); + HWND hWndCtrl = pT->GetDlgItem(nID); + if(bSave) + { + nValue = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L); + ATLASSERT(nValue >= 0 && nValue <= 2); + } + else + { + if(nValue < 0 || nValue > 2) + { + ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - dialog data checkbox value (%d) out of range.\n"), nValue); + nValue = 0; // default to off + } + ::SendMessage(hWndCtrl, BM_SETCHECK, nValue, 0L); + } + } + + // variant that supports bool (checked/not-checked, no intermediate state) + void DDX_Check(UINT nID, bool& bCheck, BOOL bSave) + { + int nValue = bCheck ? 1 : 0; + DDX_Check(nID, nValue, bSave); + + if(bSave) + { + if(nValue == 2) + ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - checkbox state (%d) out of supported range.\n"), nValue); + bCheck = (nValue == 1); + } + } + + void DDX_Radio(UINT nID, int& nValue, BOOL bSave) + { + T* pT = static_cast(this); + HWND hWndCtrl = pT->GetDlgItem(nID); + ATLASSERT(hWndCtrl != NULL); + + // must be first in a group of auto radio buttons + ATLASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP); + ATLASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON); + + if(bSave) + nValue = -1; // value if none found + + // walk all children in group + int nButton = 0; + do + { + if(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON) + { + // control in group is a radio button + if(bSave) + { + if(::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0) + { + ATLASSERT(nValue == -1); // only set once + nValue = nButton; + } + } + else + { + // select button + ::SendMessage(hWndCtrl, BM_SETCHECK, (nButton == nValue), 0L); + } + nButton++; + } + else + { + ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - skipping non-radio button in group.\n")); + } + hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT); + } + while (hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP)); + } + +// DDX support for Tab, Combo, ListBox and ListView selection index +#if (_MSC_VER >= 1300) + template + INT _getSel(TCtrl& tCtrl) + { + return tCtrl.GetCurSel(); + } + + template + void _setSel(TCtrl& tCtrl, INT iSel) + { + if(iSel < 0) + tCtrl.SetCurSel(-1); + else + tCtrl.SetCurSel(iSel); + } + +#ifdef __ATLCTRLS_H__ + // ListViewCtrl specialization + template <> + INT _getSel(WTL::CListViewCtrl& tCtrl) + { + return tCtrl.GetSelectedIndex(); + } + + template <> + void _setSel(WTL::CListViewCtrl& tCtrl, INT iSel) + { + if(iSel < 0) + tCtrl.SelectItem(-1); + else + tCtrl.SelectItem(iSel); + } +#endif // __ATLCTRLS_H__ + + template + void DDX_Index(UINT nID, INT& nVal, BOOL bSave) + { + T* pT = static_cast(this); + TCtrl ctrl(pT->GetDlgItem(nID)); + + if(bSave) + nVal = _getSel(ctrl); + else + _setSel(ctrl, nVal); + } +#endif // (_MSC_VER >= 1300) + +// Overrideables + void OnDataExchangeError(UINT nCtrlID, BOOL /*bSave*/) + { + // Override to display an error message + ::MessageBeep((UINT)-1); + T* pT = static_cast(this); + ::SetFocus(pT->GetDlgItem(nCtrlID)); + } + + void OnDataValidateError(UINT nCtrlID, BOOL /*bSave*/, _XData& /*data*/) + { + // Override to display an error message + ::MessageBeep((UINT)-1); + T* pT = static_cast(this); + ::SetFocus(pT->GetDlgItem(nCtrlID)); + } +}; + +}; // namespace WTL + +#endif // __ATLDDX_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atldlgs.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atldlgs.h new file mode 100644 index 0000000000000000000000000000000000000000..3ff14944252f9635b79d41cc824945595b8d7ced --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atldlgs.h @@ -0,0 +1,6507 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLDLGS_H__ +#define __ATLDLGS_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atldlgs.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atldlgs.h requires atlwin.h to be included first +#endif + +#include +#include + +#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) + #include +#endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CFileDialogImpl +// CFileDialog +// CFileDialogEx +// CMultiFileDialogImpl +// CMultiFileDialog +// CShellFileDialogImpl +// CShellFileOpenDialogImpl +// CShellFileOpenDialog +// CShellFileSaveDialogImpl +// CShellFileSaveDialog +// CFolderDialogImpl +// CFolderDialog +// CFontDialogImpl +// CFontDialog +// CRichEditFontDialogImpl +// CRichEditFontDialog +// CColorDialogImpl +// CColorDialog +// CPrintDialogImpl +// CPrintDialog +// CPrintDialogExImpl +// CPrintDialogEx +// CPageSetupDialogImpl +// CPageSetupDialog +// CFindReplaceDialogImpl +// CFindReplaceDialog +// +// CDialogBaseUnits +// CMemDlgTemplate +// CIndirectDialogImpl +// +// CPropertySheetWindow +// CPropertySheetImpl +// CPropertySheet +// CPropertyPageWindow +// CPropertyPageImpl +// CPropertyPage +// CAxPropertyPageImpl +// CAxPropertyPage +// +// CWizard97SheetWindow +// CWizard97SheetImpl +// CWizard97Sheet +// CWizard97PageWindow +// CWizard97PageImpl +// CWizard97ExteriorPageImpl +// CWizard97InteriorPageImpl +// +// CAeroWizardFrameWindow +// CAeroWizardFrameImpl +// CAeroWizardFrame +// CAeroWizardPageWindow +// CAeroWizardPageImpl +// CAeroWizardPage +// CAeroWizardAxPageImpl +// CAeroWizardAxPage +// +// CTaskDialogConfig +// CTaskDialogImpl +// CTaskDialog +// +// Global functions: +// AtlTaskDialog() + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CFileDialogImpl - used for File Open or File Save As + +// compatibility with the old (vc6.0) headers +#if (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400) + #ifndef CDSIZEOF_STRUCT + #define CDSIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) + #endif + #define OPENFILENAME_SIZE_VERSION_400A CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName) + #define OPENFILENAME_SIZE_VERSION_400W CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName) + #ifdef UNICODE + #define OPENFILENAME_SIZE_VERSION_400 OPENFILENAME_SIZE_VERSION_400W + #else + #define OPENFILENAME_SIZE_VERSION_400 OPENFILENAME_SIZE_VERSION_400A + #endif // !UNICODE +#endif // (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400) + +#if !defined(_WIN32_WCE) && !defined(CDN_INCLUDEITEM) + #define CDN_INCLUDEITEM (CDN_FIRST - 0x0007) +#endif + +template +class ATL_NO_VTABLE CFileDialogImpl : public ATL::CDialogImplBase +{ +public: +#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) + OPENFILENAMEEX m_ofn; +#else + OPENFILENAME m_ofn; +#endif + BOOL m_bOpenFileDialog; // TRUE for file open, FALSE for file save + TCHAR m_szFileTitle[_MAX_FNAME]; // contains file title after return + TCHAR m_szFileName[_MAX_PATH]; // contains full path name after return + + CFileDialogImpl(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs + LPCTSTR lpszDefExt = NULL, + LPCTSTR lpszFileName = NULL, + DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, + LPCTSTR lpszFilter = NULL, + HWND hWndParent = NULL) + { + memset(&m_ofn, 0, sizeof(m_ofn)); // initialize structure to 0/NULL + m_szFileName[0] = _T('\0'); + m_szFileTitle[0] = _T('\0'); + + m_bOpenFileDialog = bOpenFileDialog; + +#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) + m_ofn.lStructSize = bOpenFileDialog ? sizeof(m_ofn) : sizeof(OPENFILENAME); +#else + m_ofn.lStructSize = sizeof(m_ofn); +#endif + +#if (_WIN32_WINNT >= 0x0500) + // adjust struct size if running on older version of Windows + if(AtlIsOldWindows()) + { + ATLASSERT(sizeof(m_ofn) > OPENFILENAME_SIZE_VERSION_400); // must be + m_ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; + } +#endif // (_WIN32_WINNT >= 0x0500) + m_ofn.lpstrFile = m_szFileName; + m_ofn.nMaxFile = _MAX_PATH; + m_ofn.lpstrDefExt = lpszDefExt; + m_ofn.lpstrFileTitle = (LPTSTR)m_szFileTitle; + m_ofn.nMaxFileTitle = _MAX_FNAME; +#ifndef _WIN32_WCE + m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLESIZING; +#else // CE specific + m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK; +#endif // !_WIN32_WCE + m_ofn.lpstrFilter = lpszFilter; + m_ofn.hInstance = ModuleHelper::GetResourceInstance(); + m_ofn.lpfnHook = (LPOFNHOOKPROC)T::StartDialogProc; + m_ofn.hwndOwner = hWndParent; + + // setup initial file name + if(lpszFileName != NULL) + SecureHelper::strncpy_x(m_szFileName, _countof(m_szFileName), lpszFileName, _TRUNCATE); + } + + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT((m_ofn.Flags & OFN_ENABLEHOOK) != 0); + ATLASSERT(m_ofn.lpfnHook != NULL); // can still be a user hook + + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + if(m_ofn.hwndOwner == NULL) // set only if not specified before + m_ofn.hwndOwner = hWndParent; + + ATLASSERT(m_hWnd == NULL); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL bRetTh = m_thunk.Init(NULL, NULL); + if(bRetTh == FALSE) + { + ::SetLastError(ERROR_OUTOFMEMORY); + return -1; + } +#endif // (_ATL_VER >= 0x0800) + + ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBase*)this); + + BOOL bRet; + if(m_bOpenFileDialog) +#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) + bRet = ::GetOpenFileNameEx(&m_ofn); + else + bRet = ::GetSaveFileName((LPOPENFILENAME)&m_ofn); +#else + bRet = ::GetOpenFileName(&m_ofn); + else + bRet = ::GetSaveFileName(&m_ofn); +#endif + + m_hWnd = NULL; + + return bRet ? IDOK : IDCANCEL; + } + +// Attributes + ATL::CWindow GetFileDialogWindow() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ATL::CWindow(GetParent()); + } + + int GetFilePath(LPTSTR lpstrFilePath, int nLength) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + return (int)GetFileDialogWindow().SendMessage(CDM_GETFILEPATH, nLength, (LPARAM)lpstrFilePath); + } + + int GetFolderIDList(LPVOID lpBuff, int nLength) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERIDLIST, nLength, (LPARAM)lpBuff); + } + + int GetFolderPath(LPTSTR lpstrFolderPath, int nLength) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERPATH, nLength, (LPARAM)lpstrFolderPath); + } + + int GetSpec(LPTSTR lpstrSpec, int nLength) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + return (int)GetFileDialogWindow().SendMessage(CDM_GETSPEC, nLength, (LPARAM)lpstrSpec); + } + + void SetControlText(int nCtrlID, LPCTSTR lpstrText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + GetFileDialogWindow().SendMessage(CDM_SETCONTROLTEXT, nCtrlID, (LPARAM)lpstrText); + } + + void SetDefExt(LPCTSTR lpstrExt) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + GetFileDialogWindow().SendMessage(CDM_SETDEFEXT, 0, (LPARAM)lpstrExt); + } + + BOOL GetReadOnlyPref() const // return TRUE if readonly checked + { + return ((m_ofn.Flags & OFN_READONLY) != 0) ? TRUE : FALSE; + } + +// Operations + void HideControl(int nCtrlID) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + GetFileDialogWindow().SendMessage(CDM_HIDECONTROL, nCtrlID); + } + +// Special override for common dialogs + BOOL EndDialog(INT_PTR /*nRetCode*/ = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + GetFileDialogWindow().SendMessage(WM_COMMAND, MAKEWPARAM(IDCANCEL, 0)); + return TRUE; + } + +// Message map and handlers + BEGIN_MSG_MAP(CFileDialogImpl) + NOTIFY_CODE_HANDLER(CDN_FILEOK, _OnFileOK) + NOTIFY_CODE_HANDLER(CDN_FOLDERCHANGE, _OnFolderChange) + NOTIFY_CODE_HANDLER(CDN_HELP, _OnHelp) + NOTIFY_CODE_HANDLER(CDN_INITDONE, _OnInitDone) + NOTIFY_CODE_HANDLER(CDN_SELCHANGE, _OnSelChange) + NOTIFY_CODE_HANDLER(CDN_SHAREVIOLATION, _OnShareViolation) + NOTIFY_CODE_HANDLER(CDN_TYPECHANGE, _OnTypeChange) +#ifndef _WIN32_WCE + NOTIFY_CODE_HANDLER(CDN_INCLUDEITEM, _OnIncludeItem) +#endif // !_WIN32_WCE + END_MSG_MAP() + + LRESULT _OnFileOK(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + return !pT->OnFileOK((LPOFNOTIFY)pnmh); + } + + LRESULT _OnFolderChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + pT->OnFolderChange((LPOFNOTIFY)pnmh); + return 0; + } + + LRESULT _OnHelp(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + pT->OnHelp((LPOFNOTIFY)pnmh); + return 0; + } + + LRESULT _OnInitDone(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + pT->OnInitDone((LPOFNOTIFY)pnmh); + return 0; + } + + LRESULT _OnSelChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + pT->OnSelChange((LPOFNOTIFY)pnmh); + return 0; + } + + LRESULT _OnShareViolation(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + return pT->OnShareViolation((LPOFNOTIFY)pnmh); + } + + LRESULT _OnTypeChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + pT->OnTypeChange((LPOFNOTIFY)pnmh); + return 0; + } + +#ifndef _WIN32_WCE + LRESULT _OnIncludeItem(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + return pT->OnIncludeItem((LPOFNOTIFYEX)pnmh); + } +#endif // !_WIN32_WCE + +// Overrideables + BOOL OnFileOK(LPOFNOTIFY /*lpon*/) + { + return TRUE; + } + + void OnFolderChange(LPOFNOTIFY /*lpon*/) + { + } + + void OnHelp(LPOFNOTIFY /*lpon*/) + { + } + + void OnInitDone(LPOFNOTIFY /*lpon*/) + { + } + + void OnSelChange(LPOFNOTIFY /*lpon*/) + { + } + + int OnShareViolation(LPOFNOTIFY /*lpon*/) + { + return 0; + } + + void OnTypeChange(LPOFNOTIFY /*lpon*/) + { + } + +#ifndef _WIN32_WCE + BOOL OnIncludeItem(LPOFNOTIFYEX /*lponex*/) + { + return TRUE; // include item + } +#endif // !_WIN32_WCE +}; + +class CFileDialog : public CFileDialogImpl +{ +public: + CFileDialog(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs + LPCTSTR lpszDefExt = NULL, + LPCTSTR lpszFileName = NULL, + DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, + LPCTSTR lpszFilter = NULL, + HWND hWndParent = NULL) + : CFileDialogImpl(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent) + { } + + // override base class map and references to handlers + DECLARE_EMPTY_MSG_MAP() +}; + +#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) +class CFileDialogEx : public CFileDialogImpl +{ +public: + CFileDialogEx( // Supports only FileOpen + LPCTSTR lpszDefExt = NULL, + LPCTSTR lpszFileName = NULL, + DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, + OFN_EXFLAG ExFlags = OFN_EXFLAG_THUMBNAILVIEW, + OFN_SORTORDER dwSortOrder = OFN_SORTORDER_AUTO, + LPCTSTR lpszFilter = NULL, + HWND hWndParent = NULL) + : CFileDialogImpl(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent) + { + m_ofn.ExFlags = ExFlags; + m_ofn.dwSortOrder = dwSortOrder; + } + + // override base class map and references to handlers + DECLARE_EMPTY_MSG_MAP() +}; +#endif // defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) + + +/////////////////////////////////////////////////////////////////////////////// +// Multi File Dialog - Multi-select File Open dialog + +#ifndef _WIN32_WCE + +// The class dynamically resizes the buffer as the file selection changes +// (as described in Knowledge Base article 131462). It also expands selected +// shortcut files to take into account the full path of the target file. +// Note that this doesn't work on Win9x for the old style dialogs, as well as +// on NT for non-Unicode builds. + +#ifndef _WTL_FIXED_OFN_BUFFER_LENGTH + #define _WTL_FIXED_OFN_BUFFER_LENGTH 0x10000 +#endif + +template +class ATL_NO_VTABLE CMultiFileDialogImpl : public CFileDialogImpl< T > +{ +public: + mutable LPCTSTR m_pNextFile; +#ifndef _UNICODE + bool m_bIsNT; +#endif + + CMultiFileDialogImpl( + LPCTSTR lpszDefExt = NULL, + LPCTSTR lpszFileName = NULL, + DWORD dwFlags = OFN_HIDEREADONLY, + LPCTSTR lpszFilter = NULL, + HWND hWndParent = NULL) + : CFileDialogImpl(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent), + m_pNextFile(NULL) + { + m_ofn.Flags |= OFN_ALLOWMULTISELECT; // Force multiple selection mode + +#ifndef _UNICODE +#ifdef _versionhelpers_H_INCLUDED_ + OSVERSIONINFOEX ovi = { sizeof(OSVERSIONINFOEX) }; + ovi.dwPlatformId = VER_PLATFORM_WIN32_NT; + DWORDLONG const dwlConditionMask = ::VerSetConditionMask(0, VER_PLATFORMID, VER_EQUAL); + m_bIsNT = (::VerifyVersionInfo(&ovi, VER_PLATFORMID, dwlConditionMask) != FALSE); +#else // !_versionhelpers_H_INCLUDED_ + OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; + ::GetVersionEx(&ovi); + m_bIsNT = (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT); +#endif // _versionhelpers_H_INCLUDED_ + if (m_bIsNT) + { + // On NT platforms, GetOpenFileNameA thunks to GetOpenFileNameW and there + // is absolutely nothing we can do except to start off with a large buffer. + ATLVERIFY(ResizeFilenameBuffer(_WTL_FIXED_OFN_BUFFER_LENGTH)); + } +#endif + } + + ~CMultiFileDialogImpl() + { + if (m_ofn.lpstrFile != m_szFileName) // Free the buffer if we allocated it + delete[] m_ofn.lpstrFile; + } + +// Operations + // Get the directory that the files were chosen from. + // The function returns the number of characters copied, not including the terminating zero. + // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero. + // If the function fails, the return value is zero. + int GetDirectory(LPTSTR pBuffer, int nBufLen) const + { + if (m_ofn.lpstrFile == NULL) + return 0; + + LPCTSTR pStr = m_ofn.lpstrFile; + int nLength = lstrlen(pStr); + if (pStr[nLength + 1] == 0) + { + // The OFN buffer contains a single item so extract its path. + LPCTSTR pSep = MinCrtHelper::_strrchr(pStr, _T('\\')); + if (pSep != NULL) + nLength = (int)(DWORD_PTR)(pSep - pStr); + } + + int nRet = 0; + if (pBuffer == NULL) // If the buffer is NULL, return the required length + { + nRet = nLength + 1; + } + else if (nBufLen > nLength) + { + SecureHelper::strncpy_x(pBuffer, nBufLen, pStr, nLength); + nRet = nLength; + } + + return nRet; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + bool GetDirectory(_CSTRING_NS::CString& strDir) const + { + bool bRet = false; + + int nLength = GetDirectory(NULL, 0); + if (nLength > 0) + { + bRet = (GetDirectory(strDir.GetBuffer(nLength), nLength) > 0); + strDir.ReleaseBuffer(nLength - 1); + } + + return bRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + // Get the first filename as a pointer into the buffer. + LPCTSTR GetFirstFileName() const + { + if (m_ofn.lpstrFile == NULL) + return NULL; + + m_pNextFile = NULL; // Reset internal buffer pointer + + LPCTSTR pStr = m_ofn.lpstrFile; + int nLength = lstrlen(pStr); + if (pStr[nLength + 1] != 0) + { + // Multiple items were selected. The first string is the directory, + // so skip forwards to the second string. + pStr += nLength + 1; + + // Set up m_pNext so it points to the second item (or null). + m_pNextFile = pStr; + GetNextFileName(); + } + else + { + // A single item was selected. Skip forward past the path. + LPCTSTR pSep = MinCrtHelper::_strrchr(pStr, _T('\\')); + if (pSep != NULL) + pStr = pSep + 1; + } + + return pStr; + } + + // Get the next filename as a pointer into the buffer. + LPCTSTR GetNextFileName() const + { + if (m_pNextFile == NULL) + return NULL; + + LPCTSTR pStr = m_pNextFile; + // Set "m_pNextFile" to point to the next file name, or null if we + // have reached the last file in the list. + int nLength = lstrlen(pStr); + m_pNextFile = (pStr[nLength + 1] != 0) ? &pStr[nLength + 1] : NULL; + + return pStr; + } + + // Get the first filename as a full path. + // The function returns the number of characters copied, not including the terminating zero. + // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero. + // If the function fails, the return value is zero. + int GetFirstPathName(LPTSTR pBuffer, int nBufLen) const + { + LPCTSTR pStr = GetFirstFileName(); + int nLengthDir = GetDirectory(NULL, 0); + if((pStr == NULL) || (nLengthDir == 0)) + return 0; + + // Figure out the required length. + int nLengthTotal = nLengthDir + lstrlen(pStr); + + int nRet = 0; + if(pBuffer == NULL) // If the buffer is NULL, return the required length + { + nRet = nLengthTotal + 1; + } + else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path + { + GetDirectory(pBuffer, nBufLen); + SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\")); + SecureHelper::strcat_x(pBuffer, nBufLen, pStr); + nRet = nLengthTotal; + } + + return nRet; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + bool GetFirstPathName(_CSTRING_NS::CString& strPath) const + { + bool bRet = false; + + int nLength = GetFirstPathName(NULL, 0); + if (nLength > 0) + { + bRet = (GetFirstPathName(strPath.GetBuffer(nLength), nLength) > 0); + strPath.ReleaseBuffer(nLength - 1); + } + + return bRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + // Get the next filename as a full path. + // The function returns the number of characters copied, not including the terminating zero. + // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero. + // If the function fails, the return value is zero. + // The internal position marker is moved forward only if the function succeeds and the buffer was large enough. + int GetNextPathName(LPTSTR pBuffer, int nBufLen) const + { + if (m_pNextFile == NULL) + return 0; + + int nRet = 0; + LPCTSTR pStr = m_pNextFile; + // Does the filename contain a backslash? + if (MinCrtHelper::_strrchr(pStr, _T('\\')) != NULL) + { + // Yes, so we'll assume it's a full path. + int nLength = lstrlen(pStr); + + if (pBuffer == NULL) // If the buffer is NULL, return the required length + { + nRet = nLength + 1; + } + else if (nBufLen > nLength) // The buffer is big enough, so go ahead and copy the filename + { + SecureHelper::strcpy_x(pBuffer, nBufLen, GetNextFileName()); + nRet = nBufLen; + } + } + else + { + // The filename is relative, so construct the full path. + int nLengthDir = GetDirectory(NULL, 0); + if (nLengthDir > 0) + { + // Calculate the required space. + int nLengthTotal = nLengthDir + lstrlen(pStr); + + if(pBuffer == NULL) // If the buffer is NULL, return the required length + { + nRet = nLengthTotal + 1; + } + else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path + { + GetDirectory(pBuffer, nBufLen); + SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\")); + SecureHelper::strcat_x(pBuffer, nBufLen, GetNextFileName()); + nRet = nLengthTotal; + } + } + } + + return nRet; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + bool GetNextPathName(_CSTRING_NS::CString& strPath) const + { + bool bRet = false; + + int nLength = GetNextPathName(NULL, 0); + if (nLength > 0) + { + bRet = (GetNextPathName(strPath.GetBuffer(nLength), nLength) > 0); + strPath.ReleaseBuffer(nLength - 1); + } + + return bRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + +// Implementation + bool ResizeFilenameBuffer(DWORD dwLength) + { + if (dwLength > m_ofn.nMaxFile) + { + // Free the old buffer. + if (m_ofn.lpstrFile != m_szFileName) + { + delete[] m_ofn.lpstrFile; + m_ofn.lpstrFile = NULL; + m_ofn.nMaxFile = 0; + } + + // Allocate the new buffer. + LPTSTR lpstrBuff = NULL; + ATLTRY(lpstrBuff = new TCHAR[dwLength]); + if (lpstrBuff != NULL) + { + m_ofn.lpstrFile = lpstrBuff; + m_ofn.lpstrFile[0] = 0; + m_ofn.nMaxFile = dwLength; + } + } + + return (m_ofn.lpstrFile != NULL); + } + + void OnSelChange(LPOFNOTIFY /*lpon*/) + { +#ifndef _UNICODE + // There is no point resizing the buffer in ANSI builds running on NT. + if (m_bIsNT) + return; +#endif + + // Get the buffer length required to hold the spec. + int nLength = GetSpec(NULL, 0); + if (nLength <= 1) + return; // no files are selected, presumably + + // Add room for the directory, and an extra terminating zero. + nLength += GetFolderPath(NULL, 0) + 1; + + if (!ResizeFilenameBuffer(nLength)) + { + ATLASSERT(FALSE); + return; + } + + // If we are not following links then our work is done. + if ((m_ofn.Flags & OFN_NODEREFERENCELINKS) != 0) + return; + + // Get the file spec, which is the text in the edit control. + if (GetSpec(m_ofn.lpstrFile, m_ofn.nMaxFile) <= 0) + return; + + // Get the ID-list of the current folder. + int nBytes = GetFolderIDList(NULL, 0); +#ifdef STRICT_TYPED_ITEMIDS + CTempBuffer idlist; +#else + CTempBuffer idlist; +#endif + idlist.AllocateBytes(nBytes); + if ((nBytes <= 0) || (GetFolderIDList(idlist, nBytes) <= 0)) + return; + + // First bind to the desktop folder, then to the current folder. + ATL::CComPtr pDesktop, pFolder; + if (FAILED(::SHGetDesktopFolder(&pDesktop))) + return; + if (FAILED(pDesktop->BindToObject(idlist, NULL, IID_IShellFolder, (void**)&pFolder))) + return; + + // Work through the file spec, looking for quoted filenames. If we find a shortcut file, then + // we need to add enough extra buffer space to hold its target path. + DWORD nExtraChars = 0; + bool bInsideQuotes = false; + LPCTSTR pAnchor = m_ofn.lpstrFile; + LPCTSTR pChar = m_ofn.lpstrFile; + for ( ; *pChar; ++pChar) + { + // Look for quotation marks. + if (*pChar == _T('\"')) + { + // We are either entering or leaving a passage of quoted text. + bInsideQuotes = !bInsideQuotes; + + // Is it an opening or closing quote? + if (bInsideQuotes) + { + // We found an opening quote, so set "pAnchor" to the following character. + pAnchor = pChar + 1; + } + else // closing quote + { + // Each quoted entity should be shorter than MAX_PATH. + if (pChar - pAnchor >= MAX_PATH) + return; + + // Get the ID-list and attributes of the file. + USES_CONVERSION; + int nFileNameLength = (int)(DWORD_PTR)(pChar - pAnchor); + TCHAR szFileName[MAX_PATH] = { 0 }; + SecureHelper::strncpy_x(szFileName, MAX_PATH, pAnchor, nFileNameLength); +#ifdef STRICT_TYPED_ITEMIDS + PIDLIST_RELATIVE pidl = NULL; +#else + LPITEMIDLIST pidl = NULL; +#endif + DWORD dwAttrib = SFGAO_LINK; + if (SUCCEEDED(pFolder->ParseDisplayName(NULL, NULL, T2W(szFileName), NULL, &pidl, &dwAttrib))) + { + // Is it a shortcut file? + if (dwAttrib & SFGAO_LINK) + { + // Bind to its IShellLink interface. + ATL::CComPtr pLink; + if (SUCCEEDED(pFolder->BindToObject(pidl, NULL, IID_IShellLink, (void**)&pLink))) + { + // Get the shortcut's target path. + TCHAR szPath[MAX_PATH] = { 0 }; + if (SUCCEEDED(pLink->GetPath(szPath, MAX_PATH, NULL, 0))) + { + // If the target path is longer than the shortcut name, then add on the number + // of extra characters that are required. + int nNewLength = lstrlen(szPath); + if (nNewLength > nFileNameLength) + nExtraChars += nNewLength - nFileNameLength; + } + } + } + + // Free the ID-list returned by ParseDisplayName. + ::CoTaskMemFree(pidl); + } + } + } + } + + // If we need more space for shortcut targets, then reallocate. + if (nExtraChars > 0) + ATLVERIFY(ResizeFilenameBuffer(m_ofn.nMaxFile + nExtraChars)); + } +}; + +class CMultiFileDialog : public CMultiFileDialogImpl +{ +public: + CMultiFileDialog( + LPCTSTR lpszDefExt = NULL, + LPCTSTR lpszFileName = NULL, + DWORD dwFlags = OFN_HIDEREADONLY, + LPCTSTR lpszFilter = NULL, + HWND hWndParent = NULL) + : CMultiFileDialogImpl(lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent) + { } + + BEGIN_MSG_MAP(CMultiFileDialog) + CHAIN_MSG_MAP(CMultiFileDialogImpl) + END_MSG_MAP() +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// Shell File Dialog - new Shell File Open and Save dialogs in Vista + +// Note: Use GetPtr() to access dialog interface methods. +// Example: +// CShellFileOpenDialog dlg; +// dlg.GetPtr()->SetTitle(L"MyFileOpenDialog"); + +#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) + +/////////////////////////////////////////////////////////////////////////////// +// CShellFileDialogImpl - base class for CShellFileOpenDialogImpl and CShellFileSaveDialogImpl + +template +class ATL_NO_VTABLE CShellFileDialogImpl : public IFileDialogEvents +{ +public: +// Operations + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + INT_PTR nRet = -1; + + T* pT = static_cast(this); + if(pT->m_spFileDlg == NULL) + { + ATLASSERT(FALSE); + return nRet; + } + + DWORD dwCookie = 0; + pT->_Advise(dwCookie); + + HRESULT hRet = pT->m_spFileDlg->Show(hWndParent); + if(SUCCEEDED(hRet)) + nRet = IDOK; + else if(hRet == HRESULT_FROM_WIN32(ERROR_CANCELLED)) + nRet = IDCANCEL; + else + ATLASSERT(FALSE); // error + + pT->_Unadvise(dwCookie); + + return nRet; + } + + bool IsNull() const + { + const T* pT = static_cast(this); + return (pT->m_spFileDlg == NULL); + } + +// Operations - get file path after dialog returns + HRESULT GetFilePath(LPWSTR lpstrFilePath, int cchLength) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + + ATL::CComPtr spItem; + HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem); + + if(SUCCEEDED(hRet)) + hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, lpstrFilePath, cchLength); + + return hRet; + } + + HRESULT GetFileTitle(LPWSTR lpstrFileTitle, int cchLength) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + + ATL::CComPtr spItem; + HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem); + + if(SUCCEEDED(hRet)) + hRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, lpstrFileTitle, cchLength); + + return hRet; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + HRESULT GetFilePath(_CSTRING_NS::CString& strFilePath) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + + ATL::CComPtr spItem; + HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem); + + if(SUCCEEDED(hRet)) + hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, strFilePath); + + return hRet; + } + + HRESULT GetFileTitle(_CSTRING_NS::CString& strFileTitle) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + + ATL::CComPtr spItem; + HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem); + + if(SUCCEEDED(hRet)) + hRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, strFileTitle); + + return hRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + +// Helpers for IShellItem + static HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, LPWSTR lpstr, int cchLength) + { + ATLASSERT(pShellItem != NULL); + + LPWSTR lpstrName = NULL; + HRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName); + + if(SUCCEEDED(hRet)) + { + if(lstrlenW(lpstrName) < cchLength) + { + SecureHelper::strcpyW_x(lpstr, cchLength, lpstrName); + } + else + { + ATLASSERT(FALSE); + hRet = DISP_E_BUFFERTOOSMALL; + } + + ::CoTaskMemFree(lpstrName); + } + + return hRet; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + static HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, _CSTRING_NS::CString& str) + { + ATLASSERT(pShellItem != NULL); + + LPWSTR lpstrName = NULL; + HRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName); + + if(SUCCEEDED(hRet)) + { + str = lpstrName; + ::CoTaskMemFree(lpstrName); + } + + return hRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + +// Implementation + void _Advise(DWORD& dwCookie) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + HRESULT hRet = pT->m_spFileDlg->Advise((IFileDialogEvents*)this, &dwCookie); + ATLVERIFY(SUCCEEDED(hRet)); + } + + void _Unadvise(DWORD dwCookie) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + HRESULT hRet = pT->m_spFileDlg->Unadvise(dwCookie); + ATLVERIFY(SUCCEEDED(hRet)); + } + + void _Init(LPCWSTR lpszFileName, DWORD dwOptions, LPCWSTR lpszDefExt, const COMDLG_FILTERSPEC* arrFilterSpec, UINT uFilterSpecCount) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + + HRESULT hRet = E_FAIL; + + if(lpszFileName != NULL) + { + hRet = pT->m_spFileDlg->SetFileName(lpszFileName); + ATLASSERT(SUCCEEDED(hRet)); + } + + hRet = pT->m_spFileDlg->SetOptions(dwOptions); + ATLASSERT(SUCCEEDED(hRet)); + + if(lpszDefExt != NULL) + { + hRet = pT->m_spFileDlg->SetDefaultExtension(lpszDefExt); + ATLASSERT(SUCCEEDED(hRet)); + } + + if(arrFilterSpec != NULL && uFilterSpecCount != 0U) + { + hRet = pT->m_spFileDlg->SetFileTypes(uFilterSpecCount, arrFilterSpec); + ATLASSERT(SUCCEEDED(hRet)); + } + } + +// Implementation - IUnknown interface + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) + { + if(ppvObject == NULL) + return E_POINTER; + + T* pT = static_cast(this); + if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IFileDialogEvents)) + { + *ppvObject = (IFileDialogEvents*)pT; + // AddRef() not needed + return S_OK; + } + + return E_NOINTERFACE; + } + + virtual ULONG STDMETHODCALLTYPE AddRef() + { + return 1; + } + + virtual ULONG STDMETHODCALLTYPE Release() + { + return 1; + } + +// Implementation - IFileDialogEvents interface + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFileOk(IFileDialog* pfd) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnFileOk(); + } + + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChanging(IFileDialog* pfd, IShellItem* psiFolder) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnFolderChanging(psiFolder); + } + + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChange(IFileDialog* pfd) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnFolderChange(); + } + + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnSelectionChange(IFileDialog* pfd) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnSelectionChange(); + } + + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnShareViolation(IFileDialog* pfd, IShellItem* psi, FDE_SHAREVIOLATION_RESPONSE* pResponse) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnShareViolation(psi, pResponse); + } + + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnTypeChange(IFileDialog* pfd) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnTypeChange(); + } + + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnOverwrite(IFileDialog* pfd, IShellItem* psi, FDE_OVERWRITE_RESPONSE* pResponse) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnOverwrite(psi, pResponse); + } + +// Overrideables - Event handlers + HRESULT OnFileOk() + { + return E_NOTIMPL; + } + + HRESULT OnFolderChanging(IShellItem* /*psiFolder*/) + { + return E_NOTIMPL; + } + + HRESULT OnFolderChange() + { + return E_NOTIMPL; + } + + HRESULT OnSelectionChange() + { + return E_NOTIMPL; + } + + HRESULT OnShareViolation(IShellItem* /*psi*/, FDE_SHAREVIOLATION_RESPONSE* /*pResponse*/) + { + return E_NOTIMPL; + } + + HRESULT OnTypeChange() + { + return E_NOTIMPL; + } + + HRESULT OnOverwrite(IShellItem* /*psi*/, FDE_OVERWRITE_RESPONSE* /*pResponse*/) + { + return E_NOTIMPL; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CShellFileOpenDialogImpl - implements new Shell File Open dialog + +template +class ATL_NO_VTABLE CShellFileOpenDialogImpl : public CShellFileDialogImpl< T > +{ +public: + ATL::CComPtr m_spFileDlg; + + CShellFileOpenDialogImpl(LPCWSTR lpszFileName = NULL, + DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST, + LPCWSTR lpszDefExt = NULL, + const COMDLG_FILTERSPEC* arrFilterSpec = NULL, + UINT uFilterSpecCount = 0U) + { + HRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileOpenDialog); + + if(SUCCEEDED(hRet)) + _Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount); + } + + IFileOpenDialog* GetPtr() + { + return m_spFileDlg; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CShellFileOpenDialog - new Shell File Open dialog without events + +class CShellFileOpenDialog : public CShellFileOpenDialogImpl +{ +public: + CShellFileOpenDialog(LPCWSTR lpszFileName = NULL, + DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST, + LPCWSTR lpszDefExt = NULL, + const COMDLG_FILTERSPEC* arrFilterSpec = NULL, + UINT uFilterSpecCount = 0U) : CShellFileOpenDialogImpl(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount) + { } + +// Implementation (remove _Advise/_Unadvise code using template magic) + void _Advise(DWORD& /*dwCookie*/) + { } + + void _Unadvise(DWORD /*dwCookie*/) + { } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CShellFileSaveDialogImpl - implements new Shell File Save dialog + +template +class ATL_NO_VTABLE CShellFileSaveDialogImpl : public CShellFileDialogImpl< T > +{ +public: + ATL::CComPtr m_spFileDlg; + + CShellFileSaveDialogImpl(LPCWSTR lpszFileName = NULL, + DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT, + LPCWSTR lpszDefExt = NULL, + const COMDLG_FILTERSPEC* arrFilterSpec = NULL, + UINT uFilterSpecCount = 0U) + { + HRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileSaveDialog); + + if(SUCCEEDED(hRet)) + _Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount); + } + + IFileSaveDialog* GetPtr() + { + return m_spFileDlg; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CShellFileSaveDialog - new Shell File Save dialog without events + +class CShellFileSaveDialog : public CShellFileSaveDialogImpl +{ +public: + CShellFileSaveDialog(LPCWSTR lpszFileName = NULL, + DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT, + LPCWSTR lpszDefExt = NULL, + const COMDLG_FILTERSPEC* arrFilterSpec = NULL, + UINT uFilterSpecCount = 0U) : CShellFileSaveDialogImpl(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount) + { } + +// Implementation (remove _Advise/_Unadvise code using template magic) + void _Advise(DWORD& /*dwCookie*/) + { } + + void _Unadvise(DWORD /*dwCookie*/) + { } +}; + +#endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CFolderDialogImpl - used for browsing for a folder + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CFolderDialogImpl +{ +public: + BROWSEINFO m_bi; + LPCTSTR m_lpstrInitialFolder; + LPCITEMIDLIST m_pidlInitialSelection; + bool m_bExpandInitialSelection; + TCHAR m_szFolderDisplayName[MAX_PATH]; + TCHAR m_szFolderPath[MAX_PATH]; +#ifdef STRICT_TYPED_ITEMIDS + PIDLIST_ABSOLUTE m_pidlSelected; +#else + LPITEMIDLIST m_pidlSelected; +#endif + HWND m_hWnd; // used only in the callback function + +// Constructor + CFolderDialogImpl(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS) : + m_lpstrInitialFolder(NULL), m_pidlInitialSelection(NULL), m_bExpandInitialSelection(false), m_pidlSelected(NULL), m_hWnd(NULL) + { + memset(&m_bi, 0, sizeof(m_bi)); // initialize structure to 0/NULL + + m_bi.hwndOwner = hWndParent; + m_bi.pidlRoot = NULL; + m_bi.pszDisplayName = m_szFolderDisplayName; + m_bi.lpszTitle = lpstrTitle; + m_bi.ulFlags = uFlags; + m_bi.lpfn = BrowseCallbackProc; + m_bi.lParam = (LPARAM)static_cast(this); + + m_szFolderPath[0] = 0; + m_szFolderDisplayName[0] = 0; + } + + ~CFolderDialogImpl() + { + ::CoTaskMemFree(m_pidlSelected); + } + +// Operations + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + if(m_bi.hwndOwner == NULL) // set only if not specified before + m_bi.hwndOwner = hWndParent; + + // Clear out any previous results + m_szFolderPath[0] = 0; + m_szFolderDisplayName[0] = 0; + ::CoTaskMemFree(m_pidlSelected); + + INT_PTR nRet = IDCANCEL; + m_pidlSelected = ::SHBrowseForFolder(&m_bi); + + if(m_pidlSelected != NULL) + { + nRet = IDOK; + + // If BIF_RETURNONLYFSDIRS is set, we try to get the filesystem path. + // Otherwise, the caller must handle the ID-list directly. + if((m_bi.ulFlags & BIF_RETURNONLYFSDIRS) != 0) + { + if(::SHGetPathFromIDList(m_pidlSelected, m_szFolderPath) == FALSE) + nRet = IDCANCEL; + } + } + + return nRet; + } + + // Methods to call before DoModal + void SetInitialFolder(LPCTSTR lpstrInitialFolder, bool bExpand = true) + { + // lpstrInitialFolder may be a file if BIF_BROWSEINCLUDEFILES is specified + m_lpstrInitialFolder = lpstrInitialFolder; + m_bExpandInitialSelection = bExpand; + } + + void SetInitialSelection(LPCITEMIDLIST pidl, bool bExpand = true) + { + m_pidlInitialSelection = pidl; + m_bExpandInitialSelection = bExpand; + } + +#ifdef STRICT_TYPED_ITEMIDS + void SetRootFolder(PCIDLIST_ABSOLUTE pidl) +#else + void SetRootFolder(LPCITEMIDLIST pidl) +#endif + { + m_bi.pidlRoot = pidl; + } + + // Methods to call after DoModal + LPITEMIDLIST GetSelectedItem(bool bDetach = false) + { + LPITEMIDLIST pidl = m_pidlSelected; + if(bDetach) + m_pidlSelected = NULL; + + return pidl; + } + + LPCTSTR GetFolderPath() const + { + return m_szFolderPath; + } + + LPCTSTR GetFolderDisplayName() const + { + return m_szFolderDisplayName; + } + + int GetFolderImageIndex() const + { + return m_bi.iImage; + } + +// Callback function and overrideables + static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData) + { +#ifndef BFFM_VALIDATEFAILED + #ifdef UNICODE + const int BFFM_VALIDATEFAILED = 4; + #else + const int BFFM_VALIDATEFAILED = 3; + #endif +#endif // !BFFM_VALIDATEFAILED +#ifndef BFFM_IUNKNOWN + const int BFFM_IUNKNOWN = 5; +#endif // !BFFM_IUNKNOWN +#ifndef BIF_NEWDIALOGSTYLE + const UINT BIF_NEWDIALOGSTYLE = 0x0040; +#endif // !BIF_NEWDIALOGSTYLE + + int nRet = 0; + T* pT = (T*)lpData; + bool bClear = false; + if(pT->m_hWnd == NULL) + { + pT->m_hWnd = hWnd; + bClear = true; + } + else + { + ATLASSERT(pT->m_hWnd == hWnd); + } + + switch(uMsg) + { + case BFFM_INITIALIZED: + // Set initial selection + // Note that m_pidlInitialSelection, if set, takes precedence over m_lpstrInitialFolder + if(pT->m_pidlInitialSelection != NULL) + pT->SetSelection(pT->m_pidlInitialSelection); + else if(pT->m_lpstrInitialFolder != NULL) + pT->SetSelection(pT->m_lpstrInitialFolder); + + // Expand initial selection if appropriate + if(pT->m_bExpandInitialSelection && ((pT->m_bi.ulFlags & BIF_NEWDIALOGSTYLE) != 0)) + { + if(pT->m_pidlInitialSelection != NULL) + pT->SetExpanded(pT->m_pidlInitialSelection); + else if(pT->m_lpstrInitialFolder != NULL) + pT->SetExpanded(pT->m_lpstrInitialFolder); + } + pT->OnInitialized(); + break; + case BFFM_SELCHANGED: + pT->OnSelChanged((LPITEMIDLIST)lParam); + break; + case BFFM_VALIDATEFAILED: + nRet = pT->OnValidateFailed((LPCTSTR)lParam); + break; + case BFFM_IUNKNOWN: + pT->OnIUnknown((IUnknown*)lParam); + break; + default: + ATLTRACE2(atlTraceUI, 0, _T("Unknown message received in CFolderDialogImpl::BrowseCallbackProc\n")); + break; + } + + if(bClear) + pT->m_hWnd = NULL; + return nRet; + } + + void OnInitialized() + { + } + + void OnSelChanged(LPITEMIDLIST /*pItemIDList*/) + { + } + + int OnValidateFailed(LPCTSTR /*lpstrFolderPath*/) + { + return 1; // 1=continue, 0=EndDialog + } + + void OnIUnknown(IUnknown* /*pUnknown*/) + { + } + + // Commands - valid to call only from handlers + void EnableOK(BOOL bEnable) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, BFFM_ENABLEOK, 0, bEnable); + } + + void SetSelection(LPCITEMIDLIST pItemIDList) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, BFFM_SETSELECTION, FALSE, (LPARAM)pItemIDList); + } + + void SetSelection(LPCTSTR lpstrFolderPath) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpstrFolderPath); + } + + void SetStatusText(LPCTSTR lpstrText) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)lpstrText); + } + + void SetOKText(LPCTSTR lpstrOKText) + { +#ifndef BFFM_SETOKTEXT + const UINT BFFM_SETOKTEXT = WM_USER + 105; +#endif + ATLASSERT(m_hWnd != NULL); + USES_CONVERSION; + LPCWSTR lpstr = T2CW(lpstrOKText); + ::SendMessage(m_hWnd, BFFM_SETOKTEXT, 0, (LPARAM)lpstr); + } + + void SetExpanded(LPCITEMIDLIST pItemIDList) + { +#ifndef BFFM_SETEXPANDED + const UINT BFFM_SETEXPANDED = WM_USER + 106; +#endif + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, BFFM_SETEXPANDED, FALSE, (LPARAM)pItemIDList); + } + + void SetExpanded(LPCTSTR lpstrFolderPath) + { +#ifndef BFFM_SETEXPANDED + const UINT BFFM_SETEXPANDED = WM_USER + 106; +#endif + ATLASSERT(m_hWnd != NULL); + USES_CONVERSION; + LPCWSTR lpstr = T2CW(lpstrFolderPath); + ::SendMessage(m_hWnd, BFFM_SETEXPANDED, TRUE, (LPARAM)lpstr); + } +}; + +class CFolderDialog : public CFolderDialogImpl +{ +public: + CFolderDialog(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS) + : CFolderDialogImpl(hWndParent, lpstrTitle, uFlags) + { } +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CCommonDialogImplBase - base class for common dialog classes + +class ATL_NO_VTABLE CCommonDialogImplBase : public ATL::CWindowImplBase +{ +public: + static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + if(uMsg != WM_INITDIALOG) + return 0; + CCommonDialogImplBase* pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData(); + ATLASSERT(pT != NULL); + ATLASSERT(pT->m_hWnd == NULL); + ATLASSERT(::IsWindow(hWnd)); + // subclass dialog's window + if(!pT->SubclassWindow(hWnd)) + { + ATLTRACE2(atlTraceUI, 0, _T("Subclassing a common dialog failed\n")); + return 0; + } + // check message map for WM_INITDIALOG handler + LRESULT lRes = 0; + if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE) + return 0; + return lRes; + } + +// Special override for common dialogs + BOOL EndDialog(INT_PTR /*nRetCode*/ = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0)); + return TRUE; + } + +// Implementation - try to override these, to prevent errors + HWND Create(HWND, ATL::_U_RECT, LPCTSTR, DWORD, DWORD, ATL::_U_MENUorID, ATOM, LPVOID) + { + ATLASSERT(FALSE); // should not be called + return NULL; + } + + static LRESULT CALLBACK StartWindowProc(HWND /*hWnd*/, UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/) + { + ATLASSERT(FALSE); // should not be called + return 0; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CFontDialogImpl - font selection dialog + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CFontDialogImpl : public CCommonDialogImplBase +{ +public: + enum { _cchStyleName = 64 }; + + CHOOSEFONT m_cf; + TCHAR m_szStyleName[_cchStyleName]; // contains style name after return + LOGFONT m_lf; // default LOGFONT to store the info + +// Constructors + CFontDialogImpl(LPLOGFONT lplfInitial = NULL, + DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, + HDC hDCPrinter = NULL, + HWND hWndParent = NULL) + { + memset(&m_cf, 0, sizeof(m_cf)); + memset(&m_lf, 0, sizeof(m_lf)); + memset(&m_szStyleName, 0, sizeof(m_szStyleName)); + + m_cf.lStructSize = sizeof(m_cf); + m_cf.hwndOwner = hWndParent; + m_cf.rgbColors = RGB(0, 0, 0); + m_cf.lpszStyle = (LPTSTR)&m_szStyleName; + m_cf.Flags = dwFlags | CF_ENABLEHOOK; + m_cf.lpfnHook = (LPCFHOOKPROC)T::HookProc; + + if(lplfInitial != NULL) + { + m_cf.lpLogFont = lplfInitial; + m_cf.Flags |= CF_INITTOLOGFONTSTRUCT; + m_lf = *lplfInitial; + } + else + { + m_cf.lpLogFont = &m_lf; + } + + if(hDCPrinter != NULL) + { + m_cf.hDC = hDCPrinter; + m_cf.Flags |= CF_PRINTERFONTS; + } + } + +// Operations + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT((m_cf.Flags & CF_ENABLEHOOK) != 0); + ATLASSERT(m_cf.lpfnHook != NULL); // can still be a user hook + + if(m_cf.hwndOwner == NULL) // set only if not specified before + m_cf.hwndOwner = hWndParent; + + ATLASSERT(m_hWnd == NULL); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL bRetTh = m_thunk.Init(NULL, NULL); + if(bRetTh == FALSE) + { + ::SetLastError(ERROR_OUTOFMEMORY); + return -1; + } +#endif // (_ATL_VER >= 0x0800) + + ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); + + BOOL bRet = ::ChooseFont(&m_cf); + + m_hWnd = NULL; + + if(bRet) // copy logical font from user's initialization buffer (if needed) + SecureHelper::memcpy_x(&m_lf, sizeof(m_lf), m_cf.lpLogFont, sizeof(m_lf)); + + return bRet ? IDOK : IDCANCEL; + } + + // works only when the dialog is dislayed or after + void GetCurrentFont(LPLOGFONT lplf) const + { + ATLASSERT(lplf != NULL); + + if(m_hWnd != NULL) + ::SendMessage(m_hWnd, WM_CHOOSEFONT_GETLOGFONT, 0, (LPARAM)lplf); + else + *lplf = m_lf; + } + + // works only when the dialog is dislayed or before +#ifndef _WIN32_WCE + void SetLogFont(LPLOGFONT lplf) + { + ATLASSERT(lplf != NULL); +#ifndef WM_CHOOSEFONT_SETLOGFONT + const UINT WM_CHOOSEFONT_SETLOGFONT = (WM_USER + 101); +#endif + if(m_hWnd != NULL) + { + ::SendMessage(m_hWnd, WM_CHOOSEFONT_SETLOGFONT, 0, (LPARAM)lplf); + } + else + { + m_lf = *lplf; + m_cf.Flags |= CF_INITTOLOGFONTSTRUCT; + } + } + + void SetFlags(DWORD dwFlags) + { +#ifndef WM_CHOOSEFONT_SETFLAGS + const UINT WM_CHOOSEFONT_SETFLAGS = (WM_USER + 102); +#endif + if(m_hWnd != NULL) + { + CHOOSEFONT cf = { sizeof(CHOOSEFONT) }; + cf.Flags = dwFlags; + ::SendMessage(m_hWnd, WM_CHOOSEFONT_SETFLAGS, 0, (LPARAM)&cf); + } + else + { + m_cf.Flags = dwFlags; + } + } +#endif // !_WIN32_WCE + + // Helpers for parsing information after successful return + LPCTSTR GetFaceName() const // return the face name of the font + { + return (LPCTSTR)m_cf.lpLogFont->lfFaceName; + } + + LPCTSTR GetStyleName() const // return the style name of the font + { + return m_cf.lpszStyle; + } + + int GetSize() const // return the pt size of the font + { + return m_cf.iPointSize; + } + + COLORREF GetColor() const // return the color of the font + { + return m_cf.rgbColors; + } + + int GetWeight() const // return the chosen font weight + { + return (int)m_cf.lpLogFont->lfWeight; + } + + BOOL IsStrikeOut() const // return TRUE if strikeout + { + return (m_cf.lpLogFont->lfStrikeOut) ? TRUE : FALSE; + } + + BOOL IsUnderline() const // return TRUE if underline + { + return (m_cf.lpLogFont->lfUnderline) ? TRUE : FALSE; + } + + BOOL IsBold() const // return TRUE if bold font + { + return (m_cf.lpLogFont->lfWeight == FW_BOLD) ? TRUE : FALSE; + } + + BOOL IsItalic() const // return TRUE if italic font + { + return m_cf.lpLogFont->lfItalic ? TRUE : FALSE; + } +}; + +class CFontDialog : public CFontDialogImpl +{ +public: + CFontDialog(LPLOGFONT lplfInitial = NULL, + DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, + HDC hDCPrinter = NULL, + HWND hWndParent = NULL) + : CFontDialogImpl(lplfInitial, dwFlags, hDCPrinter, hWndParent) + { } + + DECLARE_EMPTY_MSG_MAP() +}; + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CRichEditFontDialogImpl - font selection for the Rich Edit ctrl + +#if defined(_RICHEDIT_) && !defined(_WIN32_WCE) + +template +class ATL_NO_VTABLE CRichEditFontDialogImpl : public CFontDialogImpl< T > +{ +public: + CRichEditFontDialogImpl(const CHARFORMAT& charformat, + DWORD dwFlags = CF_SCREENFONTS, + HDC hDCPrinter = NULL, + HWND hWndParent = NULL) + : CFontDialogImpl< T >(NULL, dwFlags, hDCPrinter, hWndParent) + { + m_cf.Flags |= CF_INITTOLOGFONTSTRUCT; + m_cf.Flags |= FillInLogFont(charformat); + m_cf.lpLogFont = &m_lf; + + if((charformat.dwMask & CFM_COLOR) != 0) + m_cf.rgbColors = charformat.crTextColor; + } + + void GetCharFormat(CHARFORMAT& cf) const + { + USES_CONVERSION; + cf.dwEffects = 0; + cf.dwMask = 0; + if((m_cf.Flags & CF_NOSTYLESEL) == 0) + { + cf.dwMask |= CFM_BOLD | CFM_ITALIC; + cf.dwEffects |= IsBold() ? CFE_BOLD : 0; + cf.dwEffects |= IsItalic() ? CFE_ITALIC : 0; + } + if((m_cf.Flags & CF_NOSIZESEL) == 0) + { + cf.dwMask |= CFM_SIZE; + // GetSize() returns in tenths of points so mulitply by 2 to get twips + cf.yHeight = GetSize() * 2; + } + + if((m_cf.Flags & CF_NOFACESEL) == 0) + { + cf.dwMask |= CFM_FACE; + cf.bPitchAndFamily = m_cf.lpLogFont->lfPitchAndFamily; +#if (_RICHEDIT_VER >= 0x0200) + SecureHelper::strcpy_x(cf.szFaceName, _countof(cf.szFaceName), GetFaceName()); +#else // !(_RICHEDIT_VER >= 0x0200) + SecureHelper::strcpyA_x(cf.szFaceName, _countof(cf.szFaceName), T2A((LPTSTR)(LPCTSTR)GetFaceName())); +#endif // !(_RICHEDIT_VER >= 0x0200) + } + + if((m_cf.Flags & CF_EFFECTS) != 0) + { + cf.dwMask |= CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR; + cf.dwEffects |= IsUnderline() ? CFE_UNDERLINE : 0; + cf.dwEffects |= IsStrikeOut() ? CFE_STRIKEOUT : 0; + cf.crTextColor = GetColor(); + } + if((m_cf.Flags & CF_NOSCRIPTSEL) == 0) + { + cf.bCharSet = m_cf.lpLogFont->lfCharSet; + cf.dwMask |= CFM_CHARSET; + } + cf.yOffset = 0; + } + + DWORD FillInLogFont(const CHARFORMAT& cf) + { + USES_CONVERSION; + DWORD dwFlags = 0; + if((cf.dwMask & CFM_SIZE) != 0) + { + HDC hDC = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL); + LONG yPerInch = ::GetDeviceCaps(hDC, LOGPIXELSY); + m_lf.lfHeight = -(int)((cf.yHeight * yPerInch) / 1440); + } + else + m_lf.lfHeight = 0; + + m_lf.lfWidth = 0; + m_lf.lfEscapement = 0; + m_lf.lfOrientation = 0; + + if((cf.dwMask & (CFM_ITALIC | CFM_BOLD)) == (CFM_ITALIC | CFM_BOLD)) + { + m_lf.lfWeight = ((cf.dwEffects & CFE_BOLD) != 0) ? FW_BOLD : FW_NORMAL; + m_lf.lfItalic = (BYTE)(((cf.dwEffects & CFE_ITALIC) != 0) ? TRUE : FALSE); + } + else + { + dwFlags |= CF_NOSTYLESEL; + m_lf.lfWeight = FW_DONTCARE; + m_lf.lfItalic = FALSE; + } + + if((cf.dwMask & (CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR)) == (CFM_UNDERLINE|CFM_STRIKEOUT|CFM_COLOR)) + { + dwFlags |= CF_EFFECTS; + m_lf.lfUnderline = (BYTE)(((cf.dwEffects & CFE_UNDERLINE) != 0) ? TRUE : FALSE); + m_lf.lfStrikeOut = (BYTE)(((cf.dwEffects & CFE_STRIKEOUT) != 0) ? TRUE : FALSE); + } + else + { + m_lf.lfUnderline = (BYTE)FALSE; + m_lf.lfStrikeOut = (BYTE)FALSE; + } + + if((cf.dwMask & CFM_CHARSET) != 0) + m_lf.lfCharSet = cf.bCharSet; + else + dwFlags |= CF_NOSCRIPTSEL; + m_lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + m_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + m_lf.lfQuality = DEFAULT_QUALITY; + if((cf.dwMask & CFM_FACE) != 0) + { + m_lf.lfPitchAndFamily = cf.bPitchAndFamily; +#if (_RICHEDIT_VER >= 0x0200) + SecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), cf.szFaceName); +#else // !(_RICHEDIT_VER >= 0x0200) + SecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), A2T((LPSTR)cf.szFaceName)); +#endif // !(_RICHEDIT_VER >= 0x0200) + } + else + { + m_lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE; + m_lf.lfFaceName[0] = (TCHAR)0; + } + return dwFlags; + } +}; + +class CRichEditFontDialog : public CRichEditFontDialogImpl +{ +public: + CRichEditFontDialog(const CHARFORMAT& charformat, + DWORD dwFlags = CF_SCREENFONTS, + HDC hDCPrinter = NULL, + HWND hWndParent = NULL) + : CRichEditFontDialogImpl(charformat, dwFlags, hDCPrinter, hWndParent) + { } + + DECLARE_EMPTY_MSG_MAP() +}; + +#endif // defined(_RICHEDIT_) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CColorDialogImpl - color selection + +#if !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500))) + +#ifdef _WIN32_WCE + #pragma comment(lib, "commdlg.lib") + + #ifndef SETRGBSTRING + #define SETRGBSTRING _T("commdlg_SetRGBColor") + #endif + + #ifndef COLOROKSTRING + #define COLOROKSTRING _T("commdlg_ColorOK") + #endif +#endif + +template +class ATL_NO_VTABLE CColorDialogImpl : public CCommonDialogImplBase +{ +public: + CHOOSECOLOR m_cc; + +// Constructor + CColorDialogImpl(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL) + { + memset(&m_cc, 0, sizeof(m_cc)); + + m_cc.lStructSize = sizeof(m_cc); + m_cc.lpCustColors = GetCustomColors(); + m_cc.hwndOwner = hWndParent; + m_cc.Flags = dwFlags | CC_ENABLEHOOK; + m_cc.lpfnHook = (LPCCHOOKPROC)T::HookProc; + + if(clrInit != 0) + { + m_cc.rgbResult = clrInit; + m_cc.Flags |= CC_RGBINIT; + } + } + +// Operations + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT((m_cc.Flags & CC_ENABLEHOOK) != 0); + ATLASSERT(m_cc.lpfnHook != NULL); // can still be a user hook + + if(m_cc.hwndOwner == NULL) // set only if not specified before + m_cc.hwndOwner = hWndParent; + + ATLASSERT(m_hWnd == NULL); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL bRetTh = m_thunk.Init(NULL, NULL); + if(bRetTh == FALSE) + { + ::SetLastError(ERROR_OUTOFMEMORY); + return -1; + } +#endif // (_ATL_VER >= 0x0800) + + ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); + + BOOL bRet = ::ChooseColor(&m_cc); + + m_hWnd = NULL; + + return bRet ? IDOK : IDCANCEL; + } + + // Set the current color while dialog is displayed + void SetCurrentColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + SendMessage(_GetSetRGBMessage(), 0, (LPARAM)clr); + } + + // Get the selected color after DoModal returns, or in OnColorOK + COLORREF GetColor() const + { + return m_cc.rgbResult; + } + +// Special override for the color dialog + static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + if(uMsg != WM_INITDIALOG && uMsg != _GetColorOKMessage()) + return 0; + + LPCHOOSECOLOR lpCC = (LPCHOOSECOLOR)lParam; + CCommonDialogImplBase* pT = NULL; + + if(uMsg == WM_INITDIALOG) + { + pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData(); + lpCC->lCustData = (LPARAM)pT; + ATLASSERT(pT != NULL); + ATLASSERT(pT->m_hWnd == NULL); + ATLASSERT(::IsWindow(hWnd)); + // subclass dialog's window + if(!pT->SubclassWindow(hWnd)) + { + ATLTRACE2(atlTraceUI, 0, _T("Subclassing a Color common dialog failed\n")); + return 0; + } + } + else if(uMsg == _GetColorOKMessage()) + { + pT = (CCommonDialogImplBase*)lpCC->lCustData; + ATLASSERT(pT != NULL); + ATLASSERT(::IsWindow(pT->m_hWnd)); + } + else + { + ATLASSERT(FALSE); + return 0; + } + + // pass to the message map + LRESULT lRes = 0; + if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE) + return 0; + + return lRes; + } + +// Helpers + static COLORREF* GetCustomColors() + { + static COLORREF rgbCustomColors[16] = + { + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + }; + + return rgbCustomColors; + } + + static UINT _GetSetRGBMessage() + { + static UINT uSetRGBMessage = 0; + if(uSetRGBMessage == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetSetRGBMessage.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uSetRGBMessage == 0) + uSetRGBMessage = ::RegisterWindowMessage(SETRGBSTRING); + + lock.Unlock(); + } + ATLASSERT(uSetRGBMessage != 0); + return uSetRGBMessage; + } + + static UINT _GetColorOKMessage() + { + static UINT uColorOKMessage = 0; + if(uColorOKMessage == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetColorOKMessage.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uColorOKMessage == 0) + uColorOKMessage = ::RegisterWindowMessage(COLOROKSTRING); + + lock.Unlock(); + } + ATLASSERT(uColorOKMessage != 0); + return uColorOKMessage; + } + +// Message map and handlers + BEGIN_MSG_MAP(CColorDialogImpl) + MESSAGE_HANDLER(_GetColorOKMessage(), _OnColorOK) + END_MSG_MAP() + + LRESULT _OnColorOK(UINT, WPARAM, LPARAM, BOOL&) + { + T* pT = static_cast(this); + return pT->OnColorOK(); + } + +// Overrideable + BOOL OnColorOK() // validate color + { + return FALSE; + } +}; + +class CColorDialog : public CColorDialogImpl +{ +public: + CColorDialog(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL) + : CColorDialogImpl(clrInit, dwFlags, hWndParent) + { } + + // override base class map and references to handlers + DECLARE_EMPTY_MSG_MAP() +}; + +#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500))) + + +/////////////////////////////////////////////////////////////////////////////// +// CPrintDialogImpl - used for Print... and PrintSetup... + +#ifndef _WIN32_WCE + +// global helper +static inline HDC _AtlCreateDC(HGLOBAL hDevNames, HGLOBAL hDevMode) +{ + if(hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDevNames = (LPDEVNAMES)::GlobalLock(hDevNames); + LPDEVMODE lpDevMode = (hDevMode != NULL) ? (LPDEVMODE)::GlobalLock(hDevMode) : NULL; + + if(lpDevNames == NULL) + return NULL; + + HDC hDC = ::CreateDC((LPCTSTR)lpDevNames + lpDevNames->wDriverOffset, + (LPCTSTR)lpDevNames + lpDevNames->wDeviceOffset, + (LPCTSTR)lpDevNames + lpDevNames->wOutputOffset, + lpDevMode); + + ::GlobalUnlock(hDevNames); + if(hDevMode != NULL) + ::GlobalUnlock(hDevMode); + return hDC; +} + +#pragma warning(push) +#pragma warning(disable: 4512) // assignment operator could not be generated + +template +class ATL_NO_VTABLE CPrintDialogImpl : public CCommonDialogImplBase +{ +public: + // print dialog parameter block (note this is a reference) + PRINTDLG& m_pd; + +// Constructors + CPrintDialogImpl(BOOL bPrintSetupOnly = FALSE, // TRUE for Print Setup, FALSE for Print Dialog + DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION, + HWND hWndParent = NULL) + : m_pd(m_pdActual) + { + memset(&m_pdActual, 0, sizeof(m_pdActual)); + + m_pd.lStructSize = sizeof(m_pdActual); + m_pd.hwndOwner = hWndParent; + m_pd.Flags = (dwFlags | PD_ENABLEPRINTHOOK | PD_ENABLESETUPHOOK); + m_pd.lpfnPrintHook = (LPPRINTHOOKPROC)T::HookProc; + m_pd.lpfnSetupHook = (LPSETUPHOOKPROC)T::HookProc; + + if(bPrintSetupOnly) + m_pd.Flags |= PD_PRINTSETUP; + else + m_pd.Flags |= PD_RETURNDC; + + m_pd.Flags &= ~PD_RETURNIC; // do not support information context + } + +// Operations + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT((m_pd.Flags & PD_ENABLEPRINTHOOK) != 0); + ATLASSERT((m_pd.Flags & PD_ENABLESETUPHOOK) != 0); + ATLASSERT(m_pd.lpfnPrintHook != NULL); // can still be a user hook + ATLASSERT(m_pd.lpfnSetupHook != NULL); // can still be a user hook + ATLASSERT((m_pd.Flags & PD_RETURNDEFAULT) == 0); // use GetDefaults for this + + if(m_pd.hwndOwner == NULL) // set only if not specified before + m_pd.hwndOwner = hWndParent; + + ATLASSERT(m_hWnd == NULL); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL bRetTh = m_thunk.Init(NULL, NULL); + if(bRetTh == FALSE) + { + ::SetLastError(ERROR_OUTOFMEMORY); + return -1; + } +#endif // (_ATL_VER >= 0x0800) + + ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); + + BOOL bRet = ::PrintDlg(&m_pd); + + m_hWnd = NULL; + + return bRet ? IDOK : IDCANCEL; + } + + // GetDefaults will not display a dialog but will get device defaults + BOOL GetDefaults() + { + m_pd.Flags |= PD_RETURNDEFAULT; + ATLASSERT(m_pd.hDevMode == NULL); // must be NULL + ATLASSERT(m_pd.hDevNames == NULL); // must be NULL + + return ::PrintDlg(&m_pd); + } + + // Helpers for parsing information after successful return num. copies requested + int GetCopies() const + { + if((m_pd.Flags & PD_USEDEVMODECOPIES) != 0) + { + LPDEVMODE lpDevMode = GetDevMode(); + return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1; + } + + return m_pd.nCopies; + } + + BOOL PrintCollate() const // TRUE if collate checked + { + return ((m_pd.Flags & PD_COLLATE) != 0) ? TRUE : FALSE; + } + + BOOL PrintSelection() const // TRUE if printing selection + { + return ((m_pd.Flags & PD_SELECTION) != 0) ? TRUE : FALSE; + } + + BOOL PrintAll() const // TRUE if printing all pages + { + return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE; + } + + BOOL PrintRange() const // TRUE if printing page range + { + return ((m_pd.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE; + } + + BOOL PrintToFile() const // TRUE if printing to a file + { + return ((m_pd.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE; + } + + int GetFromPage() const // starting page if valid + { + return PrintRange() ? m_pd.nFromPage : -1; + } + + int GetToPage() const // ending page if valid + { + return PrintRange() ? m_pd.nToPage : -1; + } + + LPDEVMODE GetDevMode() const // return DEVMODE + { + if(m_pd.hDevMode == NULL) + return NULL; + + return (LPDEVMODE)::GlobalLock(m_pd.hDevMode); + } + + LPCTSTR GetDriverName() const // return driver name + { + if(m_pd.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames); + if(lpDev == NULL) + return NULL; + + return (LPCTSTR)lpDev + lpDev->wDriverOffset; + } + + LPCTSTR GetDeviceName() const // return device name + { + if(m_pd.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames); + if(lpDev == NULL) + return NULL; + + return (LPCTSTR)lpDev + lpDev->wDeviceOffset; + } + + LPCTSTR GetPortName() const // return output port name + { + if(m_pd.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames); + if(lpDev == NULL) + return NULL; + + return (LPCTSTR)lpDev + lpDev->wOutputOffset; + } + + HDC GetPrinterDC() const // return HDC (caller must delete) + { + ATLASSERT((m_pd.Flags & PD_RETURNDC) != 0); + return m_pd.hDC; + } + + // This helper creates a DC based on the DEVNAMES and DEVMODE structures. + // This DC is returned, but also stored in m_pd.hDC as though it had been + // returned by CommDlg. It is assumed that any previously obtained DC + // has been/will be deleted by the user. This may be + // used without ever invoking the print/print setup dialogs. + HDC CreatePrinterDC() + { + m_pd.hDC = _AtlCreateDC(m_pd.hDevNames, m_pd.hDevMode); + return m_pd.hDC; + } + +// Implementation + PRINTDLG m_pdActual; // the Print/Print Setup need to share this + + // The following handle the case of print setup... from the print dialog + CPrintDialogImpl(PRINTDLG& pdInit) : m_pd(pdInit) + { } + + BEGIN_MSG_MAP(CPrintDialogImpl) +#ifdef psh1 + COMMAND_ID_HANDLER(psh1, OnPrintSetup) // print setup button when print is displayed +#else // !psh1 + COMMAND_ID_HANDLER(0x0400, OnPrintSetup) // value from dlgs.h +#endif // !psh1 + END_MSG_MAP() + + LRESULT OnPrintSetup(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/) + { + T dlgSetup(m_pd); + ModuleHelper::AddCreateWndData(&dlgSetup.m_thunk.cd, (CCommonDialogImplBase*)&dlgSetup); + return DefWindowProc(WM_COMMAND, MAKEWPARAM(wID, wNotifyCode), (LPARAM)hWndCtl); + } +}; + +class CPrintDialog : public CPrintDialogImpl +{ +public: + CPrintDialog(BOOL bPrintSetupOnly = FALSE, + DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION, + HWND hWndParent = NULL) + : CPrintDialogImpl(bPrintSetupOnly, dwFlags, hWndParent) + { } + + CPrintDialog(PRINTDLG& pdInit) : CPrintDialogImpl(pdInit) + { } +}; + +#pragma warning(pop) + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CPrintDialogExImpl - new print dialog for Windows 2000 + +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + +}; // namespace WTL + +#include + +extern "C" const __declspec(selectany) IID IID_IPrintDialogCallback = {0x5852a2c3, 0x6530, 0x11d1, {0xb6, 0xa3, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}}; +extern "C" const __declspec(selectany) IID IID_IPrintDialogServices = {0x509aaeda, 0x5639, 0x11d1, {0xb6, 0xa1, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}}; + +namespace WTL +{ + +template +class ATL_NO_VTABLE CPrintDialogExImpl : + public ATL::CWindow, + public ATL::CMessageMap, + public IPrintDialogCallback, + public ATL::IObjectWithSiteImpl< T > +{ +public: + PRINTDLGEX m_pdex; + +// Constructor + CPrintDialogExImpl(DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE, + HWND hWndParent = NULL) + { + memset(&m_pdex, 0, sizeof(m_pdex)); + + m_pdex.lStructSize = sizeof(PRINTDLGEX); + m_pdex.hwndOwner = hWndParent; + m_pdex.Flags = dwFlags; + m_pdex.nStartPage = START_PAGE_GENERAL; + // callback object will be set in DoModal + + m_pdex.Flags &= ~PD_RETURNIC; // do not support information context + } + +// Operations + HRESULT DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT(m_hWnd == NULL); + ATLASSERT((m_pdex.Flags & PD_RETURNDEFAULT) == 0); // use GetDefaults for this + + if(m_pdex.hwndOwner == NULL) // set only if not specified before + m_pdex.hwndOwner = hWndParent; + + T* pT = static_cast(this); + m_pdex.lpCallback = (IUnknown*)(IPrintDialogCallback*)pT; + + HRESULT hResult = ::PrintDlgEx(&m_pdex); + + m_hWnd = NULL; + + return hResult; + } + + BOOL EndDialog(INT_PTR /*nRetCode*/ = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0)); + return TRUE; + } + + // GetDefaults will not display a dialog but will get device defaults + HRESULT GetDefaults() + { + ATLASSERT(m_pdex.hDevMode == NULL); // must be NULL + ATLASSERT(m_pdex.hDevNames == NULL); // must be NULL + + if(m_pdex.hwndOwner == NULL) // set only if not specified before + m_pdex.hwndOwner = ::GetActiveWindow(); + + m_pdex.Flags |= PD_RETURNDEFAULT; + HRESULT hRet = ::PrintDlgEx(&m_pdex); + m_pdex.Flags &= ~PD_RETURNDEFAULT; + + return hRet; + } + + // Helpers for parsing information after successful return num. copies requested + int GetCopies() const + { + if((m_pdex.Flags & PD_USEDEVMODECOPIES) != 0) + { + LPDEVMODE lpDevMode = GetDevMode(); + return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1; + } + + return m_pdex.nCopies; + } + + BOOL PrintCollate() const // TRUE if collate checked + { + return ((m_pdex.Flags & PD_COLLATE) != 0) ? TRUE : FALSE; + } + + BOOL PrintSelection() const // TRUE if printing selection + { + return ((m_pdex.Flags & PD_SELECTION) != 0) ? TRUE : FALSE; + } + + BOOL PrintAll() const // TRUE if printing all pages + { + return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE; + } + + BOOL PrintRange() const // TRUE if printing page range + { + return ((m_pdex.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE; + } + + BOOL PrintToFile() const // TRUE if printing to a file + { + return ((m_pdex.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE; + } + + LPDEVMODE GetDevMode() const // return DEVMODE + { + if(m_pdex.hDevMode == NULL) + return NULL; + + return (LPDEVMODE)::GlobalLock(m_pdex.hDevMode); + } + + LPCTSTR GetDriverName() const // return driver name + { + if(m_pdex.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames); + if(lpDev == NULL) + return NULL; + + return (LPCTSTR)lpDev + lpDev->wDriverOffset; + } + + LPCTSTR GetDeviceName() const // return device name + { + if(m_pdex.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames); + if(lpDev == NULL) + return NULL; + + return (LPCTSTR)lpDev + lpDev->wDeviceOffset; + } + + LPCTSTR GetPortName() const // return output port name + { + if(m_pdex.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames); + if(lpDev == NULL) + return NULL; + + return (LPCTSTR)lpDev + lpDev->wOutputOffset; + } + + HDC GetPrinterDC() const // return HDC (caller must delete) + { + ATLASSERT((m_pdex.Flags & PD_RETURNDC) != 0); + return m_pdex.hDC; + } + + // This helper creates a DC based on the DEVNAMES and DEVMODE structures. + // This DC is returned, but also stored in m_pdex.hDC as though it had been + // returned by CommDlg. It is assumed that any previously obtained DC + // has been/will be deleted by the user. This may be + // used without ever invoking the print/print setup dialogs. + HDC CreatePrinterDC() + { + m_pdex.hDC = _AtlCreateDC(m_pdex.hDevNames, m_pdex.hDevMode); + return m_pdex.hDC; + } + +// Implementation - interfaces + +// IUnknown + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) + { + if(ppvObject == NULL) + return E_POINTER; + + T* pT = static_cast(this); + if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IPrintDialogCallback)) + { + *ppvObject = (IPrintDialogCallback*)pT; + // AddRef() not needed + return S_OK; + } + else if(IsEqualGUID(riid, IID_IObjectWithSite)) + { + *ppvObject = (IObjectWithSite*)pT; + // AddRef() not needed + return S_OK; + } + + return E_NOINTERFACE; + } + + virtual ULONG STDMETHODCALLTYPE AddRef() + { + return 1; + } + + virtual ULONG STDMETHODCALLTYPE Release() + { + return 1; + } + +// IPrintDialogCallback + STDMETHOD(InitDone)() + { + return S_FALSE; + } + + STDMETHOD(SelectionChange)() + { + return S_FALSE; + } + + STDMETHOD(HandleMessage)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plResult) + { + // set up m_hWnd the first time + if(m_hWnd == NULL) + Attach(hWnd); + + // call message map + HRESULT hRet = ProcessWindowMessage(hWnd, uMsg, wParam, lParam, *plResult, 0) ? S_OK : S_FALSE; + if(hRet == S_OK && uMsg == WM_NOTIFY) // return in DWLP_MSGRESULT + ::SetWindowLongPtr(GetParent(), DWLP_MSGRESULT, (LONG_PTR)*plResult); + + if(uMsg == WM_INITDIALOG && hRet == S_OK && (BOOL)*plResult != FALSE) + hRet = S_FALSE; + + return hRet; + } +}; + +class CPrintDialogEx : public CPrintDialogExImpl +{ +public: + CPrintDialogEx( + DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE, + HWND hWndParent = NULL) + : CPrintDialogExImpl(dwFlags, hWndParent) + { } + + DECLARE_EMPTY_MSG_MAP() +}; + +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CPageSetupDialogImpl - Page Setup dialog + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CPageSetupDialogImpl : public CCommonDialogImplBase +{ +public: + PAGESETUPDLG m_psd; + ATL::CWndProcThunk m_thunkPaint; + +// Constructors + CPageSetupDialogImpl(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL) + { + memset(&m_psd, 0, sizeof(m_psd)); + + m_psd.lStructSize = sizeof(m_psd); + m_psd.hwndOwner = hWndParent; + m_psd.Flags = (dwFlags | PSD_ENABLEPAGESETUPHOOK | PSD_ENABLEPAGEPAINTHOOK); + m_psd.lpfnPageSetupHook = (LPPAGESETUPHOOK)T::HookProc; + m_thunkPaint.Init((WNDPROC)T::PaintHookProc, this); +#if (_ATL_VER >= 0x0700) + m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)m_thunkPaint.GetWNDPROC(); +#else + m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)&(m_thunkPaint.thunk); +#endif + } + + DECLARE_EMPTY_MSG_MAP() + +// Attributes + LPDEVMODE GetDevMode() const // return DEVMODE + { + if(m_psd.hDevMode == NULL) + return NULL; + + return (LPDEVMODE)::GlobalLock(m_psd.hDevMode); + } + + LPCTSTR GetDriverName() const // return driver name + { + if(m_psd.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames); + return (LPCTSTR)lpDev + lpDev->wDriverOffset; + } + + LPCTSTR GetDeviceName() const // return device name + { + if(m_psd.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames); + return (LPCTSTR)lpDev + lpDev->wDeviceOffset; + } + + LPCTSTR GetPortName() const // return output port name + { + if(m_psd.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames); + return (LPCTSTR)lpDev + lpDev->wOutputOffset; + } + + HDC CreatePrinterDC() + { + return _AtlCreateDC(m_psd.hDevNames, m_psd.hDevMode); + } + + SIZE GetPaperSize() const + { + SIZE size = { m_psd.ptPaperSize.x, m_psd.ptPaperSize.y }; + return size; + } + + void GetMargins(LPRECT lpRectMargins, LPRECT lpRectMinMargins) const + { + if(lpRectMargins != NULL) + *lpRectMargins = m_psd.rtMargin; + if(lpRectMinMargins != NULL) + *lpRectMinMargins = m_psd.rtMinMargin; + } + +// Operations + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT((m_psd.Flags & PSD_ENABLEPAGESETUPHOOK) != 0); + ATLASSERT((m_psd.Flags & PSD_ENABLEPAGEPAINTHOOK) != 0); + ATLASSERT(m_psd.lpfnPageSetupHook != NULL); // can still be a user hook + ATLASSERT(m_psd.lpfnPagePaintHook != NULL); // can still be a user hook + + if(m_psd.hwndOwner == NULL) // set only if not specified before + m_psd.hwndOwner = hWndParent; + + ATLASSERT(m_hWnd == NULL); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL bRetTh = m_thunk.Init(NULL, NULL); + if(bRetTh == FALSE) + { + ::SetLastError(ERROR_OUTOFMEMORY); + return -1; + } +#endif // (_ATL_VER >= 0x0800) + + ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); + + BOOL bRet = ::PageSetupDlg(&m_psd); + + m_hWnd = NULL; + + return bRet ? IDOK : IDCANCEL; + } + +// Implementation + static UINT_PTR CALLBACK PaintHookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + T* pT = (T*)hWnd; + UINT_PTR uRet = 0; + switch(uMsg) + { + case WM_PSD_PAGESETUPDLG: + uRet = pT->PreDrawPage(LOWORD(wParam), HIWORD(wParam), (LPPAGESETUPDLG)lParam); + break; + case WM_PSD_FULLPAGERECT: + case WM_PSD_MINMARGINRECT: + case WM_PSD_MARGINRECT: + case WM_PSD_GREEKTEXTRECT: + case WM_PSD_ENVSTAMPRECT: + case WM_PSD_YAFULLPAGERECT: + uRet = pT->OnDrawPage(uMsg, (HDC)wParam, (LPRECT)lParam); + break; + default: + ATLTRACE2(atlTraceUI, 0, _T("CPageSetupDialogImpl::PaintHookProc - unknown message received\n")); + break; + } + return uRet; + } + +// Overridables + UINT_PTR PreDrawPage(WORD /*wPaper*/, WORD /*wFlags*/, LPPAGESETUPDLG /*pPSD*/) + { + // return 1 to prevent any more drawing + return 0; + } + + UINT_PTR OnDrawPage(UINT /*uMsg*/, HDC /*hDC*/, LPRECT /*lpRect*/) + { + return 0; // do the default + } +}; + +class CPageSetupDialog : public CPageSetupDialogImpl +{ +public: + CPageSetupDialog(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL) + : CPageSetupDialogImpl(dwFlags, hWndParent) + { } + + // override PaintHookProc and references to handlers + static UINT_PTR CALLBACK PaintHookProc(HWND, UINT, WPARAM, LPARAM) + { + return 0; + } +}; + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CFindReplaceDialogImpl - Find/FindReplace modeless dialogs + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CFindReplaceDialogImpl : public CCommonDialogImplBase +{ +public: + enum { _cchFindReplaceBuffer = 128 }; + + FINDREPLACE m_fr; + TCHAR m_szFindWhat[_cchFindReplaceBuffer]; + TCHAR m_szReplaceWith[_cchFindReplaceBuffer]; + +// Constructors + CFindReplaceDialogImpl() + { + memset(&m_fr, 0, sizeof(m_fr)); + m_szFindWhat[0] = _T('\0'); + m_szReplaceWith[0] = _T('\0'); + + m_fr.lStructSize = sizeof(m_fr); + m_fr.Flags = FR_ENABLEHOOK; + m_fr.lpfnHook = (LPFRHOOKPROC)T::HookProc; + m_fr.lpstrFindWhat = (LPTSTR)m_szFindWhat; + m_fr.wFindWhatLen = _cchFindReplaceBuffer; + m_fr.lpstrReplaceWith = (LPTSTR)m_szReplaceWith; + m_fr.wReplaceWithLen = _cchFindReplaceBuffer; + } + + // Note: You must allocate the object on the heap. + // If you do not, you must override OnFinalMessage() + virtual void OnFinalMessage(HWND /*hWnd*/) + { + delete this; + } + + HWND Create(BOOL bFindDialogOnly, // TRUE for Find, FALSE for FindReplace + LPCTSTR lpszFindWhat, + LPCTSTR lpszReplaceWith = NULL, + DWORD dwFlags = FR_DOWN, + HWND hWndParent = NULL) + { + ATLASSERT((m_fr.Flags & FR_ENABLEHOOK) != 0); + ATLASSERT(m_fr.lpfnHook != NULL); + + m_fr.Flags |= dwFlags; + + if(hWndParent == NULL) + m_fr.hwndOwner = ::GetActiveWindow(); + else + m_fr.hwndOwner = hWndParent; + ATLASSERT(m_fr.hwndOwner != NULL); // must have an owner for modeless dialog + + if(lpszFindWhat != NULL) + SecureHelper::strncpy_x(m_szFindWhat, _countof(m_szFindWhat), lpszFindWhat, _TRUNCATE); + + if(lpszReplaceWith != NULL) + SecureHelper::strncpy_x(m_szReplaceWith, _countof(m_szReplaceWith), lpszReplaceWith, _TRUNCATE); + + ATLASSERT(m_hWnd == NULL); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL bRet = m_thunk.Init(NULL, NULL); + if(bRet == FALSE) + { + ::SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } +#endif // (_ATL_VER >= 0x0800) + + ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); + + HWND hWnd = NULL; + if(bFindDialogOnly) + hWnd = ::FindText(&m_fr); + else + hWnd = ::ReplaceText(&m_fr); + + ATLASSERT(m_hWnd == hWnd); + return hWnd; + } + + static const UINT GetFindReplaceMsg() + { + static const UINT nMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING); + return nMsgFindReplace; + } + // call while handling FINDMSGSTRING registered message + // to retreive the object + static T* PASCAL GetNotifier(LPARAM lParam) + { + ATLASSERT(lParam != NULL); + T* pDlg = (T*)(lParam - offsetof(T, m_fr)); + return pDlg; + } + +// Operations + // Helpers for parsing information after successful return + LPCTSTR GetFindString() const // get find string + { + return (LPCTSTR)m_fr.lpstrFindWhat; + } + + LPCTSTR GetReplaceString() const // get replacement string + { + return (LPCTSTR)m_fr.lpstrReplaceWith; + } + + BOOL SearchDown() const // TRUE if search down, FALSE is up + { + return ((m_fr.Flags & FR_DOWN) != 0) ? TRUE : FALSE; + } + + BOOL FindNext() const // TRUE if command is find next + { + return ((m_fr.Flags & FR_FINDNEXT) != 0) ? TRUE : FALSE; + } + + BOOL MatchCase() const // TRUE if matching case + { + return ((m_fr.Flags & FR_MATCHCASE) != 0) ? TRUE : FALSE; + } + + BOOL MatchWholeWord() const // TRUE if matching whole words only + { + return ((m_fr.Flags & FR_WHOLEWORD) != 0) ? TRUE : FALSE; + } + + BOOL ReplaceCurrent() const // TRUE if replacing current string + { + return ((m_fr. Flags & FR_REPLACE) != 0) ? TRUE : FALSE; + } + + BOOL ReplaceAll() const // TRUE if replacing all occurrences + { + return ((m_fr.Flags & FR_REPLACEALL) != 0) ? TRUE : FALSE; + } + + BOOL IsTerminating() const // TRUE if terminating dialog + { + return ((m_fr.Flags & FR_DIALOGTERM) != 0) ? TRUE : FALSE ; + } +}; + +class CFindReplaceDialog : public CFindReplaceDialogImpl +{ +public: + DECLARE_EMPTY_MSG_MAP() +}; + +#endif // !_WIN32_WCE + + +///////////////////////////////////////////////////////////////////////// +// CDialogBaseUnits - Dialog Units helper +// + +class CDialogBaseUnits +{ +public: + SIZE m_sizeUnits; + +// Constructors + CDialogBaseUnits() + { + // The base units of the out-dated System Font + LONG nDlgBaseUnits = ::GetDialogBaseUnits(); + m_sizeUnits.cx = LOWORD(nDlgBaseUnits); + m_sizeUnits.cy = HIWORD(nDlgBaseUnits); + } + + CDialogBaseUnits(HWND hWnd) + { + if(!InitDialogBaseUnits(hWnd)) { + LONG nDlgBaseUnits = ::GetDialogBaseUnits(); + m_sizeUnits.cx = LOWORD(nDlgBaseUnits); + m_sizeUnits.cy = HIWORD(nDlgBaseUnits); + } + } + + CDialogBaseUnits(HFONT hFont, HWND hWnd = NULL) + { + if(!InitDialogBaseUnits(hFont, hWnd)) { + LONG nDlgBaseUnits = ::GetDialogBaseUnits(); + m_sizeUnits.cx = LOWORD(nDlgBaseUnits); + m_sizeUnits.cy = HIWORD(nDlgBaseUnits); + } + } + + CDialogBaseUnits(LOGFONT lf, HWND hWnd = NULL) + { + if(!InitDialogBaseUnits(lf, hWnd)) { + LONG nDlgBaseUnits = ::GetDialogBaseUnits(); + m_sizeUnits.cx = LOWORD(nDlgBaseUnits); + m_sizeUnits.cy = HIWORD(nDlgBaseUnits); + } + } + +// Operations + BOOL InitDialogBaseUnits(HWND hWnd) + { + ATLASSERT(::IsWindow(hWnd)); + RECT rc = { 0, 0, 4, 8 }; + if(!::MapDialogRect(hWnd, &rc)) return FALSE; + m_sizeUnits.cx = rc.right; + m_sizeUnits.cy = rc.bottom; + return TRUE; + } + + BOOL InitDialogBaseUnits(LOGFONT lf, HWND hWnd = NULL) + { + CFont font; + font.CreateFontIndirect(&lf); + if(font.IsNull()) return FALSE; + return InitDialogBaseUnits(font, hWnd); + } + + BOOL InitDialogBaseUnits(HFONT hFont, HWND hWnd = NULL) + { + ATLASSERT(hFont != NULL); + CWindowDC dc = hWnd; + TEXTMETRIC tmText = { 0 }; + SIZE sizeText = { 0 }; + HFONT hFontOld = dc.SelectFont(hFont); + dc.GetTextMetrics(&tmText); + m_sizeUnits.cy = tmText.tmHeight + tmText.tmExternalLeading; + dc.GetTextExtent(_T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), 52, &sizeText); + m_sizeUnits.cx = (sizeText.cx + 26) / 52; + dc.SelectFont(hFontOld); + return TRUE; + } + + SIZE GetDialogBaseUnits() const + { + return m_sizeUnits; + } + + INT MapDialogPixelsX(INT x) const + { + return ::MulDiv(x, 4, m_sizeUnits.cx); // Pixels X to DLU + } + + INT MapDialogPixelsY(INT y) const + { + return ::MulDiv(y, 8, m_sizeUnits.cy); // Pixels Y to DLU + } + + POINT MapDialogPixels(POINT pt) const + { + POINT out = { MapDialogPixelsX(pt.x), MapDialogPixelsY(pt.y) }; + return out; + } + + SIZE MapDialogPixels(SIZE input) const + { + SIZE out = { MapDialogPixelsX(input.cx), MapDialogPixelsY(input.cy) }; + return out; + } + + RECT MapDialogPixels(const RECT& input) const + { + RECT out = { MapDialogPixelsX(input.left), MapDialogPixelsY(input.top), MapDialogPixelsX(input.right), MapDialogPixelsY(input.bottom) }; + return out; + } + + INT MapDialogUnitsX(INT x) const + { + return ::MulDiv(x, m_sizeUnits.cx, 4); // DLU to Pixels X + } + + INT MapDialogUnitsY(INT y) const + { + return ::MulDiv(y, m_sizeUnits.cy, 8); // DLU to Pixels Y + } + + POINT MapDialogUnits(POINT pt) const + { + POINT out = { MapDialogUnitsX(pt.x), MapDialogUnitsY(pt.y) }; + return out; + } + + SIZE MapDialogUnits(SIZE input) const + { + SIZE out = { MapDialogUnitsX(input.cx), MapDialogUnitsY(input.cy) }; + return out; + } + + RECT MapDialogUnits(const RECT& input) const + { + RECT out = { MapDialogUnitsX(input.left), MapDialogUnitsY(input.top), MapDialogUnitsX(input.right), MapDialogUnitsY(input.bottom) }; + return out; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CMemDlgTemplate - in-memory dialog template - DLGTEMPLATE or DLGTEMPLATEEX + +#if (_ATL_VER >= 0x800) + typedef ATL::_DialogSplitHelper::DLGTEMPLATEEX DLGTEMPLATEEX; + typedef ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX DLGITEMTEMPLATEEX; +#else // (_ATL_VER >= 0x800) + typedef ATL::_DialogSizeHelper::_ATL_DLGTEMPLATEEX DLGTEMPLATEEX; + #pragma pack(push, 4) + struct DLGITEMTEMPLATEEX + { + DWORD helpID; + DWORD exStyle; + DWORD style; + short x; + short y; + short cx; + short cy; + DWORD id; + }; + #pragma pack(pop) +#endif // (_ATL_VER >= 0x800) + + +template +class CMemDlgTemplateT +{ +public: + enum StdCtrlType + { + CTRL_BUTTON = 0x0080, + CTRL_EDIT = 0x0081, + CTRL_STATIC = 0x0082, + CTRL_LISTBOX = 0x0083, + CTRL_SCROLLBAR = 0x0084, + CTRL_COMBOBOX = 0x0085 + }; + + HANDLE m_hData; + LPBYTE m_pData; + LPBYTE m_pPtr; + SIZE_T m_cAllocated; + + CMemDlgTemplateT() : m_hData(NULL), m_pData(NULL), m_pPtr(NULL), m_cAllocated(0) + { } + + ~CMemDlgTemplateT() + { + Reset(); + } + + bool IsValid() const + { + return (m_pData != NULL); + } + + bool IsTemplateEx() const + { + return (IsValid() && ((DLGTEMPLATEEX*)m_pData)->signature == 0xFFFF); + } + + LPDLGTEMPLATE GetTemplatePtr() + { + return reinterpret_cast(m_pData); + } + + DLGTEMPLATEEX* GetTemplateExPtr() + { + return reinterpret_cast(m_pData); + } + + void Reset() + { + if (IsValid()) { +#ifndef UNDER_CE + ::GlobalUnlock(m_pData); +#endif + ATLVERIFY(::GlobalFree(m_hData) == NULL); + } + + m_hData = NULL; + m_pData = NULL; + m_pPtr = NULL; + m_cAllocated = 0; + } + + void Create(bool bDlgEx, LPCTSTR lpszCaption, const RECT& rc, DWORD dwStyle = 0, DWORD dwExStyle = 0, + LPCTSTR lpstrFontName = NULL, WORD wFontSize = 0, WORD wWeight = 0, BYTE bItalic = 0, BYTE bCharset = 0, DWORD dwHelpID = 0, + ATL::_U_STRINGorID ClassName = 0U, ATL::_U_STRINGorID Menu = 0U) + { + Create(bDlgEx, lpszCaption, (short) rc.left, (short) rc.top, (short) (rc.right - rc.left), (short) (rc.bottom - rc.top), dwStyle, dwExStyle, + lpstrFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName.m_lpstr, Menu.m_lpstr); + } + + void Create(bool bDlgEx, LPCTSTR lpszCaption, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle = 0, DWORD dwExStyle = 0, + LPCTSTR lpstrFontName = NULL, WORD wFontSize = 0, WORD wWeight = 0, BYTE bItalic = 0, BYTE bCharset = 0, DWORD dwHelpID = 0, + ATL::_U_STRINGorID ClassName = 0U, ATL::_U_STRINGorID Menu = 0U) + { + // Should have DS_SETFONT style to set the dialog font name and size + if (lpstrFontName != NULL) + { + dwStyle |= DS_SETFONT; + } + else + { + dwStyle &= ~DS_SETFONT; + } + + if (bDlgEx) + { + DLGTEMPLATEEX dlg = {1, 0xFFFF, dwHelpID, dwExStyle, dwStyle, 0, nX, nY, nWidth, nHeight}; + AddData(&dlg, sizeof(dlg)); + } + else + { + DLGTEMPLATE dlg = {dwStyle, dwExStyle, 0, nX, nY, nWidth, nHeight}; + AddData(&dlg, sizeof(dlg)); + } + +#ifndef _WIN32_WCE + if (Menu.m_lpstr == NULL) + { + WORD menuData = 0; + AddData(&menuData, sizeof(WORD)); + } + else if (IS_INTRESOURCE(Menu.m_lpstr)) + { + WORD menuData[] = { 0xFFFF, LOWORD(Menu.m_lpstr) }; + AddData(menuData, sizeof(menuData)); + } + else + { + AddString(Menu.m_lpstr); + } +#else // _WIN32_WCE + // Windows CE doesn't support the addition of menus to a dialog box + ATLASSERT(Menu.m_lpstr == NULL); + Menu.m_lpstr; // avoid level 4 warning + WORD menuData = 0; + AddData(&menuData, sizeof(WORD)); +#endif // _WIN32_WCE + + if (ClassName.m_lpstr == NULL) + { + WORD classData = 0; + AddData(&classData, sizeof(WORD)); + } + else if (IS_INTRESOURCE(ClassName.m_lpstr)) + { + WORD classData[] = { 0xFFFF, LOWORD(ClassName.m_lpstr) }; + AddData(classData, sizeof(classData)); + } + else + { + AddString(ClassName.m_lpstr); + } + + // Set dialog caption + AddString(lpszCaption); + + if (lpstrFontName != NULL) + { + AddData(&wFontSize, sizeof(wFontSize)); + + if (bDlgEx) + { + AddData(&wWeight, sizeof(wWeight)); + AddData(&bItalic, sizeof(bItalic)); + AddData(&bCharset, sizeof(bCharset)); + } + + AddString(lpstrFontName); + } + } + + void AddControl(ATL::_U_STRINGorID ClassName, WORD wId, const RECT& rc, DWORD dwStyle, DWORD dwExStyle, + ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0) + { + AddControl(ClassName.m_lpstr, wId, (short) rc.left, (short) rc.top, (short) (rc.right - rc.left), (short) (rc.bottom - rc.top), dwStyle, dwExStyle, + Text.m_lpstr, pCreationData, nCreationData, dwHelpID); + } + + void AddControl(ATL::_U_STRINGorID ClassName, WORD wId, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle, DWORD dwExStyle, + ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0) + { + ATLASSERT(IsValid()); + + // DWORD align data + const DWORD_PTR dwDwordAlignBits = sizeof(DWORD) - 1; + m_pPtr = (LPBYTE)(((DWORD_PTR)m_pPtr + dwDwordAlignBits) & (~dwDwordAlignBits)); + + if (IsTemplateEx()) + { + DLGTEMPLATEEX* dlg = (DLGTEMPLATEEX*)m_pData; + dlg->cDlgItems++; + + DLGITEMTEMPLATEEX item = {dwHelpID, TWinTraits::GetWndExStyle(0) | dwExStyle, TWinTraits::GetWndStyle(0) | dwStyle, nX, nY, nWidth, nHeight, wId}; + AddData(&item, sizeof(item)); + } + else + { + LPDLGTEMPLATE dlg = (LPDLGTEMPLATE)m_pData; + dlg->cdit++; + + DLGITEMTEMPLATE item = {TWinTraits::GetWndStyle(0) | dwStyle, TWinTraits::GetWndExStyle(0) | dwExStyle, nX, nY, nWidth, nHeight, wId}; + AddData(&item, sizeof(item)); + } + + ATLASSERT(ClassName.m_lpstr != NULL); + if (IS_INTRESOURCE(ClassName.m_lpstr)) + { + WORD wData[] = { 0xFFFF, LOWORD(ClassName.m_lpstr) }; + AddData(wData, sizeof(wData)); + } + else + { + AddString(ClassName.m_lpstr); + } + + if (Text.m_lpstr == NULL) + { + WORD classData = 0; + AddData(&classData, sizeof(WORD)); + } + else if (IS_INTRESOURCE(Text.m_lpstr)) + { + WORD wData[] = { 0xFFFF, LOWORD(Text.m_lpstr) }; + AddData(wData, sizeof(wData)); + } + else + { + AddString(Text.m_lpstr); + } + + AddData(&nCreationData, sizeof(nCreationData)); + + if ((nCreationData != 0)) + { + ATLASSERT(pCreationData != NULL); + AddData(pCreationData, nCreationData * sizeof(WORD)); + } + } + + void AddStdControl(StdCtrlType CtrlType, WORD wId, short nX, short nY, short nWidth, short nHeight, + DWORD dwStyle, DWORD dwExStyle, ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0) + { + AddControl(CtrlType, wId, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, Text, pCreationData, nCreationData, dwHelpID); + } + + void AddData(LPCVOID pData, size_t nData) + { + ATLASSERT(pData != NULL); + + const SIZE_T ALLOCATION_INCREMENT = 1024; + + if (m_pData == NULL) + { + m_cAllocated = ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT; + m_hData = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, m_cAllocated); + ATLASSERT(m_hData != NULL); +#ifndef UNDER_CE + m_pPtr = m_pData = static_cast(::GlobalLock(m_hData)); +#else + m_pPtr = m_pData = static_cast(m_hData); +#endif + ATLASSERT(m_pData != NULL); + } + else if (((m_pPtr - m_pData) + nData) > m_cAllocated) + { + SIZE_T ptrPos = (m_pPtr - m_pData); + m_cAllocated += ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT; +#ifndef UNDER_CE + ::GlobalUnlock(m_pData); +#endif + m_hData = ::GlobalReAlloc(m_hData, m_cAllocated, GMEM_MOVEABLE | GMEM_ZEROINIT); + ATLASSERT(m_hData != NULL); +#ifndef UNDER_CE + m_pData = static_cast(::GlobalLock(m_hData)); +#else + m_pData = static_cast(m_hData); +#endif + ATLASSERT(m_pData != NULL); + m_pPtr = m_pData + ptrPos; + } + + SecureHelper::memcpy_x(m_pPtr, m_cAllocated - (m_pPtr - m_pData), pData, nData); + + m_pPtr += nData; + } + + void AddString(LPCTSTR lpszStr) + { + if (lpszStr == NULL) + { + WCHAR szEmpty = 0; + AddData(&szEmpty, sizeof(szEmpty)); + } + else + { + USES_CONVERSION; + LPCWSTR lpstr = T2CW(lpszStr); + int nSize = lstrlenW(lpstr) + 1; + AddData(lpstr, nSize * sizeof(WCHAR)); + } + } +}; + +typedef CMemDlgTemplateT CMemDlgTemplate; + + +/////////////////////////////////////////////////////////////////////////////// +// Dialog and control macros for indirect dialogs + +// for DLGTEMPLATE +#define BEGIN_DIALOG(x, y, width, height) \ + void DoInitTemplate() \ + { \ + bool bExTemplate = false; \ + short nX = x, nY = y, nWidth = width, nHeight = height; \ + LPCTSTR szCaption = NULL; \ + DWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \ + DWORD dwExStyle = 0; \ + LPCTSTR szFontName = NULL; \ + WORD wFontSize = 0; \ + WORD wWeight = 0; \ + BYTE bItalic = 0; \ + BYTE bCharset = 0; \ + DWORD dwHelpID = 0; \ + ATL::_U_STRINGorID Menu = 0U; \ + ATL::_U_STRINGorID ClassName = 0U; + +// for DLGTEMPLATEEX +#define BEGIN_DIALOG_EX(x, y, width, height, helpID) \ + void DoInitTemplate() \ + { \ + bool bExTemplate = true; \ + short nX = x, nY = y, nWidth = width, nHeight = height; \ + LPCTSTR szCaption = NULL; \ + DWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \ + DWORD dwExStyle = 0; \ + LPCTSTR szFontName = NULL; \ + WORD wFontSize = 0; \ + WORD wWeight = 0; \ + BYTE bItalic = 0; \ + BYTE bCharset = 0; \ + DWORD dwHelpID = helpID; \ + ATL::_U_STRINGorID Menu = 0U; \ + ATL::_U_STRINGorID ClassName = 0U; + +#define END_DIALOG() \ + m_Template.Create(bExTemplate, szCaption, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, szFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName, Menu); \ + }; + +#define DIALOG_CAPTION(caption) \ + szCaption = caption; +#define DIALOG_STYLE(style) \ + dwStyle = style; +#define DIALOG_EXSTYLE(exStyle) \ + dwExStyle = exStyle; +#define DIALOG_FONT(pointSize, typeFace) \ + wFontSize = pointSize; \ + szFontName = typeFace; +#define DIALOG_FONT_EX(pointsize, typeface, weight, italic, charset) \ + ATLASSERT(bExTemplate); \ + wFontSize = pointsize; \ + szFontName = typeface; \ + wWeight = weight; \ + bItalic = italic; \ + bCharset = charset; +#define DIALOG_MENU(menuName) \ + Menu = menuName; +#define DIALOG_CLASS(className) \ + ClassName = className; + +#define BEGIN_CONTROLS_MAP() \ + void DoInitControls() \ + { + +#define END_CONTROLS_MAP() \ + }; + + +#define CONTROL_LTEXT(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_LEFT | WS_GROUP, exStyle, text, NULL, 0); +#define CONTROL_CTEXT(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_CENTER | WS_GROUP, exStyle, text, NULL, 0); +#define CONTROL_RTEXT(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_RIGHT | WS_GROUP, exStyle, text, NULL, 0); +#define CONTROL_PUSHBUTTON(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_DEFPUSHBUTTON(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_DEFPUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0); +#ifndef _WIN32_WCE +#define CONTROL_PUSHBOX(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBOX | WS_TABSTOP, exStyle, text, NULL, 0); +#endif // !_WIN32_WCE +#define CONTROL_STATE3(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_3STATE | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_AUTO3STATE(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTO3STATE | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_CHECKBOX(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_CHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_AUTOCHECKBOX(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTOCHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_RADIOBUTTON(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_RADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_AUTORADIOBUTTON(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTORADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_COMBOBOX(id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_COMBOBOX, (WORD)id, x, y, width, height, style | CBS_DROPDOWN | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0); +#define CONTROL_EDITTEXT(id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_EDIT, (WORD)id, x, y, width, height, style | ES_LEFT | WS_BORDER | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0); +#define CONTROL_GROUPBOX(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_GROUPBOX, exStyle, text, NULL, 0); +#define CONTROL_LISTBOX(id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_LISTBOX, (WORD)id, x, y, width, height, style | LBS_NOTIFY | WS_BORDER, exStyle, (LPCTSTR)NULL, NULL, 0); +#define CONTROL_SCROLLBAR(id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_SCROLLBAR, (WORD)id, x, y, width, height, style | SBS_HORZ, exStyle, (LPCTSTR)NULL, NULL, 0); +#define CONTROL_ICON(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_ICON, exStyle, text, NULL, 0); +#define CONTROL_CONTROL(text, id, className, style, x, y, width, height, exStyle) \ + m_Template.AddControl(className, (WORD)id, x, y, width, height, style, exStyle, text, NULL, 0); + + +/////////////////////////////////////////////////////////////////////////////// +// CIndirectDialogImpl - dialogs with template in memory + +template +class ATL_NO_VTABLE CIndirectDialogImpl : public ATL::CDialogImpl< T, TBase > +{ +public: + enum { IDD = 0 }; // no dialog template resource + + TDlgTemplate m_Template; + + void CreateTemplate() + { + T* pT = static_cast(this); + pT->DoInitTemplate(); + pT->DoInitControls(); + } + + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_hWnd == NULL); + + if(!m_Template.IsValid()) + CreateTemplate(); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL bRet = m_thunk.Init(NULL, NULL); + if(bRet == FALSE) + { + ::SetLastError(ERROR_OUTOFMEMORY); + return -1; + } +#endif // (_ATL_VER >= 0x0800) + + ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBaseT< TBase >*)pT); + +#ifdef _DEBUG + m_bModal = true; +#endif // _DEBUG + + return ::DialogBoxIndirectParam(ModuleHelper::GetResourceInstance(), m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam); + } + + HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_hWnd == NULL); + + if(!m_Template.IsValid()) + CreateTemplate(); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL bRet = m_thunk.Init(NULL, NULL); + if(bRet == FALSE) + { + ::SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } +#endif // (_ATL_VER >= 0x0800) + + ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBaseT< TBase >*)pT); + +#ifdef _DEBUG + m_bModal = false; +#endif // _DEBUG + + HWND hWnd = ::CreateDialogIndirectParam(ModuleHelper::GetResourceInstance(), (LPCDLGTEMPLATE)m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam); + ATLASSERT(m_hWnd == hWnd); + + return hWnd; + } + + // for CComControl + HWND Create(HWND hWndParent, RECT&, LPARAM dwInitParam = NULL) + { + return Create(hWndParent, dwInitParam); + } + + void DoInitTemplate() + { + ATLASSERT(FALSE); // MUST be defined in derived class + } + + void DoInitControls() + { + ATLASSERT(FALSE); // MUST be defined in derived class + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPropertySheetWindow - client side for a property sheet + +class CPropertySheetWindow : public ATL::CWindow +{ +public: +// Constructors + CPropertySheetWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd) + { } + + CPropertySheetWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Attributes + int GetPageCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HWND hWndTabCtrl = GetTabControl(); + ATLASSERT(hWndTabCtrl != NULL); + return (int)::SendMessage(hWndTabCtrl, TCM_GETITEMCOUNT, 0, 0L); + } + + HWND GetActivePage() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0L); + } + + int GetActiveIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HWND hWndTabCtrl = GetTabControl(); + ATLASSERT(hWndTabCtrl != NULL); + return (int)::SendMessage(hWndTabCtrl, TCM_GETCURSEL, 0, 0L); + } + + BOOL SetActivePage(int nPageIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, nPageIndex, 0L); + } + + BOOL SetActivePage(HPROPSHEETPAGE hPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hPage != NULL); + return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, 0, (LPARAM)hPage); + } + + BOOL SetActivePageByID(int nPageID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSELID, 0, nPageID); + } + + void SetTitle(LPCTSTR lpszText, UINT nStyle = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid + ATLASSERT(lpszText != NULL); + ::SendMessage(m_hWnd, PSM_SETTITLE, nStyle, (LPARAM)lpszText); + } + + HWND GetTabControl() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HWND)::SendMessage(m_hWnd, PSM_GETTABCONTROL, 0, 0L); + } + + void SetFinishText(LPCTSTR lpszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_SETFINISHTEXT, 0, (LPARAM)lpszText); + } + + void SetWizardButtons(DWORD dwFlags) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::PostMessage(m_hWnd, PSM_SETWIZBUTTONS, 0, dwFlags); + } + +// Operations + BOOL AddPage(HPROPSHEETPAGE hPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hPage != NULL); + return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage); + } + + BOOL AddPage(LPCPROPSHEETPAGE pPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pPage != NULL); + HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage); + if(hPage == NULL) + return FALSE; + return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage); + } + +#ifndef _WIN32_WCE + BOOL InsertPage(int nNewPageIndex, HPROPSHEETPAGE hPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hPage != NULL); + return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage); + } + + BOOL InsertPage(int nNewPageIndex, LPCPROPSHEETPAGE pPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pPage != NULL); + HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage); + if(hPage == NULL) + return FALSE; + return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage); + } + + BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, HPROPSHEETPAGE hPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hPage != NULL); + return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage); + } + + BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, LPCPROPSHEETPAGE pPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pPage != NULL); + HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage); + if(hPage == NULL) + return FALSE; + return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage); + } +#endif // !_WIN32_WCE + + void RemovePage(int nPageIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_REMOVEPAGE, nPageIndex, 0L); + } + + void RemovePage(HPROPSHEETPAGE hPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hPage != NULL); + ::SendMessage(m_hWnd, PSM_REMOVEPAGE, 0, (LPARAM)hPage); + } + + BOOL PressButton(int nButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PSM_PRESSBUTTON, nButton, 0L); + } + + BOOL Apply() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PSM_APPLY, 0, 0L); + } + + void CancelToClose() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_CANCELTOCLOSE, 0, 0L); + } + + void SetModified(HWND hWndPage, BOOL bChanged = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(::IsWindow(hWndPage)); + UINT uMsg = bChanged ? PSM_CHANGED : PSM_UNCHANGED; + ::SendMessage(m_hWnd, uMsg, (WPARAM)hWndPage, 0L); + } + + LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::SendMessage(m_hWnd, PSM_QUERYSIBLINGS, wParam, lParam); + } + + void RebootSystem() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_REBOOTSYSTEM, 0, 0L); + } + + void RestartWindows() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_RESTARTWINDOWS, 0, 0L); + } + + BOOL IsDialogMessage(LPMSG lpMsg) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PSM_ISDIALOGMESSAGE, 0, (LPARAM)lpMsg); + } + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + int HwndToIndex(HWND hWnd) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PSM_HWNDTOINDEX, (WPARAM)hWnd, 0L); + } + + HWND IndexToHwnd(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HWND)::SendMessage(m_hWnd, PSM_INDEXTOHWND, nIndex, 0L); + } + + int PageToIndex(HPROPSHEETPAGE hPage) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PSM_PAGETOINDEX, 0, (LPARAM)hPage); + } + + HPROPSHEETPAGE IndexToPage(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HPROPSHEETPAGE)::SendMessage(m_hWnd, PSM_INDEXTOPAGE, nIndex, 0L); + } + + int IdToIndex(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PSM_IDTOINDEX, 0, nID); + } + + int IndexToId(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PSM_INDEXTOID, nIndex, 0L); + } + + int GetResult() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PSM_GETRESULT, 0, 0L); + } + + BOOL RecalcPageSizes() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PSM_RECALCPAGESIZES, 0, 0L); + } + + void SetHeaderTitle(int nIndex, LPCTSTR lpstrHeaderTitle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_SETHEADERTITLE, nIndex, (LPARAM)lpstrHeaderTitle); + } + + void SetHeaderSubTitle(int nIndex, LPCTSTR lpstrHeaderSubTitle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_SETHEADERSUBTITLE, nIndex, (LPARAM)lpstrHeaderSubTitle); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +// Implementation - override to prevent usage + HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL) + { + ATLASSERT(FALSE); + return NULL; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CPropertySheetImpl - implements a property sheet + +template +class ATL_NO_VTABLE CPropertySheetImpl : public ATL::CWindowImplBaseT< TBase > +{ +public: + PROPSHEETHEADER m_psh; + ATL::CSimpleArray m_arrPages; + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific + #ifndef PROPSHEET_LINK_SIZE + #define PROPSHEET_LINK_SIZE 128 + #endif // PROPSHEET_LINK_SIZE + TCHAR m_szLink[PROPSHEET_LINK_SIZE]; + static LPCTSTR m_pszTitle; + static LPCTSTR m_pszLink; +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + +// Construction/Destruction + CPropertySheetImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) + { + memset(&m_psh, 0, sizeof(PROPSHEETHEADER)); + m_psh.dwSize = sizeof(PROPSHEETHEADER); + m_psh.dwFlags = PSH_USECALLBACK; + m_psh.hInstance = ModuleHelper::GetResourceInstance(); + m_psh.phpage = NULL; // will be set later + m_psh.nPages = 0; // will be set later + m_psh.pszCaption = title.m_lpstr; + m_psh.nStartPage = uStartPage; + m_psh.hwndParent = hWndParent; // if NULL, will be set in DoModal/Create + m_psh.pfnCallback = T::PropSheetCallback; + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific + m_psh.dwFlags |= PSH_MAXIMIZE; + m_szLink[0] = 0; +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + } + + ~CPropertySheetImpl() + { + if(m_arrPages.GetSize() > 0) // sheet never created, destroy all pages + { + for(int i = 0; i < m_arrPages.GetSize(); i++) + ::DestroyPropertySheetPage((HPROPSHEETPAGE)m_arrPages[i]); + } + } + +// Callback function and overrideables + static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam) + { + lParam; // avoid level 4 warning + int nRet = 0; + + if(uMsg == PSCB_INITIALIZED) + { + ATLASSERT(hWnd != NULL); + T* pT = (T*)ModuleHelper::ExtractCreateWndData(); + // subclass the sheet window + pT->SubclassWindow(hWnd); + // remove page handles array + pT->_CleanUpPages(); + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific + m_pszTitle = pT->m_psh.pszCaption; + if(*pT->m_szLink != 0) + m_pszLink = pT->m_szLink; +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific + + pT->OnSheetInitialized(); + } +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific uMsg + else + { + switch(uMsg) + { + case PSCB_GETVERSION : + nRet = COMCTL32_VERSION; + break; + case PSCB_GETTITLE : + if(m_pszTitle != NULL) + { + lstrcpy((LPTSTR)lParam, m_pszTitle); + m_pszTitle = NULL; + } + break; + case PSCB_GETLINKTEXT: + if(m_pszLink != NULL) + { + lstrcpy((LPTSTR)lParam, m_pszLink); + m_pszLink = NULL; + } + break; + default: + break; + } + } +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + + return nRet; + } + + void OnSheetInitialized() + { + } + +// Create method + HWND Create(HWND hWndParent = NULL) + { + ATLASSERT(m_hWnd == NULL); + + m_psh.dwFlags |= PSH_MODELESS; + if(m_psh.hwndParent == NULL) + m_psh.hwndParent = hWndParent; + m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData(); + m_psh.nPages = m_arrPages.GetSize(); + + T* pT = static_cast(this); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL bRet = pT->m_thunk.Init(NULL, NULL); + if(bRet == FALSE) + { + ::SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } +#endif // (_ATL_VER >= 0x0800) + + ModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT); + + HWND hWnd = (HWND)::PropertySheet(&m_psh); + _CleanUpPages(); // ensure clean-up, required if call failed + + ATLASSERT(m_hWnd == hWnd); + + return hWnd; + } + + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT(m_hWnd == NULL); + + m_psh.dwFlags &= ~PSH_MODELESS; + if(m_psh.hwndParent == NULL) + m_psh.hwndParent = hWndParent; + m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData(); + m_psh.nPages = m_arrPages.GetSize(); + + T* pT = static_cast(this); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL bRet = pT->m_thunk.Init(NULL, NULL); + if(bRet == FALSE) + { + ::SetLastError(ERROR_OUTOFMEMORY); + return -1; + } +#endif // (_ATL_VER >= 0x0800) + + ModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT); + + INT_PTR nRet = ::PropertySheet(&m_psh); + _CleanUpPages(); // ensure clean-up, required if call failed + + return nRet; + } + + // implementation helper - clean up pages array + void _CleanUpPages() + { + m_psh.nPages = 0; + m_psh.phpage = NULL; + m_arrPages.RemoveAll(); + } + +// Attributes (extended overrides of client class methods) +// These now can be called before the sheet is created +// Note: Calling these after the sheet is created gives unpredictable results + int GetPageCount() const + { + if(m_hWnd == NULL) // not created yet + return m_arrPages.GetSize(); + return TBase::GetPageCount(); + } + + int GetActiveIndex() const + { + if(m_hWnd == NULL) // not created yet + return m_psh.nStartPage; + return TBase::GetActiveIndex(); + } + + HPROPSHEETPAGE GetPage(int nPageIndex) const + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + return (HPROPSHEETPAGE)m_arrPages[nPageIndex]; + } + + int GetPageIndex(HPROPSHEETPAGE hPage) const + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + return m_arrPages.Find((HPROPSHEETPAGE&)hPage); + } + + BOOL SetActivePage(int nPageIndex) + { + if(m_hWnd == NULL) // not created yet + { + ATLASSERT(nPageIndex >= 0 && nPageIndex < m_arrPages.GetSize()); + m_psh.nStartPage = nPageIndex; + return TRUE; + } + return TBase::SetActivePage(nPageIndex); + } + + BOOL SetActivePage(HPROPSHEETPAGE hPage) + { + ATLASSERT(hPage != NULL); + if (m_hWnd == NULL) // not created yet + { + int nPageIndex = GetPageIndex(hPage); + if(nPageIndex == -1) + return FALSE; + + return SetActivePage(nPageIndex); + } + return TBase::SetActivePage(hPage); + + } + + void SetTitle(LPCTSTR lpszText, UINT nStyle = 0) + { + ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid + ATLASSERT(lpszText != NULL); + + if(m_hWnd == NULL) + { + // set internal state + m_psh.pszCaption = lpszText; // must exist until sheet is created + m_psh.dwFlags &= ~PSH_PROPTITLE; + m_psh.dwFlags |= nStyle; + } + else + { + // set external state + TBase::SetTitle(lpszText, nStyle); + } + } + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific Link field + void SetLinkText(LPCTSTR lpszText) + { + ATLASSERT(lpszText != NULL); + ATLASSERT(lstrlen(lpszText) < PROPSHEET_LINK_SIZE); + lstrcpy(m_szLink, lpszText); + } +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + + void SetWizardMode() + { + m_psh.dwFlags |= PSH_WIZARD; + } + + void EnableHelp() + { + m_psh.dwFlags |= PSH_HASHELP; + } + +// Operations + BOOL AddPage(HPROPSHEETPAGE hPage) + { + ATLASSERT(hPage != NULL); + BOOL bRet = FALSE; + if(m_hWnd != NULL) + bRet = TBase::AddPage(hPage); + else // sheet not created yet, use internal data + bRet = m_arrPages.Add((HPROPSHEETPAGE&)hPage); + return bRet; + } + + BOOL AddPage(LPCPROPSHEETPAGE pPage) + { + ATLASSERT(pPage != NULL); + HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage); + if(hPage == NULL) + return FALSE; + BOOL bRet = AddPage(hPage); + if(!bRet) + ::DestroyPropertySheetPage(hPage); + return bRet; + } + + BOOL RemovePage(HPROPSHEETPAGE hPage) + { + ATLASSERT(hPage != NULL); + if (m_hWnd == NULL) // not created yet + { + int nPage = GetPageIndex(hPage); + if(nPage == -1) + return FALSE; + return RemovePage(nPage); + } + TBase::RemovePage(hPage); + return TRUE; + + } + + BOOL RemovePage(int nPageIndex) + { + BOOL bRet = TRUE; + if(m_hWnd != NULL) + TBase::RemovePage(nPageIndex); + else // sheet not created yet, use internal data + bRet = m_arrPages.RemoveAt(nPageIndex); + return bRet; + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + void SetHeader(LPCTSTR szbmHeader) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + + m_psh.dwFlags &= ~PSH_WIZARD; + m_psh.dwFlags |= (PSH_HEADER | PSH_WIZARD97); + m_psh.pszbmHeader = szbmHeader; + } + + void SetHeader(HBITMAP hbmHeader) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + + m_psh.dwFlags &= ~PSH_WIZARD; + m_psh.dwFlags |= (PSH_HEADER | PSH_USEHBMHEADER | PSH_WIZARD97); + m_psh.hbmHeader = hbmHeader; + } + + void SetWatermark(LPCTSTR szbmWatermark, HPALETTE hplWatermark = NULL) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + + m_psh.dwFlags &= ~PSH_WIZARD; + m_psh.dwFlags |= PSH_WATERMARK | PSH_WIZARD97; + m_psh.pszbmWatermark = szbmWatermark; + + if (hplWatermark != NULL) + { + m_psh.dwFlags |= PSH_USEHPLWATERMARK; + m_psh.hplWatermark = hplWatermark; + } + } + + void SetWatermark(HBITMAP hbmWatermark, HPALETTE hplWatermark = NULL) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + + m_psh.dwFlags &= ~PSH_WIZARD; + m_psh.dwFlags |= (PSH_WATERMARK | PSH_USEHBMWATERMARK | PSH_WIZARD97); + m_psh.hbmWatermark = hbmWatermark; + + if (hplWatermark != NULL) + { + m_psh.dwFlags |= PSH_USEHPLWATERMARK; + m_psh.hplWatermark = hplWatermark; + } + } + + void StretchWatermark(bool bStretchWatermark) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + if (bStretchWatermark) + m_psh.dwFlags |= PSH_STRETCHWATERMARK; + else + m_psh.dwFlags &= ~PSH_STRETCHWATERMARK; + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +// Message map and handlers + BEGIN_MSG_MAP(CPropertySheetImpl) + MESSAGE_HANDLER(WM_COMMAND, OnCommand) + MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand) + END_MSG_MAP() + + LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + if(HIWORD(wParam) == BN_CLICKED && (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) && + ((m_psh.dwFlags & PSH_MODELESS) != 0) && (GetActivePage() == NULL)) + DestroyWindow(); + return lRet; + } + + LRESULT OnSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(((m_psh.dwFlags & PSH_MODELESS) == PSH_MODELESS) && ((wParam & 0xFFF0) == SC_CLOSE)) + SendMessage(WM_CLOSE); + else + bHandled = FALSE; + return 0; + } +}; + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC static pointers +template < class T, class TBase > +LPCWSTR CPropertySheetImpl::m_pszTitle = NULL; +template < class T, class TBase> +LPCWSTR CPropertySheetImpl::m_pszLink = NULL; +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + +// for non-customized sheets +class CPropertySheet : public CPropertySheetImpl +{ +public: + CPropertySheet(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) + : CPropertySheetImpl(title, uStartPage, hWndParent) + { } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPropertyPageWindow - client side for a property page + +class CPropertyPageWindow : public ATL::CWindow +{ +public: +// Constructors + CPropertyPageWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd) + { } + + CPropertyPageWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Attributes + CPropertySheetWindow GetPropertySheet() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CPropertySheetWindow(GetParent()); + } + +// Operations + BOOL Apply() + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + return GetPropertySheet().Apply(); + } + + void CancelToClose() + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetPropertySheet().CancelToClose(); + } + + void SetModified(BOOL bChanged = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetPropertySheet().SetModified(m_hWnd, bChanged); + } + + LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + return GetPropertySheet().QuerySiblings(wParam, lParam); + } + + void RebootSystem() + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetPropertySheet().RebootSystem(); + } + + void RestartWindows() + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetPropertySheet().RestartWindows(); + } + + void SetWizardButtons(DWORD dwFlags) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetPropertySheet().SetWizardButtons(dwFlags); + } + +// Implementation - overrides to prevent usage + HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL) + { + ATLASSERT(FALSE); + return NULL; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CPropertyPageImpl - implements a property page + +template +class ATL_NO_VTABLE CPropertyPageImpl : public ATL::CDialogImplBaseT< TBase > +{ +public: + PROPSHEETPAGE m_psp; + + operator PROPSHEETPAGE*() { return &m_psp; } + +// Construction + CPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) + { + // initialize PROPSHEETPAGE struct + memset(&m_psp, 0, sizeof(PROPSHEETPAGE)); + m_psp.dwSize = sizeof(PROPSHEETPAGE); + m_psp.dwFlags = PSP_USECALLBACK; + m_psp.hInstance = ModuleHelper::GetResourceInstance(); + T* pT = static_cast(this); + m_psp.pszTemplate = MAKEINTRESOURCE(pT->IDD); + m_psp.pfnDlgProc = (DLGPROC)T::StartDialogProc; + m_psp.pfnCallback = T::PropPageCallback; + m_psp.lParam = (LPARAM)pT; + + if(title.m_lpstr != NULL) + SetTitle(title); + } + +// Callback function and overrideables + static UINT CALLBACK PropPageCallback(HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp) + { + hWnd; // avoid level 4 warning + ATLASSERT(hWnd == NULL); + T* pT = (T*)ppsp->lParam; + UINT uRet = 0; + + switch(uMsg) + { + case PSPCB_CREATE: + { + ATL::CDialogImplBaseT< TBase >* pPage = (ATL::CDialogImplBaseT< TBase >*)pT; + ModuleHelper::AddCreateWndData(&pPage->m_thunk.cd, pPage); + uRet = pT->OnPageCreate() ? 1 : 0; + } + break; +#if (_WIN32_IE >= 0x0500) + case PSPCB_ADDREF: + pT->OnPageAddRef(); + break; +#endif // (_WIN32_IE >= 0x0500) + case PSPCB_RELEASE: + pT->OnPageRelease(); + break; + default: + break; + } + + return uRet; + } + + bool OnPageCreate() + { + return true; // true - allow page to be created, false - prevent creation + } + +#if (_WIN32_IE >= 0x0500) + void OnPageAddRef() + { + } +#endif // (_WIN32_IE >= 0x0500) + + void OnPageRelease() + { + } + +// Create method + HPROPSHEETPAGE Create() + { + return ::CreatePropertySheetPage(&m_psp); + } + +// Attributes + void SetTitle(ATL::_U_STRINGorID title) + { + m_psp.pszTitle = title.m_lpstr; + m_psp.dwFlags |= PSP_USETITLE; + } + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + void SetHeaderTitle(LPCTSTR lpstrHeaderTitle) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + m_psp.dwFlags |= PSP_USEHEADERTITLE; + m_psp.pszHeaderTitle = lpstrHeaderTitle; + } + + void SetHeaderSubTitle(LPCTSTR lpstrHeaderSubTitle) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + m_psp.dwFlags |= PSP_USEHEADERSUBTITLE; + m_psp.pszHeaderSubTitle = lpstrHeaderSubTitle; + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +// Operations + void EnableHelp() + { + m_psp.dwFlags |= PSP_HASHELP; + } + +// Message map and handlers + BEGIN_MSG_MAP(CPropertyPageImpl) + MESSAGE_HANDLER(WM_NOTIFY, OnNotify) + END_MSG_MAP() + + // NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification + // handlers that return direct values without any restrictions + LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { +#ifndef _WIN32_WCE + // This notification is sometimes received on Windows CE after the window is already destroyed + ATLASSERT(::IsWindow(m_hWnd)); +#endif + NMHDR* pNMHDR = (NMHDR*)lParam; + + // don't handle messages not from the page/sheet itself + if(pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd)) + { + bHandled = FALSE; + return 1; + } +#ifdef _WIN32_WCE + ATLASSERT(::IsWindow(m_hWnd)); +#endif + + T* pT = static_cast(this); + LRESULT lResult = 0; + switch(pNMHDR->code) + { +#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS + case PSN_SETACTIVE: + lResult = pT->OnSetActive(); + break; + case PSN_KILLACTIVE: + lResult = pT->OnKillActive(); + break; + case PSN_APPLY: + lResult = pT->OnApply(); + break; + case PSN_RESET: + pT->OnReset(); + break; + case PSN_QUERYCANCEL: + lResult = pT->OnQueryCancel(); + break; + case PSN_WIZNEXT: + lResult = pT->OnWizardNext(); + break; + case PSN_WIZBACK: + lResult = pT->OnWizardBack(); + break; + case PSN_WIZFINISH: + lResult = pT->OnWizardFinish(); + break; + case PSN_HELP: + pT->OnHelp(); + break; +#ifndef _WIN32_WCE +#if (_WIN32_IE >= 0x0400) + case PSN_GETOBJECT: + if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam)) + bHandled = FALSE; + break; +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) + case PSN_TRANSLATEACCELERATOR: + { + LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam; + lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam); + } + break; + case PSN_QUERYINITIALFOCUS: + { + LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam; + lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam); + } + break; +#endif // (_WIN32_IE >= 0x0500) +#endif // !_WIN32_WCE + +#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS + case PSN_SETACTIVE: + lResult = pT->OnSetActive() ? 0 : -1; + break; + case PSN_KILLACTIVE: + lResult = !pT->OnKillActive(); + break; + case PSN_APPLY: + lResult = pT->OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE; + break; + case PSN_RESET: + pT->OnReset(); + break; + case PSN_QUERYCANCEL: + lResult = !pT->OnQueryCancel(); + break; + case PSN_WIZNEXT: + lResult = pT->OnWizardNext(); + break; + case PSN_WIZBACK: + lResult = pT->OnWizardBack(); + break; + case PSN_WIZFINISH: + lResult = !pT->OnWizardFinish(); + break; + case PSN_HELP: + pT->OnHelp(); + break; +#ifndef _WIN32_WCE +#if (_WIN32_IE >= 0x0400) + case PSN_GETOBJECT: + if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam)) + bHandled = FALSE; + break; +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) + case PSN_TRANSLATEACCELERATOR: + { + LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam; + lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR; + } + break; + case PSN_QUERYINITIALFOCUS: + { + LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam; + lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam); + } + break; +#endif // (_WIN32_IE >= 0x0500) +#endif // !_WIN32_WCE + +#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS + default: + bHandled = FALSE; // not handled + } + + return lResult; + } + +// Overridables + // NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification + // handlers that return direct values without any restrictions +#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS + int OnSetActive() + { + // 0 = allow activate + // -1 = go back that was active + // page ID = jump to page + return 0; + } + + BOOL OnKillActive() + { + // FALSE = allow deactivate + // TRUE = prevent deactivation + return FALSE; + } + + int OnApply() + { + // PSNRET_NOERROR = apply OK + // PSNRET_INVALID = apply not OK, return to this page + // PSNRET_INVALID_NOCHANGEPAGE = apply not OK, don't change focus + return PSNRET_NOERROR; + } + + void OnReset() + { + } + + BOOL OnQueryCancel() + { + // FALSE = allow cancel + // TRUE = prevent cancel + return FALSE; + } + + int OnWizardBack() + { + // 0 = goto previous page + // -1 = prevent page change + // >0 = jump to page by dlg ID + return 0; + } + + int OnWizardNext() + { + // 0 = goto next page + // -1 = prevent page change + // >0 = jump to page by dlg ID + return 0; + } + + INT_PTR OnWizardFinish() + { + // FALSE = allow finish + // TRUE = prevent finish + // HWND = prevent finish and set focus to HWND (CommCtrl 5.80 only) + return FALSE; + } + + void OnHelp() + { + } + +#ifndef _WIN32_WCE +#if (_WIN32_IE >= 0x0400) + BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/) + { + return FALSE; // not processed + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) + int OnTranslateAccelerator(LPMSG /*lpMsg*/) + { + // PSNRET_NOERROR - message not handled + // PSNRET_MESSAGEHANDLED - message handled + return PSNRET_NOERROR; + } + + HWND OnQueryInitialFocus(HWND /*hWndFocus*/) + { + // NULL = set focus to default control + // HWND = set focus to HWND + return NULL; + } +#endif // (_WIN32_IE >= 0x0500) +#endif // !_WIN32_WCE + +#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS + BOOL OnSetActive() + { + return TRUE; + } + + BOOL OnKillActive() + { + return TRUE; + } + + BOOL OnApply() + { + return TRUE; + } + + void OnReset() + { + } + + BOOL OnQueryCancel() + { + return TRUE; // ok to cancel + } + + int OnWizardBack() + { + // 0 = goto previous page + // -1 = prevent page change + // >0 = jump to page by dlg ID + return 0; + } + + int OnWizardNext() + { + // 0 = goto next page + // -1 = prevent page change + // >0 = jump to page by dlg ID + return 0; + } + + BOOL OnWizardFinish() + { + return TRUE; + } + + void OnHelp() + { + } + +#ifndef _WIN32_WCE +#if (_WIN32_IE >= 0x0400) + BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/) + { + return FALSE; // not processed + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) + BOOL OnTranslateAccelerator(LPMSG /*lpMsg*/) + { + return FALSE; // not translated + } + + HWND OnQueryInitialFocus(HWND /*hWndFocus*/) + { + return NULL; // default + } +#endif // (_WIN32_IE >= 0x0500) +#endif // !_WIN32_WCE + +#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS +}; + +// for non-customized pages +template +class CPropertyPage : public CPropertyPageImpl > +{ +public: + enum { IDD = t_wDlgTemplateID }; + + CPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl(title) + { } + + DECLARE_EMPTY_MSG_MAP() +}; + +/////////////////////////////////////////////////////////////////////////////// +// CAxPropertyPageImpl - property page that hosts ActiveX controls + +#ifndef _ATL_NO_HOSTING + +// Note: You must #include to use these classes + +template +class ATL_NO_VTABLE CAxPropertyPageImpl : public CPropertyPageImpl< T, TBase > +{ +public: +// Data members + HGLOBAL m_hInitData; + HGLOBAL m_hDlgRes; + HGLOBAL m_hDlgResSplit; + +// Constructor/destructor + CAxPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : + CPropertyPageImpl< T, TBase >(title), + m_hInitData(NULL), m_hDlgRes(NULL), m_hDlgResSplit(NULL) + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + + // initialize ActiveX hosting and modify dialog template + ATL::AtlAxWinInit(); + + HINSTANCE hInstance = ModuleHelper::GetResourceInstance(); + LPCTSTR lpTemplateName = MAKEINTRESOURCE(pT->IDD); + HRSRC hDlg = ::FindResource(hInstance, lpTemplateName, (LPTSTR)RT_DIALOG); + if(hDlg != NULL) + { + HRSRC hDlgInit = ::FindResource(hInstance, lpTemplateName, (LPTSTR)_ATL_RT_DLGINIT); + + BYTE* pInitData = NULL; + if(hDlgInit != NULL) + { + m_hInitData = ::LoadResource(hInstance, hDlgInit); + pInitData = (BYTE*)::LockResource(m_hInitData); + } + + m_hDlgRes = ::LoadResource(hInstance, hDlg); + DLGTEMPLATE* pDlg = (DLGTEMPLATE*)::LockResource(m_hDlgRes); + LPCDLGTEMPLATE lpDialogTemplate = ATL::_DialogSplitHelper::SplitDialogTemplate(pDlg, pInitData); + if(lpDialogTemplate != pDlg) + m_hDlgResSplit = GlobalHandle(lpDialogTemplate); + + // set up property page to use in-memory dialog template + if(lpDialogTemplate != NULL) + { + m_psp.dwFlags |= PSP_DLGINDIRECT; + m_psp.pResource = lpDialogTemplate; + } + else + { + ATLASSERT(FALSE && _T("CAxPropertyPageImpl - ActiveX initializtion failed!")); + } + } + else + { + ATLASSERT(FALSE && _T("CAxPropertyPageImpl - Cannot find dialog template!")); + } + } + + ~CAxPropertyPageImpl() + { + if(m_hInitData != NULL) + { + UnlockResource(m_hInitData); + FreeResource(m_hInitData); + } + if(m_hDlgRes != NULL) + { + UnlockResource(m_hDlgRes); + FreeResource(m_hDlgRes); + } + if(m_hDlgResSplit != NULL) + { + ::GlobalFree(m_hDlgResSplit); + } + } + +// Methods + // call this one to handle keyboard message for ActiveX controls + BOOL PreTranslateMessage(LPMSG pMsg) + { + if ((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) && + (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST)) + return FALSE; + // find a direct child of the dialog from the window that has focus + HWND hWndCtl = ::GetFocus(); + if (IsChild(hWndCtl) && ::GetParent(hWndCtl) != m_hWnd) + { + do + { + hWndCtl = ::GetParent(hWndCtl); + } + while (::GetParent(hWndCtl) != m_hWnd); + } + // give controls a chance to translate this message + return (BOOL)::SendMessage(hWndCtl, WM_FORWARDMSG, 0, (LPARAM)pMsg); + } + +// Overridables +#if (_WIN32_IE >= 0x0500) + // new default implementation for ActiveX hosting pages +#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS + int OnTranslateAccelerator(LPMSG lpMsg) + { + T* pT = static_cast(this); + return (pT->PreTranslateMessage(lpMsg) != FALSE) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR; + } +#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS + BOOL OnTranslateAccelerator(LPMSG lpMsg) + { + T* pT = static_cast(this); + return pT->PreTranslateMessage(lpMsg); + } +#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS +#endif // (_WIN32_IE >= 0x0500) + +// Support for new stuff in ATL7 +#if (_ATL_VER >= 0x0700) + int GetIDD() + { + return( static_cast(this)->IDD ); + } + + virtual DLGPROC GetDialogProc() + { + return DialogProc; + } + + static INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + CAxPropertyPageImpl< T, TBase >* pThis = (CAxPropertyPageImpl< T, TBase >*)hWnd; + if (uMsg == WM_INITDIALOG) + { + HRESULT hr; + if (FAILED(hr = pThis->CreateActiveXControls(pThis->GetIDD()))) + { + ATLASSERT(FALSE); + return FALSE; + } + } + return CPropertyPageImpl< T, TBase >::DialogProc(hWnd, uMsg, wParam, lParam); + } + +// ActiveX controls creation + virtual HRESULT CreateActiveXControls(UINT nID) + { + // Load dialog template and InitData + HRSRC hDlgInit = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)_ATL_RT_DLGINIT); + BYTE* pInitData = NULL; + HGLOBAL hData = NULL; + HRESULT hr = S_OK; + if (hDlgInit != NULL) + { + hData = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlgInit); + if (hData != NULL) + pInitData = (BYTE*) ::LockResource(hData); + } + + HRSRC hDlg = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)RT_DIALOG); + if (hDlg != NULL) + { + HGLOBAL hResource = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlg); + DLGTEMPLATE* pDlg = NULL; + if (hResource != NULL) + { + pDlg = (DLGTEMPLATE*) ::LockResource(hResource); + if (pDlg != NULL) + { + // Get first control on the template + BOOL bDialogEx = ATL::_DialogSplitHelper::IsDialogEx(pDlg); + WORD nItems = ATL::_DialogSplitHelper::DlgTemplateItemCount(pDlg); + + // Get first control on the dialog + DLGITEMTEMPLATE* pItem = ATL::_DialogSplitHelper::FindFirstDlgItem(pDlg); + HWND hWndPrev = GetWindow(GW_CHILD); + + // Create all ActiveX cotnrols in the dialog template and place them in the correct tab order (z-order) + for (WORD nItem = 0; nItem < nItems; nItem++) + { + DWORD wID = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : pItem->id; + if (ATL::_DialogSplitHelper::IsActiveXControl(pItem, bDialogEx)) + { + BYTE* pData = NULL; + DWORD dwLen = ATL::_DialogSplitHelper::FindCreateData(wID, pInitData, &pData); + ATL::CComPtr spStream; + if (dwLen != 0) + { + HGLOBAL h = GlobalAlloc(GHND, dwLen); + if (h != NULL) + { + BYTE* pBytes = (BYTE*) GlobalLock(h); + BYTE* pSource = pData; + SecureHelper::memcpy_x(pBytes, dwLen, pSource, dwLen); + GlobalUnlock(h); + CreateStreamOnHGlobal(h, TRUE, &spStream); + } + else + { + hr = E_OUTOFMEMORY; + break; + } + } + + ATL::CComBSTR bstrLicKey; + hr = ATL::_DialogSplitHelper::ParseInitData(spStream, &bstrLicKey.m_str); + if (SUCCEEDED(hr)) + { + ATL::CAxWindow2 wnd; + // Get control caption. + LPWSTR pszClassName = + bDialogEx ? + (LPWSTR)(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem) + 1) : + (LPWSTR)(pItem + 1); + // Get control rect. + RECT rect = { 0 }; + rect.left = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->x : pItem->x; + rect.top = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->y : pItem->y; + rect.right = rect.left + (bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cx : pItem->cx); + rect.bottom = rect.top + (bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cy : pItem->cy); + + // Convert from dialog units to screen units + MapDialogRect(&rect); + + // Create AxWindow with a NULL caption. + wnd.Create(m_hWnd, + &rect, + NULL, + (bDialogEx ? + ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->style : + pItem->style) | WS_TABSTOP, + bDialogEx ? + ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->exStyle : + 0, + bDialogEx ? + ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : + pItem->id, + NULL); + + if (wnd != NULL) + { +#ifndef _WIN32_WCE + // Set the Help ID + if (bDialogEx && ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID != 0) + wnd.SetWindowContextHelpId(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID); +#endif // !_WIN32_WCE + // Try to create the ActiveX control. + hr = wnd.CreateControlLic(pszClassName, spStream, NULL, bstrLicKey); + if (FAILED(hr)) + break; + // Set the correct tab position. + if (nItem == 0) + hWndPrev = HWND_TOP; + wnd.SetWindowPos(hWndPrev, 0,0,0,0,SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + hWndPrev = wnd; + } + else + { + hr = ATL::AtlHresultFromLastError(); + } + } + } + else + { + if (nItem != 0) + hWndPrev = ::GetWindow(hWndPrev, GW_HWNDNEXT); + } + pItem = ATL::_DialogSplitHelper::FindNextDlgItem(pItem, bDialogEx); + } + } + else + hr = ATL::AtlHresultFromLastError(); + } + else + hr = ATL::AtlHresultFromLastError(); + } + return hr; + } + +// Event handling support + HRESULT AdviseSinkMap(bool bAdvise) + { + if(!bAdvise && m_hWnd == NULL) + { + // window is gone, controls are already unadvised + ATLTRACE2(atlTraceUI, 0, _T("CAxPropertyPageImpl::AdviseSinkMap called after the window was destroyed\n")); + return S_OK; + } + HRESULT hRet = E_NOTIMPL; + __if_exists(T::_GetSinkMapFinder) + { + T* pT = static_cast(this); + hRet = AtlAdviseSinkMap(pT, bAdvise); + } + return hRet; + } + +// Message map and handlers + typedef CPropertyPageImpl< T, TBase> _baseClass; + BEGIN_MSG_MAP(CAxPropertyPageImpl) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + // initialize controls in dialog with DLGINIT resource section + ExecuteDlgInit(static_cast(this)->IDD); + AdviseSinkMap(true); + bHandled = FALSE; + return 1; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + AdviseSinkMap(false); + bHandled = FALSE; + return 1; + } +#endif // (_ATL_VER >= 0x0700) +}; + +// for non-customized pages +template +class CAxPropertyPage : public CAxPropertyPageImpl > +{ +public: + enum { IDD = t_wDlgTemplateID }; + + CAxPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl(title) + { } + +#if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700) + // not empty so we handle accelerators/create controls + BEGIN_MSG_MAP(CAxPropertyPage) + CHAIN_MSG_MAP(CAxPropertyPageImpl >) + END_MSG_MAP() +#else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)) + DECLARE_EMPTY_MSG_MAP() +#endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)) +}; + +#endif // _ATL_NO_HOSTING + + +/////////////////////////////////////////////////////////////////////////////// +// Wizard97 Support + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +// Sample wizard dialog resources: +// +// IDD_WIZ97_INTERIOR_BLANK DIALOG 0, 0, 317, 143 +// STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION +// CAPTION "Wizard97 Property Page - Interior" +// FONT 8, "MS Shell Dlg" +// BEGIN +// END +// +// IDD_WIZ97_EXTERIOR_BLANK DIALOGEX 0, 0, 317, 193 +// STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION +// CAPTION "Wizard97 Property Page - Welcome/Complete" +// FONT 8, "MS Shell Dlg", 0, 0, 0x0 +// BEGIN +// LTEXT "Welcome to the X Wizard",IDC_WIZ97_EXTERIOR_TITLE,115,8, +// 195,24 +// LTEXT "Wizard Explanation\r\n(The height of the static text should be in multiples of 8 dlus)", +// IDC_STATIC,115,40,195,16 +// LTEXT "h",IDC_WIZ97_BULLET1,118,64,8,8 +// LTEXT "List Item 1 (the h is turned into a bullet)",IDC_STATIC, +// 127,63,122,8 +// LTEXT "h",IDC_WIZ97_BULLET2,118,79,8,8 +// LTEXT "List Item 2. Keep 7 dlus between paragraphs",IDC_STATIC, +// 127,78,33,8 +// CONTROL "&Do not show this Welcome page again", +// IDC_WIZ97_WELCOME_NOTAGAIN,"Button",BS_AUTOCHECKBOX | +// WS_TABSTOP,115,169,138,10 +// END +// +// GUIDELINES DESIGNINFO +// BEGIN +// IDD_WIZ97_INTERIOR_BLANK, DIALOG +// BEGIN +// LEFTMARGIN, 7 +// RIGHTMARGIN, 310 +// VERTGUIDE, 21 +// VERTGUIDE, 31 +// VERTGUIDE, 286 +// VERTGUIDE, 296 +// TOPMARGIN, 7 +// BOTTOMMARGIN, 136 +// HORZGUIDE, 8 +// END +// +// IDD_WIZ97_EXTERIOR_BLANK, DIALOG +// BEGIN +// RIGHTMARGIN, 310 +// VERTGUIDE, 115 +// VERTGUIDE, 118 +// VERTGUIDE, 127 +// TOPMARGIN, 7 +// BOTTOMMARGIN, 186 +// HORZGUIDE, 8 +// HORZGUIDE, 32 +// HORZGUIDE, 40 +// HORZGUIDE, 169 +// END +// END + +/////////////////////////////////////////////////////////////////////////////// +// CWizard97SheetWindow - client side for a Wizard 97 style wizard sheet + +class CWizard97SheetWindow : public CPropertySheetWindow +{ +public: +// Constructors + CWizard97SheetWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd) + { } + + CWizard97SheetWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Operations + HFONT GetExteriorPageTitleFont(void) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HFONT)::SendMessage(m_hWnd, GetMessage_GetExteriorPageTitleFont(), 0, 0L); + } + + HFONT GetBulletFont(void) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HFONT)::SendMessage(m_hWnd, GetMessage_GetBulletFont(), 0, 0L); + } + +// Helpers + static UINT GetMessage_GetExteriorPageTitleFont() + { + static UINT uGetExteriorPageTitleFont = 0; + if(uGetExteriorPageTitleFont == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont().\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uGetExteriorPageTitleFont == 0) + uGetExteriorPageTitleFont = ::RegisterWindowMessage(_T("GetExteriorPageTitleFont_531AF056-B8BE-4c4c-B786-AC608DF0DF12")); + + lock.Unlock(); + } + ATLASSERT(uGetExteriorPageTitleFont != 0); + return uGetExteriorPageTitleFont; + } + + static UINT GetMessage_GetBulletFont() + { + static UINT uGetBulletFont = 0; + if(uGetBulletFont == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetBulletFont().\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uGetBulletFont == 0) + uGetBulletFont = ::RegisterWindowMessage(_T("GetBulletFont_AD347D08-8F65-45ef-982E-6352E8218AD5")); + + lock.Unlock(); + } + ATLASSERT(uGetBulletFont != 0); + return uGetBulletFont; + } + +// Implementation - override to prevent usage + HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL) + { + ATLASSERT(FALSE); + return NULL; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CWizard97SheetImpl - implements a Wizard 97 style wizard sheet + +template +class ATL_NO_VTABLE CWizard97SheetImpl : public CPropertySheetImpl< T, TBase > +{ +protected: +// Typedefs + typedef CWizard97SheetImpl< T, TBase > thisClass; + typedef CPropertySheetImpl< T, TBase > baseClass; + +// Member variables + CFont m_fontExteriorPageTitle; // Welcome and Completion page title font + CFont m_fontBullet; // Bullet font (used on static text 'h' to produce a small bullet) + bool m_bReceivedFirstSizeMessage; + +public: + CWizard97SheetImpl(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) : + baseClass(title, uStartPage, hWndParent), + m_bReceivedFirstSizeMessage(false) + { + m_psh.dwFlags &= ~(PSH_NOCONTEXTHELP); + m_psh.dwFlags &= ~(PSH_WIZARD | PSH_WIZARD_LITE); + + m_psh.dwFlags |= (PSH_HASHELP | PSH_WIZARDCONTEXTHELP); + m_psh.dwFlags |= PSH_WIZARD97; + + baseClass::SetHeader(headerBitmap.m_lpstr); + baseClass::SetWatermark(watermarkBitmap.m_lpstr); + } + +// Overrides from base class + void OnSheetInitialized() + { + T* pT = static_cast(this); + pT->_InitializeFonts(); + + // We'd like to center the wizard here, but its too early. + // Instead, we'll do CenterWindow upon our first WM_SIZE message + } + +// Initialization + void _InitializeFonts() + { + // Setup the Title and Bullet Font + // (Property pages can send the "get external page title font" and "get bullet font" messages) + // The derived class needs to do the actual SetFont for the dialog items) + + CFontHandle fontThisDialog = this->GetFont(); + CClientDC dcScreen(NULL); + + LOGFONT titleLogFont = {0}; + LOGFONT bulletLogFont = {0}; + fontThisDialog.GetLogFont(&titleLogFont); + fontThisDialog.GetLogFont(&bulletLogFont); + + // The Wizard 97 Spec recommends to do the Title Font + // as Verdana Bold, 12pt. + titleLogFont.lfCharSet = DEFAULT_CHARSET; + titleLogFont.lfWeight = FW_BOLD; + SecureHelper::strcpy_x(titleLogFont.lfFaceName, _countof(titleLogFont.lfFaceName), _T("Verdana Bold")); + INT titleFontPointSize = 12; + titleLogFont.lfHeight = -::MulDiv(titleFontPointSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72); + m_fontExteriorPageTitle.CreateFontIndirect(&titleLogFont); + + // The Wizard 97 Spec recommends to do Bullets by having + // static text of "h" in the Marlett font. + bulletLogFont.lfCharSet = DEFAULT_CHARSET; + bulletLogFont.lfWeight = FW_NORMAL; + SecureHelper::strcpy_x(bulletLogFont.lfFaceName, _countof(bulletLogFont.lfFaceName), _T("Marlett")); + INT bulletFontSize = 8; + bulletLogFont.lfHeight = -::MulDiv(bulletFontSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72); + m_fontBullet.CreateFontIndirect(&bulletLogFont); + } + +// Message Handling + BEGIN_MSG_MAP(thisClass) + MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont(), OnGetExteriorPageTitleFont) + MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetBulletFont(), OnGetBulletFont) + MESSAGE_HANDLER(WM_SIZE, OnSize) + CHAIN_MSG_MAP(baseClass) + END_MSG_MAP() + + LRESULT OnGetExteriorPageTitleFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return (LRESULT)(HFONT)m_fontExteriorPageTitle; + } + + LRESULT OnGetBulletFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return (LRESULT)(HFONT)m_fontBullet; + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(!m_bReceivedFirstSizeMessage) + { + m_bReceivedFirstSizeMessage = true; + this->CenterWindow(); + } + + bHandled = FALSE; + return 0; + } +}; + +// for non-customized sheets +class CWizard97Sheet : public CWizard97SheetImpl +{ +protected: +// Typedefs + typedef CWizard97Sheet thisClass; + typedef CWizard97SheetImpl baseClass; + +public: + CWizard97Sheet(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) : + baseClass(title, headerBitmap, watermarkBitmap, uStartPage, hWndParent) + { } + + BEGIN_MSG_MAP(thisClass) + CHAIN_MSG_MAP(baseClass) + END_MSG_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CWizard97PageWindow - client side for a Wizard 97 style wizard page + +#define WIZARD97_EXTERIOR_CXDLG 317 +#define WIZARD97_EXTERIOR_CYDLG 193 + +#define WIZARD97_INTERIOR_CXDLG 317 +#define WIZARD97_INTERIOR_CYDLG 143 + +class CWizard97PageWindow : public CPropertyPageWindow +{ +public: +// Constructors + CWizard97PageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd) + { } + + CWizard97PageWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Attributes + CWizard97SheetWindow GetPropertySheet() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CWizard97SheetWindow(GetParent()); + } + +// Operations + HFONT GetExteriorPageTitleFont(void) + { + ATLASSERT(::IsWindow(m_hWnd)); + return GetPropertySheet().GetExteriorPageTitleFont(); + } + + HFONT GetBulletFont(void) + { + ATLASSERT(::IsWindow(m_hWnd)); + return GetPropertySheet().GetBulletFont(); + } + +// Implementation - overrides to prevent usage + HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL) + { + ATLASSERT(FALSE); + return NULL; + } + +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CWizard97PageImpl - implements a Wizard 97 style wizard page + +template +class ATL_NO_VTABLE CWizard97PageImpl : public CPropertyPageImpl< T, TBase > +{ +protected: +// Typedefs + typedef CWizard97PageImpl< T, TBase > thisClass; + typedef CPropertyPageImpl< T, TBase > baseClass; + +public: + CWizard97PageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title) + { } + +// Message Handling + BEGIN_MSG_MAP(thisClass) + CHAIN_MSG_MAP(baseClass) + END_MSG_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CWizard97ExteriorPageImpl - implements a Wizard 97 style exterior wizard page + +template +class ATL_NO_VTABLE CWizard97ExteriorPageImpl : public CPropertyPageImpl< T, TBase > +{ +protected: +// Typedefs + typedef CWizard97ExteriorPageImpl< T, TBase > thisClass; + typedef CPropertyPageImpl< T, TBase > baseClass; + +public: +// Constructors + CWizard97ExteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title) + { + m_psp.dwFlags |= PSP_HASHELP; + m_psp.dwFlags |= PSP_HIDEHEADER; + } + +// Message Handling + BEGIN_MSG_MAP(thisClass) + CHAIN_MSG_MAP(baseClass) + END_MSG_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CWizard97InteriorPageImpl - implements a Wizard 97 style interior wizard page + +template +class ATL_NO_VTABLE CWizard97InteriorPageImpl : public CPropertyPageImpl< T, TBase > +{ +protected: +// Typedefs + typedef CWizard97InteriorPageImpl< T, TBase > thisClass; + typedef CPropertyPageImpl< T, TBase > baseClass; + +public: +// Constructors + CWizard97InteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title) + { + m_psp.dwFlags |= PSP_HASHELP; + m_psp.dwFlags &= ~PSP_HIDEHEADER; + m_psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; + + // Be sure to have the derived class define this in the constructor. + // We'll default it to something obvious in case its forgotten. + baseClass::SetHeaderTitle(_T("Call SetHeaderTitle in Derived Class")); + baseClass::SetHeaderSubTitle(_T("Call SetHeaderSubTitle in the constructor of the Derived Class.")); + } + +// Message Handling + BEGIN_MSG_MAP(thisClass) + CHAIN_MSG_MAP(baseClass) + END_MSG_MAP() +}; + +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// Aero Wizard support + +#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardFrameWindow - client side for an Aero Wizard frame window + +class CAeroWizardFrameWindow : public CPropertySheetWindow +{ +public: +// Constructors + CAeroWizardFrameWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd) + { } + + CAeroWizardFrameWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Operations - new, Aero Wizard only + void SetNextText(LPCWSTR lpszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_SETNEXTTEXT, 0, (LPARAM)lpszText); + } + + void ShowWizardButtons(DWORD dwButtons, DWORD dwStates) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::PostMessage(m_hWnd, PSM_SHOWWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons); + } + + void EnableWizardButtons(DWORD dwButtons, DWORD dwStates) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::PostMessage(m_hWnd, PSM_ENABLEWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons); + } + + void SetButtonText(DWORD dwButton, LPCWSTR lpszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_SETBUTTONTEXT, (WPARAM)dwButton, (LPARAM)lpszText); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardFrameImpl - implements an Aero Wizard frame + +template +class ATL_NO_VTABLE CAeroWizardFrameImpl : public CPropertySheetImpl +{ +public: +// Constructor + CAeroWizardFrameImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) : + CPropertySheetImpl(title, uStartPage, hWndParent) + { + m_psh.dwFlags |= PSH_WIZARD | PSH_AEROWIZARD; + } + +// Operations + void EnableResizing() + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + m_psh.dwFlags |= PSH_RESIZABLE; + } + + void UseHeaderBitmap() + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + m_psh.dwFlags |= PSH_HEADERBITMAP; + } + + void SetNoMargin() + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + m_psh.dwFlags |= PSH_NOMARGIN; + } + +// Override to prevent use + HWND Create(HWND /*hWndParent*/ = NULL) + { + ATLASSERT(FALSE); // not supported for Aero Wizard + return NULL; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardFrame - for non-customized frames + +class CAeroWizardFrame : public CAeroWizardFrameImpl +{ +public: + CAeroWizardFrame(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) + : CAeroWizardFrameImpl(title, uStartPage, hWndParent) + { } + + BEGIN_MSG_MAP(CAeroWizardFrame) + MESSAGE_HANDLER(WM_COMMAND, CAeroWizardFrameImpl::OnCommand) + END_MSG_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardPageWindow - client side for an Aero Wizard page + +class CAeroWizardPageWindow : public CPropertyPageWindow +{ +public: +// Constructors + CAeroWizardPageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd) + { } + + CAeroWizardPageWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Attributes + CAeroWizardFrameWindow GetAeroWizardFrame() const + { + ATLASSERT(::IsWindow(m_hWnd)); + // This is not really top-level frame window, but it processes all frame messages + return CAeroWizardFrameWindow(GetParent()); + } + +// Operations - new, Aero Wizard only + void SetNextText(LPCWSTR lpszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetAeroWizardFrame().SetNextText(lpszText); + } + + void ShowWizardButtons(DWORD dwButtons, DWORD dwStates) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetAeroWizardFrame().ShowWizardButtons(dwButtons, dwStates); + } + + void EnableWizardButtons(DWORD dwButtons, DWORD dwStates) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetAeroWizardFrame().EnableWizardButtons(dwButtons, dwStates); + } + + void SetButtonText(DWORD dwButton, LPCWSTR lpszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetAeroWizardFrame().SetButtonText(dwButton, lpszText); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardPageImpl - implements an Aero Wizard page + +template +class ATL_NO_VTABLE CAeroWizardPageImpl : public CPropertyPageImpl +{ +public: + CAeroWizardPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl(title) + { } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardPage - for non-customized pages + +template +class CAeroWizardPage : public CAeroWizardPageImpl > +{ +public: + enum { IDD = t_wDlgTemplateID }; + + CAeroWizardPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardPageImpl(title) + { } + + DECLARE_EMPTY_MSG_MAP() +}; + + +#ifndef _ATL_NO_HOSTING + +// Note: You must #include to use these classes + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardAxPageImpl - Aero Wizard page that hosts ActiveX controls + +template +class ATL_NO_VTABLE CAeroWizardAxPageImpl : public CAxPropertyPageImpl< T, TBase > +{ +public: + CAeroWizardAxPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl< T, TBase >(title) + { } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardAxPage - for non-customized pages + +template +class CAeroWizardAxPage : public CAeroWizardAxPageImpl > +{ +public: + enum { IDD = t_wDlgTemplateID }; + + CAeroWizardAxPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardAxPageImpl(title) + { } + +#if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700) + // not empty so we handle accelerators/create controls + BEGIN_MSG_MAP(CAeroWizardAxPage) + CHAIN_MSG_MAP(CAeroWizardAxPageImpl >) + END_MSG_MAP() +#else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)) + DECLARE_EMPTY_MSG_MAP() +#endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)) +}; + +#endif // _ATL_NO_HOSTING + +#endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// TaskDialog support + +#if ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE) + +/////////////////////////////////////////////////////////////////////////////// +// AtlTaskDialog - support for TaskDialog() function + +inline int AtlTaskDialog(HWND hWndParent, + ATL::_U_STRINGorID WindowTitle, ATL::_U_STRINGorID MainInstructionText, ATL::_U_STRINGorID ContentText, + TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons = 0U, ATL::_U_STRINGorID Icon = (LPCTSTR)NULL) +{ + int nRet = -1; + +#ifdef _WTL_TASKDIALOG_DIRECT + USES_CONVERSION; + HRESULT hRet = ::TaskDialog(hWndParent, ModuleHelper::GetResourceInstance(), + IS_INTRESOURCE(WindowTitle.m_lpstr) ? (LPCWSTR) WindowTitle.m_lpstr : T2CW(WindowTitle.m_lpstr), + IS_INTRESOURCE(MainInstructionText.m_lpstr) ? (LPCWSTR) MainInstructionText.m_lpstr : T2CW(MainInstructionText.m_lpstr), + IS_INTRESOURCE(ContentText.m_lpstr) ? (LPCWSTR) ContentText.m_lpstr : T2CW(ContentText.m_lpstr), + dwCommonButtons, + IS_INTRESOURCE(Icon.m_lpstr) ? (LPCWSTR) Icon.m_lpstr : T2CW(Icon.m_lpstr), + &nRet); + ATLVERIFY(SUCCEEDED(hRet)); +#else + // This allows apps to run on older versions of Windows + typedef HRESULT (STDAPICALLTYPE *PFN_TaskDialog)(HWND hwndParent, HINSTANCE hInstance, PCWSTR pszWindowTitle, PCWSTR pszMainInstruction, PCWSTR pszContent, TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons, PCWSTR pszIcon, int* pnButton); + + HMODULE m_hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll")); + if(m_hCommCtrlDLL != NULL) + { + PFN_TaskDialog pfnTaskDialog = (PFN_TaskDialog)::GetProcAddress(m_hCommCtrlDLL, "TaskDialog"); + if(pfnTaskDialog != NULL) + { + USES_CONVERSION; + HRESULT hRet = pfnTaskDialog(hWndParent, ModuleHelper::GetResourceInstance(), + IS_INTRESOURCE(WindowTitle.m_lpstr) ? (LPCWSTR) WindowTitle.m_lpstr : T2CW(WindowTitle.m_lpstr), + IS_INTRESOURCE(MainInstructionText.m_lpstr) ? (LPCWSTR) MainInstructionText.m_lpstr : T2CW(MainInstructionText.m_lpstr), + IS_INTRESOURCE(ContentText.m_lpstr) ? (LPCWSTR) ContentText.m_lpstr : T2CW(ContentText.m_lpstr), + dwCommonButtons, + IS_INTRESOURCE(Icon.m_lpstr) ? (LPCWSTR) Icon.m_lpstr : T2CW(Icon.m_lpstr), + &nRet); + ATLVERIFY(SUCCEEDED(hRet)); + } + + ::FreeLibrary(m_hCommCtrlDLL); + } +#endif + + return nRet; +} + + +/////////////////////////////////////////////////////////////////////////////// +// CTaskDialogConfig - TASKDIALOGCONFIG wrapper + +class CTaskDialogConfig : public TASKDIALOGCONFIG +{ +public: +// Constructor + CTaskDialogConfig() + { + Init(); + } + + void Init() + { + memset(this, 0, sizeof(TASKDIALOGCONFIG)); // initialize structure to 0/NULL + this->cbSize = sizeof(TASKDIALOGCONFIG); + this->hInstance = ModuleHelper::GetResourceInstance(); + } + +// Operations - setting values + // common buttons + void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtonsArg) + { + this->dwCommonButtons = dwCommonButtonsArg; + } + + // window title text + void SetWindowTitle(UINT nID) + { + this->pszWindowTitle = MAKEINTRESOURCEW(nID); + } + + void SetWindowTitle(LPCWSTR lpstrWindowTitle) + { + this->pszWindowTitle = lpstrWindowTitle; + } + + // main icon + void SetMainIcon(HICON hIcon) + { + this->dwFlags |= TDF_USE_HICON_MAIN; + this->hMainIcon = hIcon; + } + + void SetMainIcon(UINT nID) + { + this->dwFlags &= ~TDF_USE_HICON_MAIN; + this->pszMainIcon = MAKEINTRESOURCEW(nID); + } + + void SetMainIcon(LPCWSTR lpstrMainIcon) + { + this->dwFlags &= ~TDF_USE_HICON_MAIN; + this->pszMainIcon = lpstrMainIcon; + } + + // main instruction text + void SetMainInstructionText(UINT nID) + { + this->pszMainInstruction = MAKEINTRESOURCEW(nID); + } + + void SetMainInstructionText(LPCWSTR lpstrMainInstruction) + { + this->pszMainInstruction = lpstrMainInstruction; + } + + // content text + void SetContentText(UINT nID) + { + this->pszContent = MAKEINTRESOURCEW(nID); + } + + void SetContentText(LPCWSTR lpstrContent) + { + this->pszContent = lpstrContent; + } + + // buttons + void SetButtons(const TASKDIALOG_BUTTON* pButtonsArg, UINT cButtonsArg, int nDefaultButtonArg = 0) + { + this->pButtons = pButtonsArg; + this->cButtons = cButtonsArg; + if(nDefaultButtonArg != 0) + this->nDefaultButton = nDefaultButtonArg; + } + + void SetDefaultButton(int nDefaultButtonArg) + { + this->nDefaultButton = nDefaultButtonArg; + } + + // radio buttons + void SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtonsArg, UINT cRadioButtonsArg, int nDefaultRadioButtonArg = 0) + { + this->pRadioButtons = pRadioButtonsArg; + this->cRadioButtons = cRadioButtonsArg; + if(nDefaultRadioButtonArg != 0) + this->nDefaultRadioButton = nDefaultRadioButtonArg; + } + + void SetDefaultRadioButton(int nDefaultRadioButtonArg) + { + this->nDefaultRadioButton = nDefaultRadioButtonArg; + } + + // verification text + void SetVerificationText(UINT nID) + { + this->pszVerificationText = MAKEINTRESOURCEW(nID); + } + + void SetVerificationText(LPCWSTR lpstrVerificationText) + { + this->pszVerificationText = lpstrVerificationText; + } + + // expanded information text + void SetExpandedInformationText(UINT nID) + { + this->pszExpandedInformation = MAKEINTRESOURCEW(nID); + } + + void SetExpandedInformationText(LPCWSTR lpstrExpandedInformation) + { + this->pszExpandedInformation = lpstrExpandedInformation; + } + + // expanded control text + void SetExpandedControlText(UINT nID) + { + this->pszExpandedControlText = MAKEINTRESOURCEW(nID); + } + + void SetExpandedControlText(LPCWSTR lpstrExpandedControlText) + { + this->pszExpandedControlText = lpstrExpandedControlText; + } + + // collapsed control text + void SetCollapsedControlText(UINT nID) + { + this->pszCollapsedControlText = MAKEINTRESOURCEW(nID); + } + + void SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText) + { + this->pszCollapsedControlText = lpstrCollapsedControlText; + } + + // footer icon + void SetFooterIcon(HICON hIcon) + { + this->dwFlags |= TDF_USE_HICON_FOOTER; + this->hFooterIcon = hIcon; + } + + void SetFooterIcon(UINT nID) + { + this->dwFlags &= ~TDF_USE_HICON_FOOTER; + this->pszFooterIcon = MAKEINTRESOURCEW(nID); + } + + void SetFooterIcon(LPCWSTR lpstrFooterIcon) + { + this->dwFlags &= ~TDF_USE_HICON_FOOTER; + this->pszFooterIcon = lpstrFooterIcon; + } + + // footer text + void SetFooterText(UINT nID) + { + this->pszFooter = MAKEINTRESOURCEW(nID); + } + + void SetFooterText(LPCWSTR lpstrFooterText) + { + this->pszFooter = lpstrFooterText; + } + + // width (in DLUs) + void SetWidth(UINT cxWidthArg) + { + this->cxWidth = cxWidthArg; + } + + // modify flags + void ModifyFlags(DWORD dwRemove, DWORD dwAdd) + { + this->dwFlags = (this->dwFlags & ~dwRemove) | dwAdd; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CTaskDialogImpl - implements a Task Dialog + +template +class ATL_NO_VTABLE CTaskDialogImpl +{ +public: + CTaskDialogConfig m_tdc; + HWND m_hWnd; // used only in callback functions + +// Constructor + CTaskDialogImpl(HWND hWndParent = NULL) : m_hWnd(NULL) + { + m_tdc.hwndParent = hWndParent; + m_tdc.pfCallback = T::TaskDialogCallback; + m_tdc.lpCallbackData = (LONG_PTR)static_cast(this); + } + +// Operations + HRESULT DoModal(HWND hWndParent = ::GetActiveWindow(), int* pnButton = NULL, int* pnRadioButton = NULL, BOOL* pfVerificationFlagChecked = NULL) + { + if(m_tdc.hwndParent == NULL) + m_tdc.hwndParent = hWndParent; + +#ifdef _WTL_TASKDIALOG_DIRECT + return ::TaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked); +#else + + // This allows apps to run on older versions of Windows + typedef HRESULT (STDAPICALLTYPE *PFN_TaskDialogIndirect)(const TASKDIALOGCONFIG* pTaskConfig, int* pnButton, int* pnRadioButton, BOOL* pfVerificationFlagChecked); + + HRESULT hRet = E_UNEXPECTED; + HMODULE m_hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll")); + if(m_hCommCtrlDLL != NULL) + { + PFN_TaskDialogIndirect pfnTaskDialogIndirect = (PFN_TaskDialogIndirect)::GetProcAddress(m_hCommCtrlDLL, "TaskDialogIndirect"); + if(pfnTaskDialogIndirect != NULL) + hRet = pfnTaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked); + + ::FreeLibrary(m_hCommCtrlDLL); + } + + return hRet; +#endif + } + +// Operations - setting values of TASKDIALOGCONFIG + // common buttons + void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons) + { m_tdc.SetCommonButtons(dwCommonButtons); } + // window title text + void SetWindowTitle(UINT nID) + { m_tdc.SetWindowTitle(nID); } + void SetWindowTitle(LPCWSTR lpstrWindowTitle) + { m_tdc.SetWindowTitle(lpstrWindowTitle); } + // main icon + void SetMainIcon(HICON hIcon) + { m_tdc.SetMainIcon(hIcon); } + void SetMainIcon(UINT nID) + { m_tdc.SetMainIcon(nID); } + void SetMainIcon(LPCWSTR lpstrMainIcon) + { m_tdc.SetMainIcon(lpstrMainIcon); } + // main instruction text + void SetMainInstructionText(UINT nID) + { m_tdc.SetMainInstructionText(nID); } + void SetMainInstructionText(LPCWSTR lpstrMainInstruction) + { m_tdc.SetMainInstructionText(lpstrMainInstruction); } + // content text + void SetContentText(UINT nID) + { m_tdc.SetContentText(nID); } + void SetContentText(LPCWSTR lpstrContent) + { m_tdc.SetContentText(lpstrContent); } + // buttons + void SetButtons(const TASKDIALOG_BUTTON* pButtons, UINT cButtons, int nDefaultButton = 0) + { m_tdc.SetButtons(pButtons, cButtons, nDefaultButton); } + void SetDefaultButton(int nDefaultButton) + { m_tdc.SetDefaultButton(nDefaultButton); } + // radio buttons + void SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtons, UINT cRadioButtons, int nDefaultRadioButton = 0) + { m_tdc.SetRadioButtons(pRadioButtons, cRadioButtons, nDefaultRadioButton); } + void SetDefaultRadioButton(int nDefaultRadioButton) + { m_tdc.SetDefaultRadioButton(nDefaultRadioButton); } + // verification text + void SetVerificationText(UINT nID) + { m_tdc.SetVerificationText(nID); } + void SetVerificationText(LPCWSTR lpstrVerificationText) + { m_tdc.SetVerificationText(lpstrVerificationText); } + // expanded information text + void SetExpandedInformationText(UINT nID) + { m_tdc.SetExpandedInformationText(nID); } + void SetExpandedInformationText(LPCWSTR lpstrExpandedInformation) + { m_tdc.SetExpandedInformationText(lpstrExpandedInformation); } + // expanded control text + void SetExpandedControlText(UINT nID) + { m_tdc.SetExpandedControlText(nID); } + void SetExpandedControlText(LPCWSTR lpstrExpandedControlText) + { m_tdc.SetExpandedControlText(lpstrExpandedControlText); } + // collapsed control text + void SetCollapsedControlText(UINT nID) + { m_tdc.SetCollapsedControlText(nID); } + void SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText) + { m_tdc.SetCollapsedControlText(lpstrCollapsedControlText); } + // footer icon + void SetFooterIcon(HICON hIcon) + { m_tdc.SetFooterIcon(hIcon); } + void SetFooterIcon(UINT nID) + { m_tdc.SetFooterIcon(nID); } + void SetFooterIcon(LPCWSTR lpstrFooterIcon) + { m_tdc.SetFooterIcon(lpstrFooterIcon); } + // footer text + void SetFooterText(UINT nID) + { m_tdc.SetFooterText(nID); } + void SetFooterText(LPCWSTR lpstrFooterText) + { m_tdc.SetFooterText(lpstrFooterText); } + // width (in DLUs) + void SetWidth(UINT cxWidth) + { m_tdc.SetWidth(cxWidth); } + // modify flags + void ModifyFlags(DWORD dwRemove, DWORD dwAdd) + { m_tdc.ModifyFlags(dwRemove, dwAdd); } + +// Implementation + static HRESULT CALLBACK TaskDialogCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData) + { + T* pT = (T*)lpRefData; + ATLASSERT(pT->m_hWnd == NULL || pT->m_hWnd == hWnd); + + BOOL bRet = FALSE; + switch(uMsg) + { + case TDN_DIALOG_CONSTRUCTED: + pT->m_hWnd = hWnd; + pT->OnDialogConstructed(); + break; + case TDN_CREATED: + pT->OnCreated(); + break; + case TDN_BUTTON_CLICKED: + bRet = pT->OnButtonClicked((int)wParam); + break; + case TDN_RADIO_BUTTON_CLICKED: + pT->OnRadioButtonClicked((int)wParam); + break; + case TDN_HYPERLINK_CLICKED: + pT->OnHyperlinkClicked((LPCWSTR)lParam); + break; + case TDN_EXPANDO_BUTTON_CLICKED: + pT->OnExpandoButtonClicked((wParam != 0)); + break; + case TDN_VERIFICATION_CLICKED: + pT->OnVerificationClicked((wParam != 0)); + break; + case TDN_HELP: + pT->OnHelp(); + break; + case TDN_TIMER: + bRet = pT->OnTimer((DWORD)wParam); + break; + case TDN_NAVIGATED: + pT->OnNavigated(); + break; + case TDN_DESTROYED: + pT->OnDestroyed(); + pT->m_hWnd = NULL; + break; + default: + ATLTRACE2(atlTraceUI, 0, _T("Unknown notification received in CTaskDialogImpl::TaskDialogCallback\n")); + break; + } + + return (bRet != FALSE) ? S_OK : S_FALSE; + } + +// Overrideables - notification handlers + void OnDialogConstructed() + { + } + + void OnCreated() + { + } + + BOOL OnButtonClicked(int /*nButton*/) + { + return FALSE; // don't prevent dialog to close + } + + void OnRadioButtonClicked(int /*nRadioButton*/) + { + } + + void OnHyperlinkClicked(LPCWSTR /*pszHREF*/) + { + } + + void OnExpandoButtonClicked(bool /*bExpanded*/) + { + } + + void OnVerificationClicked(bool /*bChecked*/) + { + } + + void OnHelp() + { + } + + BOOL OnTimer(DWORD /*dwTickCount*/) + { + return FALSE; // don't reset counter + } + + void OnNavigated() + { + } + + void OnDestroyed() + { + } + +// Commands - valid to call only from handlers + void NavigatePage(TASKDIALOGCONFIG& tdc) + { + ATLASSERT(m_hWnd != NULL); + + tdc.cbSize = sizeof(TASKDIALOGCONFIG); + if(tdc.hwndParent == NULL) + tdc.hwndParent = m_tdc.hwndParent; + tdc.pfCallback = m_tdc.pfCallback; + tdc.lpCallbackData = m_tdc.lpCallbackData; + (TASKDIALOGCONFIG)m_tdc = tdc; + + ::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&tdc); + } + + // modify TASKDIALOGCONFIG values, then call this to update task dialog + void NavigatePage() + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&m_tdc); + } + + void ClickButton(int nButton) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_CLICK_BUTTON, nButton, 0L); + } + + void SetMarqueeProgressBar(BOOL bMarquee) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_SET_MARQUEE_PROGRESS_BAR, bMarquee, 0L); + } + + BOOL SetProgressBarState(int nNewState) + { + ATLASSERT(m_hWnd != NULL); + return (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_STATE, nNewState, 0L); + } + + DWORD SetProgressBarRange(int nMinRange, int nMaxRange) + { + ATLASSERT(m_hWnd != NULL); + return (DWORD)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(nMinRange, nMaxRange)); + } + + int SetProgressBarPos(int nNewPos) + { + ATLASSERT(m_hWnd != NULL); + return (int)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_POS, nNewPos, 0L); + } + + BOOL SetProgressBarMarquee(BOOL bMarquee, UINT uSpeed) + { + ATLASSERT(m_hWnd != NULL); + return (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_MARQUEE, bMarquee, uSpeed); + } + + void SetElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_SET_ELEMENT_TEXT, element, (LPARAM)lpstrText); + } + + void ClickRadioButton(int nRadioButton) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_CLICK_RADIO_BUTTON, nRadioButton, 0L); + } + + void EnableButton(int nButton, BOOL bEnable) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_ENABLE_BUTTON, nButton, bEnable); + } + + void EnableRadioButton(int nButton, BOOL bEnable) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_ENABLE_RADIO_BUTTON, nButton, bEnable); + } + + void ClickVerification(BOOL bCheck, BOOL bFocus) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_CLICK_VERIFICATION, bCheck, bFocus); + } + + void UpdateElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_UPDATE_ELEMENT_TEXT, element, (LPARAM)lpstrText); + } + + void SetButtonElevationRequiredState(int nButton, BOOL bElevation) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, nButton, bElevation); + } + + void UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, HICON hIcon) + { + ATLASSERT(m_hWnd != NULL); +#ifdef _DEBUG + if(element == TDIE_ICON_MAIN) + ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) != 0); + else if(element == TDIE_ICON_FOOTER) + ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) != 0); +#endif // _DEBUG + ::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)hIcon); + } + + void UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, LPCWSTR lpstrIcon) + { + ATLASSERT(m_hWnd != NULL); +#ifdef _DEBUG + if(element == TDIE_ICON_MAIN) + ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) == 0); + else if(element == TDIE_ICON_FOOTER) + ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) == 0); +#endif // _DEBUG + ::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)lpstrIcon); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CTaskDialog - for non-customized task dialogs + +class CTaskDialog : public CTaskDialogImpl +{ +public: + CTaskDialog(HWND hWndParent = NULL) : CTaskDialogImpl(hWndParent) + { + m_tdc.pfCallback = NULL; + } +}; + +#endif // ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE) + +}; // namespace WTL + +#endif // __ATLDLGS_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atldwm.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atldwm.h new file mode 100644 index 0000000000000000000000000000000000000000..52b67c658f33a0e2d35a1d30e861f3a0d556f22c --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atldwm.h @@ -0,0 +1,505 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLDWM_H__ +#define __ATLDWM_H__ + +#pragma once + +#ifdef _WIN32_WCE + #error atldwm.h is not supported on Windows CE +#endif + +#ifndef __ATLAPP_H__ + #error atldwm.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atldwm.h requires atlwin.h to be included first +#endif + +#if (_WIN32_WINNT < 0x0600) + #error atldwm.h requires _WIN32_WINNT >= 0x0600 +#endif + +#ifndef _DWMAPI_H_ + #include +#endif +#pragma comment(lib, "dwmapi.lib") + +// Note: To create an application that also runs on older versions of Windows, +// use delay load of dwmapi.dll and ensure that no calls to the DWM API are +// Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib, +// and add dwmapi.dll in the Linker.Input.Delay Loaded DLLs section of the +// project properties. +#if (_MSC_VER < 1300) && !defined(_WTL_NO_DWMAPI_DELAYLOAD) + #pragma comment(lib, "delayimp.lib") + #pragma comment(linker, "/delayload:dwmapi.dll") +#endif // (_MSC_VER < 1300) && !defined(_WTL_NO_DWMAPI_DELAYLOAD) + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CDwm +// CDwmImpl +// CDwmWindowT - CDwmWindow +// CDwmThumbnailT +// CDwmThumbnail +// CDwmThumbnailHandle +// CAeroControlImpl + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CDwm - wrapper for DWM handle + +class CDwm +{ +public: +// Data members + static int m_nIsDwmSupported; + +// Constructor + CDwm() + { + IsDwmSupported(); + } + +// Dwm support helper + static bool IsDwmSupported() + { + if(m_nIsDwmSupported == -1) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CDwm::IsDwmSupported.\n")); + ATLASSERT(FALSE); + return false; + } + + if(m_nIsDwmSupported == -1) + { + HMODULE hDwmDLL = ::LoadLibrary(_T("dwmapi.dll")); + m_nIsDwmSupported = (hDwmDLL != NULL) ? 1 : 0; + if(hDwmDLL != NULL) + ::FreeLibrary(hDwmDLL); + } + + lock.Unlock(); + } + + ATLASSERT(m_nIsDwmSupported != -1); + return (m_nIsDwmSupported == 1); + } + +// Operations + BOOL DwmIsCompositionEnabled() const + { + if(!IsDwmSupported()) + return FALSE; + + BOOL bRes = FALSE; + return (SUCCEEDED(::DwmIsCompositionEnabled(&bRes)) && bRes) ? TRUE : FALSE; + } + + BOOL DwmEnableComposition(UINT fEnable) + { + if(!IsDwmSupported()) + return FALSE; + + return SUCCEEDED(::DwmEnableComposition(fEnable)) ? TRUE : FALSE; + } + + BOOL DwmEnableMMCSS(BOOL fEnableMMCSS) + { + if(!IsDwmSupported()) + return FALSE; + + return SUCCEEDED(::DwmEnableMMCSS(fEnableMMCSS)) ? TRUE : FALSE; + } + + HRESULT DwmGetColorizationColor(DWORD* pcrColorization, BOOL* pfOpaqueBlend) + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + return ::DwmGetColorizationColor(pcrColorization, pfOpaqueBlend); + } + + HRESULT DwmFlush() + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + return ::DwmFlush(); + } +}; + +__declspec(selectany) int CDwm::m_nIsDwmSupported = -1; + + +/////////////////////////////////////////////////////////////////////////////// +// CDwmImpl - DWM window support + +template +class CDwmImpl : public TBase +{ +public: + HRESULT DwmEnableBlurBehindWindow(const DWM_BLURBEHIND* pBB) + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmEnableBlurBehindWindow(pT->m_hWnd, pBB); + } + + HRESULT DwmExtendFrameIntoClientArea(const MARGINS* pMargins) + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmExtendFrameIntoClientArea(pT->m_hWnd, pMargins); + } + + HRESULT DwmExtendFrameIntoEntireClientArea() + { + MARGINS margins = { -1 }; + return DwmExtendFrameIntoClientArea(&margins); + } + + HRESULT DwmGetCompositionTimingInfo(DWM_TIMING_INFO* pTimingInfo) + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmGetCompositionTimingInfo(pT->m_hWnd, pTimingInfo); + } + + HRESULT DwmGetWindowAttribute(DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute) + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmGetWindowAttribute(pT->m_hWnd, dwAttribute, pvAttribute, cbAttribute); + } + + HRESULT DwmModifyPreviousDxFrameDuration(INT cRefreshes, BOOL fRelative) + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmModifyPreviousDxFrameDuration(pT->m_hWnd, cRefreshes, fRelative); + } + + HRESULT DwmSetDxFrameDuration(INT cRefreshes) + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmSetDxFrameDuration(pT->m_hWnd, cRefreshes); + } + + HRESULT DwmSetPresentParameters(DWM_PRESENT_PARAMETERS* pPresentParams) + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmSetPresentParameters(pT->m_hWnd, pPresentParams); + } + + HRESULT DwmSetWindowAttribute(DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute) + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmSetWindowAttribute(pT->m_hWnd, dwAttribute, pvAttribute, cbAttribute); + } + + HRESULT DwmAttachMilContent() + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmAttachMilContent(pT->m_hWnd); + } + + HRESULT DwmDetachMilContent() + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DwmDetachMilContent(pT->m_hWnd); + } +}; + +template +class CDwmWindowT : public TBase, public CDwmImpl > +{ +public: + CDwmWindowT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CDwmWindowT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } +}; + +typedef CDwmWindowT CDwmWindow; + + +/////////////////////////////////////////////////////////////////////////////// +// CDwmThumbnail - provides DWM thumbnail support + +template +class CDwmThumbnailT : public TBase +{ +public: +// Data members + HTHUMBNAIL m_hThumbnail; + +// Constructor + CDwmThumbnailT(HTHUMBNAIL hThumbnail = NULL) : m_hThumbnail(hThumbnail) + { } + + ~CDwmThumbnailT() + { + if(t_bManaged && (m_hThumbnail != NULL)) + Unregister(); + } + +// Operations + CDwmThumbnailT& operator =(HTHUMBNAIL hThumbnail) + { + Attach(hThumbnail); + return *this; + } + + void Attach(HTHUMBNAIL hThumbnailNew) + { + if(t_bManaged && m_hThumbnail != NULL && m_hThumbnail != hThumbnailNew) + Unregister(); + m_hThumbnail = hThumbnailNew; + } + + HTHUMBNAIL Detach() + { + HTHUMBNAIL hThumbnail = m_hThumbnail; + m_hThumbnail = NULL; + return hThumbnail; + } + + HRESULT Register(HWND hwndDestination, HWND hwndSource) + { + ATLASSERT(::IsWindow(hwndDestination)); + ATLASSERT(::IsWindow(hwndSource)); + ATLASSERT(m_hThumbnail==NULL); + + if(!IsDwmSupported()) + return E_NOTIMPL; + + return ::DwmRegisterThumbnail(hwndDestination, hwndSource, &m_hThumbnail); + } + + HRESULT Unregister() + { + if(!IsDwmSupported()) + return E_NOTIMPL; + if(m_hThumbnail == NULL) + return S_FALSE; + + HRESULT Hr = ::DwmUnregisterThumbnail(m_hThumbnail); + if(SUCCEEDED(Hr)) + m_hThumbnail = NULL; + + return Hr; + } + + operator HTHUMBNAIL() const { return m_hThumbnail; } + + bool IsNull() const { return (m_hThumbnail == NULL); } + + HRESULT UpdateProperties(const DWM_THUMBNAIL_PROPERTIES* ptnProperties) + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + ATLASSERT(m_hThumbnail != NULL); + return ::DwmUpdateThumbnailProperties(m_hThumbnail, ptnProperties); + } + +// Attributes + HRESULT QuerySourceSize(PSIZE pSize) + { + if(!IsDwmSupported()) + return E_NOTIMPL; + + ATLASSERT(m_hThumbnail != NULL); + return ::DwmQueryThumbnailSourceSize(m_hThumbnail, pSize); + } +}; + +typedef CDwmThumbnailT CDwmThumbnail; +typedef CDwmThumbnailT CDwmThumbnailHandle; + + +#ifdef __ATLTHEME_H__ + +/////////////////////////////////////////////////////////////////////////////// +// CAeroControlImpl - Base class for controls on Glass + +template +class CAeroControlImpl : public CThemeImpl, + public CBufferedPaintImpl, + public ATL::CWindowImpl +{ +public: + typedef CThemeImpl _themeClass; + typedef CBufferedPaintImpl _baseClass; + typedef ATL::CWindowImpl _windowClass; + + CAeroControlImpl() + { + m_PaintParams.dwFlags = BPPF_ERASE; + } + + static LPCWSTR GetThemeName() + { +#ifdef _UNICODE + return TBase::GetWndClassName(); +#else + ATLASSERT(!_T("Return UNICODE string of window classname / theme class")); + return NULL; +#endif // _UNICODE + } + +// Message map and handlers + BEGIN_MSG_MAP(CAeroControlImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) + CHAIN_MSG_MAP(_themeClass) + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->Init(); + + bHandled = FALSE; + return 0; + } + + LRESULT OnActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(IsThemingSupported()) + Invalidate(FALSE); + + bHandled = FALSE; + return 0; + } + +// Operations + BOOL SubclassWindow(HWND hWnd) + { + ATLASSERT(m_hWnd == NULL); + ATLASSERT(::IsWindow(hWnd)); + BOOL bRet = _windowClass::SubclassWindow(hWnd); + if(bRet) + { + T* pT = static_cast(this); + pT->Init(); + } + + return bRet; + } + +// Implementation + LRESULT DefWindowProc() + { + const ATL::_ATL_MSG* pMsg = m_pCurrentMsg; + LRESULT lRes = 0; + if(pMsg != NULL) + lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam); + + return lRes; + } + + LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + T* pT = static_cast(this); + LRESULT lRes = 0; + if(::DwmDefWindowProc(pT->m_hWnd, uMsg, wParam, lParam, &lRes) != FALSE) + return lRes; + + return _windowClass::DefWindowProc(uMsg, wParam, lParam); + } + + void DoBufferedPaint(HDC hDC, RECT& rcPaint) + { + T* pT = static_cast(this); + HDC hDCPaint = NULL; + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + m_BufferedPaint.Begin(hDC, &rcClient, m_dwFormat, &m_PaintParams, &hDCPaint); + ATLASSERT(hDCPaint != NULL); + pT->DoAeroPaint(hDCPaint, rcClient, rcPaint); + m_BufferedPaint.End(); + } + + void DoPaint(HDC /*hdc*/, RECT& /*rcClient*/) + { + DefWindowProc(); + } + +// Overridables + void Init() + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + SetThemeClassList(pT->GetThemeName()); + if(m_lpstrThemeClassList != NULL) + OpenThemeData(); + } + + void DoAeroPaint(HDC hDC, RECT& /*rcClient*/, RECT& rcPaint) + { + DefWindowProc(WM_PAINT, (WPARAM) hDC, 0L); + m_BufferedPaint.MakeOpaque(&rcPaint); + } +}; + +#endif // __ATLTHEME_H__ + +}; // namespace WTL + +#endif // __ATLDWM_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlfind.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlfind.h new file mode 100644 index 0000000000000000000000000000000000000000..25bd3e412edbbee88aea926b8eda865ca869947c --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlfind.h @@ -0,0 +1,1012 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLFIND_H__ +#define __ATLFIND_H__ + +#pragma once + +#ifdef _WIN32_WCE + #error atlfind.h is not supported on Windows CE +#endif + +#ifndef __ATLCTRLS_H__ + #error atlfind.h requires atlctrls.h to be included first +#endif + +#ifndef __ATLDLGS_H__ + #error atlfind.h requires atldlgs.h to be included first +#endif + +#if !((defined(__ATLMISC_H__) && defined(_WTL_USE_CSTRING)) || defined(__ATLSTR_H__)) + #error atlfind.h requires CString (either from ATL's atlstr.h or WTL's atlmisc.h with _WTL_USE_CSTRING) +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CEditFindReplaceImplBase +// CEditFindReplaceImpl +// CRichEditFindReplaceImpl + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CEditFindReplaceImplBase - Base class for mixin classes that +// help implement Find/Replace for CEdit or CRichEditCtrl based window classes. + +template +class CEditFindReplaceImplBase +{ +protected: +// Typedefs + typedef CEditFindReplaceImplBase thisClass; + +// Data members + TFindReplaceDialog* m_pFindReplaceDialog; + _CSTRING_NS::CString m_sFindNext, m_sReplaceWith; + BOOL m_bFindOnly, m_bFirstSearch, m_bMatchCase, m_bWholeWord, m_bFindDown; + LONG m_nInitialSearchPos; + HCURSOR m_hOldCursor; + +// Enumerations + enum TranslationTextItem + { + eText_OnReplaceAllMessage = 0, + eText_OnReplaceAllTitle = 1, + eText_OnTextNotFoundMessage = 2, + eText_OnTextNotFoundTitle = 3 + }; + +public: +// Constructors + CEditFindReplaceImplBase() : + m_pFindReplaceDialog(NULL), + m_bFindOnly(TRUE), + m_bFirstSearch(TRUE), + m_bMatchCase(FALSE), + m_bWholeWord(FALSE), + m_bFindDown(TRUE), + m_nInitialSearchPos(0), + m_hOldCursor(NULL) + { + } + +// Message Handlers + BEGIN_MSG_MAP(thisClass) + ALT_MSG_MAP(1) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(TFindReplaceDialog::GetFindReplaceMsg(), OnFindReplaceCmd) + COMMAND_ID_HANDLER(ID_EDIT_FIND, OnEditFind) + COMMAND_ID_HANDLER(ID_EDIT_REPEAT, OnEditRepeat) + COMMAND_ID_HANDLER(ID_EDIT_REPLACE, OnEditReplace) + END_MSG_MAP() + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_pFindReplaceDialog != NULL) + { + m_pFindReplaceDialog->SendMessage(WM_CLOSE); + ATLASSERT(m_pFindReplaceDialog == NULL); + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnFindReplaceCmd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + + TFindReplaceDialog* pDialog = TFindReplaceDialog::GetNotifier(lParam); + if(pDialog == NULL) + { + ATLASSERT(FALSE); + ::MessageBeep(MB_ICONERROR); + return 1; + } + ATLASSERT(pDialog == m_pFindReplaceDialog); + + LPFINDREPLACE findReplace = (LPFINDREPLACE)lParam; + if((m_pFindReplaceDialog != NULL) && (findReplace != NULL)) + { + if(pDialog->FindNext()) + { + pT->OnFindNext(pDialog->GetFindString(), pDialog->SearchDown(), + pDialog->MatchCase(), pDialog->MatchWholeWord()); + } + else if(pDialog->ReplaceCurrent()) + { + pT->OnReplaceSel(pDialog->GetFindString(), + pDialog->SearchDown(), pDialog->MatchCase(), pDialog->MatchWholeWord(), + pDialog->GetReplaceString()); + } + else if(pDialog->ReplaceAll()) + { + pT->OnReplaceAll(pDialog->GetFindString(), pDialog->GetReplaceString(), + pDialog->MatchCase(), pDialog->MatchWholeWord()); + } + else if(pDialog->IsTerminating()) + { + // Dialog is going away (but hasn't gone away yet) + // OnFinalMessage will "delete this" + pT->OnTerminatingFindReplaceDialog(m_pFindReplaceDialog); + m_pFindReplaceDialog = NULL; + } + } + + return 0; + } + + LRESULT OnEditFind(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->FindReplace(TRUE); + + return 0; + } + + LRESULT OnEditRepeat(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + + // If the user is holding down SHIFT when hitting F3, we'll + // search in reverse. Otherwise, we'll search forward. + // (be sure to have an accelerator mapped to ID_EDIT_REPEAT + // for both F3 and Shift+F3) + m_bFindDown = !((::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000); + + if(m_sFindNext.IsEmpty()) + { + pT->FindReplace(TRUE); + } + else + { + if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) + pT->TextNotFound(m_sFindNext); + } + + return 0; + } + + LRESULT OnEditReplace(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& bHandled) + { + T* pT = static_cast(this); + + DWORD style = pT->GetStyle(); + if((style & ES_READONLY) != ES_READONLY) + { + pT->FindReplace(FALSE); + } + else + { + // Don't allow replace when the edit control is read only + bHandled = FALSE; + } + + return 0; + } + +// Operations (overrideable) + TFindReplaceDialog* CreateFindReplaceDialog(BOOL bFindOnly, // TRUE for Find, FALSE for FindReplace + LPCTSTR lpszFindWhat, + LPCTSTR lpszReplaceWith = NULL, + DWORD dwFlags = FR_DOWN, + HWND hWndParent = NULL) + { + // You can override all of this in a derived class + + TFindReplaceDialog* findReplaceDialog = new TFindReplaceDialog(); + if(findReplaceDialog == NULL) + { + ::MessageBeep(MB_ICONHAND); + } + else + { + HWND hWndFindReplace = findReplaceDialog->Create(bFindOnly, + lpszFindWhat, lpszReplaceWith, dwFlags, hWndParent); + if(hWndFindReplace == NULL) + { + delete findReplaceDialog; + findReplaceDialog = NULL; + } + else + { + findReplaceDialog->SetActiveWindow(); + findReplaceDialog->ShowWindow(SW_SHOW); + } + } + + return findReplaceDialog; + } + + void AdjustDialogPosition(HWND hWndDialog) + { + ATLASSERT((hWndDialog != NULL) && ::IsWindow(hWndDialog)); + + T* pT = static_cast(this); + LONG nStartChar = 0, nEndChar = 0; + // Send EM_GETSEL so we can use both Edit and RichEdit + // (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&) + ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); + POINT point = pT->PosFromChar(nStartChar); + ::ClientToScreen(pT->GetParent(), &point); + CRect rect; + ::GetWindowRect(hWndDialog, &rect); + if(rect.PtInRect(point)) + { + if(point.y > rect.Height()) + { + rect.OffsetRect(0, point.y - rect.bottom - 20); + } + else + { + int nVertExt = GetSystemMetrics(SM_CYSCREEN); + if(point.y + rect.Height() < nVertExt) + rect.OffsetRect(0, 40 + point.y - rect.top); + } + + ::MoveWindow(hWndDialog, rect.left, rect.top, rect.Width(), rect.Height(), TRUE); + } + } + + DWORD GetFindReplaceDialogFlags(void) const + { + DWORD dwFlags = 0; + if(m_bFindDown) + dwFlags |= FR_DOWN; + if(m_bMatchCase) + dwFlags |= FR_MATCHCASE; + if(m_bWholeWord) + dwFlags |= FR_WHOLEWORD; + + return dwFlags; + } + + void FindReplace(BOOL bFindOnly) + { + T* pT = static_cast(this); + m_bFirstSearch = TRUE; + if(m_pFindReplaceDialog != NULL) + { + if(m_bFindOnly == bFindOnly) + { + m_pFindReplaceDialog->SetActiveWindow(); + m_pFindReplaceDialog->ShowWindow(SW_SHOW); + return; + } + else + { + m_pFindReplaceDialog->SendMessage(WM_CLOSE); + ATLASSERT(m_pFindReplaceDialog == NULL); + } + } + + ATLASSERT(m_pFindReplaceDialog == NULL); + + _CSTRING_NS::CString findNext; + pT->GetSelText(findNext); + // if selection is empty or spans multiple lines use old find text + if(findNext.IsEmpty() || (findNext.FindOneOf(_T("\n\r")) != -1)) + findNext = m_sFindNext; + _CSTRING_NS::CString replaceWith = m_sReplaceWith; + DWORD dwFlags = pT->GetFindReplaceDialogFlags(); + + m_pFindReplaceDialog = pT->CreateFindReplaceDialog(bFindOnly, + findNext, replaceWith, dwFlags, pT->operator HWND()); + ATLASSERT(m_pFindReplaceDialog != NULL); + if(m_pFindReplaceDialog != NULL) + m_bFindOnly = bFindOnly; + } + + BOOL SameAsSelected(LPCTSTR lpszCompare, BOOL bMatchCase, BOOL /*bWholeWord*/) + { + T* pT = static_cast(this); + + // check length first + size_t nLen = lstrlen(lpszCompare); + LONG nStartChar = 0, nEndChar = 0; + // Send EM_GETSEL so we can use both Edit and RichEdit + // (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&) + ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); + if(nLen != (size_t)(nEndChar - nStartChar)) + return FALSE; + + // length is the same, check contents + _CSTRING_NS::CString selectedText; + pT->GetSelText(selectedText); + + return (bMatchCase && selectedText.Compare(lpszCompare) == 0) || + (!bMatchCase && selectedText.CompareNoCase(lpszCompare) == 0); + } + + void TextNotFound(LPCTSTR lpszFind) + { + T* pT = static_cast(this); + m_bFirstSearch = TRUE; + pT->OnTextNotFound(lpszFind); + } + + _CSTRING_NS::CString GetTranslationText(enum TranslationTextItem eItem) const + { + _CSTRING_NS::CString text; + switch(eItem) + { + case eText_OnReplaceAllMessage: + text = _T("Replaced %d occurances of \"%s\" with \"%s\""); + break; + case eText_OnReplaceAllTitle: + text = _T("Replace All"); + break; + case eText_OnTextNotFoundMessage: + text = _T("Unable to find the text \"%s\""); + break; + case eText_OnTextNotFoundTitle: + text = _T("Text not found"); + break; + } + + return text; + } + +// Overrideable Handlers + void OnFindNext(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord) + { + T* pT = static_cast(this); + + m_sFindNext = lpszFind; + m_bMatchCase = bMatchCase; + m_bWholeWord = bWholeWord; + m_bFindDown = bFindDown; + + if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) + pT->TextNotFound(m_sFindNext); + else + pT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND()); + } + + void OnReplaceSel(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord, LPCTSTR lpszReplace) + { + T* pT = static_cast(this); + + m_sFindNext = lpszFind; + m_sReplaceWith = lpszReplace; + m_bMatchCase = bMatchCase; + m_bWholeWord = bWholeWord; + m_bFindDown = bFindDown; + + if(pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord)) + pT->ReplaceSel(m_sReplaceWith); + + if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) + pT->TextNotFound(m_sFindNext); + else + pT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND()); + } + + void OnReplaceAll(LPCTSTR lpszFind, LPCTSTR lpszReplace, BOOL bMatchCase, BOOL bWholeWord) + { + T* pT = static_cast(this); + + m_sFindNext = lpszFind; + m_sReplaceWith = lpszReplace; + m_bMatchCase = bMatchCase; + m_bWholeWord = bWholeWord; + m_bFindDown = TRUE; + + // no selection or different than what looking for + if(!pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord)) + { + if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) + { + pT->TextNotFound(m_sFindNext); + return; + } + } + + pT->OnReplaceAllCoreBegin(); + + int replaceCount=0; + do + { + ++replaceCount; + pT->ReplaceSel(m_sReplaceWith); + } while(pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)); + + pT->OnReplaceAllCoreEnd(replaceCount); + } + + void OnReplaceAllCoreBegin() + { + T* pT = static_cast(this); + + m_hOldCursor = ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); + + pT->HideSelection(TRUE, FALSE); + + } + + void OnReplaceAllCoreEnd(int replaceCount) + { + T* pT = static_cast(this); + pT->HideSelection(FALSE, FALSE); + + ::SetCursor(m_hOldCursor); + + _CSTRING_NS::CString message = pT->GetTranslationText(eText_OnReplaceAllMessage); + if(message.GetLength() > 0) + { + _CSTRING_NS::CString formattedMessage; + formattedMessage.Format(message, replaceCount, m_sFindNext, m_sReplaceWith); + if(m_pFindReplaceDialog != NULL) + { + m_pFindReplaceDialog->MessageBox(formattedMessage, + pT->GetTranslationText(eText_OnReplaceAllTitle), + MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); + } + else + { + pT->MessageBox(formattedMessage, + pT->GetTranslationText(eText_OnReplaceAllTitle), + MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); + } + } + } + + void OnTextNotFound(LPCTSTR lpszFind) + { + T* pT = static_cast(this); + _CSTRING_NS::CString message = pT->GetTranslationText(eText_OnTextNotFoundMessage); + if(message.GetLength() > 0) + { + _CSTRING_NS::CString formattedMessage; + formattedMessage.Format(message, lpszFind); + if(m_pFindReplaceDialog != NULL) + { + m_pFindReplaceDialog->MessageBox(formattedMessage, + pT->GetTranslationText(eText_OnTextNotFoundTitle), + MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); + } + else + { + pT->MessageBox(formattedMessage, + pT->GetTranslationText(eText_OnTextNotFoundTitle), + MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); + } + } + else + { + ::MessageBeep(MB_ICONHAND); + } + } + + void OnTerminatingFindReplaceDialog(TFindReplaceDialog*& /*findReplaceDialog*/) + { + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CEditFindReplaceImpl - Mixin class for implementing Find/Replace for CEdit +// based window classes. + +// Chain to CEditFindReplaceImpl message map. Your class must also derive from CEdit. +// Example: +// class CMyEdit : public CWindowImpl, +// public CEditFindReplaceImpl +// { +// public: +// BEGIN_MSG_MAP(CMyEdit) +// // your handlers... +// CHAIN_MSG_MAP_ALT(CEditFindReplaceImpl, 1) +// END_MSG_MAP() +// // other stuff... +// }; + +template +class CEditFindReplaceImpl : public CEditFindReplaceImplBase +{ +protected: + typedef CEditFindReplaceImpl thisClass; + typedef CEditFindReplaceImplBase baseClass; + +// Data members + LPTSTR m_pShadowBuffer; // Special shadow buffer only used in some cases. + UINT m_nShadowSize; + int m_bShadowBufferNeeded; // TRUE, FALSE, < 0 => Need to check + +public: +// Constructors + CEditFindReplaceImpl() : + m_pShadowBuffer(NULL), + m_nShadowSize(0), + m_bShadowBufferNeeded(-1) + { + } + + virtual ~CEditFindReplaceImpl() + { + if(m_pShadowBuffer != NULL) + { + delete [] m_pShadowBuffer; + m_pShadowBuffer = NULL; + } + } + +// Message Handlers + BEGIN_MSG_MAP(thisClass) + ALT_MSG_MAP(1) + CHAIN_MSG_MAP_ALT(baseClass, 1) + END_MSG_MAP() + +// Operations + // Supported only for RichEdit, so this does nothing for Edit + void HideSelection(BOOL /*bHide*/ = TRUE, BOOL /*bChangeStyle*/ = FALSE) + { + } + +// Operations (overrideable) + BOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE) + { + T* pT = static_cast(this); + + ATLASSERT(lpszFind != NULL); + ATLASSERT(*lpszFind != _T('\0')); + + UINT nLen = pT->GetBufferLength(); + int nStartChar = 0, nEndChar = 0; + pT->GetSel(nStartChar, nEndChar); + UINT nStart = nStartChar; + int iDir = bFindDown ? +1 : -1; + + // can't find a match before the first character + if((nStart == 0) && (iDir < 0)) + return FALSE; + + LPCTSTR lpszText = pT->LockBuffer(); + + bool isDBCS = false; +#ifdef _MBCS + CPINFO info = { 0 }; + ::GetCPInfo(::GetOEMCP(), &info); + isDBCS = (info.MaxCharSize > 1); +#endif + + if(iDir < 0) + { + // always go back one for search backwards + nStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart)); + } + else if((nStartChar != nEndChar) && (pT->SameAsSelected(lpszFind, bMatchCase, bWholeWord))) + { + // easy to go backward/forward with SBCS +#ifndef _UNICODE + if(::IsDBCSLeadByte(lpszText[nStart])) + nStart++; +#endif + nStart += iDir; + } + + // handle search with nStart past end of buffer + UINT nLenFind = ::lstrlen(lpszFind); + if((nStart + nLenFind - 1) >= nLen) + { + if((iDir < 0) && (nLen >= nLenFind)) + { + if(isDBCS) + { + // walk back to previous character n times + nStart = nLen; + int n = nLenFind; + while(n--) + { + nStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart)); + } + } + else + { + // single-byte character set is easy and fast + nStart = nLen - nLenFind; + } + ATLASSERT((nStart + nLenFind - 1) <= nLen); + } + else + { + pT->UnlockBuffer(); + return FALSE; + } + } + + // start the search at nStart + LPCTSTR lpsz = lpszText + nStart; + typedef int (WINAPI* CompareProc)(LPCTSTR str1, LPCTSTR str2); + CompareProc pfnCompare = bMatchCase ? lstrcmp : lstrcmpi; + + if(isDBCS) + { + // double-byte string search + LPCTSTR lpszStop = NULL; + if(iDir > 0) + { + // start at current and find _first_ occurrance + lpszStop = lpszText + nLen - nLenFind + 1; + } + else + { + // start at top and find _last_ occurrance + lpszStop = lpsz; + lpsz = lpszText; + } + + LPCTSTR lpszFound = NULL; + while(lpsz <= lpszStop) + { +#ifndef _UNICODE + if(!bMatchCase || (*lpsz == *lpszFind && (!::IsDBCSLeadByte(*lpsz) || lpsz[1] == lpszFind[1]))) +#else + if(!bMatchCase || (*lpsz == *lpszFind && lpsz[1] == lpszFind[1])) +#endif + { + LPTSTR lpch = (LPTSTR)(lpsz + nLenFind); + TCHAR chSave = *lpch; + *lpch = _T('\0'); + int nResult = (*pfnCompare)(lpsz, lpszFind); + *lpch = chSave; + if(nResult == 0) + { + lpszFound = lpsz; + if(iDir > 0) + break; + } + } + lpsz = ::CharNext(lpsz); + } + pT->UnlockBuffer(); + + if(lpszFound != NULL) + { + int n = (int)(lpszFound - lpszText); + pT->SetSel(n, n + nLenFind); + return TRUE; + } + } + else + { + // single-byte string search + UINT nCompare = 0; + if(iDir < 0) + nCompare = (UINT)(lpsz - lpszText) + 1; + else + nCompare = nLen - (UINT)(lpsz - lpszText) - nLenFind + 1; + + while(nCompare > 0) + { + ATLASSERT(lpsz >= lpszText); + ATLASSERT((lpsz + nLenFind - 1) <= (lpszText + nLen - 1)); + + LPSTR lpch = (LPSTR)(lpsz + nLenFind); + char chSave = *lpch; + *lpch = '\0'; + int nResult = (*pfnCompare)(lpsz, lpszFind); + *lpch = chSave; + if(nResult == 0) + { + pT->UnlockBuffer(); + int n = (int)(lpsz - lpszText); + pT->SetSel(n, n + nLenFind); + return TRUE; + } + + // restore character at end of search + *lpch = chSave; + + // move on to next substring + nCompare--; + lpsz += iDir; + } + pT->UnlockBuffer(); + } + + return FALSE; + } + + LPCTSTR LockBuffer() const + { + const T* pT = static_cast(this); + ATLASSERT(pT->m_hWnd != NULL); + + BOOL useShadowBuffer = pT->UseShadowBuffer(); + if(useShadowBuffer) + { + if((m_pShadowBuffer == NULL) || pT->GetModify()) + { + ATLASSERT((m_pShadowBuffer != NULL) || (m_nShadowSize == 0)); + UINT nSize = pT->GetWindowTextLength() + 1; + if(nSize > m_nShadowSize) + { + // need more room for shadow buffer + T* pThisNoConst = const_cast(pT); + delete[] m_pShadowBuffer; + pThisNoConst->m_pShadowBuffer = NULL; + pThisNoConst->m_nShadowSize = 0; + pThisNoConst->m_pShadowBuffer = new TCHAR[nSize]; + pThisNoConst->m_nShadowSize = nSize; + } + + // update the shadow buffer with GetWindowText + ATLASSERT(m_nShadowSize >= nSize); + ATLASSERT(m_pShadowBuffer != NULL); + pT->GetWindowText(m_pShadowBuffer, nSize); + } + + return m_pShadowBuffer; + } + + HLOCAL hLocal = pT->GetHandle(); + ATLASSERT(hLocal != NULL); + LPCTSTR lpszText = (LPCTSTR)::LocalLock(hLocal); + ATLASSERT(lpszText != NULL); + + return lpszText; + } + + void UnlockBuffer() const + { + const T* pT = static_cast(this); + ATLASSERT(pT->m_hWnd != NULL); + + BOOL useShadowBuffer = pT->UseShadowBuffer(); + if(!useShadowBuffer) + { + HLOCAL hLocal = pT->GetHandle(); + ATLASSERT(hLocal != NULL); + ::LocalUnlock(hLocal); + } + } + + UINT GetBufferLength() const + { + const T* pT = static_cast(this); + ATLASSERT(pT->m_hWnd != NULL); + + UINT nLen = 0; + LPCTSTR lpszText = pT->LockBuffer(); + if(lpszText != NULL) + nLen = ::lstrlen(lpszText); + pT->UnlockBuffer(); + + return nLen; + } + + LONG EndOfLine(LPCTSTR lpszText, UINT nLen, UINT nIndex) const + { + LPCTSTR lpsz = lpszText + nIndex; + LPCTSTR lpszStop = lpszText + nLen; + while(lpsz < lpszStop && *lpsz != _T('\r')) + ++lpsz; + return LONG(lpsz - lpszText); + } + + LONG GetSelText(_CSTRING_NS::CString& strText) const + { + const T* pT = static_cast(this); + + int nStartChar = 0, nEndChar = 0; + pT->GetSel(nStartChar, nEndChar); + ATLASSERT((UINT)nEndChar <= pT->GetBufferLength()); + LPCTSTR lpszText = pT->LockBuffer(); + LONG nLen = pT->EndOfLine(lpszText, nEndChar, nStartChar) - nStartChar; + SecureHelper::memcpy_x(strText.GetBuffer(nLen), nLen * sizeof(TCHAR), lpszText + nStartChar, nLen * sizeof(TCHAR)); + strText.ReleaseBuffer(nLen); + pT->UnlockBuffer(); + + return nLen; + } + + BOOL UseShadowBuffer(void) const + { + const T* pT = static_cast(this); + + if(pT->m_bShadowBufferNeeded < 0) + { + T* pThisNoConst = const_cast(pT); + +#ifdef _versionhelpers_H_INCLUDED_ + OSVERSIONINFOEX ovi = { sizeof(OSVERSIONINFOEX) }; + ovi.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; + DWORDLONG const dwlConditionMask = ::VerSetConditionMask(0, VER_PLATFORMID, VER_EQUAL); + bool bWin9x = (::VerifyVersionInfo(&ovi, VER_PLATFORMID, dwlConditionMask) != FALSE); +#else // !_versionhelpers_H_INCLUDED_ + OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; + ::GetVersionEx(&ovi); + + bool bWin9x = (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); +#endif // _versionhelpers_H_INCLUDED_ + if(bWin9x) + { + // Windows 95, 98, ME + // Under Win9x, it is necessary to maintain a shadow buffer. + // It is only updated when the control contents have been changed. + pThisNoConst->m_bShadowBufferNeeded = TRUE; + } + else + { + // Windows NT, 2000, XP, etc. + pThisNoConst->m_bShadowBufferNeeded = FALSE; + +#ifndef _UNICODE + // On Windows XP (or later), if common controls version 6 is in use + // (such as via theming), then EM_GETHANDLE will always return a UNICODE string. + // If theming is enabled and Common Controls version 6 is in use, + // you're really not suppose to superclass or subclass common controls + // with an ANSI windows procedure (so its best to only theme if you use UNICODE). + // Using a shadow buffer uses GetWindowText instead, so it solves + // this problem for us (although it makes it a little less efficient). + +#ifdef _versionhelpers_H_INCLUDED_ + if(::IsWindowsXPOrGreater()) +#else // !_versionhelpers_H_INCLUDED_ + if ((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5)) +#endif // _versionhelpers_H_INCLUDED_ + { + DWORD dwMajor = 0, dwMinor = 0; + HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor); + if(SUCCEEDED(hRet)) + { + if(dwMajor >= 6) + { + pThisNoConst->m_bShadowBufferNeeded = TRUE; + + ATLTRACE2(atlTraceUI, 0, _T("Warning: You have compiled for MBCS/ANSI but are using common controls version 6 or later (likely through a manifest file).\r\n")); + ATLTRACE2(atlTraceUI, 0, _T("If you use common controls version 6 or later, you should only do so for UNICODE builds.\r\n")); + } + } + } +#endif // !_UNICODE + } + } + + return (pT->m_bShadowBufferNeeded != FALSE); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CRichEditFindReplaceImpl - Mixin class for implementing Find/Replace for CRichEditCtrl +// based window classes. + +// Chain to CRichEditFindReplaceImpl message map. Your class must also derive from CRichEditCtrl. +// Example: +// class CMyRichEdit : public CWindowImpl, +// public CRichEditFindReplaceImpl +// { +// public: +// BEGIN_MSG_MAP(CMyRichEdit) +// // your handlers... +// CHAIN_MSG_MAP_ALT(CRichEditFindReplaceImpl, 1) +// END_MSG_MAP() +// // other stuff... +// }; + +template +class CRichEditFindReplaceImpl : public CEditFindReplaceImplBase +{ +protected: + typedef CRichEditFindReplaceImpl thisClass; + typedef CEditFindReplaceImplBase baseClass; + +public: + BEGIN_MSG_MAP(thisClass) + ALT_MSG_MAP(1) + CHAIN_MSG_MAP_ALT(baseClass, 1) + END_MSG_MAP() + +// Operations (overrideable) + BOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE) + { + T* pT = static_cast(this); + + ATLASSERT(lpszFind != NULL); + FINDTEXTEX ft = { 0 }; + + pT->GetSel(ft.chrg); + if(m_bFirstSearch) + { + if(bFindDown) + m_nInitialSearchPos = ft.chrg.cpMin; + else + m_nInitialSearchPos = ft.chrg.cpMax; + m_bFirstSearch = FALSE; + } + +#if (_RICHEDIT_VER >= 0x0200) + ft.lpstrText = (LPTSTR)lpszFind; +#else // !(_RICHEDIT_VER >= 0x0200) + USES_CONVERSION; + ft.lpstrText = T2A((LPTSTR)lpszFind); +#endif // !(_RICHEDIT_VER >= 0x0200) + + if(ft.chrg.cpMin != ft.chrg.cpMax) // i.e. there is a selection + { + if(bFindDown) + { + ft.chrg.cpMin++; + } + else + { + // won't wraparound backwards + ft.chrg.cpMin = __max(ft.chrg.cpMin, 0); + } + } + + DWORD dwFlags = bMatchCase ? FR_MATCHCASE : 0; + dwFlags |= bWholeWord ? FR_WHOLEWORD : 0; + + ft.chrg.cpMax = pT->GetTextLength() + m_nInitialSearchPos; + + if(bFindDown) + { + if(m_nInitialSearchPos >= 0) + ft.chrg.cpMax = pT->GetTextLength(); + + dwFlags |= FR_DOWN; + ATLASSERT(ft.chrg.cpMax >= ft.chrg.cpMin); + } + else + { + if(m_nInitialSearchPos >= 0) + ft.chrg.cpMax = 0; + + dwFlags &= ~FR_DOWN; + ATLASSERT(ft.chrg.cpMax <= ft.chrg.cpMin); + } + + BOOL bRet = FALSE; + if(pT->FindAndSelect(dwFlags, ft) != -1) + { + bRet = TRUE; // we found the text + } + else if(m_nInitialSearchPos > 0) + { + // if the original starting point was not the beginning + // of the buffer and we haven't already been here + if(bFindDown) + { + ft.chrg.cpMin = 0; + ft.chrg.cpMax = m_nInitialSearchPos; + } + else + { + ft.chrg.cpMin = pT->GetTextLength(); + ft.chrg.cpMax = m_nInitialSearchPos; + } + m_nInitialSearchPos = m_nInitialSearchPos - pT->GetTextLength(); + + bRet = (pT->FindAndSelect(dwFlags, ft) != -1) ? TRUE : FALSE; + } + + return bRet; + } + + long FindAndSelect(DWORD dwFlags, FINDTEXTEX& ft) + { + T* pT = static_cast(this); + LONG index = pT->FindText(dwFlags, ft); + if(index != -1) // i.e. we found something + pT->SetSel(ft.chrgText); + + return index; + } +}; + +}; // namespace WTL + +#endif // __ATLFIND_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlframe.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlframe.h new file mode 100644 index 0000000000000000000000000000000000000000..e8dc66b7db9d3ce7cf0a84e316ab176aa1d501a6 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlframe.h @@ -0,0 +1,3696 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLFRAME_H__ +#define __ATLFRAME_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atlframe.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlframe.h requires atlwin.h to be included first +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CFrameWindowImpl +// CMDIWindow +// CMDIFrameWindowImpl +// CMDIChildWindowImpl +// COwnerDraw +// CUpdateUIBase +// CUpdateUI +// CDynamicUpdateUI +// CAutoUpdateUI +// CDialogResize +// CDoubleBufferImpl +// CDoubleBufferWindowImpl +// +// Global functions: +// AtlCreateSimpleToolBar() + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CFrameWndClassInfo - Manages frame window Windows class information + +class CFrameWndClassInfo +{ +public: +#ifndef _WIN32_WCE + enum { cchAutoName = 5 + sizeof(void*) * 2 }; // sizeof(void*) * 2 is the number of digits %p outputs + WNDCLASSEX m_wc; +#else // CE specific + enum { cchAutoName = MAX_PATH }; // MAX_PATH because this can be set in the wizard generated CMainFrame::ActivatePreviousInstance to a user defined string. + WNDCLASS m_wc; +#endif // !_WIN32_WCE + LPCTSTR m_lpszOrigName; + WNDPROC pWndProc; + LPCTSTR m_lpszCursorID; + BOOL m_bSystemCursor; + ATOM m_atom; + TCHAR m_szAutoName[cchAutoName]; + UINT m_uCommonResourceID; + +#ifndef _WIN32_WCE + ATOM Register(WNDPROC* pProc) + { + if (m_atom == 0) + { + CWindowCreateCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(m_atom == 0) + { + HINSTANCE hInst = ModuleHelper::GetModuleInstance(); + + if (m_lpszOrigName != NULL) + { + ATLASSERT(pProc != NULL); + LPCTSTR lpsz = m_wc.lpszClassName; + WNDPROC proc = m_wc.lpfnWndProc; + + WNDCLASSEX wc = { sizeof(WNDCLASSEX) }; + // try process local class first + if(!::GetClassInfoEx(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc)) + { + // try global class + if(!::GetClassInfoEx(NULL, m_lpszOrigName, &wc)) + { + lock.Unlock(); + return 0; + } + } + m_wc = wc; + pWndProc = m_wc.lpfnWndProc; + m_wc.lpszClassName = lpsz; + m_wc.lpfnWndProc = proc; + } + else + { + m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID); + } + + m_wc.hInstance = hInst; + m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes + if (m_wc.lpszClassName == NULL) + { +#if (_WIN32_WINNT >= 0x0500) || defined(_WIN64) + SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%p"), &m_wc); +#else // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64)) + SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc); +#endif // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64)) + m_wc.lpszClassName = m_szAutoName; + } + + WNDCLASSEX wcTemp = m_wc; + m_atom = (ATOM)::GetClassInfoEx(m_wc.hInstance, m_wc.lpszClassName, &wcTemp); + if (m_atom == 0) + { + if(m_uCommonResourceID != 0) // use it if not zero + { + m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), + MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, + ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR); + m_wc.hIconSm = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), + MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, + ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + } + m_atom = ::RegisterClassEx(&m_wc); + } + } + + lock.Unlock(); + } + + if (m_lpszOrigName != NULL) + { + ATLASSERT(pProc != NULL); + ATLASSERT(pWndProc != NULL); + *pProc = pWndProc; + } + + return m_atom; + } +#else // CE specific + ATOM Register(WNDPROC* pProc) + { + if (m_atom == 0) + { + CWindowCreateCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(m_atom == 0) + { + HINSTANCE hInst = ModuleHelper::GetModuleInstance(); + + if (m_lpszOrigName != NULL) + { + ATLASSERT(pProc != NULL); + LPCTSTR lpsz = m_wc.lpszClassName; + WNDPROC proc = m_wc.lpfnWndProc; + + WNDCLASS wc = { 0 }; + // try process local class first + if(!::GetClassInfo(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc)) + { + // try global class + if(!::GetClassInfo(NULL, m_lpszOrigName, &wc)) + { + lock.Unlock(); + return 0; + } + } + m_wc = wc; + pWndProc = m_wc.lpfnWndProc; + m_wc.lpszClassName = lpsz; + m_wc.lpfnWndProc = proc; + } + else + { +#if defined(GWES_CURSOR) || defined(GWES_MCURSOR) + m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID); +#else // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR)) + m_wc.hCursor = NULL; +#endif // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR)) + } + + m_wc.hInstance = hInst; + m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes + if (m_wc.lpszClassName == NULL) + { + wsprintf(m_szAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc); + m_wc.lpszClassName = m_szAutoName; + } + + WNDCLASS wcTemp = m_wc; + m_atom = (ATOM)::GetClassInfo(m_wc.hInstance, m_wc.lpszClassName, &wcTemp); + if (m_atom == 0) + { + if(m_uCommonResourceID != 0) // use it if not zero + m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), + MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, + ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR); + m_atom = ::RegisterClass(&m_wc); + } + } + + lock.Unlock(); + } + + if (m_lpszOrigName != NULL) + { + ATLASSERT(pProc != NULL); + ATLASSERT(pWndProc != NULL); + *pProc = pWndProc; + } + + return m_atom; + } +#endif // _WIN32_WCE +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Macros for declaring frame window WNDCLASS + +#ifndef _WIN32_WCE + +#define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { sizeof(WNDCLASSEX), 0, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { sizeof(WNDCLASSEX), style, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { sizeof(WNDCLASSEX), 0, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \ + OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#else // CE specific + +#define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { 0, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { style, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { NULL, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName }, \ + OrigWndClassName, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CFrameWindowImpl + +// Client window command chaining macro (only for frame windows) +#define CHAIN_CLIENT_COMMANDS() \ + if(uMsg == WM_COMMAND && m_hWndClient != NULL) \ + ::SendMessage(m_hWndClient, uMsg, wParam, lParam); + +// standard toolbar styles +#define ATL_SIMPLE_TOOLBAR_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS) +// toolbar in a rebar pane +#define ATL_SIMPLE_TOOLBAR_PANE_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT) +// standard rebar styles +#if (_WIN32_IE >= 0x0400) + #define ATL_SIMPLE_REBAR_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE) +#else + #define ATL_SIMPLE_REBAR_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS) +#endif // !(_WIN32_IE >= 0x0400) +// rebar without borders +#if (_WIN32_IE >= 0x0400) + #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE | CCS_NODIVIDER) +#else + #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | CCS_NODIVIDER) +#endif // !(_WIN32_IE >= 0x0400) + +// command bar support +#if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) + +#define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND +#define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu +#define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu + +struct _AtlFrameWnd_CmdBarPopupMenu +{ + int cbSize; + HMENU hMenu; + UINT uFlags; + int x; + int y; + LPTPMPARAMS lptpm; +}; + +#define CBRPOPUPMENU _AtlFrameWnd_CmdBarPopupMenu + +#endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) + + +template +class ATL_NO_VTABLE CFrameWindowImplBase : public ATL::CWindowImplBaseT< TBase, TWinTraits > +{ +public: + DECLARE_FRAME_WND_CLASS(NULL, 0) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + struct _ChevronMenuInfo + { + HMENU hMenu; + LPNMREBARCHEVRON lpnm; + bool bCmdBar; + }; +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +// Data members + HWND m_hWndToolBar; + HWND m_hWndStatusBar; + HWND m_hWndClient; + +#ifdef _WIN32_WCE + HWND m_hWndCECommandBar; +#endif // _WIN32_WCE + + HACCEL m_hAccel; + +// Constructor + CFrameWindowImplBase() : + m_hWndToolBar(NULL), + m_hWndStatusBar(NULL), + m_hWndClient(NULL), +#ifdef _WIN32_WCE + m_hWndCECommandBar(NULL), +#endif // _WIN32_WCE + m_hAccel(NULL) + { } + +// Methods + HWND Create(HWND hWndParent, ATL::_U_RECT rect, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle, ATL::_U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam) + { + ATLASSERT(m_hWnd == NULL); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL bRet = m_thunk.Init(NULL, NULL); + if(bRet == FALSE) + { + ::SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } +#endif // (_ATL_VER >= 0x0800) + + if(atom == 0) + return NULL; + + ModuleHelper::AddCreateWndData(&m_thunk.cd, this); + + if(MenuOrID.m_hMenu == NULL && (dwStyle & WS_CHILD)) + MenuOrID.m_hMenu = (HMENU)(UINT_PTR)this; + if(rect.m_lpRect == NULL) + rect.m_lpRect = &TBase::rcDefault; + + HWND hWnd = ::CreateWindowEx(dwExStyle, MAKEINTATOM(atom), szWindowName, + dwStyle, rect.m_lpRect->left, rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left, + rect.m_lpRect->bottom - rect.m_lpRect->top, hWndParent, MenuOrID.m_hMenu, + ModuleHelper::GetModuleInstance(), lpCreateParam); + + ATLASSERT(hWnd == NULL || m_hWnd == hWnd); + + return hWnd; + } + + static HWND CreateSimpleToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, + DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + HINSTANCE hInst = ModuleHelper::GetResourceInstance(); + HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_TOOLBAR); + if (hRsrc == NULL) + return NULL; + + HGLOBAL hGlobal = ::LoadResource(hInst, hRsrc); + if (hGlobal == NULL) + return NULL; + + _AtlToolBarData* pData = (_AtlToolBarData*)::LockResource(hGlobal); + if (pData == NULL) + return NULL; + ATLASSERT(pData->wVersion == 1); + + WORD* pItems = pData->items(); + int nItems = pData->wItemCount + (bInitialSeparator ? 1 : 0); + CTempBuffer buff; + TBBUTTON* pTBBtn = buff.Allocate(nItems); + ATLASSERT(pTBBtn != NULL); + if(pTBBtn == NULL) + return NULL; + + const int cxSeparator = 8; + + // set initial separator (half width) + if(bInitialSeparator) + { + pTBBtn[0].iBitmap = cxSeparator / 2; + pTBBtn[0].idCommand = 0; + pTBBtn[0].fsState = 0; + pTBBtn[0].fsStyle = BTNS_SEP; + pTBBtn[0].dwData = 0; + pTBBtn[0].iString = 0; + } + + int nBmp = 0; + for(int i = 0, j = bInitialSeparator ? 1 : 0; i < pData->wItemCount; i++, j++) + { + if(pItems[i] != 0) + { + pTBBtn[j].iBitmap = nBmp++; + pTBBtn[j].idCommand = pItems[i]; + pTBBtn[j].fsState = TBSTATE_ENABLED; + pTBBtn[j].fsStyle = BTNS_BUTTON; + pTBBtn[j].dwData = 0; + pTBBtn[j].iString = 0; + } + else + { + pTBBtn[j].iBitmap = cxSeparator; + pTBBtn[j].idCommand = 0; + pTBBtn[j].fsState = 0; + pTBBtn[j].fsStyle = BTNS_SEP; + pTBBtn[j].dwData = 0; + pTBBtn[j].iString = 0; + } + } + +#ifndef _WIN32_WCE + HWND hWnd = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL); + if(hWnd == NULL) + { + ATLASSERT(FALSE); + return NULL; + } +#else // CE specific + dwStyle; + nID; + // The toolbar must go onto the existing CommandBar or MenuBar + HWND hWnd = hWndParent; +#endif // _WIN32_WCE + + ::SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L); + + // check if font is taller than our bitmaps + CFontHandle font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L); + if(font.IsNull()) + font = (HFONT)::GetStockObject(SYSTEM_FONT); + LOGFONT lf = { 0 }; + font.GetLogFont(lf); + WORD cyFontHeight = (WORD)abs(lf.lfHeight); + +#ifndef _WIN32_WCE + WORD bitsPerPixel = AtlGetBitmapResourceBitsPerPixel(nResourceID); + if(bitsPerPixel > 4) + { + COLORREF crMask = CLR_DEFAULT; + if(bitsPerPixel == 32) + { + // 32-bit color bitmap with alpha channel (valid for Windows XP and later) + crMask = CLR_NONE; + } + HIMAGELIST hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nResourceID), pData->wWidth, 1, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_DEFAULTSIZE); + ATLASSERT(hImageList != NULL); + ::SendMessage(hWnd, TB_SETIMAGELIST, 0, (LPARAM)hImageList); + } + else +#endif // !_WIN32_WCE + { + TBADDBITMAP tbab = { 0 }; + tbab.hInst = hInst; + tbab.nID = nResourceID; + ::SendMessage(hWnd, TB_ADDBITMAP, nBmp, (LPARAM)&tbab); + } + + ::SendMessage(hWnd, TB_ADDBUTTONS, nItems, (LPARAM)pTBBtn); + ::SendMessage(hWnd, TB_SETBITMAPSIZE, 0, MAKELONG(pData->wWidth, __max(pData->wHeight, cyFontHeight))); + const int cxyButtonMargin = 7; + ::SendMessage(hWnd, TB_SETBUTTONSIZE, 0, MAKELONG(pData->wWidth + cxyButtonMargin, __max(pData->wHeight, cyFontHeight) + cxyButtonMargin)); + + return hWnd; + } + +#ifndef _WIN32_WCE + static HWND CreateSimpleReBarCtrl(HWND hWndParent, DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + // Ensure style combinations for proper rebar painting + if(dwStyle & CCS_NODIVIDER && dwStyle & WS_BORDER) + dwStyle &= ~WS_BORDER; + else if(!(dwStyle & WS_BORDER) && !(dwStyle & CCS_NODIVIDER)) + dwStyle |= CCS_NODIVIDER; + + // Create rebar window + HWND hWndReBar = ::CreateWindowEx(0, REBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL); + if(hWndReBar == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("Failed to create rebar.\n")); + return NULL; + } + + // Initialize and send the REBARINFO structure + REBARINFO rbi = { sizeof(REBARINFO), 0 }; + if(::SendMessage(hWndReBar, RB_SETBARINFO, 0, (LPARAM)&rbi) == 0) + { + ATLTRACE2(atlTraceUI, 0, _T("Failed to initialize rebar.\n")); + ::DestroyWindow(hWndReBar); + return NULL; + } + + return hWndReBar; + } + + BOOL CreateSimpleReBar(DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + ATLASSERT(!::IsWindow(m_hWndToolBar)); + m_hWndToolBar = CreateSimpleReBarCtrl(m_hWnd, dwStyle, nID); + return (m_hWndToolBar != NULL); + } + + static BOOL AddSimpleReBarBandCtrl(HWND hWndReBar, HWND hWndBand, int nID = 0, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE) + { + ATLASSERT(::IsWindow(hWndReBar)); // must be already created +#ifdef _DEBUG + // block - check if this is really a rebar + { + TCHAR lpszClassName[sizeof(REBARCLASSNAME)] = { 0 }; + ::GetClassName(hWndReBar, lpszClassName, sizeof(REBARCLASSNAME)); + ATLASSERT(lstrcmp(lpszClassName, REBARCLASSNAME) == 0); + } +#endif // _DEBUG + ATLASSERT(::IsWindow(hWndBand)); // must be already created + + // Get number of buttons on the toolbar + int nBtnCount = (int)::SendMessage(hWndBand, TB_BUTTONCOUNT, 0, 0L); + + // Set band info structure + REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() }; +#if (_WIN32_IE >= 0x0400) + rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE | RBBIM_IDEALSIZE; +#else + rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE; +#endif // !(_WIN32_IE >= 0x0400) + if(lpstrTitle != NULL) + rbBand.fMask |= RBBIM_TEXT; + rbBand.fStyle = RBBS_CHILDEDGE; +#if (_WIN32_IE >= 0x0500) + if(nBtnCount > 0) // add chevron style for toolbar with buttons + rbBand.fStyle |= RBBS_USECHEVRON; +#endif // (_WIN32_IE >= 0x0500) + if(bNewRow) + rbBand.fStyle |= RBBS_BREAK; + + rbBand.lpText = (LPTSTR)lpstrTitle; + rbBand.hwndChild = hWndBand; + if(nID == 0) // calc band ID + nID = ATL_IDW_BAND_FIRST + (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L); + rbBand.wID = nID; + + // Calculate the size of the band + BOOL bRet = FALSE; + RECT rcTmp = { 0 }; + if(nBtnCount > 0) + { + bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, nBtnCount - 1, (LPARAM)&rcTmp); + ATLASSERT(bRet); + rbBand.cx = (cxWidth != 0) ? cxWidth : rcTmp.right; + rbBand.cyMinChild = rcTmp.bottom - rcTmp.top; + if(bFullWidthAlways) + { + rbBand.cxMinChild = rbBand.cx; + } + else if(lpstrTitle == NULL) + { + bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, 0, (LPARAM)&rcTmp); + ATLASSERT(bRet); + rbBand.cxMinChild = rcTmp.right; + } + else + { + rbBand.cxMinChild = 0; + } + } + else // no buttons, either not a toolbar or really has no buttons + { + bRet = ::GetWindowRect(hWndBand, &rcTmp); + ATLASSERT(bRet); + rbBand.cx = (cxWidth != 0) ? cxWidth : (rcTmp.right - rcTmp.left); + rbBand.cxMinChild = bFullWidthAlways ? rbBand.cx : 0; + rbBand.cyMinChild = rcTmp.bottom - rcTmp.top; + } + +#if (_WIN32_IE >= 0x0400) + rbBand.cxIdeal = rbBand.cx; +#endif // (_WIN32_IE >= 0x0400) + + // Add the band + LRESULT lRes = ::SendMessage(hWndReBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); + if(lRes == 0) + { + ATLTRACE2(atlTraceUI, 0, _T("Failed to add a band to the rebar.\n")); + return FALSE; + } + +#if (_WIN32_IE >= 0x0501) + DWORD dwExStyle = (DWORD)::SendMessage(hWndBand, TB_GETEXTENDEDSTYLE, 0, 0L); + ::SendMessage(hWndBand, TB_SETEXTENDEDSTYLE, 0, dwExStyle | TBSTYLE_EX_HIDECLIPPEDBUTTONS); +#endif // (_WIN32_IE >= 0x0501) + + return TRUE; + } + + BOOL AddSimpleReBarBand(HWND hWndBand, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE) + { + ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar + ATLASSERT(::IsWindow(hWndBand)); // must be created + return AddSimpleReBarBandCtrl(m_hWndToolBar, hWndBand, 0, lpstrTitle, bNewRow, cxWidth, bFullWidthAlways); + } + +#if (_WIN32_IE >= 0x0400) + void SizeSimpleReBarBands() + { + ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar + + int nCount = (int)::SendMessage(m_hWndToolBar, RB_GETBANDCOUNT, 0, 0L); + + for(int i = 0; i < nCount; i++) + { + REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() }; + rbBand.fMask = RBBIM_SIZE; + BOOL bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_GETBANDINFO, i, (LPARAM)&rbBand); + ATLASSERT(bRet); + RECT rect = { 0 }; + ::SendMessage(m_hWndToolBar, RB_GETBANDBORDERS, i, (LPARAM)&rect); + rbBand.cx += rect.left + rect.right; + bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_SETBANDINFO, i, (LPARAM)&rbBand); + ATLASSERT(bRet); + } + } +#endif // (_WIN32_IE >= 0x0400) +#endif // _WIN32_WCE + +#ifndef _WIN32_WCE + BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) +#else // CE specific + BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR) +#endif // _WIN32_WCE + { + ATLASSERT(!::IsWindow(m_hWndStatusBar)); + m_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, m_hWnd, nID); + return (m_hWndStatusBar != NULL); + } + +#ifndef _WIN32_WCE + BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) +#else // CE specific + BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR) +#endif // _WIN32_WCE + { + const int cchMax = 128; // max text length is 127 for status bars (+1 for null) + TCHAR szText[cchMax] = { 0 }; + ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax); + return CreateSimpleStatusBar(szText, dwStyle, nID); + } + +#ifdef _WIN32_WCE + BOOL CreateSimpleCECommandBar(LPTSTR pszMenu = NULL, WORD iButton = 0, DWORD dwFlags = 0, int nCmdBarID = 1) + { + ATLASSERT(m_hWndCECommandBar == NULL); + ATLASSERT(m_hWndToolBar == NULL); + + m_hWndCECommandBar = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), m_hWnd, nCmdBarID); + if(m_hWndCECommandBar == NULL) + return FALSE; + + m_hWndToolBar = m_hWndCECommandBar; + + BOOL bRet = TRUE; + + if(pszMenu != NULL) + bRet &= ::CommandBar_InsertMenubarEx(m_hWndCECommandBar, IS_INTRESOURCE(pszMenu) ? ModuleHelper::GetResourceInstance() : NULL, pszMenu, iButton); + + bRet &= ::CommandBar_AddAdornments(m_hWndCECommandBar, dwFlags, 0); + + return bRet; + } + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + BOOL CreateSimpleCEMenuBar(UINT nToolBarId = ATL_IDW_MENU_BAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0) + { + ATLASSERT(m_hWndCECommandBar == NULL); + + SHMENUBARINFO mbi = { 0 }; + mbi.cbSize = sizeof(mbi); + mbi.hwndParent = m_hWnd; + mbi.dwFlags = dwFlags; + mbi.nToolBarId = nToolBarId; + mbi.hInstRes = ModuleHelper::GetResourceInstance(); + mbi.nBmpId = nBmpId; + mbi.cBmpImages = cBmpImages; + mbi.hwndMB = NULL; // This gets set by SHCreateMenuBar + + BOOL bRet = ::SHCreateMenuBar(&mbi); + if(bRet != FALSE) + { + m_hWndCECommandBar = mbi.hwndMB; + SizeToMenuBar(); + } + + return bRet; + } + + void SizeToMenuBar() // for menu bar only + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(::IsWindow(m_hWndCECommandBar)); + + RECT rect = { 0 }; + GetWindowRect(&rect); + RECT rectMB = { 0 }; + ::GetWindowRect(m_hWndCECommandBar, &rectMB); + int cy = ::IsWindowVisible(m_hWndCECommandBar) ? rectMB.top - rect.top : rectMB.bottom - rect.top; + SetWindowPos(NULL, 0, 0, rect.right - rect.left, cy, SWP_NOZORDER | SWP_NOMOVE); + } +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) +#endif // _WIN32_WCE + + void UpdateLayout(BOOL bResizeBars = TRUE) + { + RECT rect = { 0 }; + GetClientRect(&rect); + + // position bars and offset their dimensions + UpdateBarsPosition(rect, bResizeBars); + + // resize client window + if(m_hWndClient != NULL) + ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOZORDER | SWP_NOACTIVATE); + } + + void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE) + { + // resize toolbar + if(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE)) + { + if(bResizeBars != FALSE) + { + ::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0); + ::InvalidateRect(m_hWndToolBar, NULL, TRUE); + } + RECT rectTB = { 0 }; + ::GetWindowRect(m_hWndToolBar, &rectTB); + rect.top += rectTB.bottom - rectTB.top; + } + + // resize status bar + if(m_hWndStatusBar != NULL && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE)) + { + if(bResizeBars != FALSE) + ::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0); + RECT rectSB = { 0 }; + ::GetWindowRect(m_hWndStatusBar, &rectSB); + rect.bottom -= rectSB.bottom - rectSB.top; + } + } + + BOOL PreTranslateMessage(MSG* pMsg) + { + if(m_hAccel != NULL && ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg)) + return TRUE; + return FALSE; + } + + BEGIN_MSG_MAP(CFrameWindowImplBase) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) +#ifndef _WIN32_WCE + NOTIFY_CODE_HANDLER(TTN_GETDISPINFOA, OnToolTipTextA) + NOTIFY_CODE_HANDLER(TTN_GETDISPINFOW, OnToolTipTextW) +#endif // !_WIN32_WCE + END_MSG_MAP() + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_hWndClient != NULL) // view will paint itself instead + return 1; + + bHandled = FALSE; + return 0; + } + +#ifndef _WIN32_WCE + LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + bHandled = FALSE; + + if(m_hWndStatusBar == NULL) + return 1; + + WORD wFlags = HIWORD(wParam); + if(wFlags == 0xFFFF && lParam == NULL) // menu closing + { + ::SendMessage(m_hWndStatusBar, SB_SIMPLE, FALSE, 0L); + } + else + { + const int cchBuff = 256; + TCHAR szBuff[cchBuff] = { 0 }; + if(!(wFlags & MF_POPUP)) + { + WORD wID = LOWORD(wParam); + // check for special cases + if(wID >= 0xF000 && wID < 0xF1F0) // system menu IDs + wID = (WORD)(((wID - 0xF000) >> 4) + ATL_IDS_SCFIRST); + else if(wID >= ID_FILE_MRU_FIRST && wID <= ID_FILE_MRU_LAST) // MRU items + wID = ATL_IDS_MRU_FILE; + else if(wID >= ATL_IDM_FIRST_MDICHILD && wID <= ATL_IDM_LAST_MDICHILD) // MDI child windows + wID = ATL_IDS_MDICHILD; + + int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), wID, szBuff, cchBuff); + for(int i = 0; i < nRet; i++) + { + if(szBuff[i] == _T('\n')) + { + szBuff[i] = 0; + break; + } + } + } + ::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L); + ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)szBuff); + } + + return 1; + } +#endif // !_WIN32_WCE + + LRESULT OnSetFocus(UINT, WPARAM, LPARAM, BOOL& bHandled) + { + if(m_hWndClient != NULL) + ::SetFocus(m_hWndClient); + + bHandled = FALSE; + return 1; + } + + LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled) + { + if((GetStyle() & (WS_CHILD | WS_POPUP)) == 0) + ::PostQuitMessage(1); + + bHandled = FALSE; + return 1; + } + +#ifndef _WIN32_WCE + LRESULT OnToolTipTextA(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + LPNMTTDISPINFOA pDispInfo = (LPNMTTDISPINFOA)pnmh; + if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND)) + { + const int cchBuff = 256; + char szBuff[cchBuff] = { 0 }; + int nRet = ::LoadStringA(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff); + for(int i = 0; i < nRet; i++) + { + if(szBuff[i] == '\n') + { + SecureHelper::strncpyA_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE); + break; + } + } +#if (_WIN32_IE >= 0x0300) + if(nRet > 0) // string was loaded, save it + pDispInfo->uFlags |= TTF_DI_SETITEM; +#endif // (_WIN32_IE >= 0x0300) + } + + return 0; + } + + LRESULT OnToolTipTextW(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + LPNMTTDISPINFOW pDispInfo = (LPNMTTDISPINFOW)pnmh; + if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND)) + { + const int cchBuff = 256; + wchar_t szBuff[cchBuff] = { 0 }; + int nRet = ::LoadStringW(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff); + for(int i = 0; i < nRet; i++) + { + if(szBuff[i] == L'\n') + { + SecureHelper::strncpyW_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE); + break; + } + } +#if (_WIN32_IE >= 0x0300) + if(nRet > 0) // string was loaded, save it + pDispInfo->uFlags |= TTF_DI_SETITEM; +#endif // (_WIN32_IE >= 0x0300) + } + + return 0; + } +#endif // !_WIN32_WCE + +// Implementation - chevron menu support +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + bool PrepareChevronMenu(_ChevronMenuInfo& cmi) + { + // get rebar and toolbar + REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() }; + rbbi.fMask = RBBIM_CHILD; + BOOL bRet = (BOOL)::SendMessage(cmi.lpnm->hdr.hwndFrom, RB_GETBANDINFO, cmi.lpnm->uBand, (LPARAM)&rbbi); + ATLASSERT(bRet); + + // assume the band is a toolbar + ATL::CWindow wnd = rbbi.hwndChild; + int nCount = (int)wnd.SendMessage(TB_BUTTONCOUNT); + if(nCount <= 0) // probably not a toolbar + return false; + + // check if it's a command bar + CMenuHandle menuCmdBar = (HMENU)wnd.SendMessage(CBRM_GETMENU); + cmi.bCmdBar = (menuCmdBar.m_hMenu != NULL); + + // build a menu from hidden items + CMenuHandle menu; + bRet = menu.CreatePopupMenu(); + ATLASSERT(bRet); + RECT rcClient = { 0 }; + bRet = wnd.GetClientRect(&rcClient); + ATLASSERT(bRet); + for(int i = 0; i < nCount; i++) + { + TBBUTTON tbb = { 0 }; + bRet = (BOOL)wnd.SendMessage(TB_GETBUTTON, i, (LPARAM)&tbb); + ATLASSERT(bRet); + // skip hidden buttons + if((tbb.fsState & TBSTATE_HIDDEN) != 0) + continue; + RECT rcButton = { 0 }; + bRet = (BOOL)wnd.SendMessage(TB_GETITEMRECT, i, (LPARAM)&rcButton); + ATLASSERT(bRet); + bool bEnabled = ((tbb.fsState & TBSTATE_ENABLED) != 0); + if((rcButton.right > rcClient.right) || (rcButton.bottom > rcClient.bottom)) + { + if(tbb.fsStyle & BTNS_SEP) + { + if(menu.GetMenuItemCount() > 0) + menu.AppendMenu(MF_SEPARATOR); + } + else if(cmi.bCmdBar) + { + const int cchBuff = 200; + TCHAR szBuff[cchBuff] = { 0 }; + CMenuItemInfo mii; + mii.fMask = MIIM_TYPE | MIIM_SUBMENU; + mii.dwTypeData = szBuff; + mii.cch = cchBuff; + bRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + // Note: CmdBar currently supports only drop-down items + ATLASSERT(::IsMenu(mii.hSubMenu)); + bRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData); + ATLASSERT(bRet); + } + else + { + // get button's text + const int cchBuff = 200; + TCHAR szBuff[cchBuff] = { 0 }; + LPCTSTR lpstrText = szBuff; + TBBUTTONINFO tbbi = { 0 }; + tbbi.cbSize = sizeof(TBBUTTONINFO); + tbbi.dwMask = TBIF_TEXT; + tbbi.pszText = szBuff; + tbbi.cchText = cchBuff; + if((wnd.SendMessage(TB_GETBUTTONINFO, tbb.idCommand, (LPARAM)&tbbi) == -1) || (szBuff[0] == 0)) + { + // no text for this button, try a resource string + lpstrText = _T(""); + int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), tbb.idCommand, szBuff, cchBuff); + for(int n = 0; n < nRet; n++) + { + if(szBuff[n] == _T('\n')) + { + lpstrText = &szBuff[n + 1]; + break; + } + } + } + bRet = menu.AppendMenu(MF_STRING | (bEnabled ? MF_ENABLED : MF_GRAYED), tbb.idCommand, lpstrText); + ATLASSERT(bRet); + } + } + } + + if(menu.GetMenuItemCount() == 0) // no hidden buttons after all + { + menu.DestroyMenu(); + ::MessageBeep((UINT)-1); + return false; + } + + cmi.hMenu = menu; + return true; + } + + void DisplayChevronMenu(_ChevronMenuInfo& cmi) + { +#ifndef TPM_VERPOSANIMATION + const UINT TPM_VERPOSANIMATION = 0x1000L; // Menu animation flag +#endif + // convert chevron rect to screen coordinates + ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom; + POINT pt = { cmi.lpnm->rc.left, cmi.lpnm->rc.bottom }; + wndFrom.MapWindowPoints(NULL, &pt, 1); + RECT rc = cmi.lpnm->rc; + wndFrom.MapWindowPoints(NULL, &rc); + // set up flags and rect + UINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | (!AtlIsOldWindows() ? TPM_VERPOSANIMATION : 0); + TPMPARAMS TPMParams = { 0 }; + TPMParams.cbSize = sizeof(TPMPARAMS); + TPMParams.rcExclude = rc; + // check if this window has a command bar + HWND hWndCmdBar = (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L); + if(::IsWindow(hWndCmdBar)) + { + CBRPOPUPMENU CBRPopupMenu = { sizeof(CBRPOPUPMENU), cmi.hMenu, uMenuFlags, pt.x, pt.y, &TPMParams }; + ::SendMessage(hWndCmdBar, CBRM_TRACKPOPUPMENU, 0, (LPARAM)&CBRPopupMenu); + } + else + { + CMenuHandle menu = cmi.hMenu; + menu.TrackPopupMenuEx(uMenuFlags, pt.x, pt.y, m_hWnd, &TPMParams); + } + } + + void CleanupChevronMenu(_ChevronMenuInfo& cmi) + { + CMenuHandle menu = cmi.hMenu; + // if menu is from a command bar, detach submenus so they are not destroyed + if(cmi.bCmdBar) + { + for(int i = menu.GetMenuItemCount() - 1; i >=0; i--) + menu.RemoveMenu(i, MF_BYPOSITION); + } + // destroy menu + menu.DestroyMenu(); + // convert chevron rect to screen coordinates + ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom; + RECT rc = cmi.lpnm->rc; + wndFrom.MapWindowPoints(NULL, &rc); + // eat next message if click is on the same button + MSG msg = { 0 }; + if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rc, msg.pt)) + ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +}; + + +template +class ATL_NO_VTABLE CFrameWindowImpl : public CFrameWindowImplBase< TBase, TWinTraits > +{ +public: + HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) + { + ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); + + dwStyle = T::GetWndStyle(dwStyle); + dwExStyle = T::GetWndExStyle(dwExStyle); + + if(rect.m_lpRect == NULL) + rect.m_lpRect = &TBase::rcDefault; + + return CFrameWindowImplBase< TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam); + } + + HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) + { + const int cchName = 256; + TCHAR szWindowName[cchName] = { 0 }; +#ifndef _WIN32_WCE + ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); + HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); +#else // CE specific + ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); + + // This always needs to be NULL for Windows CE. + // Frame Window menus have to go onto the CommandBar. + // Use CreateSimpleCECommandBar + HMENU hMenu = NULL; +#endif // _WIN32_WCE + + T* pT = static_cast(this); + HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); + + if(hWnd != NULL) + m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); + + return hWnd; + } + + BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + if(nResourceID == 0) + nResourceID = T::GetWndClassInfo().m_uCommonResourceID; +#ifndef _WIN32_WCE + ATLASSERT(!::IsWindow(m_hWndToolBar)); + m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); + return (m_hWndToolBar != NULL); +#else // CE specific + HWND hWnd= T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID); + return (hWnd != NULL); +#endif // _WIN32_WCE + } + +#ifdef _WIN32_WCE + // CE specific variant that returns the handle of the toolbar + HWND CreateSimpleCEToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + if(nResourceID == 0) + nResourceID = T::GetWndClassInfo().m_uCommonResourceID; + + return T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID); + } +#endif // _WIN32_WCE + +// message map and handlers + typedef CFrameWindowImplBase< TBase, TWinTraits > _baseClass; + + BEGIN_MSG_MAP(CFrameWindowImpl) + MESSAGE_HANDLER(WM_SIZE, OnSize) +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +#endif // !_ATL_NO_REBAR_SUPPORT + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam != SIZE_MINIMIZED) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + bHandled = FALSE; + return 1; + } + +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(FALSE); + return 0; + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + T* pT = static_cast(this); + _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; + if(!pT->PrepareChevronMenu(cmi)) + { + bHandled = FALSE; + return 1; + } + // display a popup menu with hidden items + pT->DisplayChevronMenu(cmi); + // cleanup + pT->CleanupChevronMenu(cmi); + return 0; + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +#endif // !_ATL_NO_REBAR_SUPPORT +}; + + +/////////////////////////////////////////////////////////////////////////////// +// AtlCreateSimpleToolBar - helper for creating simple toolbars + +#ifndef _WIN32_WCE + +inline HWND AtlCreateSimpleToolBar(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, + DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) +{ + return CFrameWindowImplBase<>::CreateSimpleToolBarCtrl(hWndParent, nResourceID, bInitialSeparator, dwStyle, nID); +} + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMDIWindow + +#ifndef _WIN32_WCE + +#ifndef _WTL_MDIWINDOWMENU_TEXT +#define _WTL_MDIWINDOWMENU_TEXT _T("&Window") +#endif + +class CMDIWindow : public ATL::CWindow +{ +public: +// Data members + HWND m_hWndMDIClient; + HMENU m_hMenu; + +// Constructors + CMDIWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd), m_hWndMDIClient(NULL), m_hMenu(NULL) + { } + + CMDIWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Operations + HWND MDIGetActive(BOOL* lpbMaximized = NULL) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized); + } + + void MDIActivate(HWND hWndChildToActivate) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(::IsWindow(hWndChildToActivate)); + ::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChildToActivate, 0); + } + + void MDINext(HWND hWndChild, BOOL bPrevious = FALSE) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(hWndChild == NULL || ::IsWindow(hWndChild)); + ::SendMessage(m_hWndMDIClient, WM_MDINEXT, (WPARAM)hWndChild, (LPARAM)bPrevious); + } + + void MDIMaximize(HWND hWndChildToMaximize) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(::IsWindow(hWndChildToMaximize)); + ::SendMessage(m_hWndMDIClient, WM_MDIMAXIMIZE, (WPARAM)hWndChildToMaximize, 0); + } + + void MDIRestore(HWND hWndChildToRestore) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(::IsWindow(hWndChildToRestore)); + ::SendMessage(m_hWndMDIClient, WM_MDIRESTORE, (WPARAM)hWndChildToRestore, 0); + } + + void MDIDestroy(HWND hWndChildToDestroy) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(::IsWindow(hWndChildToDestroy)); + ::SendMessage(m_hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChildToDestroy, 0); + } + + BOOL MDICascade(UINT uFlags = 0) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDICASCADE, (WPARAM)uFlags, 0); + } + + BOOL MDITile(UINT uFlags = MDITILE_HORIZONTAL) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDITILE, (WPARAM)uFlags, 0); + } + + void MDIIconArrange() + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, 0, 0); + } + + HMENU MDISetMenu(HMENU hMenuFrame, HMENU hMenuWindow) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuFrame, (LPARAM)hMenuWindow); + } + + HMENU MDIRefreshMenu() + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0); + } + +// Additional operations + static HMENU GetStandardWindowMenu(HMENU hMenu) + { + int nCount = ::GetMenuItemCount(hMenu); + if(nCount == -1) + return NULL; + int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION); + if(nLen == 0) + return NULL; + CTempBuffer buff; + LPTSTR lpszText = buff.Allocate(nLen + 1); + if(lpszText == NULL) + return NULL; + if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen) + return NULL; + if(lstrcmp(lpszText, _WTL_MDIWINDOWMENU_TEXT) != 0) + return NULL; + return ::GetSubMenu(hMenu, nCount - 2); + } + + void SetMDIFrameMenu() + { + HMENU hWindowMenu = GetStandardWindowMenu(m_hMenu); + MDISetMenu(m_hMenu, hWindowMenu); + MDIRefreshMenu(); + ::DrawMenuBar(GetMDIFrame()); + } + + HWND GetMDIFrame() const + { + return ::GetParent(m_hWndMDIClient); + } +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMDIFrameWindowImpl + +#ifndef _WIN32_WCE + +// MDI child command chaining macro (only for MDI frame windows) +#define CHAIN_MDI_CHILD_COMMANDS() \ + if(uMsg == WM_COMMAND) \ + { \ + HWND hWndChild = MDIGetActive(); \ + if(hWndChild != NULL) \ + ::SendMessage(hWndChild, uMsg, wParam, lParam); \ + } + +template +class ATL_NO_VTABLE CMDIFrameWindowImpl : public CFrameWindowImplBase +{ +public: + HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) + { + m_hMenu = hMenu; + ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); + + dwStyle = T::GetWndStyle(dwStyle); + dwExStyle = T::GetWndExStyle(dwExStyle); + + if(rect.m_lpRect == NULL) + rect.m_lpRect = &TBase::rcDefault; + + return CFrameWindowImplBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam); + } + + HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) + { + const int cchName = 256; + TCHAR szWindowName[cchName] = { 0 }; + ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); + HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); + + T* pT = static_cast(this); + HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); + + if(hWnd != NULL) + m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); + + return hWnd; + } + + BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + ATLASSERT(!::IsWindow(m_hWndToolBar)); + if(nResourceID == 0) + nResourceID = T::GetWndClassInfo().m_uCommonResourceID; + m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); + return (m_hWndToolBar != NULL); + } + + virtual WNDPROC GetWindowProc() + { + return MDIFrameWindowProc; + } + + static LRESULT CALLBACK MDIFrameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + CMDIFrameWindowImpl< T, TBase, TWinTraits >* pThis = (CMDIFrameWindowImpl< T, TBase, TWinTraits >*)hWnd; + // set a ptr to this message and save the old value +#if (_ATL_VER >= 0x0700) + ATL::_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam); + const ATL::_ATL_MSG* pOldMsg = pThis->m_pCurrentMsg; +#else // !(_ATL_VER >= 0x0700) + MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } }; + const MSG* pOldMsg = pThis->m_pCurrentMsg; +#endif // !(_ATL_VER >= 0x0700) + pThis->m_pCurrentMsg = &msg; + // pass to the message map to process + LRESULT lRes = 0; + BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0); + // restore saved value for the current message + ATLASSERT(pThis->m_pCurrentMsg == &msg); + pThis->m_pCurrentMsg = pOldMsg; + // do the default processing if message was not handled + if(!bRet) + { + if(uMsg != WM_NCDESTROY) + { + lRes = pThis->DefWindowProc(uMsg, wParam, lParam); + } + else + { + // unsubclass, if needed + LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC); + lRes = pThis->DefWindowProc(uMsg, wParam, lParam); + if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc) + ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc); +#if (_ATL_VER >= 0x0700) + // mark window as destryed + pThis->m_dwState |= WINSTATE_DESTROYED; +#else // !(_ATL_VER >= 0x0700) + // clear out window handle + HWND hWnd = pThis->m_hWnd; + pThis->m_hWnd = NULL; + // clean up after window is destroyed + pThis->OnFinalMessage(hWnd); +#endif // !(_ATL_VER >= 0x0700) + } + } +#if (_ATL_VER >= 0x0700) + if(pThis->m_dwState & WINSTATE_DESTROYED && pThis->m_pCurrentMsg == NULL) + { + // clear out window handle + HWND hWndThis = pThis->m_hWnd; + pThis->m_hWnd = NULL; + pThis->m_dwState &= ~WINSTATE_DESTROYED; + // clean up after window is destroyed + pThis->OnFinalMessage(hWndThis); + } +#endif // (_ATL_VER >= 0x0700) + return lRes; + } + + // Overriden to call DefWindowProc which uses DefFrameProc + LRESULT DefWindowProc() + { + const MSG* pMsg = m_pCurrentMsg; + LRESULT lRes = 0; + if (pMsg != NULL) + lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam); + return lRes; + } + + LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + return ::DefFrameProc(m_hWnd, m_hWndMDIClient, uMsg, wParam, lParam); + } + + BOOL PreTranslateMessage(MSG* pMsg) + { + if(CFrameWindowImplBase::PreTranslateMessage(pMsg)) + return TRUE; + return ::TranslateMDISysAccel(m_hWndMDIClient, pMsg); + } + + HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD) + { + DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES; + DWORD dwExStyle = WS_EX_CLIENTEDGE; + + CLIENTCREATESTRUCT ccs = { 0 }; + ccs.hWindowMenu = hWindowMenu; + ccs.idFirstChild = nFirstChildID; + + if((GetStyle() & (WS_HSCROLL | WS_VSCROLL)) != 0) + { + // parent MDI frame's scroll styles move to the MDICLIENT + dwStyle |= (GetStyle() & (WS_HSCROLL | WS_VSCROLL)); + + // fast way to turn off the scrollbar bits (without a resize) + ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, SWP_NOREDRAW | SWP_FRAMECHANGED); + } + + // Create MDICLIENT window + m_hWndClient = ::CreateWindowEx(dwExStyle, _T("MDIClient"), NULL, + dwStyle, 0, 0, 1, 1, m_hWnd, (HMENU)LongToHandle(nID), + ModuleHelper::GetModuleInstance(), (LPVOID)&ccs); + if (m_hWndClient == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("MDI Frame failed to create MDICLIENT.\n")); + return NULL; + } + + // Move it to the top of z-order + ::BringWindowToTop(m_hWndClient); + + // set as MDI client window + m_hWndMDIClient = m_hWndClient; + + // update to proper size + T* pT = static_cast(this); + pT->UpdateLayout(); + + return m_hWndClient; + } + + typedef CFrameWindowImplBase _baseClass; + + BEGIN_MSG_MAP(CMDIFrameWindowImpl) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu) +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) + NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) +#endif // (_WIN32_IE >= 0x0500) +#endif // !_ATL_NO_REBAR_SUPPORT + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(wParam != SIZE_MINIMIZED) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + // message must be handled, otherwise DefFrameProc would resize the client again + return 0; + } + + LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + // don't allow CFrameWindowImplBase to handle this one + return DefWindowProc(uMsg, wParam, lParam); + } + + LRESULT OnMDISetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + SetMDIFrameMenu(); + return 0; + } + +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(FALSE); + return 0; + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) + LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + T* pT = static_cast(this); + _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; + if(!pT->PrepareChevronMenu(cmi)) + { + bHandled = FALSE; + return 1; + } + // display a popup menu with hidden items + pT->DisplayChevronMenu(cmi); + // cleanup + pT->CleanupChevronMenu(cmi); + return 0; + } +#endif // (_WIN32_IE >= 0x0500) +#endif // !_ATL_NO_REBAR_SUPPORT +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMDIChildWindowImpl + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CMDIChildWindowImpl : public CFrameWindowImplBase +{ +public: + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + UINT nMenuID = 0, LPVOID lpCreateParam = NULL) + { + ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); + + if(nMenuID != 0) + m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nMenuID)); + + dwStyle = T::GetWndStyle(dwStyle); + dwExStyle = T::GetWndExStyle(dwExStyle); + + dwExStyle |= WS_EX_MDICHILD; // force this one + m_pfnSuperWindowProc = ::DefMDIChildProc; + m_hWndMDIClient = hWndParent; + ATLASSERT(::IsWindow(m_hWndMDIClient)); + + if(rect.m_lpRect == NULL) + rect.m_lpRect = &TBase::rcDefault; + + // If the currently active MDI child is maximized, we want to create this one maximized too + ATL::CWindow wndParent = hWndParent; + BOOL bMaximized = FALSE; + wndParent.SendMessage(WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); + if(bMaximized) + wndParent.SetRedraw(FALSE); + + HWND hWnd = CFrameWindowImplBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, (UINT)0U, atom, lpCreateParam); + + if(bMaximized) + { + // Maximize and redraw everything + if(hWnd != NULL) + MDIMaximize(hWnd); + wndParent.SetRedraw(TRUE); + wndParent.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); + ::SetFocus(GetMDIFrame()); // focus will be set back to this window + } + else if(hWnd != NULL && ::IsWindowVisible(m_hWnd) && !::IsChild(hWnd, ::GetFocus())) + { + ::SetFocus(hWnd); + } + + return hWnd; + } + + HWND CreateEx(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR lpcstrWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) + { + const int cchName = 256; + TCHAR szWindowName[cchName] = { 0 }; + if(lpcstrWindowName == NULL) + { + ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); + lpcstrWindowName = szWindowName; + } + + T* pT = static_cast(this); + HWND hWnd = pT->Create(hWndParent, rect, lpcstrWindowName, dwStyle, dwExStyle, T::GetWndClassInfo().m_uCommonResourceID, lpCreateParam); + + if(hWnd != NULL) + m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); + + return hWnd; + } + + BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + ATLASSERT(!::IsWindow(m_hWndToolBar)); + if(nResourceID == 0) + nResourceID = T::GetWndClassInfo().m_uCommonResourceID; + m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); + return (m_hWndToolBar != NULL); + } + + BOOL UpdateClientEdge(LPRECT lpRect = NULL) + { + // only adjust for active MDI child window + HWND hWndChild = MDIGetActive(); + if(hWndChild != NULL && hWndChild != m_hWnd) + return FALSE; + + // need to adjust the client edge style as max/restore happens + DWORD dwStyle = ::GetWindowLong(m_hWndMDIClient, GWL_EXSTYLE); + DWORD dwNewStyle = dwStyle; + if(hWndChild != NULL && ((GetExStyle() & WS_EX_CLIENTEDGE) == 0) && ((GetStyle() & WS_MAXIMIZE) != 0)) + dwNewStyle &= ~(WS_EX_CLIENTEDGE); + else + dwNewStyle |= WS_EX_CLIENTEDGE; + + if(dwStyle != dwNewStyle) + { + // SetWindowPos will not move invalid bits + ::RedrawWindow(m_hWndMDIClient, NULL, NULL, + RDW_INVALIDATE | RDW_ALLCHILDREN); + // remove/add WS_EX_CLIENTEDGE to MDI client area + ::SetWindowLong(m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle); + ::SetWindowPos(m_hWndMDIClient, NULL, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | + SWP_NOZORDER | SWP_NOCOPYBITS); + + // return new client area + if (lpRect != NULL) + ::GetClientRect(m_hWndMDIClient, lpRect); + + return TRUE; + } + + return FALSE; + } + + typedef CFrameWindowImplBase _baseClass; + BEGIN_MSG_MAP(CMDIChildWindowImpl) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged) + MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) + MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) + MESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) + NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) +#endif // (_WIN32_IE >= 0x0500) +#endif // !_ATL_NO_REBAR_SUPPORT + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + DefWindowProc(uMsg, wParam, lParam); // needed for MDI children + if(wParam != SIZE_MINIMIZED) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + return 0; + } + + LRESULT OnWindowPosChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + // update MDI client edge and adjust MDI child rect + LPWINDOWPOS lpWndPos = (LPWINDOWPOS)lParam; + + if(!(lpWndPos->flags & SWP_NOSIZE)) + { + RECT rectClient = { 0 }; + if(UpdateClientEdge(&rectClient) && ((GetStyle() & WS_MAXIMIZE) != 0)) + { + ::AdjustWindowRectEx(&rectClient, GetStyle(), FALSE, GetExStyle()); + lpWndPos->x = rectClient.left; + lpWndPos->y = rectClient.top; + lpWndPos->cx = rectClient.right - rectClient.left; + lpWndPos->cy = rectClient.bottom - rectClient.top; + } + } + + bHandled = FALSE; + return 1; + } + + LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRes = DefWindowProc(uMsg, wParam, lParam); + + // Activate this MDI window if needed + if(lRes == MA_ACTIVATE || lRes == MA_ACTIVATEANDEAT) + { + if(MDIGetActive() != m_hWnd) + MDIActivate(m_hWnd); + } + + return lRes; + } + + LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + return ::SendMessage(GetMDIFrame(), uMsg, wParam, lParam); + } + + LRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if((HWND)lParam == m_hWnd && m_hMenu != NULL) + SetMDIFrameMenu(); + else if((HWND)lParam == NULL) + ::SendMessage(GetMDIFrame(), WM_MDISETMENU, 0, 0); + + bHandled = FALSE; + return 1; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_hMenu != NULL) + { + ::DestroyMenu(m_hMenu); + m_hMenu = NULL; + } + UpdateClientEdge(); + bHandled = FALSE; + return 1; + } + +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(FALSE); + return 0; + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) + LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + T* pT = static_cast(this); + _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; + if(!pT->PrepareChevronMenu(cmi)) + { + bHandled = FALSE; + return 1; + } + // display a popup menu with hidden items + pT->DisplayChevronMenu(cmi); + // cleanup + pT->CleanupChevronMenu(cmi); + return 0; + } +#endif // (_WIN32_IE >= 0x0500) +#endif // !_ATL_NO_REBAR_SUPPORT +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// COwnerDraw - MI class for owner-draw support + +template +class COwnerDraw +{ +public: +#if (_ATL_VER < 0x0700) + BOOL m_bHandledOD; + + BOOL IsMsgHandled() const + { + return m_bHandledOD; + } + void SetMsgHandled(BOOL bHandled) + { + m_bHandledOD = bHandled; + } +#endif // (_ATL_VER < 0x0700) + +// Message map and handlers + BEGIN_MSG_MAP(COwnerDraw< T >) + MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem) + MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem) + MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem) + MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem) + ALT_MSG_MAP(1) + MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem) + MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem) + MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem) + MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem) + END_MSG_MAP() + + LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + pT->DrawItem((LPDRAWITEMSTRUCT)lParam); + bHandled = pT->IsMsgHandled(); + return (LRESULT)TRUE; + } + + LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + pT->MeasureItem((LPMEASUREITEMSTRUCT)lParam); + bHandled = pT->IsMsgHandled(); + return (LRESULT)TRUE; + } + + LRESULT OnCompareItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + bHandled = pT->IsMsgHandled(); + return (LRESULT)pT->CompareItem((LPCOMPAREITEMSTRUCT)lParam); + } + + LRESULT OnDeleteItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + pT->DeleteItem((LPDELETEITEMSTRUCT)lParam); + bHandled = pT->IsMsgHandled(); + return (LRESULT)TRUE; + } + +// Overrideables + void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/) + { + // must be implemented + ATLASSERT(FALSE); + } + + void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) + { + if(lpMeasureItemStruct->CtlType != ODT_MENU) + { + // return default height for a system font + T* pT = static_cast(this); + HWND hWnd = pT->GetDlgItem(lpMeasureItemStruct->CtlID); + CClientDC dc(hWnd); + TEXTMETRIC tm = { 0 }; + dc.GetTextMetrics(&tm); + + lpMeasureItemStruct->itemHeight = tm.tmHeight; + } + else + lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU); + } + + int CompareItem(LPCOMPAREITEMSTRUCT /*lpCompareItemStruct*/) + { + // all items are equal + return 0; + } + + void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/) + { + // default - nothing + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Update UI macros + +// these build the Update UI map inside a class definition +#define BEGIN_UPDATE_UI_MAP(thisClass) \ + static const CUpdateUIBase::_AtlUpdateUIMap* GetUpdateUIMap() \ + { \ + static const _AtlUpdateUIMap theMap[] = \ + { + +#define UPDATE_ELEMENT(nID, wType) \ + { nID, wType }, + +#define END_UPDATE_UI_MAP() \ + { (WORD)-1, 0 } \ + }; \ + return theMap; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// CUpdateUI - manages UI elements updating + +class CUpdateUIBase +{ +public: + // constants + enum + { + // UI element type + UPDUI_MENUPOPUP = 0x0001, + UPDUI_MENUBAR = 0x0002, + UPDUI_CHILDWINDOW = 0x0004, + UPDUI_TOOLBAR = 0x0008, + UPDUI_STATUSBAR = 0x0010, + // state + UPDUI_ENABLED = 0x0000, + UPDUI_DISABLED = 0x0100, + UPDUI_CHECKED = 0x0200, + UPDUI_CHECKED2 = 0x0400, + UPDUI_RADIO = 0x0800, + UPDUI_DEFAULT = 0x1000, + UPDUI_TEXT = 0x2000, + // internal state + UPDUI_CLEARDEFAULT = 0x4000, + }; + + // element data + struct _AtlUpdateUIElement + { + HWND m_hWnd; + WORD m_wType; + + bool operator ==(const _AtlUpdateUIElement& e) const + { return (m_hWnd == e.m_hWnd && m_wType == e.m_wType); } + }; + + // map data + struct _AtlUpdateUIMap + { + WORD m_nID; + WORD m_wType; + + bool operator ==(const _AtlUpdateUIMap& e) const + { return (m_nID == e.m_nID && m_wType == e.m_wType); } + }; + + // instance data +#pragma warning(push) +#pragma warning(disable: 4201) // nameless unions are part of C++ + + struct _AtlUpdateUIData + { + WORD m_wState; + union + { + void* m_lpData; + LPTSTR m_lpstrText; + struct + { + WORD m_nIDFirst; + WORD m_nIDLast; + }; + }; + + bool operator ==(const _AtlUpdateUIData& e) const + { return (m_wState == e.m_wState && m_lpData == e.m_lpData); } + }; + +#pragma warning(pop) + + ATL::CSimpleArray<_AtlUpdateUIElement> m_UIElements; // elements data + const _AtlUpdateUIMap* m_pUIMap; // static UI data + _AtlUpdateUIData* m_pUIData; // instance UI data + WORD m_wDirtyType; // global dirty flag + + bool m_bBlockAccelerators; + + +// Constructor, destructor + CUpdateUIBase() : m_pUIMap(NULL), m_pUIData(NULL), m_wDirtyType(0), m_bBlockAccelerators(false) + { } + + ~CUpdateUIBase() + { + if(m_pUIMap != NULL && m_pUIData != NULL) + { + const _AtlUpdateUIMap* pUIMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + while(pUIMap->m_nID != (WORD)-1) + { + if(pUIData->m_wState & UPDUI_TEXT) + delete [] pUIData->m_lpstrText; + pUIMap++; + pUIData++; + } + delete [] m_pUIData; + } + } + +// Check for disabled commands + bool UIGetBlockAccelerators() const + { + return m_bBlockAccelerators; + } + + bool UISetBlockAccelerators(bool bBlock) + { + bool bOld = m_bBlockAccelerators; + m_bBlockAccelerators = bBlock; + return bOld; + } + +// Add elements + BOOL UIAddMenuBar(HWND hWnd) // menu bar (main menu) + { + if(hWnd == NULL) + return FALSE; + _AtlUpdateUIElement e; + e.m_hWnd = hWnd; + e.m_wType = UPDUI_MENUBAR; + return m_UIElements.Add(e); + } + + BOOL UIAddToolBar(HWND hWnd) // toolbar + { + if(hWnd == NULL) + return FALSE; + _AtlUpdateUIElement e; + e.m_hWnd = hWnd; + e.m_wType = UPDUI_TOOLBAR; + return m_UIElements.Add(e); + } + + BOOL UIAddStatusBar(HWND hWnd) // status bar + { + if(hWnd == NULL) + return FALSE; + _AtlUpdateUIElement e; + e.m_hWnd = hWnd; + e.m_wType = UPDUI_STATUSBAR; + return m_UIElements.Add(e); + } + + BOOL UIAddChildWindowContainer(HWND hWnd) // child window + { + if(hWnd == NULL) + return FALSE; + _AtlUpdateUIElement e; + e.m_hWnd = hWnd; + e.m_wType = UPDUI_CHILDWINDOW; + return m_UIElements.Add(e); + } + +// Message map for popup menu updates and accelerator blocking + BEGIN_MSG_MAP(CUpdateUIBase) + MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) + MESSAGE_HANDLER(WM_COMMAND, OnCommand) + END_MSG_MAP() + + LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; + HMENU hMenu = (HMENU)wParam; + if(hMenu == NULL) + return 1; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return 1; + const _AtlUpdateUIMap* pMap = m_pUIMap; + while(pMap->m_nID != (WORD)-1) + { + if(pMap->m_wType & UPDUI_MENUPOPUP) + { + UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu); + + if((pUIData->m_wState & UPDUI_RADIO) != 0) + ::CheckMenuRadioItem(hMenu, pUIData->m_nIDFirst, pUIData->m_nIDLast, pMap->m_nID, MF_BYCOMMAND); + } + pMap++; + pUIData++; + } + return 0; + } + + LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; + if(m_bBlockAccelerators && HIWORD(wParam) == 1) // accelerators only + { + int nID = LOWORD(wParam); + if((UIGetState(nID) & UPDUI_DISABLED) == UPDUI_DISABLED) + { + ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIBase::OnCommand - blocked disabled command 0x%4.4X\n"), nID); + bHandled = TRUE; // eat the command, UI item is disabled + } + } + return 0; + } + +// methods for setting UI element state + BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + if(bEnable) + { + if(pUIData->m_wState & UPDUI_DISABLED) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_DISABLED; + } + } + else + { + if(!(pUIData->m_wState & UPDUI_DISABLED)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState |= UPDUI_DISABLED; + } + } + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + + BOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + switch(nCheck) + { + case 0: + if((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_CHECKED2)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~(UPDUI_CHECKED | UPDUI_CHECKED2); + } + break; + case 1: + if(!(pUIData->m_wState & UPDUI_CHECKED)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_CHECKED2; + pUIData->m_wState |= UPDUI_CHECKED; + } + break; + case 2: + if(!(pUIData->m_wState & UPDUI_CHECKED2)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_CHECKED; + pUIData->m_wState |= UPDUI_CHECKED2; + } + break; + } + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + + // variant that supports bool (checked/not-checked, no intermediate state) + BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE) + { + return UISetCheck(nID, bCheck ? 1 : 0, bForceUpdate); + } + + BOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + if(bRadio) + { + if(!(pUIData->m_wState & UPDUI_RADIO)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState |= UPDUI_RADIO; + } + } + else + { + if(pUIData->m_wState & UPDUI_RADIO) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_RADIO; + } + } + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + + // for menu items + BOOL UISetRadioMenuItem(int nID, int nIDFirst, int nIDLast, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState |= UPDUI_RADIO; + pUIData->m_nIDFirst = (WORD)nIDFirst; + pUIData->m_nIDLast = (WORD)nIDLast; + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + } + else if(pMap->m_nID >= nIDFirst && pMap->m_nID <= nIDLast) + { + if(pUIData->m_wState & UPDUI_RADIO) + { + pUIData->m_wState &= ~pMap->m_wType; + pUIData->m_wState &= ~UPDUI_RADIO; + pUIData->m_nIDFirst = 0; + pUIData->m_nIDLast = 0; + } + } + + if(pMap->m_nID == nIDLast) + break; + } + + return TRUE; + } + + BOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + if(lpstrText == NULL) + lpstrText = _T(""); + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + if(pUIData->m_lpstrText == NULL || lstrcmp(pUIData->m_lpstrText, lpstrText)) + { + delete [] pUIData->m_lpstrText; + pUIData->m_lpstrText = NULL; + int nStrLen = lstrlen(lpstrText); + ATLTRY(pUIData->m_lpstrText = new TCHAR[nStrLen + 1]); + if(pUIData->m_lpstrText == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("UISetText - memory allocation failed\n")); + break; + } + SecureHelper::strcpy_x(pUIData->m_lpstrText, nStrLen + 1, lpstrText); + pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType); + } + + if(bForceUpdate) + pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType); + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + + BOOL UISetDefault(int nID, BOOL bDefault, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + if(bDefault) + { + if((pUIData->m_wState & UPDUI_DEFAULT) == 0) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState |= UPDUI_DEFAULT; + } + } + else + { + if((pUIData->m_wState & UPDUI_DEFAULT) != 0) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_DEFAULT; + pUIData->m_wState |= UPDUI_CLEARDEFAULT; + } + } + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + +// methods for complete state set/get + BOOL UISetState(int nID, DWORD dwState) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + pUIData->m_wState = (WORD)(dwState | pMap->m_wType); + m_wDirtyType |= pMap->m_wType; + break; // found + } + } + return TRUE; + } + + DWORD UIGetState(int nID) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return 0; + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + return pUIData->m_wState; + } + return 0; + } + +// methods for updating UI +#ifndef _WIN32_WCE + BOOL UIUpdateMenuBar(BOOL bForceUpdate = FALSE, BOOL bMainMenu = FALSE) + { + if(!(m_wDirtyType & UPDUI_MENUBAR) && !bForceUpdate) + return TRUE; + + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + while(pMap->m_nID != (WORD)-1) + { + for(int i = 0; i < m_UIElements.GetSize(); i++) + { + if(m_UIElements[i].m_wType == UPDUI_MENUBAR) + { + HMENU hMenu = ::GetMenu(m_UIElements[i].m_hWnd); + if(hMenu != NULL && (pUIData->m_wState & UPDUI_MENUBAR) && (pMap->m_wType & UPDUI_MENUBAR)) + UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu); + } + if(bMainMenu) + ::DrawMenuBar(m_UIElements[i].m_hWnd); + } + pMap++; + pUIData->m_wState &= ~UPDUI_MENUBAR; + if(pUIData->m_wState & UPDUI_TEXT) + { + delete [] pUIData->m_lpstrText; + pUIData->m_lpstrText = NULL; + pUIData->m_wState &= ~UPDUI_TEXT; + } + pUIData++; + } + + m_wDirtyType &= ~UPDUI_MENUBAR; + return TRUE; + } +#endif // !_WIN32_WCE + + BOOL UIUpdateToolBar(BOOL bForceUpdate = FALSE) + { + if(!(m_wDirtyType & UPDUI_TOOLBAR) && !bForceUpdate) + return TRUE; + + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + while(pMap->m_nID != (WORD)-1) + { + for(int i = 0; i < m_UIElements.GetSize(); i++) + { + if(m_UIElements[i].m_wType == UPDUI_TOOLBAR) + { + if((pUIData->m_wState & UPDUI_TOOLBAR) && (pMap->m_wType & UPDUI_TOOLBAR)) + UIUpdateToolBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); + } + } + pMap++; + pUIData->m_wState &= ~UPDUI_TOOLBAR; + pUIData++; + } + + m_wDirtyType &= ~UPDUI_TOOLBAR; + return TRUE; + } + + BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE) + { + if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate) + return TRUE; + + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + while(pMap->m_nID != (WORD)-1) + { + for(int i = 0; i < m_UIElements.GetSize(); i++) + { + if(m_UIElements[i].m_wType == UPDUI_STATUSBAR) + { + if((pUIData->m_wState & UPDUI_STATUSBAR) && (pMap->m_wType & UPDUI_STATUSBAR)) + UIUpdateStatusBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); + } + } + pMap++; + pUIData->m_wState &= ~UPDUI_STATUSBAR; + if(pUIData->m_wState & UPDUI_TEXT) + { + delete [] pUIData->m_lpstrText; + pUIData->m_lpstrText = NULL; + pUIData->m_wState &= ~UPDUI_TEXT; + } + pUIData++; + } + + m_wDirtyType &= ~UPDUI_STATUSBAR; + return TRUE; + } + + BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE) + { + if(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate) + return TRUE; + + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + while(pMap->m_nID != (WORD)-1) + { + for(int i = 0; i < m_UIElements.GetSize(); i++) + { + if(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW) + { + if((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW)) + UIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); + } + } + pMap++; + pUIData->m_wState &= ~UPDUI_CHILDWINDOW; + if(pUIData->m_wState & UPDUI_TEXT) + { + delete [] pUIData->m_lpstrText; + pUIData->m_lpstrText = NULL; + pUIData->m_wState &= ~UPDUI_TEXT; + } + pUIData++; + } + + m_wDirtyType &= ~UPDUI_CHILDWINDOW; + return TRUE; + } + +// internal element specific methods + static void UIUpdateMenuBarElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu) + { +#ifndef _WIN32_WCE + if((pUIData->m_wState & UPDUI_CLEARDEFAULT) != 0) + { + ::SetMenuDefaultItem(hMenu, (UINT)-1, 0); + pUIData->m_wState &= ~UPDUI_CLEARDEFAULT; + } +#endif // !_WIN32_WCE + + CMenuItemInfo mii; + mii.fMask = MIIM_STATE; + mii.wID = nID; + +#ifndef _WIN32_WCE + if((pUIData->m_wState & UPDUI_DISABLED) != 0) + mii.fState |= MFS_DISABLED | MFS_GRAYED; + else + mii.fState |= MFS_ENABLED; + + if((pUIData->m_wState & UPDUI_CHECKED) != 0) + mii.fState |= MFS_CHECKED; + else + mii.fState |= MFS_UNCHECKED; + + if((pUIData->m_wState & UPDUI_DEFAULT) != 0) + mii.fState |= MFS_DEFAULT; +#else // CE specific + // ::SetMenuItemInfo() can't disable or check menu items + // on Windows CE, so we have to do that directly + UINT uEnable = MF_BYCOMMAND; + if((pUIData->m_wState & UPDUI_DISABLED) != 0) + uEnable |= MF_GRAYED; + else + uEnable |= MF_ENABLED; + ::EnableMenuItem(hMenu, nID, uEnable); + + UINT uCheck = MF_BYCOMMAND; + if((pUIData->m_wState & UPDUI_CHECKED) != 0) + uCheck |= MF_CHECKED; + else + uCheck |= MF_UNCHECKED; + ::CheckMenuItem(hMenu, nID, uCheck); +#endif // _WIN32_WCE + + if((pUIData->m_wState & UPDUI_TEXT) != 0) + { + CMenuItemInfo miiNow; + miiNow.fMask = MIIM_TYPE; + miiNow.wID = nID; + if(::GetMenuItemInfo(hMenu, nID, FALSE, &miiNow)) + { + mii.fMask |= MIIM_TYPE; + // MFT_BITMAP and MFT_SEPARATOR don't go together with MFT_STRING +#ifndef _WIN32_WCE + mii.fType |= (miiNow.fType & ~(MFT_BITMAP | MFT_SEPARATOR)) | MFT_STRING; +#else // CE specific + mii.fType |= (miiNow.fType & ~(MFT_SEPARATOR)) | MFT_STRING; +#endif // _WIN32_WCE + mii.dwTypeData = pUIData->m_lpstrText; + } + } + + ::SetMenuItemInfo(hMenu, nID, FALSE, &mii); + } + + static void UIUpdateToolBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndToolBar) + { + // Note: only handles enabled/disabled, checked state, and radio (press) + ::SendMessage(hWndToolBar, TB_ENABLEBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE); + ::SendMessage(hWndToolBar, TB_CHECKBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED) ? TRUE : FALSE); + ::SendMessage(hWndToolBar, TB_INDETERMINATE, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED2) ? TRUE : FALSE); + ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_RADIO) ? TRUE : FALSE); + } + + static void UIUpdateStatusBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndStatusBar) + { + // Note: only handles text + if(pUIData->m_wState & UPDUI_TEXT) + ::SendMessage(hWndStatusBar, SB_SETTEXT, nID, (LPARAM)pUIData->m_lpstrText); + } + + static void UIUpdateChildWindow(int nID, _AtlUpdateUIData* pUIData, HWND hWnd) + { + HWND hChild = ::GetDlgItem(hWnd, nID); + + ::EnableWindow(hChild, (pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE); + // for check and radio, assume that window is a button + int nCheck = BST_UNCHECKED; + if(pUIData->m_wState & UPDUI_CHECKED || pUIData->m_wState & UPDUI_RADIO) + nCheck = BST_CHECKED; + else if(pUIData->m_wState & UPDUI_CHECKED2) + nCheck = BST_INDETERMINATE; + ::SendMessage(hChild, BM_SETCHECK, nCheck, 0L); + if(pUIData->m_wState & UPDUI_DEFAULT) + { + DWORD dwRet = (DWORD)::SendMessage(hWnd, DM_GETDEFID, 0, 0L); + if(HIWORD(dwRet) == DC_HASDEFID) + { + HWND hOldDef = ::GetDlgItem(hWnd, (int)(short)LOWORD(dwRet)); + // remove BS_DEFPUSHBUTTON + ::SendMessage(hOldDef, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0)); + } + ::SendMessage(hWnd, DM_SETDEFID, nID, 0L); + } + if(pUIData->m_wState & UPDUI_TEXT) + ::SetWindowText(hChild, pUIData->m_lpstrText); + } +}; + +template +class CUpdateUI : public CUpdateUIBase +{ +public: + CUpdateUI() + { + T* pT = static_cast(this); + pT; + const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap(); + m_pUIMap = pMap; + ATLASSERT(m_pUIMap != NULL); + int nCount = 1; + for( ; pMap->m_nID != (WORD)-1; nCount++) + pMap++; + + // check for duplicates (debug only) +#ifdef _DEBUG + for(int i = 0; i < nCount; i++) + { + for(int j = 0; j < nCount; j++) + { + // shouldn't have duplicates in the update UI map + if(i != j) + ATLASSERT(m_pUIMap[j].m_nID != m_pUIMap[i].m_nID); + } + } +#endif // _DEBUG + + ATLTRY(m_pUIData = new _AtlUpdateUIData[nCount]); + ATLASSERT(m_pUIData != NULL); + + if(m_pUIData != NULL) + memset(m_pUIData, 0, sizeof(_AtlUpdateUIData) * nCount); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CDynamicUpdateUI - allows update elements to dynamically added and removed +// in addition to a static update UI map + +template +class CDynamicUpdateUI : public CUpdateUIBase +{ +public: +// Data members + ATL::CSimpleArray<_AtlUpdateUIMap> m_arrUIMap; // copy of the static UI data + ATL::CSimpleArray<_AtlUpdateUIData> m_arrUIData; // instance UI data + +// Constructor/destructor + CDynamicUpdateUI() + { + T* pT = static_cast(this); + pT; + const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap(); + ATLASSERT(pMap != NULL); + + for(;;) + { + BOOL bRet = m_arrUIMap.Add(*(_AtlUpdateUIMap*)pMap); + ATLASSERT(bRet); + + if(bRet != FALSE) + { + _AtlUpdateUIData data = { 0, NULL }; + bRet = m_arrUIData.Add(data); + ATLASSERT(bRet); + } + + if(pMap->m_nID == (WORD)-1) + break; + + pMap++; + } + + ATLASSERT(m_arrUIMap.GetSize() == m_arrUIData.GetSize()); + +#ifdef _DEBUG + // check for duplicates (debug only) + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + for(int j = 0; j < m_arrUIMap.GetSize(); j++) + { + // shouldn't have duplicates in the update UI map + if(i != j) + ATLASSERT(m_arrUIMap[j].m_nID != m_arrUIMap[i].m_nID); + } + } +#endif // _DEBUG + + // Set internal data pointers to point to the new data arrays + m_pUIMap = m_arrUIMap.m_aT; + m_pUIData = m_arrUIData.m_aT; + } + + ~CDynamicUpdateUI() + { + for(int i = 0; i < m_arrUIData.GetSize(); i++) + { + if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0) + delete [] m_arrUIData[i].m_lpstrText; + } + + // Reset internal data pointers (memory will be released by CSimpleArray d-tor) + m_pUIMap = NULL; + m_pUIData = NULL; + } + +// Methods for dynamically adding and removing update elements + bool UIAddUpdateElement(WORD nID, WORD wType) + { + // check for duplicates + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + // shouldn't have duplicates in the update UI map + ATLASSERT(m_arrUIMap[i].m_nID != nID); + if(m_arrUIMap[i].m_nID == nID) + return false; + } + + bool bRetVal = false; + + // Add new end element + _AtlUpdateUIMap uumEnd = { (WORD)-1, 0 }; + BOOL bRet = m_arrUIMap.Add(uumEnd); + ATLASSERT(bRet); + + if(bRet != FALSE) + { + _AtlUpdateUIData uud = { 0, NULL }; + bRet = m_arrUIData.Add(uud); + ATLASSERT(bRet); + + // Set new data to the previous end element + if(bRet != FALSE) + { + int nSize = m_arrUIMap.GetSize(); + _AtlUpdateUIMap uum = { nID, wType }; + m_arrUIMap.SetAtIndex(nSize - 2, uum); + m_arrUIData.SetAtIndex(nSize - 2, uud); + + // Set internal data pointers again, just in case that memory moved + m_pUIMap = m_arrUIMap.m_aT; + m_pUIData = m_arrUIData.m_aT; + + bRetVal = true; + } + } + + return bRetVal; + } + + bool UIRemoveUpdateElement(WORD nID) + { + bool bRetVal = false; + + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) + { + if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0) + delete [] m_arrUIData[i].m_lpstrText; + + BOOL bRet = m_arrUIMap.RemoveAt(i); + ATLASSERT(bRet); + bRet = m_arrUIData.RemoveAt(i); + ATLASSERT(bRet); + + bRetVal = true; + break; + } + } + + return bRetVal; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAutoUpdateUI : Automatic mapping of UI elements + +template +class CAutoUpdateUI : public CDynamicUpdateUI +{ +public: + LPCTSTR UIGetText(int nID) + { + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) + return m_arrUIData[i].m_lpstrText; + } + + return NULL; + } + +// Element + template + bool UIAddElement(UINT nID) + { + // check for existing UI map element + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) + { + // set requested type + m_arrUIMap[i].m_wType |= t_wType; + return true; + } + } + + // Add element to UI map with requested type + return UIAddUpdateElement((WORD)nID, t_wType); + } + + template + bool UIRemoveElement(UINT nID) + { + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) // matching UI map element + { + WORD wType = m_arrUIMap[i].m_wType & ~t_wType; + if (wType != 0) // has other types + { + m_arrUIMap[i].m_wType = wType; // keep other types + return true; + } + else + { + return UIRemoveUpdateElement((WORD)nID); + } + } + } + + return false; + } + +// Menu + bool UIAddMenu(HMENU hMenu, bool bSetText = false) + { +#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) + using ATL::GetMenuString; +#endif + ATLASSERT(::IsMenu(hMenu)); + MENUITEMINFO mii = {sizeof(MENUITEMINFO), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU}; + + // Complete the UI map + for (INT uItem = 0; CMenuHandle(hMenu).GetMenuItemInfo(uItem, TRUE, &mii); uItem++) + { + if(mii.hSubMenu) + { + // Add submenu to UI map + UIAddMenu(mii.hSubMenu, bSetText); + } + else if (mii.wID != 0) + { + // Add element to UI map + UIAddElement(mii.wID); +#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + if (bSetText) + { + TCHAR sText[64] = { 0 }; + if (GetMenuString(hMenu, uItem, sText, 64, MF_BYPOSITION)) + UISetText(mii.wID, sText); + } +#else + bSetText; +#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + } + } + + return true; + } + + bool UIAddMenu(UINT uID, bool bSetText = false) + { + CMenu menu; + ATLVERIFY(menu.LoadMenu(uID)); + return UIAddMenu(menu, bSetText); + } + +// ToolBar +#if !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX)) + bool UIAddToolBar(HWND hWndToolBar) + { + ATLASSERT(::IsWindow(hWndToolBar)); + TBBUTTONINFO tbbi = { sizeof(TBBUTTONINFO), TBIF_COMMAND | TBIF_STYLE | TBIF_BYINDEX }; + + // Add toolbar buttons + for (int uItem = 0; ::SendMessage(hWndToolBar, TB_GETBUTTONINFO, uItem, (LPARAM)&tbbi) != -1; uItem++) + { + if (tbbi.fsStyle ^ BTNS_SEP) + UIAddElement(tbbi.idCommand); + } + + // Add embedded controls if any + if (::GetWindow(hWndToolBar, GW_CHILD)) + UIAddChildWindowContainer(hWndToolBar); + + return (CUpdateUIBase::UIAddToolBar(hWndToolBar) != FALSE); + } +#endif // !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX)) + +// Container + bool UIAddChildWindowContainer(HWND hWnd) + { + ATLASSERT(::IsWindow(hWnd)); + + // Add children controls if any + for (ATL::CWindow wCtl = ::GetWindow(hWnd, GW_CHILD); wCtl.IsWindow(); wCtl = wCtl.GetWindow(GW_HWNDNEXT)) + { + int id = wCtl.GetDlgCtrlID(); + if(id != 0) + UIAddElement(id); + } + + return (CUpdateUIBase::UIAddChildWindowContainer(hWnd) != FALSE); + } + +// StatusBar + BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE) + { + if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate) + return TRUE; + + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + for(int e = 0; e < m_UIElements.GetSize(); e++) + { + if((m_UIElements[e].m_wType == UPDUI_STATUSBAR) && + (m_arrUIMap[i].m_wType & UPDUI_STATUSBAR) && + (m_arrUIData[i].m_wState & UPDUI_STATUSBAR)) + { + UIUpdateStatusBarElement(m_arrUIMap[i].m_nID, &m_arrUIData[i], m_UIElements[e].m_hWnd); + m_arrUIData[i].m_wState &= ~UPDUI_STATUSBAR; + if(m_arrUIData[i].m_wState & UPDUI_TEXT) + m_arrUIData[i].m_wState &= ~UPDUI_TEXT; + } + } + } + + m_wDirtyType &= ~UPDUI_STATUSBAR; + return TRUE; + } + + bool UIAddStatusBar(HWND hWndStatusBar, INT nPanes = 1) + { + ATLASSERT(::IsWindow(hWndStatusBar)); + + // Add StatusBar panes + for (int iPane = 0; iPane < nPanes; iPane++) + UIAddElement(ID_DEFAULT_PANE + iPane); + + return (CUpdateUIBase::UIAddStatusBar(hWndStatusBar) != FALSE); + } + +// UI Map used if derived class has none + BEGIN_UPDATE_UI_MAP(CAutoUpdateUI) + END_UPDATE_UI_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CDialogResize - provides support for resizing dialog controls +// (works for any window that has child controls) + +// Put CDialogResize in the list of base classes for a dialog (or even plain window), +// then implement DLGRESIZE map by specifying controls and groups of control +// and using DLSZ_* values to specify how are they supposed to be resized. +// +// Notes: +// - Resizeable border (WS_THICKFRAME style) should be set in the dialog template +// for top level dialogs (popup or overlapped), so that users can resize the dialog. +// - Some flags cannot be combined; for instance DLSZ_CENTER_X overrides DLSZ_SIZE_X, +// DLSZ_SIZE_X overrides DLSZ_MOVE_X. X and Y flags can be combined. +// - Order of controls is important - group controls are resized and moved based +// on the position of the previous control in a group. + +// dialog resize map macros +#define BEGIN_DLGRESIZE_MAP(thisClass) \ + static const _AtlDlgResizeMap* GetDlgResizeMap() \ + { \ + static const _AtlDlgResizeMap theMap[] = \ + { + +#define END_DLGRESIZE_MAP() \ + { -1, 0 }, \ + }; \ + return theMap; \ + } + +#define DLGRESIZE_CONTROL(id, flags) \ + { id, flags }, + +#define BEGIN_DLGRESIZE_GROUP() \ + { -1, _DLSZ_BEGIN_GROUP }, + +#define END_DLGRESIZE_GROUP() \ + { -1, _DLSZ_END_GROUP }, + + +template +class CDialogResize +{ +public: +// Data declarations and members + enum + { + DLSZ_SIZE_X = 0x00000001, + DLSZ_SIZE_Y = 0x00000002, + DLSZ_MOVE_X = 0x00000004, + DLSZ_MOVE_Y = 0x00000008, + DLSZ_REPAINT = 0x00000010, + DLSZ_CENTER_X = 0x00000020, + DLSZ_CENTER_Y = 0x00000040, + + // internal use only + _DLSZ_BEGIN_GROUP = 0x00001000, + _DLSZ_END_GROUP = 0x00002000, + _DLSZ_GRIPPER = 0x00004000 + }; + + struct _AtlDlgResizeMap + { + int m_nCtlID; + DWORD m_dwResizeFlags; + }; + + struct _AtlDlgResizeData + { + int m_nCtlID; + DWORD m_dwResizeFlags; + RECT m_rect; + + int GetGroupCount() const + { + return (int)LOBYTE(HIWORD(m_dwResizeFlags)); + } + + void SetGroupCount(int nCount) + { + ATLASSERT(nCount > 0 && nCount < 256); + DWORD dwCount = (DWORD)MAKELONG(0, MAKEWORD(nCount, 0)); + m_dwResizeFlags &= 0xFF00FFFF; + m_dwResizeFlags |= dwCount; + } + + bool operator ==(const _AtlDlgResizeData& r) const + { return (m_nCtlID == r.m_nCtlID && m_dwResizeFlags == r.m_dwResizeFlags); } + }; + + ATL::CSimpleArray<_AtlDlgResizeData> m_arrData; + SIZE m_sizeDialog; + POINT m_ptMinTrackSize; + bool m_bGripper; + + +// Constructor + CDialogResize() : m_bGripper(false) + { + m_sizeDialog.cx = 0; + m_sizeDialog.cy = 0; + m_ptMinTrackSize.x = -1; + m_ptMinTrackSize.y = -1; + } + +// Operations + void DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true, DWORD dwForceStyle = WS_CLIPCHILDREN) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + DWORD dwStyle = pT->GetStyle(); + +#ifdef _DEBUG + // Debug only: Check if top level dialogs have a resizeable border. + if(((dwStyle & WS_CHILD) == 0) && ((dwStyle & WS_THICKFRAME) == 0)) + ATLTRACE2(atlTraceUI, 0, _T("DlgResize_Init - warning: top level dialog without the WS_THICKFRAME style - user cannot resize it\n")); +#endif // _DEBUG + + // Force specified styles (default WS_CLIPCHILDREN reduces flicker) + if((dwStyle & dwForceStyle) != dwForceStyle) + pT->ModifyStyle(0, dwForceStyle); + +#ifndef _WIN32_WCE + // Adding this style removes an empty icon that dialogs with WS_THICKFRAME have. + // Setting icon to NULL is required when XP themes are active. + // Note: This will not prevent adding an icon for the dialog using SetIcon() + if((dwStyle & WS_CHILD) == 0) + { + pT->ModifyStyleEx(0, WS_EX_DLGMODALFRAME); + if(pT->GetIcon(FALSE) == NULL) + pT->SetIcon(NULL, FALSE); + } +#endif + + // Cleanup in case of multiple initialization + // block: first check for the gripper control, destroy it if needed + { + ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); + if(wndGripper.IsWindow() && m_arrData.GetSize() > 0 && (m_arrData[0].m_dwResizeFlags & _DLSZ_GRIPPER) != 0) + wndGripper.DestroyWindow(); + } + // clear out everything else + m_arrData.RemoveAll(); + m_sizeDialog.cx = 0; + m_sizeDialog.cy = 0; + m_ptMinTrackSize.x = -1; + m_ptMinTrackSize.y = -1; + + // Get initial dialog client size + RECT rectDlg = { 0 }; + pT->GetClientRect(&rectDlg); + m_sizeDialog.cx = rectDlg.right; + m_sizeDialog.cy = rectDlg.bottom; + +#ifndef _WIN32_WCE + // Create gripper if requested + m_bGripper = false; + if(bAddGripper) + { + // shouldn't exist already + ATLASSERT(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR))); + if(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR))) + { + ATL::CWindow wndGripper; + wndGripper.Create(_T("SCROLLBAR"), pT->m_hWnd, rectDlg, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEBOX | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, ATL_IDW_STATUS_BAR); + ATLASSERT(wndGripper.IsWindow()); + if(wndGripper.IsWindow()) + { + m_bGripper = true; + RECT rectCtl = { 0 }; + wndGripper.GetWindowRect(&rectCtl); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); + _AtlDlgResizeData data = { ATL_IDW_STATUS_BAR, DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | _DLSZ_GRIPPER, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } }; + m_arrData.Add(data); + } + } + } +#else // CE specific + bAddGripper; // avoid level 4 warning +#endif // _WIN32_WCE + + // Get min track position if requested + if(bUseMinTrackSize) + { + if((dwStyle & WS_CHILD) != 0) + { + RECT rect = { 0 }; + pT->GetClientRect(&rect); + m_ptMinTrackSize.x = rect.right - rect.left; + m_ptMinTrackSize.y = rect.bottom - rect.top; + } + else + { + RECT rect = { 0 }; + pT->GetWindowRect(&rect); + m_ptMinTrackSize.x = rect.right - rect.left; + m_ptMinTrackSize.y = rect.bottom - rect.top; + } + } + + // Walk the map and initialize data + const _AtlDlgResizeMap* pMap = pT->GetDlgResizeMap(); + ATLASSERT(pMap != NULL); + int nGroupStart = -1; + for(int nCount = 1; !(pMap->m_nCtlID == -1 && pMap->m_dwResizeFlags == 0); nCount++, pMap++) + { + if(pMap->m_nCtlID == -1) + { + switch(pMap->m_dwResizeFlags) + { + case _DLSZ_BEGIN_GROUP: + ATLASSERT(nGroupStart == -1); + nGroupStart = m_arrData.GetSize(); + break; + case _DLSZ_END_GROUP: + { + ATLASSERT(nGroupStart != -1); + int nGroupCount = m_arrData.GetSize() - nGroupStart; + m_arrData[nGroupStart].SetGroupCount(nGroupCount); + nGroupStart = -1; + } + break; + default: + ATLASSERT(FALSE && _T("Invalid DLGRESIZE Map Entry")); + break; + } + } + else + { + // this ID conflicts with the default gripper one + ATLASSERT(m_bGripper ? (pMap->m_nCtlID != ATL_IDW_STATUS_BAR) : TRUE); + + ATL::CWindow ctl = pT->GetDlgItem(pMap->m_nCtlID); + ATLASSERT(ctl.IsWindow()); + RECT rectCtl = { 0 }; + ctl.GetWindowRect(&rectCtl); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); + + DWORD dwGroupFlag = (nGroupStart != -1 && m_arrData.GetSize() == nGroupStart) ? _DLSZ_BEGIN_GROUP : 0; + _AtlDlgResizeData data = { pMap->m_nCtlID, pMap->m_dwResizeFlags | dwGroupFlag, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } }; + m_arrData.Add(data); + } + } + ATLASSERT((nGroupStart == -1) && _T("No End Group Entry in the DLGRESIZE Map")); + } + + void DlgResize_UpdateLayout(int cxWidth, int cyHeight) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + // Restrict minimum size if requested + if(((pT->GetStyle() & WS_CHILD) != 0) && m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1) + { + if(cxWidth < m_ptMinTrackSize.x) + cxWidth = m_ptMinTrackSize.x; + if(cyHeight < m_ptMinTrackSize.y) + cyHeight = m_ptMinTrackSize.y; + } + + BOOL bVisible = pT->IsWindowVisible(); + if(bVisible) + pT->SetRedraw(FALSE); + + for(int i = 0; i < m_arrData.GetSize(); i++) + { + if((m_arrData[i].m_dwResizeFlags & _DLSZ_BEGIN_GROUP) != 0) // start of a group + { + int nGroupCount = m_arrData[i].GetGroupCount(); + ATLASSERT(nGroupCount > 0 && i + nGroupCount - 1 < m_arrData.GetSize()); + RECT rectGroup = m_arrData[i].m_rect; + + int j = 1; + for(j = 1; j < nGroupCount; j++) + { + rectGroup.left = __min(rectGroup.left, m_arrData[i + j].m_rect.left); + rectGroup.top = __min(rectGroup.top, m_arrData[i + j].m_rect.top); + rectGroup.right = __max(rectGroup.right, m_arrData[i + j].m_rect.right); + rectGroup.bottom = __max(rectGroup.bottom, m_arrData[i + j].m_rect.bottom); + } + + for(j = 0; j < nGroupCount; j++) + { + _AtlDlgResizeData* pDataPrev = NULL; + if(j > 0) + pDataPrev = &(m_arrData[i + j - 1]); + pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i + j], true, pDataPrev); + } + + i += nGroupCount - 1; // increment to skip all group controls + } + else // one control entry + { + RECT rectGroup = { 0 }; + pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i], false); + } + } + + if(bVisible) + pT->SetRedraw(TRUE); + + pT->RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + } + +// Message map and handlers + BEGIN_MSG_MAP(CDialogResize) + MESSAGE_HANDLER(WM_SIZE, OnSize) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo) +#endif // _WIN32_WCE + END_MSG_MAP() + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); +#ifndef _WIN32_WCE + if(m_bGripper) + { + ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); + if(wParam == SIZE_MAXIMIZED) + wndGripper.ShowWindow(SW_HIDE); + else if(wParam == SIZE_RESTORED) + wndGripper.ShowWindow(SW_SHOW); + } +#endif // _WIN32_WCE + if(wParam != SIZE_MINIMIZED) + { + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DlgResize_UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + } + return 0; + } + +#ifndef _WIN32_WCE + LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + if(m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1) + { + LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; + lpMMI->ptMinTrackSize = m_ptMinTrackSize; + } + return 0; + } +#endif // _WIN32_WCE + +// Implementation + bool DlgResize_PositionControl(int cxWidth, int cyHeight, RECT& rectGroup, _AtlDlgResizeData& data, bool bGroup, + _AtlDlgResizeData* pDataPrev = NULL) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + ATL::CWindow ctl; + RECT rectCtl = { 0 }; + + ctl = pT->GetDlgItem(data.m_nCtlID); + if(!ctl.GetWindowRect(&rectCtl)) + return false; + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); + + if(bGroup) + { + if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0) + { + int cxRight = rectGroup.right + cxWidth - m_sizeDialog.cx; + int cxCtl = data.m_rect.right - data.m_rect.left; + rectCtl.left = rectGroup.left + (cxRight - rectGroup.left - cxCtl) / 2; + rectCtl.right = rectCtl.left + cxCtl; + } + else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0) + { + rectCtl.left = rectGroup.left + ::MulDiv(data.m_rect.left - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left); + + if((data.m_dwResizeFlags & DLSZ_SIZE_X) != 0) + { + rectCtl.right = rectGroup.left + ::MulDiv(data.m_rect.right - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left); + + if(pDataPrev != NULL) + { + ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID); + RECT rcPrev = { 0 }; + ctlPrev.GetWindowRect(&rcPrev); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2); + int dxAdjust = (rectCtl.left - rcPrev.right) - (data.m_rect.left - pDataPrev->m_rect.right); + rcPrev.right += dxAdjust; + ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); + } + } + else + { + rectCtl.right = rectCtl.left + (data.m_rect.right - data.m_rect.left); + } + } + + if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0) + { + int cyBottom = rectGroup.bottom + cyHeight - m_sizeDialog.cy; + int cyCtl = data.m_rect.bottom - data.m_rect.top; + rectCtl.top = rectGroup.top + (cyBottom - rectGroup.top - cyCtl) / 2; + rectCtl.bottom = rectCtl.top + cyCtl; + } + else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0) + { + rectCtl.top = rectGroup.top + ::MulDiv(data.m_rect.top - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top); + + if((data.m_dwResizeFlags & DLSZ_SIZE_Y) != 0) + { + rectCtl.bottom = rectGroup.top + ::MulDiv(data.m_rect.bottom - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top); + + if(pDataPrev != NULL) + { + ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID); + RECT rcPrev = { 0 }; + ctlPrev.GetWindowRect(&rcPrev); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2); + int dxAdjust = (rectCtl.top - rcPrev.bottom) - (data.m_rect.top - pDataPrev->m_rect.bottom); + rcPrev.bottom += dxAdjust; + ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); + } + } + else + { + rectCtl.bottom = rectCtl.top + (data.m_rect.bottom - data.m_rect.top); + } + } + } + else // no group + { + if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0) + { + int cxCtl = data.m_rect.right - data.m_rect.left; + rectCtl.left = (cxWidth - cxCtl) / 2; + rectCtl.right = rectCtl.left + cxCtl; + } + else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0) + { + rectCtl.right = data.m_rect.right + (cxWidth - m_sizeDialog.cx); + + if((data.m_dwResizeFlags & DLSZ_MOVE_X) != 0) + rectCtl.left = rectCtl.right - (data.m_rect.right - data.m_rect.left); + } + + if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0) + { + int cyCtl = data.m_rect.bottom - data.m_rect.top; + rectCtl.top = (cyHeight - cyCtl) / 2; + rectCtl.bottom = rectCtl.top + cyCtl; + } + else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0) + { + rectCtl.bottom = data.m_rect.bottom + (cyHeight - m_sizeDialog.cy); + + if((data.m_dwResizeFlags & DLSZ_MOVE_Y) != 0) + rectCtl.top = rectCtl.bottom - (data.m_rect.bottom - data.m_rect.top); + } + } + + if((data.m_dwResizeFlags & DLSZ_REPAINT) != 0) + ctl.Invalidate(); + + if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y | DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | DLSZ_CENTER_X | DLSZ_CENTER_Y)) != 0) + ctl.SetWindowPos(NULL, &rectCtl, SWP_NOZORDER | SWP_NOACTIVATE); + + return true; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CDoubleBufferImpl - Provides double-buffer painting support to any window + +template +class CDoubleBufferImpl +{ +public: +// Overrideables + void DoPaint(CDCHandle /*dc*/) + { + // must be implemented in a derived class + ATLASSERT(FALSE); + } + +// Message map and handlers + BEGIN_MSG_MAP(CDoubleBufferImpl) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) +#endif // !_WIN32_WCE + END_MSG_MAP() + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background painting needed + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + if(wParam != NULL) + { + RECT rect = { 0 }; + pT->GetClientRect(&rect); + CMemoryDC dcMem((HDC)wParam, rect); + pT->DoPaint(dcMem.m_hDC); + } + else + { + CPaintDC dc(pT->m_hWnd); + CMemoryDC dcMem(dc.m_hDC, dc.m_ps.rcPaint); + pT->DoPaint(dcMem.m_hDC); + } + + return 0; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CDoubleBufferWindowImpl - Implements a double-buffer painting window + +template +class ATL_NO_VTABLE CDoubleBufferWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CDoubleBufferImpl< T > +{ +public: + BEGIN_MSG_MAP(CDoubleBufferWindowImpl) + CHAIN_MSG_MAP(CDoubleBufferImpl< T >) + END_MSG_MAP() +}; + + +// command bar support +#if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) + #undef CBRM_GETMENU + #undef CBRM_TRACKPOPUPMENU + #undef CBRM_GETCMDBAR + #undef CBRPOPUPMENU +#endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) + +}; // namespace WTL + +#endif // __ATLFRAME_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlgdi.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlgdi.h new file mode 100644 index 0000000000000000000000000000000000000000..946e8de6530df0eb9355f3de2a13c691e412f34a --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlgdi.h @@ -0,0 +1,3889 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLGDI_H__ +#define __ATLGDI_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atlgdi.h requires atlapp.h to be included first +#endif + + +// protect template members from windowsx.h macros +#ifdef _INC_WINDOWSX + #undef CopyRgn + #undef CreateBrush + #undef CreatePen + #undef SelectBrush + #undef SelectPen + #undef SelectFont + #undef SelectBitmap +#endif // _INC_WINDOWSX + +// required libraries +#if !defined(_ATL_NO_MSIMG) && !defined(_WIN32_WCE) + #pragma comment(lib, "msimg32.lib") +#endif +#if !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE) + #pragma comment(lib, "opengl32.lib") +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CPenT +// CBrushT +// CLogFont +// CFontT +// CBitmapT +// CPaletteT +// CRgnT +// CDCT +// CPaintDC +// CClientDC +// CWindowDC +// CMemoryDC +// CEnhMetaFileInfo +// CEnhMetaFileT +// CEnhMetaFileDC +// +// Global functions: +// AtlGetBitmapResourceInfo() +// AtlGetBitmapResourceBitsPerPixel() +// AtlIsAlphaBitmapResource() +// AtlIsDib16() +// AtlGetDibColorTableSize() +// AtlGetDibNumColors(), +// AtlGetDibBitmap() +// AtlCopyBitmap() +// AtlCreatePackedDib16() +// AtlSetClipboardDib16() +// AtlGetClipboardDib() + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// Bitmap resource helpers to extract bitmap information for a bitmap resource + +inline LPBITMAPINFOHEADER AtlGetBitmapResourceInfo(HMODULE hModule, ATL::_U_STRINGorID image) +{ + HRSRC hResource = ::FindResource(hModule, image.m_lpstr, RT_BITMAP); + ATLASSERT(hResource != NULL); + HGLOBAL hGlobal = ::LoadResource(hModule, hResource); + ATLASSERT(hGlobal != NULL); + LPBITMAPINFOHEADER pBitmapInfoHeader = (LPBITMAPINFOHEADER)::LockResource(hGlobal); + ATLASSERT(pBitmapInfoHeader != NULL); + return pBitmapInfoHeader; +} + +inline WORD AtlGetBitmapResourceBitsPerPixel(HMODULE hModule, ATL::_U_STRINGorID image) +{ + LPBITMAPINFOHEADER pBitmapInfoHeader = AtlGetBitmapResourceInfo(hModule, image); + ATLASSERT(pBitmapInfoHeader != NULL); + return pBitmapInfoHeader->biBitCount; +} + +inline WORD AtlGetBitmapResourceBitsPerPixel(ATL::_U_STRINGorID image) +{ + return AtlGetBitmapResourceBitsPerPixel(ModuleHelper::GetResourceInstance(), image); +} + +/////////////////////////////////////////////////////////////////////////////// +// 32-bit (alpha channel) bitmap resource helper + +// Note: 32-bit (alpha channel) images work only on Windows XP with Common Controls version 6. +// If you want your app to work on older version of Windows, load non-alpha images if Common +// Controls version is less than 6. + +inline bool AtlIsAlphaBitmapResource(ATL::_U_STRINGorID image) +{ + return (AtlGetBitmapResourceBitsPerPixel(image) == 32); +} + + +/////////////////////////////////////////////////////////////////////////////// +// CPen + +template +class CPenT +{ +public: +// Data members + HPEN m_hPen; + +// Constructor/destructor/operators + CPenT(HPEN hPen = NULL) : m_hPen(hPen) + { } + + ~CPenT() + { + if(t_bManaged && m_hPen != NULL) + DeleteObject(); + } + + CPenT& operator =(HPEN hPen) + { + Attach(hPen); + return *this; + } + + void Attach(HPEN hPen) + { + if(t_bManaged && m_hPen != NULL && m_hPen != hPen) + ::DeleteObject(m_hPen); + m_hPen = hPen; + } + + HPEN Detach() + { + HPEN hPen = m_hPen; + m_hPen = NULL; + return hPen; + } + + operator HPEN() const { return m_hPen; } + + bool IsNull() const { return (m_hPen == NULL); } + +// Create methods + HPEN CreatePen(int nPenStyle, int nWidth, COLORREF crColor) + { + ATLASSERT(m_hPen == NULL); + m_hPen = ::CreatePen(nPenStyle, nWidth, crColor); + return m_hPen; + } + +#ifndef _WIN32_WCE + HPEN CreatePen(int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount = 0, const DWORD* lpStyle = NULL) + { + ATLASSERT(m_hPen == NULL); + m_hPen = ::ExtCreatePen(nPenStyle, nWidth, pLogBrush, nStyleCount, lpStyle); + return m_hPen; + } +#endif // !_WIN32_WCE + + HPEN CreatePenIndirect(LPLOGPEN lpLogPen) + { + ATLASSERT(m_hPen == NULL); + m_hPen = ::CreatePenIndirect(lpLogPen); + return m_hPen; + } + + BOOL DeleteObject() + { + ATLASSERT(m_hPen != NULL); + BOOL bRet = ::DeleteObject(m_hPen); + if(bRet) + m_hPen = NULL; + return bRet; + } + +// Attributes + int GetLogPen(LOGPEN* pLogPen) const + { + ATLASSERT(m_hPen != NULL); + return ::GetObject(m_hPen, sizeof(LOGPEN), pLogPen); + } + + bool GetLogPen(LOGPEN& LogPen) const + { + ATLASSERT(m_hPen != NULL); + return (::GetObject(m_hPen, sizeof(LOGPEN), &LogPen) == sizeof(LOGPEN)); + } + +#ifndef _WIN32_WCE + int GetExtLogPen(EXTLOGPEN* pLogPen, int nSize = sizeof(EXTLOGPEN)) const + { + ATLASSERT(m_hPen != NULL); + return ::GetObject(m_hPen, nSize, pLogPen); + } + + bool GetExtLogPen(EXTLOGPEN& ExtLogPen, int nSize = sizeof(EXTLOGPEN)) const + { + ATLASSERT(m_hPen != NULL); + int nRet = ::GetObject(m_hPen, nSize, &ExtLogPen); + return ((nRet > 0) && (nRet <= nSize)); + } +#endif // !_WIN32_WCE +}; + +typedef CPenT CPenHandle; +typedef CPenT CPen; + + +/////////////////////////////////////////////////////////////////////////////// +// CBrush + +template +class CBrushT +{ +public: +// Data members + HBRUSH m_hBrush; + +// Constructor/destructor/operators + CBrushT(HBRUSH hBrush = NULL) : m_hBrush(hBrush) + { } + + ~CBrushT() + { + if(t_bManaged && m_hBrush != NULL) + DeleteObject(); + } + + CBrushT& operator =(HBRUSH hBrush) + { + Attach(hBrush); + return *this; + } + + void Attach(HBRUSH hBrush) + { + if(t_bManaged && m_hBrush != NULL && m_hBrush != hBrush) + ::DeleteObject(m_hBrush); + m_hBrush = hBrush; + } + + HBRUSH Detach() + { + HBRUSH hBrush = m_hBrush; + m_hBrush = NULL; + return hBrush; + } + + operator HBRUSH() const { return m_hBrush; } + + bool IsNull() const { return (m_hBrush == NULL); } + +// Create methods + HBRUSH CreateSolidBrush(COLORREF crColor) + { + ATLASSERT(m_hBrush == NULL); + m_hBrush = ::CreateSolidBrush(crColor); + return m_hBrush; + } + +#ifndef _WIN32_WCE + HBRUSH CreateHatchBrush(int nIndex, COLORREF crColor) + { + ATLASSERT(m_hBrush == NULL); + m_hBrush = ::CreateHatchBrush(nIndex, crColor); + return m_hBrush; + } +#endif // !_WIN32_WCE + +#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + HBRUSH CreateBrushIndirect(const LOGBRUSH* lpLogBrush) + { + ATLASSERT(m_hBrush == NULL); +#ifndef _WIN32_WCE + m_hBrush = ::CreateBrushIndirect(lpLogBrush); +#else // CE specific + m_hBrush = ATL::CreateBrushIndirect(lpLogBrush); +#endif // _WIN32_WCE + return m_hBrush; + } +#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + + HBRUSH CreatePatternBrush(HBITMAP hBitmap) + { + ATLASSERT(m_hBrush == NULL); + m_hBrush = ::CreatePatternBrush(hBitmap); + return m_hBrush; + } + + HBRUSH CreateDIBPatternBrush(HGLOBAL hPackedDIB, UINT nUsage) + { + ATLASSERT(hPackedDIB != NULL); + const void* lpPackedDIB = GlobalLock(hPackedDIB); + ATLASSERT(lpPackedDIB != NULL); + m_hBrush = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage); + GlobalUnlock(hPackedDIB); + return m_hBrush; + } + + HBRUSH CreateDIBPatternBrush(const void* lpPackedDIB, UINT nUsage) + { + ATLASSERT(m_hBrush == NULL); + m_hBrush = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage); + return m_hBrush; + } + + HBRUSH CreateSysColorBrush(int nIndex) + { + ATLASSERT(m_hBrush == NULL); + m_hBrush = ::GetSysColorBrush(nIndex); + return m_hBrush; + } + + BOOL DeleteObject() + { + ATLASSERT(m_hBrush != NULL); + BOOL bRet = ::DeleteObject(m_hBrush); + if(bRet) + m_hBrush = NULL; + return bRet; + } + +// Attributes + int GetLogBrush(LOGBRUSH* pLogBrush) const + { + ATLASSERT(m_hBrush != NULL); + return ::GetObject(m_hBrush, sizeof(LOGBRUSH), pLogBrush); + } + + bool GetLogBrush(LOGBRUSH& LogBrush) const + { + ATLASSERT(m_hBrush != NULL); + return (::GetObject(m_hBrush, sizeof(LOGBRUSH), &LogBrush) == sizeof(LOGBRUSH)); + } +}; + +typedef CBrushT CBrushHandle; +typedef CBrushT CBrush; + + +/////////////////////////////////////////////////////////////////////////////// +// CFont + +class CLogFont : public LOGFONT +{ +public: + CLogFont() + { + memset(this, 0, sizeof(LOGFONT)); + } + + CLogFont(const LOGFONT& lf) + { + Copy(&lf); + } + + CLogFont(HFONT hFont) + { + ATLASSERT(::GetObjectType(hFont) == OBJ_FONT); + ::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this); + } + + HFONT CreateFontIndirect() + { + return ::CreateFontIndirect(this); + } + + void SetBold() + { + lfWeight = FW_BOLD; + } + + bool IsBold() const + { + return (lfWeight >= FW_BOLD); + } + + void MakeBolder(int iScale = 1) + { + lfWeight += FW_BOLD * iScale; + } + + void MakeLarger(int iScale) + { + if(lfHeight > 0) + lfHeight += iScale; + else + lfHeight -= iScale; + } + + void SetHeight(LONG nPointSize, HDC hDC = NULL) + { + HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); + // For MM_TEXT mapping mode + lfHeight = -::MulDiv(nPointSize, ::GetDeviceCaps(hDC1, LOGPIXELSY), 72); + if(hDC == NULL) + ::ReleaseDC(NULL, hDC1); + } + + LONG GetHeight(HDC hDC = NULL) const + { + HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); + // For MM_TEXT mapping mode + LONG nPointSize = ::MulDiv(-lfHeight, 72, ::GetDeviceCaps(hDC1, LOGPIXELSY)); + if(hDC == NULL) + ::ReleaseDC(NULL, hDC1); + + return nPointSize; + } + + LONG GetDeciPointHeight(HDC hDC = NULL) const + { + HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); +#ifndef _WIN32_WCE + POINT ptOrg = { 0, 0 }; + ::DPtoLP(hDC1, &ptOrg, 1); + POINT pt = { 0, 0 }; + pt.y = abs(lfHeight) + ptOrg.y; + ::LPtoDP(hDC1, &pt,1); + LONG nDeciPoint = ::MulDiv(pt.y, 720, ::GetDeviceCaps(hDC1, LOGPIXELSY)); // 72 points/inch, 10 decipoints/point +#else // CE specific + // DP and LP are always the same on CE + LONG nDeciPoint = ::MulDiv(abs(lfHeight), 720, ::GetDeviceCaps(hDC1, LOGPIXELSY)); // 72 points/inch, 10 decipoints/point +#endif // _WIN32_WCE + if(hDC == NULL) + ::ReleaseDC(NULL, hDC1); + + return nDeciPoint; + } + + void SetHeightFromDeciPoint(LONG nDeciPtHeight, HDC hDC = NULL) + { + HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); +#ifndef _WIN32_WCE + POINT pt = { 0, 0 }; + pt.y = ::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), nDeciPtHeight, 720); // 72 points/inch, 10 decipoints/point + ::DPtoLP(hDC1, &pt, 1); + POINT ptOrg = { 0, 0 }; + ::DPtoLP(hDC1, &ptOrg, 1); + lfHeight = -abs(pt.y - ptOrg.y); +#else // CE specific + // DP and LP are always the same on CE + lfHeight = -abs(::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), nDeciPtHeight, 720)); // 72 points/inch, 10 decipoints/point +#endif // _WIN32_WCE + if(hDC == NULL) + ::ReleaseDC(NULL, hDC1); + } + +#ifndef _WIN32_WCE + void SetCaptionFont() + { + NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; + ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)); + Copy(&ncm.lfCaptionFont); + } + + void SetMenuFont() + { + NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; + ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)); + Copy(&ncm.lfMenuFont); + } + + void SetStatusFont() + { + NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; + ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)); + Copy(&ncm.lfStatusFont); + } + + void SetMessageBoxFont() + { + NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; + ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)); + Copy(&ncm.lfMessageFont); + } +#endif // !_WIN32_WCE + + void Copy(const LOGFONT* pLogFont) + { + ATLASSERT(pLogFont != NULL); + *(LOGFONT*)this = *pLogFont; + } + + CLogFont& operator =(const CLogFont& src) + { + Copy(&src); + return *this; + } + + CLogFont& operator =(const LOGFONT& src) + { + Copy(&src); + return *this; + } + + CLogFont& operator =(HFONT hFont) + { + ATLASSERT(::GetObjectType(hFont) == OBJ_FONT); + ::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this); + return *this; + } + + bool operator ==(const LOGFONT& logfont) const + { + return(logfont.lfHeight == lfHeight && + logfont.lfWidth == lfWidth && + logfont.lfEscapement == lfEscapement && + logfont.lfOrientation == lfOrientation && + logfont.lfWeight == lfWeight && + logfont.lfItalic == lfItalic && + logfont.lfUnderline == lfUnderline && + logfont.lfStrikeOut == lfStrikeOut && + logfont.lfCharSet == lfCharSet && + logfont.lfOutPrecision == lfOutPrecision && + logfont.lfClipPrecision == lfClipPrecision && + logfont.lfQuality == lfQuality && + logfont.lfPitchAndFamily == lfPitchAndFamily && + lstrcmp(logfont.lfFaceName, lfFaceName) == 0); + } +}; + + +template +class CFontT +{ +public: +// Data members + HFONT m_hFont; + +// Constructor/destructor/operators + CFontT(HFONT hFont = NULL) : m_hFont(hFont) + { } + + ~CFontT() + { + if(t_bManaged && m_hFont != NULL) + DeleteObject(); + } + + CFontT& operator =(HFONT hFont) + { + Attach(hFont); + return *this; + } + + void Attach(HFONT hFont) + { + if(t_bManaged && m_hFont != NULL && m_hFont != hFont) + ::DeleteObject(m_hFont); + m_hFont = hFont; + } + + HFONT Detach() + { + HFONT hFont = m_hFont; + m_hFont = NULL; + return hFont; + } + + operator HFONT() const { return m_hFont; } + + bool IsNull() const { return (m_hFont == NULL); } + +// Create methods + HFONT CreateFontIndirect(const LOGFONT* lpLogFont) + { + ATLASSERT(m_hFont == NULL); + m_hFont = ::CreateFontIndirect(lpLogFont); + return m_hFont; + } + +#if !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0500) + HFONT CreateFontIndirectEx(CONST ENUMLOGFONTEXDV* penumlfex) + { + ATLASSERT(m_hFont == NULL); + m_hFont = ::CreateFontIndirectEx(penumlfex); + return m_hFont; + } +#endif // !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0500) + +#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + HFONT CreateFont(int nHeight, int nWidth, int nEscapement, + int nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline, + BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision, + BYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily, + LPCTSTR lpszFacename) + { + ATLASSERT(m_hFont == NULL); +#ifndef _WIN32_WCE + m_hFont = ::CreateFont(nHeight, nWidth, nEscapement, + nOrientation, nWeight, bItalic, bUnderline, cStrikeOut, + nCharSet, nOutPrecision, nClipPrecision, nQuality, + nPitchAndFamily, lpszFacename); +#else // CE specific + m_hFont = ATL::CreateFont(nHeight, nWidth, nEscapement, + nOrientation, nWeight, bItalic, bUnderline, cStrikeOut, + nCharSet, nOutPrecision, nClipPrecision, nQuality, + nPitchAndFamily, lpszFacename); +#endif // _WIN32_WCE + return m_hFont; + } +#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + + HFONT CreatePointFont(int nPointSize, LPCTSTR lpszFaceName, HDC hDC = NULL, bool bBold = false, bool bItalic = false) + { + LOGFONT logFont = { 0 }; + logFont.lfCharSet = DEFAULT_CHARSET; + logFont.lfHeight = nPointSize; + SecureHelper::strncpy_x(logFont.lfFaceName, _countof(logFont.lfFaceName), lpszFaceName, _TRUNCATE); + + if(bBold) + logFont.lfWeight = FW_BOLD; + if(bItalic) + logFont.lfItalic = (BYTE)TRUE; + + return CreatePointFontIndirect(&logFont, hDC); + } + + HFONT CreatePointFontIndirect(const LOGFONT* lpLogFont, HDC hDC = NULL) + { + HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); + + // convert nPointSize to logical units based on hDC + LOGFONT logFont = *lpLogFont; +#ifndef _WIN32_WCE + POINT pt = { 0, 0 }; + pt.y = ::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), logFont.lfHeight, 720); // 72 points/inch, 10 decipoints/point + ::DPtoLP(hDC1, &pt, 1); + POINT ptOrg = { 0, 0 }; + ::DPtoLP(hDC1, &ptOrg, 1); + logFont.lfHeight = -abs(pt.y - ptOrg.y); +#else // CE specific + // DP and LP are always the same on CE + logFont.lfHeight = -abs(::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), logFont.lfHeight, 720)); // 72 points/inch, 10 decipoints/point +#endif // _WIN32_WCE + + if(hDC == NULL) + ::ReleaseDC(NULL, hDC1); + + return CreateFontIndirect(&logFont); + } + + BOOL DeleteObject() + { + ATLASSERT(m_hFont != NULL); + BOOL bRet = ::DeleteObject(m_hFont); + if(bRet) + m_hFont = NULL; + return bRet; + } + +// Attributes + int GetLogFont(LOGFONT* pLogFont) const + { + ATLASSERT(m_hFont != NULL); + return ::GetObject(m_hFont, sizeof(LOGFONT), pLogFont); + } + + bool GetLogFont(LOGFONT& LogFont) const + { + ATLASSERT(m_hFont != NULL); + return (::GetObject(m_hFont, sizeof(LOGFONT), &LogFont) == sizeof(LOGFONT)); + } +}; + +typedef CFontT CFontHandle; +typedef CFontT CFont; + + +/////////////////////////////////////////////////////////////////////////////// +// CBitmap + +template +class CBitmapT +{ +public: +// Data members + HBITMAP m_hBitmap; + +// Constructor/destructor/operators + CBitmapT(HBITMAP hBitmap = NULL) : m_hBitmap(hBitmap) + { } + + ~CBitmapT() + { + if(t_bManaged && m_hBitmap != NULL) + DeleteObject(); + } + + CBitmapT& operator =(HBITMAP hBitmap) + { + Attach(hBitmap); + return *this; + } + + void Attach(HBITMAP hBitmap) + { + if(t_bManaged && m_hBitmap != NULL&& m_hBitmap != hBitmap) + ::DeleteObject(m_hBitmap); + m_hBitmap = hBitmap; + } + + HBITMAP Detach() + { + HBITMAP hBitmap = m_hBitmap; + m_hBitmap = NULL; + return hBitmap; + } + + operator HBITMAP() const { return m_hBitmap; } + + bool IsNull() const { return (m_hBitmap == NULL); } + +// Create and load methods + HBITMAP LoadBitmap(ATL::_U_STRINGorID bitmap) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr); + return m_hBitmap; + } + + HBITMAP LoadOEMBitmap(UINT nIDBitmap) // for OBM_/OCR_/OIC_ + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::LoadBitmap(NULL, MAKEINTRESOURCE(nIDBitmap)); + return m_hBitmap; + } + +#ifndef _WIN32_WCE + HBITMAP LoadMappedBitmap(UINT nIDBitmap, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateMappedBitmap(ModuleHelper::GetResourceInstance(), nIDBitmap, (WORD)nFlags, lpColorMap, nMapSize); + return m_hBitmap; + } +#endif // !_WIN32_WCE + + HBITMAP CreateBitmap(int nWidth, int nHeight, UINT nPlanes, UINT nBitsPerPixel, const void* lpBits) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateBitmap(nWidth, nHeight, nPlanes, nBitsPerPixel, lpBits); + return m_hBitmap; + } + +#ifndef _WIN32_WCE + HBITMAP CreateBitmapIndirect(LPBITMAP lpBitmap) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateBitmapIndirect(lpBitmap); + return m_hBitmap; + } +#endif // !_WIN32_WCE + + HBITMAP CreateCompatibleBitmap(HDC hDC, int nWidth, int nHeight) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateCompatibleBitmap(hDC, nWidth, nHeight); + return m_hBitmap; + } + +#ifndef _WIN32_WCE + HBITMAP CreateDiscardableBitmap(HDC hDC, int nWidth, int nHeight) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateDiscardableBitmap(hDC, nWidth, nHeight); + return m_hBitmap; + } +#endif // !_WIN32_WCE + + BOOL DeleteObject() + { + ATLASSERT(m_hBitmap != NULL); + BOOL bRet = ::DeleteObject(m_hBitmap); + if(bRet) + m_hBitmap = NULL; + return bRet; + } + +// Attributes + int GetBitmap(BITMAP* pBitMap) const + { + ATLASSERT(m_hBitmap != NULL); + return ::GetObject(m_hBitmap, sizeof(BITMAP), pBitMap); + } + + bool GetBitmap(BITMAP& bm) const + { + ATLASSERT(m_hBitmap != NULL); + return (::GetObject(m_hBitmap, sizeof(BITMAP), &bm) == sizeof(BITMAP)); + } + + bool GetSize(SIZE& size) const + { + ATLASSERT(m_hBitmap != NULL); + BITMAP bm = { 0 }; + if(!GetBitmap(&bm)) + return false; + size.cx = bm.bmWidth; + size.cy = bm.bmHeight; + return true; + } + +#ifndef _WIN32_WCE + DWORD GetBitmapBits(DWORD dwCount, LPVOID lpBits) const + { + ATLASSERT(m_hBitmap != NULL); + return ::GetBitmapBits(m_hBitmap, dwCount, lpBits); + } +#endif // !_WIN32_WCE + +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 410) + DWORD SetBitmapBits(DWORD dwCount, const void* lpBits) + { + ATLASSERT(m_hBitmap != NULL); + return ::SetBitmapBits(m_hBitmap, dwCount, lpBits); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 410) + +#ifndef _WIN32_WCE + BOOL GetBitmapDimension(LPSIZE lpSize) const + { + ATLASSERT(m_hBitmap != NULL); + return ::GetBitmapDimensionEx(m_hBitmap, lpSize); + } + + BOOL SetBitmapDimension(int nWidth, int nHeight, LPSIZE lpSize = NULL) + { + ATLASSERT(m_hBitmap != NULL); + return ::SetBitmapDimensionEx(m_hBitmap, nWidth, nHeight, lpSize); + } + +// DIB support + HBITMAP CreateDIBitmap(HDC hDC, CONST BITMAPINFOHEADER* lpbmih, DWORD dwInit, CONST VOID* lpbInit, CONST BITMAPINFO* lpbmi, UINT uColorUse) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateDIBitmap(hDC, lpbmih, dwInit, lpbInit, lpbmi, uColorUse); + return m_hBitmap; + } +#endif // !_WIN32_WCE + + HBITMAP CreateDIBSection(HDC hDC, CONST BITMAPINFO* lpbmi, UINT uColorUse, VOID** ppvBits, HANDLE hSection, DWORD dwOffset) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateDIBSection(hDC, lpbmi, uColorUse, ppvBits, hSection, dwOffset); + return m_hBitmap; + } + +#ifndef _WIN32_WCE + int GetDIBits(HDC hDC, UINT uStartScan, UINT cScanLines, LPVOID lpvBits, LPBITMAPINFO lpbmi, UINT uColorUse) const + { + ATLASSERT(m_hBitmap != NULL); + return ::GetDIBits(hDC, m_hBitmap, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse); + } + + int SetDIBits(HDC hDC, UINT uStartScan, UINT cScanLines, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse) + { + ATLASSERT(m_hBitmap != NULL); + return ::SetDIBits(hDC, m_hBitmap, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse); + } +#endif // !_WIN32_WCE +}; + +typedef CBitmapT CBitmapHandle; +typedef CBitmapT CBitmap; + + +/////////////////////////////////////////////////////////////////////////////// +// CPalette + +template +class CPaletteT +{ +public: +// Data members + HPALETTE m_hPalette; + +// Constructor/destructor/operators + CPaletteT(HPALETTE hPalette = NULL) : m_hPalette(hPalette) + { } + + ~CPaletteT() + { + if(t_bManaged && m_hPalette != NULL) + DeleteObject(); + } + + CPaletteT& operator =(HPALETTE hPalette) + { + Attach(hPalette); + return *this; + } + + void Attach(HPALETTE hPalette) + { + if(t_bManaged && m_hPalette != NULL && m_hPalette != hPalette) + ::DeleteObject(m_hPalette); + m_hPalette = hPalette; + } + + HPALETTE Detach() + { + HPALETTE hPalette = m_hPalette; + m_hPalette = NULL; + return hPalette; + } + + operator HPALETTE() const { return m_hPalette; } + + bool IsNull() const { return (m_hPalette == NULL); } + +// Create methods + HPALETTE CreatePalette(LPLOGPALETTE lpLogPalette) + { + ATLASSERT(m_hPalette == NULL); + m_hPalette = ::CreatePalette(lpLogPalette); + return m_hPalette; + } + +#ifndef _WIN32_WCE + HPALETTE CreateHalftonePalette(HDC hDC) + { + ATLASSERT(m_hPalette == NULL); + ATLASSERT(hDC != NULL); + m_hPalette = ::CreateHalftonePalette(hDC); + return m_hPalette; + } +#endif // !_WIN32_WCE + + BOOL DeleteObject() + { + ATLASSERT(m_hPalette != NULL); + BOOL bRet = ::DeleteObject(m_hPalette); + if(bRet) + m_hPalette = NULL; + return bRet; + } + +// Attributes + int GetEntryCount() const + { + ATLASSERT(m_hPalette != NULL); + WORD nEntries = 0; + ::GetObject(m_hPalette, sizeof(WORD), &nEntries); + return (int)nEntries; + } + + UINT GetPaletteEntries(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors) const + { + ATLASSERT(m_hPalette != NULL); + return ::GetPaletteEntries(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors); + } + + UINT SetPaletteEntries(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors) + { + ATLASSERT(m_hPalette != NULL); + return ::SetPaletteEntries(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors); + } + +// Operations +#ifndef _WIN32_WCE + void AnimatePalette(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors) + { + ATLASSERT(m_hPalette != NULL); + ::AnimatePalette(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors); + } + + BOOL ResizePalette(UINT nNumEntries) + { + ATLASSERT(m_hPalette != NULL); + return ::ResizePalette(m_hPalette, nNumEntries); + } +#endif // !_WIN32_WCE + + UINT GetNearestPaletteIndex(COLORREF crColor) const + { + ATLASSERT(m_hPalette != NULL); + return ::GetNearestPaletteIndex(m_hPalette, crColor); + } +}; + +typedef CPaletteT CPaletteHandle; +typedef CPaletteT CPalette; + + +/////////////////////////////////////////////////////////////////////////////// +// CRgn + +template +class CRgnT +{ +public: +// Data members + HRGN m_hRgn; + +// Constructor/destructor/operators + CRgnT(HRGN hRgn = NULL) : m_hRgn(hRgn) + { } + + ~CRgnT() + { + if(t_bManaged && m_hRgn != NULL) + DeleteObject(); + } + + CRgnT& operator =(HRGN hRgn) + { + Attach(hRgn); + return *this; + } + + void Attach(HRGN hRgn) + { + if(t_bManaged && m_hRgn != NULL && m_hRgn != hRgn) + ::DeleteObject(m_hRgn); + m_hRgn = hRgn; + } + + HRGN Detach() + { + HRGN hRgn = m_hRgn; + m_hRgn = NULL; + return hRgn; + } + + operator HRGN() const { return m_hRgn; } + + bool IsNull() const { return (m_hRgn == NULL); } + +// Create methods + HRGN CreateRectRgn(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreateRectRgn(x1, y1, x2, y2); + return m_hRgn; + } + + HRGN CreateRectRgnIndirect(LPCRECT lpRect) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreateRectRgnIndirect(lpRect); + return m_hRgn; + } + +#ifndef _WIN32_WCE + HRGN CreateEllipticRgn(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreateEllipticRgn(x1, y1, x2, y2); + return m_hRgn; + } + + HRGN CreateEllipticRgnIndirect(LPCRECT lpRect) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreateEllipticRgnIndirect(lpRect); + return m_hRgn; + } + + HRGN CreatePolygonRgn(LPPOINT lpPoints, int nCount, int nMode) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreatePolygonRgn(lpPoints, nCount, nMode); + return m_hRgn; + } + + HRGN CreatePolyPolygonRgn(LPPOINT lpPoints, LPINT lpPolyCounts, int nCount, int nPolyFillMode) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreatePolyPolygonRgn(lpPoints, lpPolyCounts, nCount, nPolyFillMode); + return m_hRgn; + } + + HRGN CreateRoundRectRgn(int x1, int y1, int x2, int y2, int x3, int y3) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreateRoundRectRgn(x1, y1, x2, y2, x3, y3); + return m_hRgn; + } + + HRGN CreateFromPath(HDC hDC) + { + ATLASSERT(m_hRgn == NULL); + ATLASSERT(hDC != NULL); + m_hRgn = ::PathToRegion(hDC); + return m_hRgn; + } + + HRGN CreateFromData(const XFORM* lpXForm, int nCount, const RGNDATA* pRgnData) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::ExtCreateRegion(lpXForm, nCount, pRgnData); + return m_hRgn; + } +#endif // !_WIN32_WCE + + BOOL DeleteObject() + { + ATLASSERT(m_hRgn != NULL); + BOOL bRet = ::DeleteObject(m_hRgn); + if(bRet) + m_hRgn = NULL; + return bRet; + } + +// Operations + void SetRectRgn(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hRgn != NULL); + ::SetRectRgn(m_hRgn, x1, y1, x2, y2); + } + + void SetRectRgn(LPCRECT lpRect) + { + ATLASSERT(m_hRgn != NULL); + ::SetRectRgn(m_hRgn, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + + int CombineRgn(HRGN hRgnSrc1, HRGN hRgnSrc2, int nCombineMode) + { + ATLASSERT(m_hRgn != NULL); + return ::CombineRgn(m_hRgn, hRgnSrc1, hRgnSrc2, nCombineMode); + } + + int CombineRgn(HRGN hRgnSrc, int nCombineMode) + { + ATLASSERT(m_hRgn != NULL); + return ::CombineRgn(m_hRgn, m_hRgn, hRgnSrc, nCombineMode); + } + + int CopyRgn(HRGN hRgnSrc) + { + ATLASSERT(m_hRgn != NULL); + return ::CombineRgn(m_hRgn, hRgnSrc, NULL, RGN_COPY); + } + + BOOL EqualRgn(HRGN hRgn) const + { + ATLASSERT(m_hRgn != NULL); + return ::EqualRgn(m_hRgn, hRgn); + } + + int OffsetRgn(int x, int y) + { + ATLASSERT(m_hRgn != NULL); + return ::OffsetRgn(m_hRgn, x, y); + } + + int OffsetRgn(POINT point) + { + ATLASSERT(m_hRgn != NULL); + return ::OffsetRgn(m_hRgn, point.x, point.y); + } + + int GetRgnBox(LPRECT lpRect) const + { + ATLASSERT(m_hRgn != NULL); + return ::GetRgnBox(m_hRgn, lpRect); + } + + BOOL PtInRegion(int x, int y) const + { + ATLASSERT(m_hRgn != NULL); + return ::PtInRegion(m_hRgn, x, y); + } + + BOOL PtInRegion(POINT point) const + { + ATLASSERT(m_hRgn != NULL); + return ::PtInRegion(m_hRgn, point.x, point.y); + } + + BOOL RectInRegion(LPCRECT lpRect) const + { + ATLASSERT(m_hRgn != NULL); + return ::RectInRegion(m_hRgn, lpRect); + } + + int GetRegionData(LPRGNDATA lpRgnData, int nDataSize) const + { + ATLASSERT(m_hRgn != NULL); + return (int)::GetRegionData(m_hRgn, nDataSize, lpRgnData); + } +}; + +typedef CRgnT CRgnHandle; +typedef CRgnT CRgn; + + +/////////////////////////////////////////////////////////////////////////////// +// CDC - The device context class + +template +class CDCT +{ +public: +// Data members + HDC m_hDC; + +// Constructor/destructor/operators + CDCT(HDC hDC = NULL) : m_hDC(hDC) + { + } + + ~CDCT() + { + if(t_bManaged && m_hDC != NULL) + ::DeleteDC(Detach()); + } + + CDCT& operator =(HDC hDC) + { + Attach(hDC); + return *this; + } + + void Attach(HDC hDC) + { + if(t_bManaged && m_hDC != NULL && m_hDC != hDC) + ::DeleteDC(m_hDC); + m_hDC = hDC; + } + + HDC Detach() + { + HDC hDC = m_hDC; + m_hDC = NULL; + return hDC; + } + + operator HDC() const { return m_hDC; } + + bool IsNull() const { return (m_hDC == NULL); } + +// Operations +#ifndef _WIN32_WCE + HWND WindowFromDC() const + { + ATLASSERT(m_hDC != NULL); + return ::WindowFromDC(m_hDC); + } +#endif // !_WIN32_WCE + + CPenHandle GetCurrentPen() const + { + ATLASSERT(m_hDC != NULL); + return CPenHandle((HPEN)::GetCurrentObject(m_hDC, OBJ_PEN)); + } + + CBrushHandle GetCurrentBrush() const + { + ATLASSERT(m_hDC != NULL); + return CBrushHandle((HBRUSH)::GetCurrentObject(m_hDC, OBJ_BRUSH)); + } + + CPaletteHandle GetCurrentPalette() const + { + ATLASSERT(m_hDC != NULL); + return CPaletteHandle((HPALETTE)::GetCurrentObject(m_hDC, OBJ_PAL)); + } + + CFontHandle GetCurrentFont() const + { + ATLASSERT(m_hDC != NULL); + return CFontHandle((HFONT)::GetCurrentObject(m_hDC, OBJ_FONT)); + } + + CBitmapHandle GetCurrentBitmap() const + { + ATLASSERT(m_hDC != NULL); + return CBitmapHandle((HBITMAP)::GetCurrentObject(m_hDC, OBJ_BITMAP)); + } + + HDC CreateDC(LPCTSTR lpszDriverName, LPCTSTR lpszDeviceName, LPCTSTR lpszOutput, const DEVMODE* lpInitData) + { + ATLASSERT(m_hDC == NULL); + m_hDC = ::CreateDC(lpszDriverName, lpszDeviceName, lpszOutput, lpInitData); + return m_hDC; + } + + HDC CreateCompatibleDC(HDC hDC = NULL) + { + ATLASSERT(m_hDC == NULL); + m_hDC = ::CreateCompatibleDC(hDC); + return m_hDC; + } + + BOOL DeleteDC() + { + if(m_hDC == NULL) + return FALSE; + BOOL bRet = ::DeleteDC(m_hDC); + if(bRet) + m_hDC = NULL; + return bRet; + } + +// Device-Context Functions + int SaveDC() + { + ATLASSERT(m_hDC != NULL); + return ::SaveDC(m_hDC); + } + + BOOL RestoreDC(int nSavedDC) + { + ATLASSERT(m_hDC != NULL); + return ::RestoreDC(m_hDC, nSavedDC); + } + + int GetDeviceCaps(int nIndex) const + { + ATLASSERT(m_hDC != NULL); + return ::GetDeviceCaps(m_hDC, nIndex); + } + +#ifndef _WIN32_WCE + UINT SetBoundsRect(LPCRECT lpRectBounds, UINT flags) + { + ATLASSERT(m_hDC != NULL); + return ::SetBoundsRect(m_hDC, lpRectBounds, flags); + } + + UINT GetBoundsRect(LPRECT lpRectBounds, UINT flags) const + { + ATLASSERT(m_hDC != NULL); + return ::GetBoundsRect(m_hDC, lpRectBounds, flags); + } + + BOOL ResetDC(const DEVMODE* lpDevMode) + { + ATLASSERT(m_hDC != NULL); + return ::ResetDC(m_hDC, lpDevMode) != NULL; + } + +// Drawing-Tool Functions + BOOL GetBrushOrg(LPPOINT lpPoint) const + { + ATLASSERT(m_hDC != NULL); + return ::GetBrushOrgEx(m_hDC, lpPoint); + } +#endif // !_WIN32_WCE + + BOOL SetBrushOrg(int x, int y, LPPOINT lpPoint = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::SetBrushOrgEx(m_hDC, x, y, lpPoint); + } + + BOOL SetBrushOrg(POINT point, LPPOINT lpPointRet = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::SetBrushOrgEx(m_hDC, point.x, point.y, lpPointRet); + } + +#ifndef _WIN32_WCE + int EnumObjects(int nObjectType, int (CALLBACK* lpfn)(LPVOID, LPARAM), LPARAM lpData) + { + ATLASSERT(m_hDC != NULL); +#ifdef STRICT + return ::EnumObjects(m_hDC, nObjectType, (GOBJENUMPROC)lpfn, lpData); +#else + return ::EnumObjects(m_hDC, nObjectType, (GOBJENUMPROC)lpfn, (LPVOID)lpData); +#endif + } +#endif // !_WIN32_WCE + +// Type-safe selection helpers + HPEN SelectPen(HPEN hPen) + { + ATLASSERT(m_hDC != NULL); +#ifndef _WIN32_WCE + ATLASSERT(hPen == NULL || ::GetObjectType(hPen) == OBJ_PEN || ::GetObjectType(hPen) == OBJ_EXTPEN); +#else // CE specific + ATLASSERT(hPen == NULL || ::GetObjectType(hPen) == OBJ_PEN); +#endif // _WIN32_WCE + return (HPEN)::SelectObject(m_hDC, hPen); + } + + HBRUSH SelectBrush(HBRUSH hBrush) + { + ATLASSERT(m_hDC != NULL); + ATLASSERT(hBrush == NULL || ::GetObjectType(hBrush) == OBJ_BRUSH); + return (HBRUSH)::SelectObject(m_hDC, hBrush); + } + + HFONT SelectFont(HFONT hFont) + { + ATLASSERT(m_hDC != NULL); + ATLASSERT(hFont == NULL || ::GetObjectType(hFont) == OBJ_FONT); + return (HFONT)::SelectObject(m_hDC, hFont); + } + + HBITMAP SelectBitmap(HBITMAP hBitmap) + { + ATLASSERT(m_hDC != NULL); + ATLASSERT(hBitmap == NULL || ::GetObjectType(hBitmap) == OBJ_BITMAP); + return (HBITMAP)::SelectObject(m_hDC, hBitmap); + } + + int SelectRgn(HRGN hRgn) // special return for regions + { + ATLASSERT(m_hDC != NULL); + ATLASSERT(hRgn == NULL || ::GetObjectType(hRgn) == OBJ_REGION); + return PtrToInt(::SelectObject(m_hDC, hRgn)); + } + +// Type-safe selection helpers for stock objects + HPEN SelectStockPen(int nPen) + { + ATLASSERT(m_hDC != NULL); +#if (_WIN32_WINNT >= 0x0500) + ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN); +#else + ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN); +#endif // !(_WIN32_WINNT >= 0x0500) + return SelectPen((HPEN)::GetStockObject(nPen)); + } + + HBRUSH SelectStockBrush(int nBrush) + { +#if (_WIN32_WINNT >= 0x0500) + ATLASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH); +#else + ATLASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH); +#endif // !(_WIN32_WINNT >= 0x0500) + return SelectBrush((HBRUSH)::GetStockObject(nBrush)); + } + + HFONT SelectStockFont(int nFont) + { +#ifndef _WIN32_WCE + ATLASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFont == DEFAULT_GUI_FONT); +#else // CE specific + ATLASSERT(nFont == SYSTEM_FONT); +#endif // _WIN32_WCE + return SelectFont((HFONT)::GetStockObject(nFont)); + } + + HPALETTE SelectStockPalette(int nPalette, BOOL bForceBackground) + { + ATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported + return SelectPalette((HPALETTE)::GetStockObject(nPalette), bForceBackground); + } + +// Color and Color Palette Functions + COLORREF GetNearestColor(COLORREF crColor) const + { + ATLASSERT(m_hDC != NULL); + return ::GetNearestColor(m_hDC, crColor); + } + + HPALETTE SelectPalette(HPALETTE hPalette, BOOL bForceBackground) + { + ATLASSERT(m_hDC != NULL); + + return ::SelectPalette(m_hDC, hPalette, bForceBackground); + } + + UINT RealizePalette() + { + ATLASSERT(m_hDC != NULL); + return ::RealizePalette(m_hDC); + } + +#ifndef _WIN32_WCE + void UpdateColors() + { + ATLASSERT(m_hDC != NULL); + ::UpdateColors(m_hDC); + } +#endif // !_WIN32_WCE + +// Drawing-Attribute Functions + COLORREF GetBkColor() const + { + ATLASSERT(m_hDC != NULL); + return ::GetBkColor(m_hDC); + } + + int GetBkMode() const + { + ATLASSERT(m_hDC != NULL); + return ::GetBkMode(m_hDC); + } + +#ifndef _WIN32_WCE + int GetPolyFillMode() const + { + ATLASSERT(m_hDC != NULL); + return ::GetPolyFillMode(m_hDC); + } + + int GetROP2() const + { + ATLASSERT(m_hDC != NULL); + return ::GetROP2(m_hDC); + } + + int GetStretchBltMode() const + { + ATLASSERT(m_hDC != NULL); + return ::GetStretchBltMode(m_hDC); + } +#endif // !_WIN32_WCE + + COLORREF GetTextColor() const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextColor(m_hDC); + } + + COLORREF SetBkColor(COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::SetBkColor(m_hDC, crColor); + } + + int SetBkMode(int nBkMode) + { + ATLASSERT(m_hDC != NULL); + return ::SetBkMode(m_hDC, nBkMode); + } + +#ifndef _WIN32_WCE + int SetPolyFillMode(int nPolyFillMode) + { + ATLASSERT(m_hDC != NULL); + return ::SetPolyFillMode(m_hDC, nPolyFillMode); + } +#endif // !_WIN32_WCE + + int SetROP2(int nDrawMode) + { + ATLASSERT(m_hDC != NULL); + return ::SetROP2(m_hDC, nDrawMode); + } + +#ifndef _WIN32_WCE + int SetStretchBltMode(int nStretchMode) + { + ATLASSERT(m_hDC != NULL); + return ::SetStretchBltMode(m_hDC, nStretchMode); + } +#endif // !_WIN32_WCE + + COLORREF SetTextColor(COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::SetTextColor(m_hDC, crColor); + } + +#ifndef _WIN32_WCE + BOOL GetColorAdjustment(LPCOLORADJUSTMENT lpColorAdjust) const + { + ATLASSERT(m_hDC != NULL); + return ::GetColorAdjustment(m_hDC, lpColorAdjust); + } + + BOOL SetColorAdjustment(const COLORADJUSTMENT* lpColorAdjust) + { + ATLASSERT(m_hDC != NULL); + return ::SetColorAdjustment(m_hDC, lpColorAdjust); + } + +// Mapping Functions + int GetMapMode() const + { + ATLASSERT(m_hDC != NULL); + return ::GetMapMode(m_hDC); + } + + BOOL GetViewportOrg(LPPOINT lpPoint) const + { + ATLASSERT(m_hDC != NULL); + return ::GetViewportOrgEx(m_hDC, lpPoint); + } + + int SetMapMode(int nMapMode) + { + ATLASSERT(m_hDC != NULL); + return ::SetMapMode(m_hDC, nMapMode); + } +#endif // !_WIN32_WCE + + // Viewport Origin + BOOL SetViewportOrg(int x, int y, LPPOINT lpPoint = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::SetViewportOrgEx(m_hDC, x, y, lpPoint); + } + + BOOL SetViewportOrg(POINT point, LPPOINT lpPointRet = NULL) + { + ATLASSERT(m_hDC != NULL); + return SetViewportOrg(point.x, point.y, lpPointRet); + } + +#ifndef _WIN32_WCE + BOOL OffsetViewportOrg(int nWidth, int nHeight, LPPOINT lpPoint = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::OffsetViewportOrgEx(m_hDC, nWidth, nHeight, lpPoint); + } + + // Viewport Extent + BOOL GetViewportExt(LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + return ::GetViewportExtEx(m_hDC, lpSize); + } + + BOOL SetViewportExt(int x, int y, LPSIZE lpSize = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::SetViewportExtEx(m_hDC, x, y, lpSize); + } + + BOOL SetViewportExt(SIZE size, LPSIZE lpSizeRet = NULL) + { + ATLASSERT(m_hDC != NULL); + return SetViewportExt(size.cx, size.cy, lpSizeRet); + } + + BOOL ScaleViewportExt(int xNum, int xDenom, int yNum, int yDenom, LPSIZE lpSize = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::ScaleViewportExtEx(m_hDC, xNum, xDenom, yNum, yDenom, lpSize); + } +#endif // !_WIN32_WCE + + // Window Origin +#ifndef _WIN32_WCE + BOOL GetWindowOrg(LPPOINT lpPoint) const + { + ATLASSERT(m_hDC != NULL); + return ::GetWindowOrgEx(m_hDC, lpPoint); + } + + BOOL SetWindowOrg(int x, int y, LPPOINT lpPoint = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::SetWindowOrgEx(m_hDC, x, y, lpPoint); + } + + BOOL SetWindowOrg(POINT point, LPPOINT lpPointRet = NULL) + { + ATLASSERT(m_hDC != NULL); + return SetWindowOrg(point.x, point.y, lpPointRet); + } + + BOOL OffsetWindowOrg(int nWidth, int nHeight, LPPOINT lpPoint = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::OffsetWindowOrgEx(m_hDC, nWidth, nHeight, lpPoint); + } + + // Window extent + BOOL GetWindowExt(LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + return ::GetWindowExtEx(m_hDC, lpSize); + } + + BOOL SetWindowExt(int x, int y, LPSIZE lpSize = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::SetWindowExtEx(m_hDC, x, y, lpSize); + } + + BOOL SetWindowExt(SIZE size, LPSIZE lpSizeRet = NULL) + { + ATLASSERT(m_hDC != NULL); + return SetWindowExt(size.cx, size.cy, lpSizeRet); + } + + BOOL ScaleWindowExt(int xNum, int xDenom, int yNum, int yDenom, LPSIZE lpSize = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::ScaleWindowExtEx(m_hDC, xNum, xDenom, yNum, yDenom, lpSize); + } + +// Coordinate Functions + BOOL DPtoLP(LPPOINT lpPoints, int nCount = 1) const + { + ATLASSERT(m_hDC != NULL); + return ::DPtoLP(m_hDC, lpPoints, nCount); + } + + BOOL DPtoLP(LPRECT lpRect) const + { + ATLASSERT(m_hDC != NULL); + return ::DPtoLP(m_hDC, (LPPOINT)lpRect, 2); + } + + BOOL DPtoLP(LPSIZE lpSize) const + { + SIZE sizeWinExt = { 0, 0 }; + if(!GetWindowExt(&sizeWinExt)) + return FALSE; + SIZE sizeVpExt = { 0, 0 }; + if(!GetViewportExt(&sizeVpExt)) + return FALSE; + lpSize->cx = ::MulDiv(lpSize->cx, abs(sizeWinExt.cx), abs(sizeVpExt.cx)); + lpSize->cy = ::MulDiv(lpSize->cy, abs(sizeWinExt.cy), abs(sizeVpExt.cy)); + return TRUE; + } + + BOOL LPtoDP(LPPOINT lpPoints, int nCount = 1) const + { + ATLASSERT(m_hDC != NULL); + return ::LPtoDP(m_hDC, lpPoints, nCount); + } + + BOOL LPtoDP(LPRECT lpRect) const + { + ATLASSERT(m_hDC != NULL); + return ::LPtoDP(m_hDC, (LPPOINT)lpRect, 2); + } + + BOOL LPtoDP(LPSIZE lpSize) const + { + SIZE sizeWinExt = { 0, 0 }; + if(!GetWindowExt(&sizeWinExt)) + return FALSE; + SIZE sizeVpExt = { 0, 0 }; + if(!GetViewportExt(&sizeVpExt)) + return FALSE; + lpSize->cx = ::MulDiv(lpSize->cx, abs(sizeVpExt.cx), abs(sizeWinExt.cx)); + lpSize->cy = ::MulDiv(lpSize->cy, abs(sizeVpExt.cy), abs(sizeWinExt.cy)); + return TRUE; + } + +// Special Coordinate Functions (useful for dealing with metafiles and OLE) + #define HIMETRIC_INCH 2540 // HIMETRIC units per inch + + void DPtoHIMETRIC(LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + int nMapMode; + if((nMapMode = GetMapMode()) < MM_ISOTROPIC && nMapMode != MM_TEXT) + { + // when using a constrained map mode, map against physical inch + ((CDCHandle*)this)->SetMapMode(MM_HIMETRIC); + DPtoLP(lpSize); + ((CDCHandle*)this)->SetMapMode(nMapMode); + } + else + { + // map against logical inch for non-constrained mapping modes + int cxPerInch = GetDeviceCaps(LOGPIXELSX); + int cyPerInch = GetDeviceCaps(LOGPIXELSY); + ATLASSERT(cxPerInch != 0 && cyPerInch != 0); + lpSize->cx = ::MulDiv(lpSize->cx, HIMETRIC_INCH, cxPerInch); + lpSize->cy = ::MulDiv(lpSize->cy, HIMETRIC_INCH, cyPerInch); + } + } + + void HIMETRICtoDP(LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + int nMapMode; + if((nMapMode = GetMapMode()) < MM_ISOTROPIC && nMapMode != MM_TEXT) + { + // when using a constrained map mode, map against physical inch + ((CDCHandle*)this)->SetMapMode(MM_HIMETRIC); + LPtoDP(lpSize); + ((CDCHandle*)this)->SetMapMode(nMapMode); + } + else + { + // map against logical inch for non-constrained mapping modes + int cxPerInch = GetDeviceCaps(LOGPIXELSX); + int cyPerInch = GetDeviceCaps(LOGPIXELSY); + ATLASSERT(cxPerInch != 0 && cyPerInch != 0); + lpSize->cx = ::MulDiv(lpSize->cx, cxPerInch, HIMETRIC_INCH); + lpSize->cy = ::MulDiv(lpSize->cy, cyPerInch, HIMETRIC_INCH); + } + } + + void LPtoHIMETRIC(LPSIZE lpSize) const + { + LPtoDP(lpSize); + DPtoHIMETRIC(lpSize); + } + + void HIMETRICtoLP(LPSIZE lpSize) const + { + HIMETRICtoDP(lpSize); + DPtoLP(lpSize); + } +#endif // !_WIN32_WCE + +// Region Functions + BOOL FillRgn(HRGN hRgn, HBRUSH hBrush) + { + ATLASSERT(m_hDC != NULL); + return ::FillRgn(m_hDC, hRgn, hBrush); + } + +#ifndef _WIN32_WCE + BOOL FrameRgn(HRGN hRgn, HBRUSH hBrush, int nWidth, int nHeight) + { + ATLASSERT(m_hDC != NULL); + return ::FrameRgn(m_hDC, hRgn, hBrush, nWidth, nHeight); + } + + BOOL InvertRgn(HRGN hRgn) + { + ATLASSERT(m_hDC != NULL); + return ::InvertRgn(m_hDC, hRgn); + } + + BOOL PaintRgn(HRGN hRgn) + { + ATLASSERT(m_hDC != NULL); + return ::PaintRgn(m_hDC, hRgn); + } +#endif // !_WIN32_WCE + +// Clipping Functions + int GetClipBox(LPRECT lpRect) const + { + ATLASSERT(m_hDC != NULL); + return ::GetClipBox(m_hDC, lpRect); + } + + int GetClipRgn(CRgn& region) const + { + ATLASSERT(m_hDC != NULL); + if(region.IsNull()) + region.CreateRectRgn(0, 0, 0, 0); + + int nRet = ::GetClipRgn(m_hDC, region); + if(nRet != 1) + region.DeleteObject(); + + return nRet; + } + +#ifndef _WIN32_WCE + BOOL PtVisible(int x, int y) const + { + ATLASSERT(m_hDC != NULL); + return ::PtVisible(m_hDC, x, y); + } + + BOOL PtVisible(POINT point) const + { + ATLASSERT(m_hDC != NULL); + return ::PtVisible(m_hDC, point.x, point.y); + } +#endif // !_WIN32_WCE + + BOOL RectVisible(LPCRECT lpRect) const + { + ATLASSERT(m_hDC != NULL); + return ::RectVisible(m_hDC, lpRect); + } + + int SelectClipRgn(HRGN hRgn) + { + ATLASSERT(m_hDC != NULL); + return ::SelectClipRgn(m_hDC, (HRGN)hRgn); + } + + int ExcludeClipRect(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hDC != NULL); + return ::ExcludeClipRect(m_hDC, x1, y1, x2, y2); + } + + int ExcludeClipRect(LPCRECT lpRect) + { + ATLASSERT(m_hDC != NULL); + return ::ExcludeClipRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + +#ifndef _WIN32_WCE + int ExcludeUpdateRgn(HWND hWnd) + { + ATLASSERT(m_hDC != NULL); + return ::ExcludeUpdateRgn(m_hDC, hWnd); + } +#endif // !_WIN32_WCE + + int IntersectClipRect(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hDC != NULL); + return ::IntersectClipRect(m_hDC, x1, y1, x2, y2); + } + + int IntersectClipRect(LPCRECT lpRect) + { + ATLASSERT(m_hDC != NULL); + return ::IntersectClipRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + +#ifndef _WIN32_WCE + int OffsetClipRgn(int x, int y) + { + ATLASSERT(m_hDC != NULL); + return ::OffsetClipRgn(m_hDC, x, y); + } + + int OffsetClipRgn(SIZE size) + { + ATLASSERT(m_hDC != NULL); + return ::OffsetClipRgn(m_hDC, size.cx, size.cy); + } + + int SelectClipRgn(HRGN hRgn, int nMode) + { + ATLASSERT(m_hDC != NULL); + return ::ExtSelectClipRgn(m_hDC, hRgn, nMode); + } +#endif // !_WIN32_WCE + +// Line-Output Functions +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + BOOL GetCurrentPosition(LPPOINT lpPoint) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCurrentPositionEx(m_hDC, lpPoint); + } + + BOOL MoveTo(int x, int y, LPPOINT lpPoint = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::MoveToEx(m_hDC, x, y, lpPoint); + } + + BOOL MoveTo(POINT point, LPPOINT lpPointRet = NULL) + { + ATLASSERT(m_hDC != NULL); + return MoveTo(point.x, point.y, lpPointRet); + } + + BOOL LineTo(int x, int y) + { + ATLASSERT(m_hDC != NULL); + return ::LineTo(m_hDC, x, y); + } + + BOOL LineTo(POINT point) + { + ATLASSERT(m_hDC != NULL); + return LineTo(point.x, point.y); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + +#ifndef _WIN32_WCE + BOOL Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) + { + ATLASSERT(m_hDC != NULL); + return ::Arc(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4); + } + + BOOL Arc(LPCRECT lpRect, POINT ptStart, POINT ptEnd) + { + ATLASSERT(m_hDC != NULL); + return ::Arc(m_hDC, lpRect->left, lpRect->top, + lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, + ptEnd.x, ptEnd.y); + } +#endif // !_WIN32_WCE + + BOOL Polyline(const POINT* lpPoints, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::Polyline(m_hDC, lpPoints, nCount); + } + +#ifndef _WIN32_WCE + BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle) + { + ATLASSERT(m_hDC != NULL); + return ::AngleArc(m_hDC, x, y, nRadius, fStartAngle, fSweepAngle); + } + + BOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) + { + ATLASSERT(m_hDC != NULL); + return ::ArcTo(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4); + } + + BOOL ArcTo(LPCRECT lpRect, POINT ptStart, POINT ptEnd) + { + ATLASSERT(m_hDC != NULL); + return ArcTo(lpRect->left, lpRect->top, lpRect->right, + lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); + } + + int GetArcDirection() const + { + ATLASSERT(m_hDC != NULL); + return ::GetArcDirection(m_hDC); + } + + int SetArcDirection(int nArcDirection) + { + ATLASSERT(m_hDC != NULL); + return ::SetArcDirection(m_hDC, nArcDirection); + } + + BOOL PolyDraw(const POINT* lpPoints, const BYTE* lpTypes, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::PolyDraw(m_hDC, lpPoints, lpTypes, nCount); + } + + BOOL PolylineTo(const POINT* lpPoints, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::PolylineTo(m_hDC, lpPoints, nCount); + } + + BOOL PolyPolyline(const POINT* lpPoints, + const DWORD* lpPolyPoints, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::PolyPolyline(m_hDC, lpPoints, lpPolyPoints, nCount); + } + + BOOL PolyBezier(const POINT* lpPoints, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::PolyBezier(m_hDC, lpPoints, nCount); + } + + BOOL PolyBezierTo(const POINT* lpPoints, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::PolyBezierTo(m_hDC, lpPoints, nCount); + } +#endif // !_WIN32_WCE + +// Simple Drawing Functions + BOOL FillRect(LPCRECT lpRect, HBRUSH hBrush) + { + ATLASSERT(m_hDC != NULL); + return ::FillRect(m_hDC, lpRect, hBrush); + } + + BOOL FillRect(LPCRECT lpRect, int nColorIndex) + { + ATLASSERT(m_hDC != NULL); +#ifndef _WIN32_WCE + return ::FillRect(m_hDC, lpRect, (HBRUSH)LongToPtr(nColorIndex + 1)); +#else // CE specific + return ::FillRect(m_hDC, lpRect, ::GetSysColorBrush(nColorIndex)); +#endif // _WIN32_WCE + } + +#ifndef _WIN32_WCE + BOOL FrameRect(LPCRECT lpRect, HBRUSH hBrush) + { + ATLASSERT(m_hDC != NULL); + return ::FrameRect(m_hDC, lpRect, hBrush); + } +#endif // !_WIN32_WCE + +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 420) + BOOL InvertRect(LPCRECT lpRect) + { + ATLASSERT(m_hDC != NULL); + return ::InvertRect(m_hDC, lpRect); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420) + + BOOL DrawIcon(int x, int y, HICON hIcon) + { + ATLASSERT(m_hDC != NULL); +#ifndef _WIN32_WCE + return ::DrawIcon(m_hDC, x, y, hIcon); +#else // CE specific + return ::DrawIconEx(m_hDC, x, y, hIcon, 0, 0, 0, NULL, DI_NORMAL); +#endif // _WIN32_WCE + } + + BOOL DrawIcon(POINT point, HICON hIcon) + { + ATLASSERT(m_hDC != NULL); +#ifndef _WIN32_WCE + return ::DrawIcon(m_hDC, point.x, point.y, hIcon); +#else // CE specific + return ::DrawIconEx(m_hDC, point.x, point.y, hIcon, 0, 0, 0, NULL, DI_NORMAL); +#endif // _WIN32_WCE + } + + BOOL DrawIconEx(int x, int y, HICON hIcon, int cxWidth, int cyWidth, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawIconEx(m_hDC, x, y, hIcon, cxWidth, cyWidth, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); + } + + BOOL DrawIconEx(POINT point, HICON hIcon, SIZE size, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawIconEx(m_hDC, point.x, point.y, hIcon, size.cx, size.cy, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); + } + +#ifndef _WIN32_WCE + BOOL DrawState(POINT pt, SIZE size, HBITMAP hBitmap, UINT nFlags, HBRUSH hBrush = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawState(m_hDC, hBrush, NULL, (LPARAM)hBitmap, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_BITMAP); + } + + BOOL DrawState(POINT pt, SIZE size, HICON hIcon, UINT nFlags, HBRUSH hBrush = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawState(m_hDC, hBrush, NULL, (LPARAM)hIcon, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_ICON); + } + + BOOL DrawState(POINT pt, SIZE size, LPCTSTR lpszText, UINT nFlags, BOOL bPrefixText = TRUE, int nTextLen = 0, HBRUSH hBrush = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawState(m_hDC, hBrush, NULL, (LPARAM)lpszText, (WPARAM)nTextLen, pt.x, pt.y, size.cx, size.cy, nFlags | (bPrefixText ? DST_PREFIXTEXT : DST_TEXT)); + } + + BOOL DrawState(POINT pt, SIZE size, DRAWSTATEPROC lpDrawProc, LPARAM lData, UINT nFlags, HBRUSH hBrush = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawState(m_hDC, hBrush, lpDrawProc, lData, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_COMPLEX); + } +#endif // !_WIN32_WCE + +// Ellipse and Polygon Functions +#ifndef _WIN32_WCE + BOOL Chord(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) + { + ATLASSERT(m_hDC != NULL); + return ::Chord(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4); + } + + BOOL Chord(LPCRECT lpRect, POINT ptStart, POINT ptEnd) + { + ATLASSERT(m_hDC != NULL); + return ::Chord(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); + } +#endif // !_WIN32_WCE + + void DrawFocusRect(LPCRECT lpRect) + { + ATLASSERT(m_hDC != NULL); + ::DrawFocusRect(m_hDC, lpRect); + } + + BOOL Ellipse(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hDC != NULL); + return ::Ellipse(m_hDC, x1, y1, x2, y2); + } + + BOOL Ellipse(LPCRECT lpRect) + { + ATLASSERT(m_hDC != NULL); + return ::Ellipse(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + +#ifndef _WIN32_WCE + BOOL Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) + { + ATLASSERT(m_hDC != NULL); + return ::Pie(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4); + } + + BOOL Pie(LPCRECT lpRect, POINT ptStart, POINT ptEnd) + { + ATLASSERT(m_hDC != NULL); + return ::Pie(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); + } +#endif // !_WIN32_WCE + + BOOL Polygon(const POINT* lpPoints, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::Polygon(m_hDC, lpPoints, nCount); + } + +#ifndef _WIN32_WCE + BOOL PolyPolygon(const POINT* lpPoints, const INT* lpPolyCounts, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::PolyPolygon(m_hDC, lpPoints, lpPolyCounts, nCount); + } +#endif // !_WIN32_WCE + + BOOL Rectangle(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hDC != NULL); + return ::Rectangle(m_hDC, x1, y1, x2, y2); + } + + BOOL Rectangle(LPCRECT lpRect) + { + ATLASSERT(m_hDC != NULL); + return ::Rectangle(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + + BOOL RoundRect(int x1, int y1, int x2, int y2, int x3, int y3) + { + ATLASSERT(m_hDC != NULL); + return ::RoundRect(m_hDC, x1, y1, x2, y2, x3, y3); + } + + BOOL RoundRect(LPCRECT lpRect, POINT point) + { + ATLASSERT(m_hDC != NULL); + return ::RoundRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, point.x, point.y); + } + +// Bitmap Functions + BOOL PatBlt(int x, int y, int nWidth, int nHeight, DWORD dwRop) + { + ATLASSERT(m_hDC != NULL); + return ::PatBlt(m_hDC, x, y, nWidth, nHeight, dwRop); + } + + BOOL BitBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, + int xSrc, int ySrc, DWORD dwRop) + { + ATLASSERT(m_hDC != NULL); + return ::BitBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, dwRop); + } + + BOOL StretchBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop) + { + ATLASSERT(m_hDC != NULL); + return ::StretchBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwRop); + } + + COLORREF GetPixel(int x, int y) const + { + ATLASSERT(m_hDC != NULL); + return ::GetPixel(m_hDC, x, y); + } + + COLORREF GetPixel(POINT point) const + { + ATLASSERT(m_hDC != NULL); + return ::GetPixel(m_hDC, point.x, point.y); + } + + COLORREF SetPixel(int x, int y, COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::SetPixel(m_hDC, x, y, crColor); + } + + COLORREF SetPixel(POINT point, COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::SetPixel(m_hDC, point.x, point.y, crColor); + } + +#ifndef _WIN32_WCE + BOOL FloodFill(int x, int y, COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::FloodFill(m_hDC, x, y, crColor); + } + + BOOL ExtFloodFill(int x, int y, COLORREF crColor, UINT nFillType) + { + ATLASSERT(m_hDC != NULL); + return ::ExtFloodFill(m_hDC, x, y, crColor, nFillType); + } +#endif // !_WIN32_WCE + + BOOL MaskBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, HBITMAP hMaskBitmap, int xMask, int yMask, DWORD dwRop) + { + ATLASSERT(m_hDC != NULL); + return ::MaskBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, hMaskBitmap, xMask, yMask, dwRop); + } + +#ifndef _WIN32_WCE + BOOL PlgBlt(LPPOINT lpPoint, HDC hSrcDC, int xSrc, int ySrc, int nWidth, int nHeight, HBITMAP hMaskBitmap, int xMask, int yMask) + { + ATLASSERT(m_hDC != NULL); + return ::PlgBlt(m_hDC, lpPoint, hSrcDC, xSrc, ySrc, nWidth, nHeight, hMaskBitmap, xMask, yMask); + } + + BOOL SetPixelV(int x, int y, COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::SetPixelV(m_hDC, x, y, crColor); + } + + BOOL SetPixelV(POINT point, COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::SetPixelV(m_hDC, point.x, point.y, crColor); + } +#endif // !_WIN32_WCE + +#if !defined(_ATL_NO_MSIMG) || defined(_WIN32_WCE) +#ifndef _WIN32_WCE + BOOL TransparentBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent) + { + ATLASSERT(m_hDC != NULL); + return ::TransparentBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent); + } +#else // CE specific + BOOL TransparentImage(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent) + { + ATLASSERT(m_hDC != NULL); + return ::TransparentImage(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent); + } +#endif // _WIN32_WCE + +#if (!defined(_WIN32_WCE) || (_WIN32_WCE >= 420)) + BOOL GradientFill(const PTRIVERTEX pVertices, DWORD nVertices, void* pMeshElements, DWORD nMeshElements, DWORD dwMode) + { + ATLASSERT(m_hDC != NULL); + return ::GradientFill(m_hDC, pVertices, nVertices, pMeshElements, nMeshElements, dwMode); + } + + BOOL GradientFillRect(RECT& rect, COLORREF clr1, COLORREF clr2, bool bHorizontal) + { + ATLASSERT(m_hDC != NULL); + + TRIVERTEX arrTvx[2] = { { 0 }, { 0 } }; + + arrTvx[0].x = rect.left; + arrTvx[0].y = rect.top; + arrTvx[0].Red = MAKEWORD(0, GetRValue(clr1)); + arrTvx[0].Green = MAKEWORD(0, GetGValue(clr1)); + arrTvx[0].Blue = MAKEWORD(0, GetBValue(clr1)); + arrTvx[0].Alpha = 0; + + arrTvx[1].x = rect.right; + arrTvx[1].y = rect.bottom; + arrTvx[1].Red = MAKEWORD(0, GetRValue(clr2)); + arrTvx[1].Green = MAKEWORD(0, GetGValue(clr2)); + arrTvx[1].Blue = MAKEWORD(0, GetBValue(clr2)); + arrTvx[1].Alpha = 0; + + GRADIENT_RECT gr = { 0, 1 }; + + return ::GradientFill(m_hDC, arrTvx, 2, &gr, 1, bHorizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420) + +#if !defined(_WIN32_WCE) || (_WIN32_WCE > 0x500) + BOOL AlphaBlend(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, BLENDFUNCTION bf) + { + ATLASSERT(m_hDC != NULL); + return ::AlphaBlend(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, bf); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE > 0x500) +#endif // !defined(_ATL_NO_MSIMG) || defined(_WIN32_WCE) + +// Extra bitmap functions + // Helper function for painting a disabled toolbar or menu bitmap + // This function can take either an HBITMAP (for SS) or a DC with + // the bitmap already painted (for cmdbar) + BOOL DitherBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, HBITMAP hBitmap, int xSrc, int ySrc, + HBRUSH hBrushBackground = ::GetSysColorBrush(COLOR_3DFACE), + HBRUSH hBrush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT), + HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW)) + { + ATLASSERT(m_hDC != NULL || hBitmap != NULL); + ATLASSERT(nWidth > 0 && nHeight > 0); + + // Create a generic DC for all BitBlts + CDCHandle dc = (hSrcDC != NULL) ? hSrcDC : ::CreateCompatibleDC(m_hDC); + ATLASSERT(dc.m_hDC != NULL); + if(dc.m_hDC == NULL) + return FALSE; + + // Create a DC for the monochrome DIB section + CDC dcBW = ::CreateCompatibleDC(m_hDC); + ATLASSERT(dcBW.m_hDC != NULL); + if(dcBW.m_hDC == NULL) + { + if(hSrcDC == NULL) + dc.DeleteDC(); + return FALSE; + } + + // Create the monochrome DIB section with a black and white palette + struct RGBBWBITMAPINFO + { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[2]; + }; + + RGBBWBITMAPINFO rgbBWBitmapInfo = + { + { sizeof(BITMAPINFOHEADER), nWidth, nHeight, 1, 1, BI_RGB, 0, 0, 0, 0, 0 }, + { { 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 } } + }; + + VOID* pbitsBW; + CBitmap bmpBW = ::CreateDIBSection(dcBW, (LPBITMAPINFO)&rgbBWBitmapInfo, DIB_RGB_COLORS, &pbitsBW, NULL, 0); + ATLASSERT(bmpBW.m_hBitmap != NULL); + if(bmpBW.m_hBitmap == NULL) + { + if(hSrcDC == NULL) + dc.DeleteDC(); + return FALSE; + } + + // Attach the monochrome DIB section and the bitmap to the DCs + HBITMAP hbmOldBW = dcBW.SelectBitmap(bmpBW); + HBITMAP hbmOldDC = NULL; + if(hBitmap != NULL) + hbmOldDC = dc.SelectBitmap(hBitmap); + + // Block: Dark gray removal: we want (128, 128, 128) pixels to become black and not white + { + CDC dcTemp1 = ::CreateCompatibleDC(m_hDC); + CDC dcTemp2 = ::CreateCompatibleDC(m_hDC); + CBitmap bmpTemp1; + bmpTemp1.CreateCompatibleBitmap(dc, nWidth, nHeight); + CBitmap bmpTemp2; + bmpTemp2.CreateBitmap(nWidth, nHeight, 1, 1, NULL); + HBITMAP hOldBmp1 = dcTemp1.SelectBitmap(bmpTemp1); + HBITMAP hOldBmp2 = dcTemp2.SelectBitmap(bmpTemp2); + // Let's copy our image, it will be altered + dcTemp1.BitBlt(0, 0, nWidth, nHeight, dc, xSrc, ySrc, SRCCOPY); + + // All dark gray pixels will become white, the others black + dcTemp1.SetBkColor(RGB(128, 128, 128)); + dcTemp2.BitBlt(0, 0, nWidth, nHeight, dcTemp1, 0, 0, SRCCOPY); + // Do an XOR to set to black these white pixels + dcTemp1.BitBlt(0, 0, nWidth, nHeight, dcTemp2, 0, 0, SRCINVERT); + + // BitBlt the bitmap into the monochrome DIB section + // The DIB section will do a true monochrome conversion + // The magenta background being closer to white will become white + dcBW.BitBlt(0, 0, nWidth, nHeight, dcTemp1, 0, 0, SRCCOPY); + + // Cleanup + dcTemp1.SelectBitmap(hOldBmp1); + dcTemp2.SelectBitmap(hOldBmp2); + } + + // Paint the destination rectangle using hBrushBackground + if(hBrushBackground != NULL) + { + RECT rc = { x, y, x + nWidth, y + nHeight }; + FillRect(&rc, hBrushBackground); + } + + // BitBlt the black bits in the monochrome bitmap into hBrush3DEffect color in the destination DC + // The magic ROP comes from the Charles Petzold's book + HBRUSH hOldBrush = SelectBrush(hBrush3DEffect); + BitBlt(x + 1, y + 1, nWidth, nHeight, dcBW, 0, 0, 0xB8074A); + + // BitBlt the black bits in the monochrome bitmap into hBrushDisabledImage color in the destination DC + SelectBrush(hBrushDisabledImage); + BitBlt(x, y, nWidth, nHeight, dcBW, 0, 0, 0xB8074A); + + SelectBrush(hOldBrush); + dcBW.SelectBitmap(hbmOldBW); + dc.SelectBitmap(hbmOldDC); + + if(hSrcDC == NULL) + dc.DeleteDC(); + + return TRUE; + } + +// Text Functions +#ifndef _WIN32_WCE + BOOL TextOut(int x, int y, LPCTSTR lpszString, int nCount = -1) + { + ATLASSERT(m_hDC != NULL); + if(nCount == -1) + nCount = lstrlen(lpszString); + return ::TextOut(m_hDC, x, y, lpszString, nCount); + } +#endif // !_WIN32_WCE + + BOOL ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect, LPCTSTR lpszString, UINT nCount = -1, LPINT lpDxWidths = NULL) + { + ATLASSERT(m_hDC != NULL); + if(nCount == -1) + nCount = lstrlen(lpszString); + return ::ExtTextOut(m_hDC, x, y, nOptions, lpRect, lpszString, nCount, lpDxWidths); + } + +#ifndef _WIN32_WCE + SIZE TabbedTextOut(int x, int y, LPCTSTR lpszString, int nCount = -1, int nTabPositions = 0, LPINT lpnTabStopPositions = NULL, int nTabOrigin = 0) + { + ATLASSERT(m_hDC != NULL); + if(nCount == -1) + nCount = lstrlen(lpszString); + LONG lRes = ::TabbedTextOut(m_hDC, x, y, lpszString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin); + SIZE size = { GET_X_LPARAM(lRes), GET_Y_LPARAM(lRes) }; + return size; + } +#endif // !_WIN32_WCE + + int DrawText(LPCTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat) + { + ATLASSERT(m_hDC != NULL); +#ifndef _WIN32_WCE + ATLASSERT((uFormat & DT_MODIFYSTRING) == 0); +#endif // !_WIN32_WCE + return ::DrawText(m_hDC, lpstrText, cchText, lpRect, uFormat); + } + + int DrawText(LPTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat) + { + ATLASSERT(m_hDC != NULL); + return ::DrawText(m_hDC, lpstrText, cchText, lpRect, uFormat); + } + +#ifndef _WIN32_WCE + int DrawTextEx(LPTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat, LPDRAWTEXTPARAMS lpDTParams = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawTextEx(m_hDC, lpstrText, cchText, lpRect, uFormat, lpDTParams); + } +#endif // !_WIN32_WCE + +#if (_WIN32_WINNT >= 0x0501) + int DrawShadowText(LPCWSTR lpstrText, int cchText, LPRECT lpRect, DWORD dwFlags, COLORREF clrText, COLORREF clrShadow, int xOffset, int yOffset) + { + ATLASSERT(m_hDC != NULL); + // This function is present only if comctl32.dll version 6 is loaded; + // we use LoadLibrary/GetProcAddress to allow apps compiled with + // _WIN32_WINNT >= 0x0501 to run on older Windows/CommCtrl + int nRet = 0; + HMODULE hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll")); + ATLASSERT(hCommCtrlDLL != NULL); + if(hCommCtrlDLL != NULL) + { + typedef int (WINAPI *PFN_DrawShadowText)(HDC hDC, LPCWSTR lpstrText, UINT cchText, LPRECT lpRect, DWORD dwFlags, COLORREF clrText, COLORREF clrShadow, int xOffset, int yOffset); + PFN_DrawShadowText pfnDrawShadowText = (PFN_DrawShadowText)::GetProcAddress(hCommCtrlDLL, "DrawShadowText"); + ATLASSERT(pfnDrawShadowText != NULL); // this function requires CommCtrl6 + if(pfnDrawShadowText != NULL) + nRet = pfnDrawShadowText(m_hDC, lpstrText, cchText, lpRect, dwFlags, clrText, clrShadow, xOffset, yOffset); + ::FreeLibrary(hCommCtrlDLL); + } + return nRet; + } +#endif // (_WIN32_WINNT >= 0x0501) + + BOOL GetTextExtent(LPCTSTR lpszString, int nCount, LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + if(nCount == -1) + nCount = lstrlen(lpszString); + return ::GetTextExtentPoint32(m_hDC, lpszString, nCount, lpSize); + } + + BOOL GetTextExtentExPoint(LPCTSTR lpszString, int cchString, LPSIZE lpSize, int nMaxExtent, LPINT lpnFit = NULL, LPINT alpDx = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::GetTextExtentExPoint(m_hDC, lpszString, cchString, nMaxExtent, lpnFit, alpDx, lpSize); + } + +#ifndef _WIN32_WCE + DWORD GetTabbedTextExtent(LPCTSTR lpszString, int nCount = -1, int nTabPositions = 0, LPINT lpnTabStopPositions = NULL) const + { + ATLASSERT(m_hDC != NULL); + if(nCount == -1) + nCount = lstrlen(lpszString); + return ::GetTabbedTextExtent(m_hDC, lpszString, nCount, nTabPositions, lpnTabStopPositions); + } + + BOOL GrayString(HBRUSH hBrush, BOOL (CALLBACK* lpfnOutput)(HDC, LPARAM, int), LPARAM lpData, int nCount, int x, int y, int nWidth, int nHeight) + { + ATLASSERT(m_hDC != NULL); + return ::GrayString(m_hDC, hBrush, (GRAYSTRINGPROC)lpfnOutput, lpData, nCount, x, y, nWidth, nHeight); + } +#endif // !_WIN32_WCE + +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + UINT GetTextAlign() const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextAlign(m_hDC); + } + + UINT SetTextAlign(UINT nFlags) + { + ATLASSERT(m_hDC != NULL); + return ::SetTextAlign(m_hDC, nFlags); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + + int GetTextFace(LPTSTR lpszFacename, int nCount) const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextFace(m_hDC, nCount, lpszFacename); + } + + int GetTextFaceLen() const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextFace(m_hDC, 0, NULL); + } + +#ifndef _ATL_NO_COM +#ifdef _OLEAUTO_H_ + BOOL GetTextFace(BSTR& bstrFace) const + { + USES_CONVERSION; + ATLASSERT(m_hDC != NULL); + ATLASSERT(bstrFace == NULL); + + int nLen = GetTextFaceLen(); + if(nLen == 0) + return FALSE; + + CTempBuffer buff; + LPTSTR lpszText = buff.Allocate(nLen); + if(lpszText == NULL) + return FALSE; + + if(!GetTextFace(lpszText, nLen)) + return FALSE; + + bstrFace = ::SysAllocString(T2OLE(lpszText)); + return (bstrFace != NULL) ? TRUE : FALSE; + } +#endif +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetTextFace(_CSTRING_NS::CString& strFace) const + { + ATLASSERT(m_hDC != NULL); + + int nLen = GetTextFaceLen(); + if(nLen == 0) + return 0; + + LPTSTR lpstr = strFace.GetBufferSetLength(nLen); + if(lpstr == NULL) + return 0; + int nRet = GetTextFace(lpstr, nLen); + strFace.ReleaseBuffer(); + return nRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + BOOL GetTextMetrics(LPTEXTMETRIC lpMetrics) const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextMetrics(m_hDC, lpMetrics); + } + +#ifndef _WIN32_WCE + int SetTextJustification(int nBreakExtra, int nBreakCount) + { + ATLASSERT(m_hDC != NULL); + return ::SetTextJustification(m_hDC, nBreakExtra, nBreakCount); + } + + int GetTextCharacterExtra() const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextCharacterExtra(m_hDC); + } + + int SetTextCharacterExtra(int nCharExtra) + { + ATLASSERT(m_hDC != NULL); + return ::SetTextCharacterExtra(m_hDC, nCharExtra); + } +#endif // !_WIN32_WCE + +// Advanced Drawing + BOOL DrawEdge(LPRECT lpRect, UINT nEdge, UINT nFlags) + { + ATLASSERT(m_hDC != NULL); + return ::DrawEdge(m_hDC, lpRect, nEdge, nFlags); + } + + BOOL DrawFrameControl(LPRECT lpRect, UINT nType, UINT nState) + { + ATLASSERT(m_hDC != NULL); + return ::DrawFrameControl(m_hDC, lpRect, nType, nState); + } + +// Scrolling Functions + BOOL ScrollDC(int dx, int dy, LPCRECT lpRectScroll, LPCRECT lpRectClip, HRGN hRgnUpdate, LPRECT lpRectUpdate) + { + ATLASSERT(m_hDC != NULL); + return ::ScrollDC(m_hDC, dx, dy, lpRectScroll, lpRectClip, hRgnUpdate, lpRectUpdate); + } + +// Font Functions +#ifndef _WIN32_WCE + BOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharWidth(m_hDC, nFirstChar, nLastChar, lpBuffer); + } + + // GetCharWidth32 is not supported under Win9x + BOOL GetCharWidth32(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharWidth32(m_hDC, nFirstChar, nLastChar, lpBuffer); + } + + DWORD SetMapperFlags(DWORD dwFlag) + { + ATLASSERT(m_hDC != NULL); + return ::SetMapperFlags(m_hDC, dwFlag); + } + + BOOL GetAspectRatioFilter(LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + return ::GetAspectRatioFilterEx(m_hDC, lpSize); + } + + BOOL GetCharABCWidths(UINT nFirstChar, UINT nLastChar, LPABC lpabc) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharABCWidths(m_hDC, nFirstChar, nLastChar, lpabc); + } + + DWORD GetFontData(DWORD dwTable, DWORD dwOffset, LPVOID lpData, DWORD cbData) const + { + ATLASSERT(m_hDC != NULL); + return ::GetFontData(m_hDC, dwTable, dwOffset, lpData, cbData); + } + + int GetKerningPairs(int nPairs, LPKERNINGPAIR lpkrnpair) const + { + ATLASSERT(m_hDC != NULL); + return ::GetKerningPairs(m_hDC, nPairs, lpkrnpair); + } + + UINT GetOutlineTextMetrics(UINT cbData, LPOUTLINETEXTMETRIC lpotm) const + { + ATLASSERT(m_hDC != NULL); + return ::GetOutlineTextMetrics(m_hDC, cbData, lpotm); + } + + DWORD GetGlyphOutline(UINT nChar, UINT nFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpBuffer, const MAT2* lpmat2) const + { + ATLASSERT(m_hDC != NULL); + return ::GetGlyphOutline(m_hDC, nChar, nFormat, lpgm, cbBuffer, lpBuffer, lpmat2); + } + + BOOL GetCharABCWidths(UINT nFirstChar, UINT nLastChar, LPABCFLOAT lpABCF) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharABCWidthsFloat(m_hDC, nFirstChar, nLastChar, lpABCF); + } + + BOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, float* lpFloatBuffer) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharWidthFloat(m_hDC, nFirstChar, nLastChar, lpFloatBuffer); + } +#endif // !_WIN32_WCE + +// Printer/Device Escape Functions +#ifndef _WIN32_WCE + int Escape(int nEscape, int nCount, LPCSTR lpszInData, LPVOID lpOutData) + { + ATLASSERT(m_hDC != NULL); + return ::Escape(m_hDC, nEscape, nCount, lpszInData, lpOutData); + } +#endif // !_WIN32_WCE + + int Escape(int nEscape, int nInputSize, LPCSTR lpszInputData, + int nOutputSize, LPSTR lpszOutputData) + { + ATLASSERT(m_hDC != NULL); + return ::ExtEscape(m_hDC, nEscape, nInputSize, lpszInputData, nOutputSize, lpszOutputData); + } + +#ifndef _WIN32_WCE + int DrawEscape(int nEscape, int nInputSize, LPCSTR lpszInputData) + { + ATLASSERT(m_hDC != NULL); + return ::DrawEscape(m_hDC, nEscape, nInputSize, lpszInputData); + } +#endif // !_WIN32_WCE + + // Escape helpers +#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 200) && defined(StartDoc)) + int StartDoc(LPCTSTR lpszDocName) // old Win3.0 version + { + DOCINFO di = { 0 }; + di.cbSize = sizeof(DOCINFO); + di.lpszDocName = lpszDocName; + return StartDoc(&di); + } + + int StartDoc(LPDOCINFO lpDocInfo) + { + ATLASSERT(m_hDC != NULL); + return ::StartDoc(m_hDC, lpDocInfo); + } + + int StartPage() + { + ATLASSERT(m_hDC != NULL); + return ::StartPage(m_hDC); + } + + int EndPage() + { + ATLASSERT(m_hDC != NULL); + return ::EndPage(m_hDC); + } + + int SetAbortProc(BOOL (CALLBACK* lpfn)(HDC, int)) + { + ATLASSERT(m_hDC != NULL); + return ::SetAbortProc(m_hDC, (ABORTPROC)lpfn); + } + + int AbortDoc() + { + ATLASSERT(m_hDC != NULL); + return ::AbortDoc(m_hDC); + } + + int EndDoc() + { + ATLASSERT(m_hDC != NULL); + return ::EndDoc(m_hDC); + } +#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 200) && defined(StartDoc)) + +// MetaFile Functions +#ifndef _WIN32_WCE + BOOL PlayMetaFile(HMETAFILE hMF) + { + ATLASSERT(m_hDC != NULL); + if(::GetDeviceCaps(m_hDC, TECHNOLOGY) == DT_METAFILE) + { + // playing metafile in metafile, just use core windows API + return ::PlayMetaFile(m_hDC, hMF); + } + + // for special playback, lParam == pDC + return ::EnumMetaFile(m_hDC, hMF, EnumMetaFileProc, (LPARAM)this); + } + + BOOL PlayMetaFile(HENHMETAFILE hEnhMetaFile, LPCRECT lpBounds) + { + ATLASSERT(m_hDC != NULL); + return ::PlayEnhMetaFile(m_hDC, hEnhMetaFile, lpBounds); + } + + BOOL AddMetaFileComment(UINT nDataSize, const BYTE* pCommentData) // can be used for enhanced metafiles only + { + ATLASSERT(m_hDC != NULL); + return ::GdiComment(m_hDC, nDataSize, pCommentData); + } + + // Special handling for metafile playback + static int CALLBACK EnumMetaFileProc(HDC hDC, HANDLETABLE* pHandleTable, METARECORD* pMetaRec, int nHandles, LPARAM lParam) + { + CDCHandle* pDC = (CDCHandle*)lParam; + + switch (pMetaRec->rdFunction) + { + case META_SETMAPMODE: + pDC->SetMapMode((int)(short)pMetaRec->rdParm[0]); + break; + case META_SETWINDOWEXT: + pDC->SetWindowExt((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_SETWINDOWORG: + pDC->SetWindowOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_SETVIEWPORTEXT: + pDC->SetViewportExt((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_SETVIEWPORTORG: + pDC->SetViewportOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_SCALEWINDOWEXT: + pDC->ScaleWindowExt((int)(short)pMetaRec->rdParm[3], (int)(short)pMetaRec->rdParm[2], + (int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_SCALEVIEWPORTEXT: + pDC->ScaleViewportExt((int)(short)pMetaRec->rdParm[3], (int)(short)pMetaRec->rdParm[2], + (int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_OFFSETVIEWPORTORG: + pDC->OffsetViewportOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_SAVEDC: + pDC->SaveDC(); + break; + case META_RESTOREDC: + pDC->RestoreDC((int)(short)pMetaRec->rdParm[0]); + break; + case META_SETBKCOLOR: + pDC->SetBkColor(*(UNALIGNED COLORREF*)&pMetaRec->rdParm[0]); + break; + case META_SETTEXTCOLOR: + pDC->SetTextColor(*(UNALIGNED COLORREF*)&pMetaRec->rdParm[0]); + break; + + // need to watch out for SelectObject(HFONT), for custom font mapping + case META_SELECTOBJECT: + { + HGDIOBJ hObject = pHandleTable->objectHandle[pMetaRec->rdParm[0]]; + UINT nObjType = ::GetObjectType(hObject); + if(nObjType == 0) + { + // object type is unknown, determine if it is a font + HFONT hStockFont = (HFONT)::GetStockObject(SYSTEM_FONT); + HFONT hFontOld = (HFONT)::SelectObject(pDC->m_hDC, hStockFont); + HGDIOBJ hObjOld = ::SelectObject(pDC->m_hDC, hObject); + if(hObjOld == hStockFont) + { + // got the stock object back, so must be selecting a font + pDC->SelectFont((HFONT)hObject); + break; // don't play the default record + } + else + { + // didn't get the stock object back, so restore everything + ::SelectObject(pDC->m_hDC, hFontOld); + ::SelectObject(pDC->m_hDC, hObjOld); + } + // and fall through to PlayMetaFileRecord... + } + else if(nObjType == OBJ_FONT) + { + // play back as CDCHandle::SelectFont(HFONT) + pDC->SelectFont((HFONT)hObject); + break; // don't play the default record + } + } + // fall through... + + default: + ::PlayMetaFileRecord(hDC, pHandleTable, pMetaRec, nHandles); + break; + } + + return 1; + } +#endif // !_WIN32_WCE + +// Path Functions +#ifndef _WIN32_WCE + BOOL AbortPath() + { + ATLASSERT(m_hDC != NULL); + return ::AbortPath(m_hDC); + } + + BOOL BeginPath() + { + ATLASSERT(m_hDC != NULL); + return ::BeginPath(m_hDC); + } + + BOOL CloseFigure() + { + ATLASSERT(m_hDC != NULL); + return ::CloseFigure(m_hDC); + } + + BOOL EndPath() + { + ATLASSERT(m_hDC != NULL); + return ::EndPath(m_hDC); + } + + BOOL FillPath() + { + ATLASSERT(m_hDC != NULL); + return ::FillPath(m_hDC); + } + + BOOL FlattenPath() + { + ATLASSERT(m_hDC != NULL); + return ::FlattenPath(m_hDC); + } + + BOOL StrokeAndFillPath() + { + ATLASSERT(m_hDC != NULL); + return ::StrokeAndFillPath(m_hDC); + } + + BOOL StrokePath() + { + ATLASSERT(m_hDC != NULL); + return ::StrokePath(m_hDC); + } + + BOOL WidenPath() + { + ATLASSERT(m_hDC != NULL); + return ::WidenPath(m_hDC); + } + + BOOL GetMiterLimit(PFLOAT pfMiterLimit) const + { + ATLASSERT(m_hDC != NULL); + return ::GetMiterLimit(m_hDC, pfMiterLimit); + } + + BOOL SetMiterLimit(float fMiterLimit) + { + ATLASSERT(m_hDC != NULL); + return ::SetMiterLimit(m_hDC, fMiterLimit, NULL); + } + + int GetPath(LPPOINT lpPoints, LPBYTE lpTypes, int nCount) const + { + ATLASSERT(m_hDC != NULL); + return ::GetPath(m_hDC, lpPoints, lpTypes, nCount); + } + + BOOL SelectClipPath(int nMode) + { + ATLASSERT(m_hDC != NULL); + return ::SelectClipPath(m_hDC, nMode); + } +#endif // !_WIN32_WCE + +// Misc Helper Functions + static CBrushHandle PASCAL GetHalftoneBrush() + { + HBRUSH halftoneBrush = NULL; + WORD grayPattern[8] = { 0 }; + for(int i = 0; i < 8; i++) + grayPattern[i] = (WORD)(0x5555 << (i & 1)); + HBITMAP grayBitmap = CreateBitmap(8, 8, 1, 1, &grayPattern); + if(grayBitmap != NULL) + { + halftoneBrush = ::CreatePatternBrush(grayBitmap); + DeleteObject(grayBitmap); + } + return CBrushHandle(halftoneBrush); + } + + void DrawDragRect(LPCRECT lpRect, SIZE size, LPCRECT lpRectLast, SIZE sizeLast, HBRUSH hBrush = NULL, HBRUSH hBrushLast = NULL) + { + // first, determine the update region and select it + CRgn rgnOutside; + rgnOutside.CreateRectRgnIndirect(lpRect); + RECT rect = *lpRect; + ::InflateRect(&rect, -size.cx, -size.cy); + ::IntersectRect(&rect, &rect, lpRect); + CRgn rgnInside; + rgnInside.CreateRectRgnIndirect(&rect); + CRgn rgnNew; + rgnNew.CreateRectRgn(0, 0, 0, 0); + rgnNew.CombineRgn(rgnOutside, rgnInside, RGN_XOR); + + HBRUSH hBrushOld = NULL; + CBrush brushHalftone; + if(hBrush == NULL) + brushHalftone = hBrush = CDCHandle::GetHalftoneBrush(); + if(hBrushLast == NULL) + hBrushLast = hBrush; + + CRgn rgnLast; + CRgn rgnUpdate; + if(lpRectLast != NULL) + { + // find difference between new region and old region + rgnLast.CreateRectRgn(0, 0, 0, 0); + rgnOutside.SetRectRgn(lpRectLast->left, lpRectLast->top, lpRectLast->right, lpRectLast->bottom); + rect = *lpRectLast; + ::InflateRect(&rect, -sizeLast.cx, -sizeLast.cy); + ::IntersectRect(&rect, &rect, lpRectLast); + rgnInside.SetRectRgn(rect.left, rect.top, rect.right, rect.bottom); + rgnLast.CombineRgn(rgnOutside, rgnInside, RGN_XOR); + + // only diff them if brushes are the same + if(hBrush == hBrushLast) + { + rgnUpdate.CreateRectRgn(0, 0, 0, 0); + rgnUpdate.CombineRgn(rgnLast, rgnNew, RGN_XOR); + } + } + if(hBrush != hBrushLast && lpRectLast != NULL) + { + // brushes are different -- erase old region first + SelectClipRgn(rgnLast); + GetClipBox(&rect); + hBrushOld = SelectBrush(hBrushLast); + PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT); + SelectBrush(hBrushOld); + hBrushOld = NULL; + } + + // draw into the update/new region + SelectClipRgn(rgnUpdate.IsNull() ? rgnNew : rgnUpdate); + GetClipBox(&rect); + hBrushOld = SelectBrush(hBrush); + PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT); + + // cleanup DC + if(hBrushOld != NULL) + SelectBrush(hBrushOld); + SelectClipRgn(NULL); + } + + void FillSolidRect(LPCRECT lpRect, COLORREF clr) + { + ATLASSERT(m_hDC != NULL); + + COLORREF clrOld = ::SetBkColor(m_hDC, clr); + ATLASSERT(clrOld != CLR_INVALID); + if(clrOld != CLR_INVALID) + { + ::ExtTextOut(m_hDC, 0, 0, ETO_OPAQUE, lpRect, NULL, 0, NULL); + ::SetBkColor(m_hDC, clrOld); + } + } + + void FillSolidRect(int x, int y, int cx, int cy, COLORREF clr) + { + ATLASSERT(m_hDC != NULL); + + RECT rect = { x, y, x + cx, y + cy }; + FillSolidRect(&rect, clr); + } + + void Draw3dRect(LPCRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight) + { + Draw3dRect(lpRect->left, lpRect->top, lpRect->right - lpRect->left, + lpRect->bottom - lpRect->top, clrTopLeft, clrBottomRight); + } + + void Draw3dRect(int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight) + { + FillSolidRect(x, y, cx - 1, 1, clrTopLeft); + FillSolidRect(x, y, 1, cy - 1, clrTopLeft); + FillSolidRect(x + cx, y, -1, cy, clrBottomRight); + FillSolidRect(x, y + cy, cx, -1, clrBottomRight); + } + +// DIB support +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 410) + int SetDIBitsToDevice(int x, int y, DWORD dwWidth, DWORD dwHeight, int xSrc, int ySrc, UINT uStartScan, UINT cScanLines, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse) + { + ATLASSERT(m_hDC != NULL); + return ::SetDIBitsToDevice(m_hDC, x, y, dwWidth, dwHeight, xSrc, ySrc, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 410) + +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + int StretchDIBits(int x, int y, int nWidth, int nHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse, DWORD dwRop) + { + ATLASSERT(m_hDC != NULL); + return ::StretchDIBits(m_hDC, x, y, nWidth, nHeight, xSrc, ySrc, nSrcWidth, nSrcHeight, lpvBits, lpbmi, uColorUse, dwRop); + } + + UINT GetDIBColorTable(UINT uStartIndex, UINT cEntries, RGBQUAD* pColors) const + { + ATLASSERT(m_hDC != NULL); + return ::GetDIBColorTable(m_hDC, uStartIndex, cEntries, pColors); + } + + UINT SetDIBColorTable(UINT uStartIndex, UINT cEntries, CONST RGBQUAD* pColors) + { + ATLASSERT(m_hDC != NULL); + return ::SetDIBColorTable(m_hDC, uStartIndex, cEntries, pColors); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + +// OpenGL support +#if !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE) + int ChoosePixelFormat(CONST PIXELFORMATDESCRIPTOR* ppfd) + { + ATLASSERT(m_hDC != NULL); + return ::ChoosePixelFormat(m_hDC, ppfd); + } + + int DescribePixelFormat(int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd) + { + ATLASSERT(m_hDC != NULL); + return ::DescribePixelFormat(m_hDC, iPixelFormat, nBytes, ppfd); + } + + int GetPixelFormat() const + { + ATLASSERT(m_hDC != NULL); + return ::GetPixelFormat(m_hDC); + } + + BOOL SetPixelFormat(int iPixelFormat, CONST PIXELFORMATDESCRIPTOR* ppfd) + { + ATLASSERT(m_hDC != NULL); + return ::SetPixelFormat(m_hDC, iPixelFormat, ppfd); + } + + BOOL SwapBuffers() + { + ATLASSERT(m_hDC != NULL); + return ::SwapBuffers(m_hDC); + } + + HGLRC wglCreateContext() + { + ATLASSERT(m_hDC != NULL); + return ::wglCreateContext(m_hDC); + } + + HGLRC wglCreateLayerContext(int iLayerPlane) + { + ATLASSERT(m_hDC != NULL); + return ::wglCreateLayerContext(m_hDC, iLayerPlane); + } + + BOOL wglMakeCurrent(HGLRC hglrc) + { + ATLASSERT(m_hDC != NULL); + return ::wglMakeCurrent(m_hDC, hglrc); + } + + BOOL wglUseFontBitmaps(DWORD dwFirst, DWORD dwCount, DWORD listBase) + { + ATLASSERT(m_hDC != NULL); + return ::wglUseFontBitmaps(m_hDC, dwFirst, dwCount, listBase); + } + + BOOL wglUseFontOutlines(DWORD dwFirst, DWORD dwCount, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf) + { + ATLASSERT(m_hDC != NULL); + return ::wglUseFontOutlines(m_hDC, dwFirst, dwCount, listBase, deviation, extrusion, format, lpgmf); + } + + BOOL wglDescribeLayerPlane(int iPixelFormat, int iLayerPlane, UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd) + { + ATLASSERT(m_hDC != NULL); + return ::wglDescribeLayerPlane(m_hDC, iPixelFormat, iLayerPlane, nBytes, plpd); + } + + int wglSetLayerPaletteEntries(int iLayerPlane, int iStart, int cEntries, CONST COLORREF* pclr) + { + ATLASSERT(m_hDC != NULL); + return ::wglSetLayerPaletteEntries(m_hDC, iLayerPlane, iStart, cEntries, pclr); + } + + int wglGetLayerPaletteEntries(int iLayerPlane, int iStart, int cEntries, COLORREF* pclr) + { + ATLASSERT(m_hDC != NULL); + return ::wglGetLayerPaletteEntries(m_hDC, iLayerPlane, iStart, cEntries, pclr); + } + + BOOL wglRealizeLayerPalette(int iLayerPlane, BOOL bRealize) + { + ATLASSERT(m_hDC != NULL); + return ::wglRealizeLayerPalette(m_hDC, iLayerPlane, bRealize); + } + + BOOL wglSwapLayerBuffers(UINT uPlanes) + { + ATLASSERT(m_hDC != NULL); + return ::wglSwapLayerBuffers(m_hDC, uPlanes); + } +#endif // !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE) + +// New for Windows 2000 only +#if (_WIN32_WINNT >= 0x0500) + COLORREF GetDCPenColor() const + { + ATLASSERT(m_hDC != NULL); + return ::GetDCPenColor(m_hDC); + } + + COLORREF SetDCPenColor(COLORREF clr) + { + ATLASSERT(m_hDC != NULL); + return ::SetDCPenColor(m_hDC, clr); + } + + COLORREF GetDCBrushColor() const + { + ATLASSERT(m_hDC != NULL); + return ::GetDCBrushColor(m_hDC); + } + + COLORREF SetDCBrushColor(COLORREF clr) + { + ATLASSERT(m_hDC != NULL); + return ::SetDCBrushColor(m_hDC, clr); + } + +#ifndef _WIN32_WCE + DWORD GetFontUnicodeRanges(LPGLYPHSET lpgs) const + { + ATLASSERT(m_hDC != NULL); + return ::GetFontUnicodeRanges(m_hDC, lpgs); + } +#endif // !_WIN32_WCE + + DWORD GetGlyphIndices(LPCTSTR lpstr, int cch, LPWORD pgi, DWORD dwFlags) const + { + ATLASSERT(m_hDC != NULL); + return ::GetGlyphIndices(m_hDC, lpstr, cch, pgi, dwFlags); + } + + BOOL GetTextExtentPointI(LPWORD pgiIn, int cgi, LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextExtentPointI(m_hDC, pgiIn, cgi, lpSize); + } + + BOOL GetTextExtentExPointI(LPWORD pgiIn, int cgi, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextExtentExPointI(m_hDC, pgiIn, cgi, nMaxExtent, lpnFit, alpDx, lpSize); + } + + BOOL GetCharWidthI(UINT giFirst, UINT cgi, LPWORD pgi, LPINT lpBuffer) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharWidthI(m_hDC, giFirst, cgi, pgi, lpBuffer); + } + + BOOL GetCharABCWidthsI(UINT giFirst, UINT cgi, LPWORD pgi, LPABC lpabc) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharABCWidthsI(m_hDC, giFirst, cgi, pgi, lpabc); + } +#endif // (_WIN32_WINNT >= 0x0500) + +// New for Windows 2000 and Windows 98 +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + BOOL ColorCorrectPalette(HPALETTE hPalette, DWORD dwFirstEntry, DWORD dwNumOfEntries) + { + ATLASSERT(m_hDC != NULL); + return ::ColorCorrectPalette(m_hDC, hPalette, dwFirstEntry, dwNumOfEntries); + } +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) +}; + +typedef CDCT CDCHandle; +typedef CDCT CDC; + + +/////////////////////////////////////////////////////////////////////////////// +// CDC Helpers + +class CPaintDC : public CDC +{ +public: +// Data members + HWND m_hWnd; + PAINTSTRUCT m_ps; + +// Constructor/destructor + CPaintDC(HWND hWnd) + { + ATLASSERT(::IsWindow(hWnd)); + m_hWnd = hWnd; + m_hDC = ::BeginPaint(hWnd, &m_ps); + } + + ~CPaintDC() + { + ATLASSERT(m_hDC != NULL); + ATLASSERT(::IsWindow(m_hWnd)); + ::EndPaint(m_hWnd, &m_ps); + Detach(); + } +}; + +class CClientDC : public CDC +{ +public: +// Data members + HWND m_hWnd; + +// Constructor/destructor + CClientDC(HWND hWnd) + { + ATLASSERT(hWnd == NULL || ::IsWindow(hWnd)); + m_hWnd = hWnd; + m_hDC = ::GetDC(hWnd); + } + + ~CClientDC() + { + ATLASSERT(m_hDC != NULL); + ::ReleaseDC(m_hWnd, Detach()); + } +}; + +class CWindowDC : public CDC +{ +public: +// Data members + HWND m_hWnd; + +// Constructor/destructor + CWindowDC(HWND hWnd) + { + ATLASSERT(hWnd == NULL || ::IsWindow(hWnd)); + m_hWnd = hWnd; + m_hDC = ::GetWindowDC(hWnd); + } + + ~CWindowDC() + { + ATLASSERT(m_hDC != NULL); + ::ReleaseDC(m_hWnd, Detach()); + } +}; + +class CMemoryDC : public CDC +{ +public: +// Data members + HDC m_hDCOriginal; + RECT m_rcPaint; + CBitmap m_bmp; + HBITMAP m_hBmpOld; + +// Constructor/destructor + CMemoryDC(HDC hDC, const RECT& rcPaint) : m_hDCOriginal(hDC), m_hBmpOld(NULL) + { + m_rcPaint = rcPaint; + CreateCompatibleDC(m_hDCOriginal); + ATLASSERT(m_hDC != NULL); + m_bmp.CreateCompatibleBitmap(m_hDCOriginal, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top); + ATLASSERT(m_bmp.m_hBitmap != NULL); + m_hBmpOld = SelectBitmap(m_bmp); + SetViewportOrg(-m_rcPaint.left, -m_rcPaint.top); + } + + ~CMemoryDC() + { + ::BitBlt(m_hDCOriginal, m_rcPaint.left, m_rcPaint.top, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top, m_hDC, m_rcPaint.left, m_rcPaint.top, SRCCOPY); + SelectBitmap(m_hBmpOld); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Enhanced metafile support + +#ifndef _WIN32_WCE + +class CEnhMetaFileInfo +{ +public: +// Data members + HENHMETAFILE m_hEMF; + BYTE* m_pBits; + TCHAR* m_pDesc; + ENHMETAHEADER m_header; + PIXELFORMATDESCRIPTOR m_pfd; + +// Constructor/destructor + CEnhMetaFileInfo(HENHMETAFILE hEMF) : m_pBits(NULL), m_pDesc(NULL), m_hEMF(hEMF) + { } + + ~CEnhMetaFileInfo() + { + delete [] m_pBits; + delete [] m_pDesc; + } + +// Operations + BYTE* GetEnhMetaFileBits() + { + ATLASSERT(m_hEMF != NULL); + UINT nBytes = ::GetEnhMetaFileBits(m_hEMF, 0, NULL); + delete [] m_pBits; + m_pBits = NULL; + ATLTRY(m_pBits = new BYTE[nBytes]); + if (m_pBits != NULL) + ::GetEnhMetaFileBits(m_hEMF, nBytes, m_pBits); + return m_pBits; + } + + LPTSTR GetEnhMetaFileDescription() + { + ATLASSERT(m_hEMF != NULL); + UINT nLen = ::GetEnhMetaFileDescription(m_hEMF, 0, NULL); + delete [] m_pDesc; + m_pDesc = NULL; + ATLTRY(m_pDesc = new TCHAR[nLen]); + if (m_pDesc != NULL) + nLen = ::GetEnhMetaFileDescription(m_hEMF, nLen, m_pDesc); + return m_pDesc; + } + + ENHMETAHEADER* GetEnhMetaFileHeader() + { + ATLASSERT(m_hEMF != NULL); + memset(&m_header, 0, sizeof(m_header)); + m_header.iType = EMR_HEADER; + m_header.nSize = sizeof(ENHMETAHEADER); + UINT n = ::GetEnhMetaFileHeader(m_hEMF, sizeof(ENHMETAHEADER), &m_header); + return (n != 0) ? &m_header : NULL; + } + + PIXELFORMATDESCRIPTOR* GetEnhMetaFilePixelFormat() + { + ATLASSERT(m_hEMF != NULL); + memset(&m_pfd, 0, sizeof(m_pfd)); + UINT n = ::GetEnhMetaFilePixelFormat(m_hEMF, sizeof(m_pfd), &m_pfd); + return (n != 0) ? &m_pfd : NULL; + } +}; + + +template +class CEnhMetaFileT +{ +public: +// Data members + HENHMETAFILE m_hEMF; + +// Constructor/destructor + CEnhMetaFileT(HENHMETAFILE hEMF = NULL) : m_hEMF(hEMF) + { + } + + ~CEnhMetaFileT() + { + if(t_bManaged && m_hEMF != NULL) + DeleteObject(); + } + +// Operations + CEnhMetaFileT& operator =(HENHMETAFILE hEMF) + { + Attach(hEMF); + return *this; + } + + void Attach(HENHMETAFILE hEMF) + { + if(t_bManaged && m_hEMF != NULL && m_hEMF != hEMF) + DeleteObject(); + m_hEMF = hEMF; + } + + HENHMETAFILE Detach() + { + HENHMETAFILE hEMF = m_hEMF; + m_hEMF = NULL; + return hEMF; + } + + operator HENHMETAFILE() const { return m_hEMF; } + + bool IsNull() const { return (m_hEMF == NULL); } + + BOOL DeleteObject() + { + ATLASSERT(m_hEMF != NULL); + BOOL bRet = ::DeleteEnhMetaFile(m_hEMF); + m_hEMF = NULL; + return bRet; + } + + UINT GetEnhMetaFileBits(UINT cbBuffer, LPBYTE lpbBuffer) const + { + ATLASSERT(m_hEMF != NULL); + return ::GetEnhMetaFileBits(m_hEMF, cbBuffer, lpbBuffer); + } + + UINT GetEnhMetaFileDescription(UINT cchBuffer, LPTSTR lpszDescription) const + { + ATLASSERT(m_hEMF != NULL); + return ::GetEnhMetaFileDescription(m_hEMF, cchBuffer, lpszDescription); + } + + UINT GetEnhMetaFileHeader(LPENHMETAHEADER lpemh) const + { + ATLASSERT(m_hEMF != NULL); + lpemh->iType = EMR_HEADER; + lpemh->nSize = sizeof(ENHMETAHEADER); + return ::GetEnhMetaFileHeader(m_hEMF, sizeof(ENHMETAHEADER), lpemh); + } + + UINT GetEnhMetaFilePaletteEntries(UINT cEntries, LPPALETTEENTRY lppe) const + { + ATLASSERT(m_hEMF != NULL); + return ::GetEnhMetaFilePaletteEntries(m_hEMF, cEntries, lppe); + } + + UINT GetEnhMetaFilePixelFormat(DWORD cbBuffer, PIXELFORMATDESCRIPTOR* ppfd) const + { + ATLASSERT(m_hEMF != NULL); + return ::GetEnhMetaFilePixelFormat(m_hEMF, cbBuffer, ppfd); + } +}; + +typedef CEnhMetaFileT CEnhMetaFileHandle; +typedef CEnhMetaFileT CEnhMetaFile; + + +class CEnhMetaFileDC : public CDC +{ +public: +// Constructor/destructor + CEnhMetaFileDC() + { + } + + CEnhMetaFileDC(HDC hdc, LPCRECT lpRect) + { + Create(hdc, NULL, lpRect, NULL); + ATLASSERT(m_hDC != NULL); + } + + CEnhMetaFileDC(HDC hdcRef, LPCTSTR lpFilename, LPCRECT lpRect, LPCTSTR lpDescription) + { + Create(hdcRef, lpFilename, lpRect, lpDescription); + ATLASSERT(m_hDC != NULL); + } + + ~CEnhMetaFileDC() + { + HENHMETAFILE hEMF = Close(); + if (hEMF != NULL) + ::DeleteEnhMetaFile(hEMF); + } + +// Operations + void Create(HDC hdcRef, LPCTSTR lpFilename, LPCRECT lpRect, LPCTSTR lpDescription) + { + ATLASSERT(m_hDC == NULL); + m_hDC = ::CreateEnhMetaFile(hdcRef, lpFilename, lpRect, lpDescription); + } + + HENHMETAFILE Close() + { + HENHMETAFILE hEMF = NULL; + if (m_hDC != NULL) + { + hEMF = ::CloseEnhMetaFile(m_hDC); + m_hDC = NULL; + } + return hEMF; + } +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// WinCE compatible clipboard CF_DIB format support functions + +#ifndef _WTL_NO_DIB16 + +#define DIBINFO16_BITFIELDS { 31744, 992, 31 } + +// DIBINFO16 - To avoid color table problems in WinCE we only create this type of Dib +struct DIBINFO16 // a BITMAPINFO with 2 additional color bitfields +{ + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[3]; + + DIBINFO16(SIZE size) + { + BITMAPINFOHEADER bmih = { sizeof(BITMAPINFOHEADER), size.cx, size.cy, + 1, 16, BI_BITFIELDS, (DWORD)(2 * size.cx * size.cy), 0, 0, 3 }; + DWORD dw[3] = DIBINFO16_BITFIELDS ; + + bmiHeader = bmih; + SecureHelper::memcpy_x(bmiColors, sizeof(bmiColors), dw, 3 * sizeof(DWORD)); + } +}; + + +// AtlxxxDibxxx minimal packed DIB implementation and helpers to copy and paste CF_DIB + +inline bool AtlIsDib16(LPBITMAPINFOHEADER pbmih) +{ + return (pbmih->biBitCount == 16) && (pbmih->biCompression == BI_BITFIELDS); +} + +inline int AtlGetDibColorTableSize(LPBITMAPINFOHEADER pbmih) +{ + switch (pbmih->biBitCount) + { + case 2: + case 4: + case 8: + return pbmih->biClrUsed ? pbmih->biClrUsed : 1 << pbmih->biBitCount; + case 24: + break; + case 16: + case 32: + return pbmih->biCompression == BI_BITFIELDS ? 3 : 0; + default: + ATLASSERT(FALSE); // should never come here + } + + return 0; +} + +inline int AtlGetDibNumColors(LPBITMAPINFOHEADER pbmih) +{ + switch (pbmih->biBitCount) + { + case 2: + case 4: + case 8: + if (pbmih->biClrUsed) + return pbmih->biClrUsed; + else + break; + case 16: + if (pbmih->biCompression == BI_BITFIELDS ) + return 1 << 15; + else + break; + case 24: + break; + case 32: + if (pbmih->biCompression == BI_BITFIELDS ) + return 1 << 24; + else + break; + default: + ATLASSERT(FALSE); + } + + return 1 << pbmih->biBitCount; +} + +inline HBITMAP AtlGetDibBitmap(LPBITMAPINFO pbmi) +{ + CDC dc(NULL); + void* pBits = NULL; + + LPBYTE pDibBits = (LPBYTE)pbmi + sizeof(BITMAPINFOHEADER) + AtlGetDibColorTableSize(&pbmi->bmiHeader) * sizeof(RGBQUAD); + HBITMAP hbm = CreateDIBSection(dc, pbmi, DIB_RGB_COLORS, &pBits, NULL, NULL); + if (hbm != NULL) + { + int cbBits = pbmi->bmiHeader.biWidth * pbmi->bmiHeader.biHeight * pbmi->bmiHeader.biBitCount / 8; + SecureHelper::memcpy_x(pBits, cbBits, pDibBits, pbmi->bmiHeader.biSizeImage); + } + + return hbm; +} + +inline HBITMAP AtlCopyBitmap(HBITMAP hbm, SIZE sizeDst, bool bAsBitmap = false) +{ + CDC hdcSrc = CreateCompatibleDC(NULL); + CDC hdcDst = CreateCompatibleDC(NULL); + + CBitmapHandle hbmOld = NULL, hbmOld2 = NULL, bmSrc = hbm; + + CBitmap bmNew = NULL; + + SIZE sizeSrc = { 0 }; + bmSrc.GetSize(sizeSrc); + + hbmOld = hdcSrc.SelectBitmap(bmSrc); + + if (bAsBitmap) + { + bmNew.CreateCompatibleBitmap(hdcSrc, sizeDst.cx, sizeDst.cy); + } + else + { + DIBINFO16 dib16(sizeDst); + LPVOID pBits = NULL; + bmNew = CreateDIBSection(hdcDst, (const BITMAPINFO*)&dib16, DIB_RGB_COLORS, &pBits, NULL, NULL); + } + + ATLASSERT(!bmNew.IsNull()); + + hbmOld2 = hdcDst.SelectBitmap(bmNew); + BOOL bOK = FALSE; + + if ((sizeDst.cx == sizeSrc.cx) && (sizeDst.cy == sizeSrc.cy)) + bOK = hdcDst.BitBlt(0, 0, sizeDst.cx, sizeDst.cy, hdcSrc, 0, 0, SRCCOPY); + else + bOK = hdcDst.StretchBlt(0, 0, sizeDst.cx, sizeDst.cy, hdcSrc, 0, 0, sizeSrc.cx, sizeSrc.cy, SRCCOPY); + + hdcSrc.SelectBitmap(hbmOld); + hdcDst.SelectBitmap(hbmOld2); + + if (bOK == FALSE) + bmNew.DeleteObject(); + + return bmNew.Detach(); +} + +inline HLOCAL AtlCreatePackedDib16(HBITMAP hbm, SIZE size) +{ + DIBSECTION ds = { 0 }; + LPBYTE pDib = NULL; + bool bCopied = false; + + bool bOK = GetObject(hbm, sizeof(ds), &ds) == sizeof(ds); + if ((bOK == FALSE) || (ds.dsBm.bmBits == NULL) || (AtlIsDib16(&ds.dsBmih) == FALSE) || + (ds.dsBmih.biWidth != size.cx ) || (ds.dsBmih.biHeight != size.cy )) + { + if ((hbm = AtlCopyBitmap(hbm, size)) != NULL) + { + bCopied = true; + bOK = GetObject(hbm, sizeof(ds), &ds) == sizeof(ds); + } + else + { + bOK = FALSE; + } + } + + if((bOK != FALSE) && (AtlIsDib16(&ds.dsBmih) != FALSE) && (ds.dsBm.bmBits != NULL)) + { + pDib = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeof(DIBINFO16) + ds.dsBmih.biSizeImage); + if (pDib != NULL) + { + SecureHelper::memcpy_x(pDib, sizeof(DIBINFO16) + ds.dsBmih.biSizeImage, &ds.dsBmih, sizeof(DIBINFO16)); + SecureHelper::memcpy_x(pDib + sizeof(DIBINFO16), ds.dsBmih.biSizeImage, ds.dsBm.bmBits, ds.dsBmih.biSizeImage); + } + } + + if (bCopied == true) + DeleteObject(hbm); + + return (HLOCAL)pDib; +} + +inline bool AtlSetClipboardDib16(HBITMAP hbm, SIZE size, HWND hWnd) +{ + ATLASSERT(::IsWindow(hWnd)); + BOOL bOK = OpenClipboard(hWnd); + if (bOK != FALSE) + { + bOK = EmptyClipboard(); + if (bOK != FALSE) + { + HLOCAL hDib = AtlCreatePackedDib16(hbm, size); + if (hDib != NULL) + { + bOK = SetClipboardData(CF_DIB, hDib) != NULL; + if (bOK == FALSE) + LocalFree(hDib); + } + else + { + bOK = FALSE; + } + } + CloseClipboard(); + } + + return (bOK != FALSE); +} + +inline HBITMAP AtlGetClipboardDib(HWND hWnd) +{ + ATLASSERT(::IsWindow(hWnd) != FALSE); + HBITMAP hbm = NULL; + if (OpenClipboard(hWnd) != FALSE) + { + LPBITMAPINFO pbmi = (LPBITMAPINFO)GetClipboardData(CF_DIB); + if (pbmi != NULL) + hbm = AtlGetDibBitmap(pbmi); + CloseClipboard(); + } + + return hbm; +} + +#endif // _WTL_NO_DIB16 + +}; // namespace WTL + +#endif // __ATLGDI_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlmisc.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlmisc.h new file mode 100644 index 0000000000000000000000000000000000000000..ea4bb4da563a9f4e73667fd88b73aa40156d2dd7 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlmisc.h @@ -0,0 +1,3756 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLMISC_H__ +#define __ATLMISC_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atlmisc.h requires atlapp.h to be included first +#endif + + +#ifdef _ATL_TMP_NO_CSTRING + #define _WTL_NO_CSTRING +#endif + +#if defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING) + #error Conflicting options - both _WTL_USE_CSTRING and _WTL_NO_CSTRING are defined +#endif // defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING) + +#if !defined(_WTL_USE_CSTRING) && !defined(_WTL_NO_CSTRING) + #define _WTL_USE_CSTRING +#endif // !defined(_WTL_USE_CSTRING) && !defined(_WTL_NO_CSTRING) + +#ifndef _WTL_NO_CSTRING + #if defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT) + #error Cannot use CString floating point formatting with _ATL_MIN_CRT defined + #endif // defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT) +#endif // !_WTL_NO_CSTRING + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CSize +// CPoint +// CRect +// CString +// +// CRecentDocumentListBase +// CRecentDocumentList +// CFindFile +// +// Global functions: +// AtlGetStockPen() +// AtlGetStockBrush() +// AtlGetStockFont() +// AtlGetStockPalette() +// +// AtlCompactPath() + + +namespace WTL +{ + +#ifndef _WTL_NO_WTYPES + +// forward declarations +class CSize; +class CPoint; +class CRect; + +/////////////////////////////////////////////////////////////////////////////// +// CSize - Wrapper for Windows SIZE structure. + +class CSize : public SIZE +{ +public: +// Constructors + CSize() + { + cx = 0; + cy = 0; + } + + CSize(int initCX, int initCY) + { + cx = initCX; + cy = initCY; + } + + CSize(SIZE initSize) + { + *(SIZE*)this = initSize; + } + + CSize(POINT initPt) + { + *(POINT*)this = initPt; + } + + CSize(DWORD dwSize) + { + cx = (short)LOWORD(dwSize); + cy = (short)HIWORD(dwSize); + } + +// Operations + BOOL operator ==(SIZE size) const + { + return (cx == size.cx && cy == size.cy); + } + + BOOL operator !=(SIZE size) const + { + return (cx != size.cx || cy != size.cy); + } + + void operator +=(SIZE size) + { + cx += size.cx; + cy += size.cy; + } + + void operator -=(SIZE size) + { + cx -= size.cx; + cy -= size.cy; + } + + void SetSize(int CX, int CY) + { + cx = CX; + cy = CY; + } + +// Operators returning CSize values + CSize operator +(SIZE size) const + { + return CSize(cx + size.cx, cy + size.cy); + } + + CSize operator -(SIZE size) const + { + return CSize(cx - size.cx, cy - size.cy); + } + + CSize operator -() const + { + return CSize(-cx, -cy); + } + +// Operators returning CPoint values + CPoint operator +(POINT point) const; + CPoint operator -(POINT point) const; + +// Operators returning CRect values + CRect operator +(const RECT* lpRect) const; + CRect operator -(const RECT* lpRect) const; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPoint - Wrapper for Windows POINT structure. + +class CPoint : public POINT +{ +public: +// Constructors + CPoint() + { + x = 0; + y = 0; + } + + CPoint(int initX, int initY) + { + x = initX; + y = initY; + } + + CPoint(POINT initPt) + { + *(POINT*)this = initPt; + } + + CPoint(SIZE initSize) + { + *(SIZE*)this = initSize; + } + + CPoint(DWORD dwPoint) + { + x = (short)LOWORD(dwPoint); + y = (short)HIWORD(dwPoint); + } + +// Operations + void Offset(int xOffset, int yOffset) + { + x += xOffset; + y += yOffset; + } + + void Offset(POINT point) + { + x += point.x; + y += point.y; + } + + void Offset(SIZE size) + { + x += size.cx; + y += size.cy; + } + + BOOL operator ==(POINT point) const + { + return (x == point.x && y == point.y); + } + + BOOL operator !=(POINT point) const + { + return (x != point.x || y != point.y); + } + + void operator +=(SIZE size) + { + x += size.cx; + y += size.cy; + } + + void operator -=(SIZE size) + { + x -= size.cx; + y -= size.cy; + } + + void operator +=(POINT point) + { + x += point.x; + y += point.y; + } + + void operator -=(POINT point) + { + x -= point.x; + y -= point.y; + } + + void SetPoint(int X, int Y) + { + x = X; + y = Y; + } + +// Operators returning CPoint values + CPoint operator +(SIZE size) const + { + return CPoint(x + size.cx, y + size.cy); + } + + CPoint operator -(SIZE size) const + { + return CPoint(x - size.cx, y - size.cy); + } + + CPoint operator -() const + { + return CPoint(-x, -y); + } + + CPoint operator +(POINT point) const + { + return CPoint(x + point.x, y + point.y); + } + +// Operators returning CSize values + CSize operator -(POINT point) const + { + return CSize(x - point.x, y - point.y); + } + +// Operators returning CRect values + CRect operator +(const RECT* lpRect) const; + CRect operator -(const RECT* lpRect) const; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CRect - Wrapper for Windows RECT structure. + +class CRect : public RECT +{ +public: +// Constructors + CRect() + { + left = 0; + top = 0; + right = 0; + bottom = 0; + } + + CRect(int l, int t, int r, int b) + { + left = l; + top = t; + right = r; + bottom = b; + } + + CRect(const RECT& srcRect) + { + ::CopyRect(this, &srcRect); + } + + CRect(LPCRECT lpSrcRect) + { + ::CopyRect(this, lpSrcRect); + } + + CRect(POINT point, SIZE size) + { + right = (left = point.x) + size.cx; + bottom = (top = point.y) + size.cy; + } + + CRect(POINT topLeft, POINT bottomRight) + { + left = topLeft.x; + top = topLeft.y; + right = bottomRight.x; + bottom = bottomRight.y; + } + +// Attributes (in addition to RECT members) + int Width() const + { + return right - left; + } + + int Height() const + { + return bottom - top; + } + + CSize Size() const + { + return CSize(right - left, bottom - top); + } + + CPoint& TopLeft() + { + return *((CPoint*)this); + } + + CPoint& BottomRight() + { + return *((CPoint*)this + 1); + } + + const CPoint& TopLeft() const + { + return *((CPoint*)this); + } + + const CPoint& BottomRight() const + { + return *((CPoint*)this + 1); + } + + CPoint CenterPoint() const + { + return CPoint((left + right) / 2, (top + bottom) / 2); + } + + // convert between CRect and LPRECT/LPCRECT (no need for &) + operator LPRECT() + { + return this; + } + + operator LPCRECT() const + { + return this; + } + + BOOL IsRectEmpty() const + { + return ::IsRectEmpty(this); + } + + BOOL IsRectNull() const + { + return (left == 0 && right == 0 && top == 0 && bottom == 0); + } + + BOOL PtInRect(POINT point) const + { + return ::PtInRect(this, point); + } + +// Operations + void SetRect(int x1, int y1, int x2, int y2) + { + ::SetRect(this, x1, y1, x2, y2); + } + + void SetRect(POINT topLeft, POINT bottomRight) + { + ::SetRect(this, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); + } + + void SetRectEmpty() + { + ::SetRectEmpty(this); + } + + void CopyRect(LPCRECT lpSrcRect) + { + ::CopyRect(this, lpSrcRect); + } + + BOOL EqualRect(LPCRECT lpRect) const + { + return ::EqualRect(this, lpRect); + } + + void InflateRect(int x, int y) + { + ::InflateRect(this, x, y); + } + + void InflateRect(SIZE size) + { + ::InflateRect(this, size.cx, size.cy); + } + + void InflateRect(LPCRECT lpRect) + { + left -= lpRect->left; + top -= lpRect->top; + right += lpRect->right; + bottom += lpRect->bottom; + } + + void InflateRect(int l, int t, int r, int b) + { + left -= l; + top -= t; + right += r; + bottom += b; + } + + void DeflateRect(int x, int y) + { + ::InflateRect(this, -x, -y); + } + + void DeflateRect(SIZE size) + { + ::InflateRect(this, -size.cx, -size.cy); + } + + void DeflateRect(LPCRECT lpRect) + { + left += lpRect->left; + top += lpRect->top; + right -= lpRect->right; + bottom -= lpRect->bottom; + } + + void DeflateRect(int l, int t, int r, int b) + { + left += l; + top += t; + right -= r; + bottom -= b; + } + + void OffsetRect(int x, int y) + { + ::OffsetRect(this, x, y); + } + void OffsetRect(SIZE size) + { + ::OffsetRect(this, size.cx, size.cy); + } + + void OffsetRect(POINT point) + { + ::OffsetRect(this, point.x, point.y); + } + + void NormalizeRect() + { + int nTemp; + if (left > right) + { + nTemp = left; + left = right; + right = nTemp; + } + if (top > bottom) + { + nTemp = top; + top = bottom; + bottom = nTemp; + } + } + + // absolute position of rectangle + void MoveToY(int y) + { + bottom = Height() + y; + top = y; + } + + void MoveToX(int x) + { + right = Width() + x; + left = x; + } + + void MoveToXY(int x, int y) + { + MoveToX(x); + MoveToY(y); + } + + void MoveToXY(POINT pt) + { + MoveToX(pt.x); + MoveToY(pt.y); + } + + // operations that fill '*this' with result + BOOL IntersectRect(LPCRECT lpRect1, LPCRECT lpRect2) + { + return ::IntersectRect(this, lpRect1, lpRect2); + } + + BOOL UnionRect(LPCRECT lpRect1, LPCRECT lpRect2) + { + return ::UnionRect(this, lpRect1, lpRect2); + } + + BOOL SubtractRect(LPCRECT lpRectSrc1, LPCRECT lpRectSrc2) + { + return ::SubtractRect(this, lpRectSrc1, lpRectSrc2); + } + +// Additional Operations + void operator =(const RECT& srcRect) + { + ::CopyRect(this, &srcRect); + } + + BOOL operator ==(const RECT& rect) const + { + return ::EqualRect(this, &rect); + } + + BOOL operator !=(const RECT& rect) const + { + return !::EqualRect(this, &rect); + } + + void operator +=(POINT point) + { + ::OffsetRect(this, point.x, point.y); + } + + void operator +=(SIZE size) + { + ::OffsetRect(this, size.cx, size.cy); + } + + void operator +=(LPCRECT lpRect) + { + InflateRect(lpRect); + } + + void operator -=(POINT point) + { + ::OffsetRect(this, -point.x, -point.y); + } + + void operator -=(SIZE size) + { + ::OffsetRect(this, -size.cx, -size.cy); + } + + void operator -=(LPCRECT lpRect) + { + DeflateRect(lpRect); + } + + void operator &=(const RECT& rect) + { + ::IntersectRect(this, this, &rect); + } + + void operator |=(const RECT& rect) + { + ::UnionRect(this, this, &rect); + } + +// Operators returning CRect values + CRect operator +(POINT pt) const + { + CRect rect(*this); + ::OffsetRect(&rect, pt.x, pt.y); + return rect; + } + + CRect operator -(POINT pt) const + { + CRect rect(*this); + ::OffsetRect(&rect, -pt.x, -pt.y); + return rect; + } + + CRect operator +(LPCRECT lpRect) const + { + CRect rect(this); + rect.InflateRect(lpRect); + return rect; + } + + CRect operator +(SIZE size) const + { + CRect rect(*this); + ::OffsetRect(&rect, size.cx, size.cy); + return rect; + } + + CRect operator -(SIZE size) const + { + CRect rect(*this); + ::OffsetRect(&rect, -size.cx, -size.cy); + return rect; + } + + CRect operator -(LPCRECT lpRect) const + { + CRect rect(this); + rect.DeflateRect(lpRect); + return rect; + } + + CRect operator &(const RECT& rect2) const + { + CRect rect; + ::IntersectRect(&rect, this, &rect2); + return rect; + } + + CRect operator |(const RECT& rect2) const + { + CRect rect; + ::UnionRect(&rect, this, &rect2); + return rect; + } + + CRect MulDiv(int nMultiplier, int nDivisor) const + { + return CRect( + ::MulDiv(left, nMultiplier, nDivisor), + ::MulDiv(top, nMultiplier, nDivisor), + ::MulDiv(right, nMultiplier, nDivisor), + ::MulDiv(bottom, nMultiplier, nDivisor)); + } +}; + + +// CSize implementation + +inline CPoint CSize::operator +(POINT point) const +{ return CPoint(cx + point.x, cy + point.y); } + +inline CPoint CSize::operator -(POINT point) const +{ return CPoint(cx - point.x, cy - point.y); } + +inline CRect CSize::operator +(const RECT* lpRect) const +{ return CRect(lpRect) + *this; } + +inline CRect CSize::operator -(const RECT* lpRect) const +{ return CRect(lpRect) - *this; } + + +// CPoint implementation + +inline CRect CPoint::operator +(const RECT* lpRect) const +{ return CRect(lpRect) + *this; } + +inline CRect CPoint::operator -(const RECT* lpRect) const +{ return CRect(lpRect) - *this; } + +#endif // !_WTL_NO_WTYPES + + +// WTL::CSize or ATL::CSize scalar operators + +#if !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLTYPES_H__)) + +template +inline CSize operator *(SIZE s, Num n) +{ + return CSize((int)(s.cx * n), (int)(s.cy * n)); +}; + +template +inline void operator *=(SIZE & s, Num n) +{ + s = s * n; +}; + +template +inline CSize operator /(SIZE s, Num n) +{ + return CSize((int)(s.cx / n), (int)(s.cy / n)); +}; + +template +inline void operator /=(SIZE & s, Num n) +{ + s = s / n; +}; + +#endif // !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLTYPES_H__)) + + +/////////////////////////////////////////////////////////////////////////////// +// CString - String class + +#ifndef _WTL_NO_CSTRING + +struct CStringData +{ + long nRefs; // reference count + int nDataLength; + int nAllocLength; + // TCHAR data[nAllocLength] + + TCHAR* data() + { return (TCHAR*)(this + 1); } +}; + +// Globals + +// For an empty string, m_pchData will point here +// (note: avoids special case of checking for NULL m_pchData) +// empty string data (and locked) +_declspec(selectany) int rgInitData[] = { -1, 0, 0, 0 }; +_declspec(selectany) CStringData* _atltmpDataNil = (CStringData*)&rgInitData; +_declspec(selectany) LPCTSTR _atltmpPchNil = (LPCTSTR)(((BYTE*)&rgInitData) + sizeof(CStringData)); + + +class CString +{ +public: +// Constructors + CString() + { + Init(); + } + + CString(const CString& stringSrc) + { + ATLASSERT(stringSrc.GetData()->nRefs != 0); + if (stringSrc.GetData()->nRefs >= 0) + { + ATLASSERT(stringSrc.GetData() != _atltmpDataNil); + m_pchData = stringSrc.m_pchData; + InterlockedIncrement(&GetData()->nRefs); + } + else + { + Init(); + *this = stringSrc.m_pchData; + } + } + + CString(TCHAR ch, int nRepeat = 1) + { + ATLASSERT(!_istlead(ch)); // can't create a lead byte string + Init(); + if (nRepeat >= 1) + { + if(AllocBuffer(nRepeat)) + { +#ifdef _UNICODE + for (int i = 0; i < nRepeat; i++) + m_pchData[i] = ch; +#else + memset(m_pchData, ch, nRepeat); +#endif + } + } + } + + CString(LPCTSTR lpsz) + { + Init(); + if (lpsz != NULL && HIWORD(lpsz) == NULL) + { + UINT nID = LOWORD((DWORD_PTR)lpsz); + if (!LoadString(nID)) + ATLTRACE2(atlTraceUI, 0, _T("Warning: implicit LoadString(%u) in CString failed\n"), nID); + } + else + { + int nLen = SafeStrlen(lpsz); + if (nLen != 0) + { + if(AllocBuffer(nLen)) + SecureHelper::memcpy_x(m_pchData, (nLen + 1) * sizeof(TCHAR), lpsz, nLen * sizeof(TCHAR)); + } + } + } + +#ifdef _UNICODE + CString(LPCSTR lpsz) + { + Init(); +#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) + int nSrcLen = (lpsz != NULL) ? ATL::lstrlenA(lpsz) : 0; +#else + int nSrcLen = (lpsz != NULL) ? lstrlenA(lpsz) : 0; +#endif + if (nSrcLen != 0) + { + if(AllocBuffer(nSrcLen)) + { + _mbstowcsz(m_pchData, lpsz, nSrcLen + 1); + ReleaseBuffer(); + } + } + } +#else // !_UNICODE + CString(LPCWSTR lpsz) + { + Init(); + int nSrcLen = (lpsz != NULL) ? (int)wcslen(lpsz) : 0; + if (nSrcLen != 0) + { + if(AllocBuffer(nSrcLen * 2)) + { + _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1); + ReleaseBuffer(); + } + } + } +#endif // !_UNICODE + + CString(LPCTSTR lpch, int nLength) + { + Init(); + if (nLength != 0) + { + if(AllocBuffer(nLength)) + SecureHelper::memcpy_x(m_pchData, (nLength + 1) * sizeof(TCHAR), lpch, nLength * sizeof(TCHAR)); + } + } + +#ifdef _UNICODE + CString(LPCSTR lpsz, int nLength) + { + Init(); + if (nLength != 0) + { + if(AllocBuffer(nLength)) + { + int n = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nLength, m_pchData, nLength + 1); + ReleaseBuffer((n >= 0) ? n : -1); + } + } + } +#else // !_UNICODE + CString(LPCWSTR lpsz, int nLength) + { + Init(); + if (nLength != 0) + { + if(((nLength * 2) > nLength) && AllocBuffer(nLength * 2)) + { + int n = ::WideCharToMultiByte(CP_ACP, 0, lpsz, nLength, m_pchData, (nLength * 2) + 1, NULL, NULL); + ReleaseBuffer((n >= 0) ? n : -1); + } + } + } +#endif // !_UNICODE + + CString(const unsigned char* lpsz) + { + Init(); + *this = (LPCSTR)lpsz; + } + +// Attributes & Operations + int GetLength() const // as an array of characters + { + return GetData()->nDataLength; + } + + BOOL IsEmpty() const + { + return GetData()->nDataLength == 0; + } + + void Empty() // free up the data + { + if (GetData()->nDataLength == 0) + return; + + if (GetData()->nRefs >= 0) + Release(); + else + *this = _T(""); + + ATLASSERT(GetData()->nDataLength == 0); + ATLASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0); + } + + TCHAR GetAt(int nIndex) const // 0 based + { + ATLASSERT(nIndex >= 0); + ATLASSERT(nIndex < GetData()->nDataLength); + return m_pchData[nIndex]; + } + + TCHAR operator [](int nIndex) const // same as GetAt + { + // same as GetAt + ATLASSERT(nIndex >= 0); + ATLASSERT(nIndex < GetData()->nDataLength); + return m_pchData[nIndex]; + } + + void SetAt(int nIndex, TCHAR ch) + { + ATLASSERT(nIndex >= 0); + ATLASSERT(nIndex < GetData()->nDataLength); + + CopyBeforeWrite(); + m_pchData[nIndex] = ch; + } + + operator LPCTSTR() const // as a C string + { + return m_pchData; + } + + // overloaded assignment + CString& operator =(const CString& stringSrc) + { + if (m_pchData != stringSrc.m_pchData) + { + if ((GetData()->nRefs < 0 && GetData() != _atltmpDataNil) || stringSrc.GetData()->nRefs < 0) + { + // actual copy necessary since one of the strings is locked + AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData); + } + else + { + // can just copy references around + Release(); + ATLASSERT(stringSrc.GetData() != _atltmpDataNil); + m_pchData = stringSrc.m_pchData; + InterlockedIncrement(&GetData()->nRefs); + } + } + return *this; + } + + CString& operator =(TCHAR ch) + { + ATLASSERT(!_istlead(ch)); // can't set single lead byte + AssignCopy(1, &ch); + return *this; + } + +#ifdef _UNICODE + CString& operator =(char ch) + { + *this = (TCHAR)ch; + return *this; + } +#endif + + CString& operator =(LPCTSTR lpsz) + { + ATLASSERT(lpsz == NULL || _IsValidString(lpsz)); + AssignCopy(SafeStrlen(lpsz), lpsz); + return *this; + } + +#ifdef _UNICODE + CString& operator =(LPCSTR lpsz) + { +#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) + int nSrcLen = (lpsz != NULL) ? ATL::lstrlenA(lpsz) : 0; +#else + int nSrcLen = (lpsz != NULL) ? lstrlenA(lpsz) : 0; +#endif + if(AllocBeforeWrite(nSrcLen)) + { + _mbstowcsz(m_pchData, lpsz, nSrcLen + 1); + ReleaseBuffer(); + } + return *this; + } +#else // !_UNICODE + CString& operator =(LPCWSTR lpsz) + { + int nSrcLen = (lpsz != NULL) ? (int)wcslen(lpsz) : 0; + if(AllocBeforeWrite(nSrcLen * 2)) + { + _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1); + ReleaseBuffer(); + } + return *this; + } +#endif // !_UNICODE + + CString& operator =(const unsigned char* lpsz) + { + *this = (LPCSTR)lpsz; + return *this; + } + + // string concatenation + CString& operator +=(const CString& string) + { + ConcatInPlace(string.GetData()->nDataLength, string.m_pchData); + return *this; + } + + CString& operator +=(TCHAR ch) + { + ConcatInPlace(1, &ch); + return *this; + } + +#ifdef _UNICODE + CString& operator +=(char ch) + { + *this += (TCHAR)ch; + return *this; + } +#endif + + CString& operator +=(LPCTSTR lpsz) + { + ATLASSERT(lpsz == NULL || _IsValidString(lpsz)); + ConcatInPlace(SafeStrlen(lpsz), lpsz); + return *this; + } + + friend CString __stdcall operator +(const CString& string1, const CString& string2); + friend CString __stdcall operator +(const CString& string, TCHAR ch); + friend CString __stdcall operator +(TCHAR ch, const CString& string); +#ifdef _UNICODE + friend CString __stdcall operator +(const CString& string, char ch); + friend CString __stdcall operator +(char ch, const CString& string); +#endif + friend CString __stdcall operator +(const CString& string, LPCTSTR lpsz); + friend CString __stdcall operator +(LPCTSTR lpsz, const CString& string); + + // string comparison + int Compare(LPCTSTR lpsz) const // straight character (MBCS/Unicode aware) + { + return _cstrcmp(m_pchData, lpsz); + } + + int CompareNoCase(LPCTSTR lpsz) const // ignore case (MBCS/Unicode aware) + { + return _cstrcmpi(m_pchData, lpsz); + } + +#ifndef _WIN32_WCE + // CString::Collate is often slower than Compare but is MBSC/Unicode + // aware as well as locale-sensitive with respect to sort order. + int Collate(LPCTSTR lpsz) const // NLS aware + { + return _cstrcoll(m_pchData, lpsz); + } + + int CollateNoCase(LPCTSTR lpsz) const // ignore case + { + return _cstrcolli(m_pchData, lpsz); + } +#endif // !_WIN32_WCE + + // simple sub-string extraction + CString Mid(int nFirst, int nCount) const + { + // out-of-bounds requests return sensible things + if (nFirst < 0) + nFirst = 0; + if (nCount < 0) + nCount = 0; + + if (nFirst + nCount > GetData()->nDataLength) + nCount = GetData()->nDataLength - nFirst; + if (nFirst > GetData()->nDataLength) + nCount = 0; + + CString dest; + AllocCopy(dest, nCount, nFirst, 0); + return dest; + } + + CString Mid(int nFirst) const + { + return Mid(nFirst, GetData()->nDataLength - nFirst); + } + + CString Left(int nCount) const + { + if (nCount < 0) + nCount = 0; + else if (nCount > GetData()->nDataLength) + nCount = GetData()->nDataLength; + + CString dest; + AllocCopy(dest, nCount, 0, 0); + return dest; + } + + CString Right(int nCount) const + { + if (nCount < 0) + nCount = 0; + else if (nCount > GetData()->nDataLength) + nCount = GetData()->nDataLength; + + CString dest; + AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0); + return dest; + } + + CString SpanIncluding(LPCTSTR lpszCharSet) const // strspn equivalent + { + ATLASSERT(_IsValidString(lpszCharSet)); + return Left(_cstrspn(m_pchData, lpszCharSet)); + } + + CString SpanExcluding(LPCTSTR lpszCharSet) const // strcspn equivalent + { + ATLASSERT(_IsValidString(lpszCharSet)); + return Left(_cstrcspn(m_pchData, lpszCharSet)); + } + + // upper/lower/reverse conversion + void MakeUpper() + { + CopyBeforeWrite(); + CharUpper(m_pchData); + } + + void MakeLower() + { + CopyBeforeWrite(); + CharLower(m_pchData); + } + + void MakeReverse() + { + CopyBeforeWrite(); + _cstrrev(m_pchData); + } + + // trimming whitespace (either side) + void TrimRight() + { + CopyBeforeWrite(); + + // find beginning of trailing spaces by starting at beginning (DBCS aware) + LPTSTR lpsz = m_pchData; + LPTSTR lpszLast = NULL; + while (*lpsz != _T('\0')) + { + if (_cstrisspace(*lpsz)) + { + if (lpszLast == NULL) + lpszLast = lpsz; + } + else + { + lpszLast = NULL; + } + lpsz = ::CharNext(lpsz); + } + + if (lpszLast != NULL) + { + // truncate at trailing space start + *lpszLast = _T('\0'); + GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData); + } + } + + void TrimLeft() + { + CopyBeforeWrite(); + + // find first non-space character + LPCTSTR lpsz = m_pchData; + while (_cstrisspace(*lpsz)) + lpsz = ::CharNext(lpsz); + + // fix up data and length + int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData); + SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR)); + GetData()->nDataLength = nDataLength; + } + + // remove continuous occurrences of chTarget starting from right + void TrimRight(TCHAR chTarget) + { + // find beginning of trailing matches + // by starting at beginning (DBCS aware) + + CopyBeforeWrite(); + LPTSTR lpsz = m_pchData; + LPTSTR lpszLast = NULL; + + while (*lpsz != _T('\0')) + { + if (*lpsz == chTarget) + { + if (lpszLast == NULL) + lpszLast = lpsz; + } + else + lpszLast = NULL; + lpsz = ::CharNext(lpsz); + } + + if (lpszLast != NULL) + { + // truncate at left-most matching character + *lpszLast = _T('\0'); + GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData); + } + } + + // remove continuous occcurrences of characters in passed string, starting from right + void TrimRight(LPCTSTR lpszTargetList) + { + // find beginning of trailing matches by starting at beginning (DBCS aware) + + CopyBeforeWrite(); + LPTSTR lpsz = m_pchData; + LPTSTR lpszLast = NULL; + + while (*lpsz != _T('\0')) + { + TCHAR* pNext = ::CharNext(lpsz); + if(pNext > lpsz + 1) + { + if (_cstrchr_db(lpszTargetList, *lpsz, *(lpsz + 1)) != NULL) + { + if (lpszLast == NULL) + lpszLast = lpsz; + } + else + { + lpszLast = NULL; + } + } + else + { + if (_cstrchr(lpszTargetList, *lpsz) != NULL) + { + if (lpszLast == NULL) + lpszLast = lpsz; + } + else + { + lpszLast = NULL; + } + } + + lpsz = pNext; + } + + if (lpszLast != NULL) + { + // truncate at left-most matching character + *lpszLast = _T('\0'); + GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData); + } + } + + // remove continuous occurrences of chTarget starting from left + void TrimLeft(TCHAR chTarget) + { + // find first non-matching character + + CopyBeforeWrite(); + LPCTSTR lpsz = m_pchData; + + while (chTarget == *lpsz) + lpsz = ::CharNext(lpsz); + + if (lpsz != m_pchData) + { + // fix up data and length + int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData); + SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR)); + GetData()->nDataLength = nDataLength; + } + } + + // remove continuous occcurrences of characters in passed string, starting from left + void TrimLeft(LPCTSTR lpszTargets) + { + // if we're not trimming anything, we're not doing any work + if (SafeStrlen(lpszTargets) == 0) + return; + + CopyBeforeWrite(); + LPCTSTR lpsz = m_pchData; + + while (*lpsz != _T('\0')) + { + TCHAR* pNext = ::CharNext(lpsz); + if(pNext > lpsz + 1) + { + if (_cstrchr_db(lpszTargets, *lpsz, *(lpsz + 1)) == NULL) + break; + } + else + { + if (_cstrchr(lpszTargets, *lpsz) == NULL) + break; + } + lpsz = pNext; + } + + if (lpsz != m_pchData) + { + // fix up data and length + int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData); + SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR)); + GetData()->nDataLength = nDataLength; + } + } + + // advanced manipulation + // replace occurrences of chOld with chNew + int Replace(TCHAR chOld, TCHAR chNew) + { + int nCount = 0; + + // short-circuit the nop case + if (chOld != chNew) + { + // otherwise modify each character that matches in the string + CopyBeforeWrite(); + LPTSTR psz = m_pchData; + LPTSTR pszEnd = psz + GetData()->nDataLength; + while (psz < pszEnd) + { + // replace instances of the specified character only + if (*psz == chOld) + { + *psz = chNew; + nCount++; + } + psz = ::CharNext(psz); + } + } + return nCount; + } + + // replace occurrences of substring lpszOld with lpszNew; + // empty lpszNew removes instances of lpszOld + int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew) + { + // can't have empty or NULL lpszOld + + int nSourceLen = SafeStrlen(lpszOld); + if (nSourceLen == 0) + return 0; + int nReplacementLen = SafeStrlen(lpszNew); + + // loop once to figure out the size of the result string + int nCount = 0; + LPTSTR lpszStart = m_pchData; + LPTSTR lpszEnd = m_pchData + GetData()->nDataLength; + LPTSTR lpszTarget = NULL; + while (lpszStart < lpszEnd) + { + while ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL) + { + nCount++; + lpszStart = lpszTarget + nSourceLen; + } + lpszStart += lstrlen(lpszStart) + 1; + } + + // if any changes were made, make them + if (nCount > 0) + { + CopyBeforeWrite(); + + // if the buffer is too small, just allocate a new buffer (slow but sure) + int nOldLength = GetData()->nDataLength; + int nNewLength = nOldLength + (nReplacementLen - nSourceLen) * nCount; + if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1) + { + CStringData* pOldData = GetData(); + LPTSTR pstr = m_pchData; + if(!AllocBuffer(nNewLength)) + return -1; + SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, pOldData->nDataLength * sizeof(TCHAR)); + CString::Release(pOldData); + } + // else, we just do it in-place + lpszStart = m_pchData; + lpszEnd = m_pchData + GetData()->nDataLength; + + // loop again to actually do the work + while (lpszStart < lpszEnd) + { + while ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL) + { + int nBalance = nOldLength - ((int)(DWORD_PTR)(lpszTarget - m_pchData) + nSourceLen); + int cchBuffLen = GetData()->nAllocLength - (int)(DWORD_PTR)(lpszTarget - m_pchData); + SecureHelper::memmove_x(lpszTarget + nReplacementLen, (cchBuffLen - nReplacementLen + 1) * sizeof(TCHAR), lpszTarget + nSourceLen, nBalance * sizeof(TCHAR)); + SecureHelper::memcpy_x(lpszTarget, (cchBuffLen + 1) * sizeof(TCHAR), lpszNew, nReplacementLen * sizeof(TCHAR)); + lpszStart = lpszTarget + nReplacementLen; + lpszStart[nBalance] = _T('\0'); + nOldLength += (nReplacementLen - nSourceLen); + } + lpszStart += lstrlen(lpszStart) + 1; + } + ATLASSERT(m_pchData[nNewLength] == _T('\0')); + GetData()->nDataLength = nNewLength; + } + + return nCount; + } + + // remove occurrences of chRemove + int Remove(TCHAR chRemove) + { + CopyBeforeWrite(); + + LPTSTR pstrSource = m_pchData; + LPTSTR pstrDest = m_pchData; + LPTSTR pstrEnd = m_pchData + GetData()->nDataLength; + + while (pstrSource < pstrEnd) + { + if (*pstrSource != chRemove) + { + *pstrDest = *pstrSource; + pstrDest = ::CharNext(pstrDest); + } + pstrSource = ::CharNext(pstrSource); + } + *pstrDest = _T('\0'); + int nCount = (int)(DWORD_PTR)(pstrSource - pstrDest); + GetData()->nDataLength -= nCount; + + return nCount; + } + + // insert character at zero-based index; concatenates if index is past end of string + int Insert(int nIndex, TCHAR ch) + { + CopyBeforeWrite(); + + if (nIndex < 0) + nIndex = 0; + + int nNewLength = GetData()->nDataLength; + if (nIndex > nNewLength) + nIndex = nNewLength; + nNewLength++; + + if (GetData()->nAllocLength < nNewLength) + { + CStringData* pOldData = GetData(); + LPTSTR pstr = m_pchData; + if(!AllocBuffer(nNewLength)) + return -1; + SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR)); + CString::Release(pOldData); + } + + // move existing bytes down + SecureHelper::memmove_x(m_pchData + nIndex + 1, (GetData()->nAllocLength - nIndex) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex) * sizeof(TCHAR)); + m_pchData[nIndex] = ch; + GetData()->nDataLength = nNewLength; + + return nNewLength; + } + + // insert substring at zero-based index; concatenates if index is past end of string + int Insert(int nIndex, LPCTSTR pstr) + { + if (nIndex < 0) + nIndex = 0; + + int nInsertLength = SafeStrlen(pstr); + int nNewLength = GetData()->nDataLength; + if (nInsertLength > 0) + { + CopyBeforeWrite(); + if (nIndex > nNewLength) + nIndex = nNewLength; + nNewLength += nInsertLength; + + if (GetData()->nAllocLength < nNewLength) + { + CStringData* pOldData = GetData(); + LPTSTR pstrTmp = m_pchData; + if(!AllocBuffer(nNewLength)) + return -1; + SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstrTmp, (pOldData->nDataLength + 1) * sizeof(TCHAR)); + CString::Release(pOldData); + } + + // move existing bytes down + SecureHelper::memmove_x(m_pchData + nIndex + nInsertLength, (GetData()->nAllocLength + 1 - nIndex - nInsertLength) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex - nInsertLength + 1) * sizeof(TCHAR)); + SecureHelper::memcpy_x(m_pchData + nIndex, (GetData()->nAllocLength + 1 - nIndex) * sizeof(TCHAR), pstr, nInsertLength * sizeof(TCHAR)); + GetData()->nDataLength = nNewLength; + } + + return nNewLength; + } + + // delete nCount characters starting at zero-based index + int Delete(int nIndex, int nCount = 1) + { + if (nIndex < 0) + nIndex = 0; + int nLength = GetData()->nDataLength; + if (nCount > 0 && nIndex < nLength) + { + if((nIndex + nCount) > nLength) + nCount = nLength - nIndex; + CopyBeforeWrite(); + int nBytesToCopy = nLength - (nIndex + nCount) + 1; + + SecureHelper::memmove_x(m_pchData + nIndex, (GetData()->nAllocLength + 1 - nIndex) * sizeof(TCHAR), m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR)); + nLength -= nCount; + GetData()->nDataLength = nLength; + } + + return nLength; + } + + // searching (return starting index, or -1 if not found) + // look for a single character match + int Find(TCHAR ch) const // like "C" strchr + { + return Find(ch, 0); + } + + int ReverseFind(TCHAR ch) const + { + // find last single character + LPCTSTR lpsz = _cstrrchr(m_pchData, (_TUCHAR)ch); + + // return -1 if not found, distance from beginning otherwise + return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); + } + + int Find(TCHAR ch, int nStart) const // starting at index + { + int nLength = GetData()->nDataLength; + if (nStart < 0 || nStart >= nLength) + return -1; + + // find first single character + LPCTSTR lpsz = _cstrchr(m_pchData + nStart, (_TUCHAR)ch); + + // return -1 if not found and index otherwise + return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); + } + + int FindOneOf(LPCTSTR lpszCharSet) const + { + ATLASSERT(_IsValidString(lpszCharSet)); + LPCTSTR lpsz = _cstrpbrk(m_pchData, lpszCharSet); + return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); + } + + // look for a specific sub-string + // find a sub-string (like strstr) + int Find(LPCTSTR lpszSub) const // like "C" strstr + { + return Find(lpszSub, 0); + } + + int Find(LPCTSTR lpszSub, int nStart) const // starting at index + { + ATLASSERT(_IsValidString(lpszSub)); + + int nLength = GetData()->nDataLength; + if (nStart < 0 || nStart > nLength) + return -1; + + // find first matching substring + LPCTSTR lpsz = _cstrstr(m_pchData + nStart, lpszSub); + + // return -1 for not found, distance from beginning otherwise + return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); + } + + // Concatentation for non strings + CString& Append(int n) + { + const int cchBuff = 12; + TCHAR szBuffer[cchBuff] = { 0 }; + SecureHelper::wsprintf_x(szBuffer, cchBuff, _T("%d"), n); + ConcatInPlace(SafeStrlen(szBuffer), szBuffer); + return *this; + } + + // simple formatting + // formatting (using wsprintf style formatting) + BOOL __cdecl Format(LPCTSTR lpszFormat, ...) + { + ATLASSERT(_IsValidString(lpszFormat)); + + va_list argList; + va_start(argList, lpszFormat); + BOOL bRet = FormatV(lpszFormat, argList); + va_end(argList); + return bRet; + } + + BOOL __cdecl Format(UINT nFormatID, ...) + { + CString strFormat; + BOOL bRet = strFormat.LoadString(nFormatID); + ATLASSERT(bRet != 0); + + va_list argList; + va_start(argList, nFormatID); + bRet = FormatV(strFormat, argList); + va_end(argList); + return bRet; + } + + BOOL FormatV(LPCTSTR lpszFormat, va_list argList) + { + ATLASSERT(_IsValidString(lpszFormat)); + + enum _FormatModifiers + { + FORCE_ANSI = 0x10000, + FORCE_UNICODE = 0x20000, + FORCE_INT64 = 0x40000 + }; + + va_list argListSave = argList; + + // make a guess at the maximum length of the resulting string + int nMaxLen = 0; + for (LPCTSTR lpsz = lpszFormat; *lpsz != _T('\0'); lpsz = ::CharNext(lpsz)) + { + // handle '%' character, but watch out for '%%' + if (*lpsz != _T('%') || *(lpsz = ::CharNext(lpsz)) == _T('%')) + { + nMaxLen += (int)(::CharNext(lpsz) - lpsz); + continue; + } + + int nItemLen = 0; + + // handle '%' character with format + int nWidth = 0; + for (; *lpsz != _T('\0'); lpsz = ::CharNext(lpsz)) + { + // check for valid flags + if (*lpsz == _T('#')) + nMaxLen += 2; // for '0x' + else if (*lpsz == _T('*')) + nWidth = va_arg(argList, int); + else if (*lpsz == _T('-') || *lpsz == _T('+') || *lpsz == _T('0') || *lpsz == _T(' ')) + ; + else // hit non-flag character + break; + } + // get width and skip it + if (nWidth == 0) + { + // width indicated by + nWidth = _cstrtoi(lpsz); + for (; *lpsz != _T('\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz)) + ; + } + ATLASSERT(nWidth >= 0); + + int nPrecision = 0; + if (*lpsz == _T('.')) + { + // skip past '.' separator (width.precision) + lpsz = ::CharNext(lpsz); + + // get precision and skip it + if (*lpsz == _T('*')) + { + nPrecision = va_arg(argList, int); + lpsz = ::CharNext(lpsz); + } + else + { + nPrecision = _cstrtoi(lpsz); + for (; *lpsz != _T('\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz)) + ; + } + ATLASSERT(nPrecision >= 0); + } + + // should be on type modifier or specifier + int nModifier = 0; + if(lpsz[0] == _T('I')) + { + if((lpsz[1] == _T('6')) && (lpsz[2] == _T('4'))) + { + lpsz += 3; + nModifier = FORCE_INT64; + } + else if((lpsz[1] == _T('3')) && (lpsz[2] == _T('2'))) + { + lpsz += 3; + } + else + { + lpsz++; + if(sizeof(size_t) == 8) + nModifier = FORCE_INT64; + } + } + else + { + switch (*lpsz) + { + // modifiers that affect size + case _T('h'): + nModifier = FORCE_ANSI; + lpsz = ::CharNext(lpsz); + break; + case _T('l'): + nModifier = FORCE_UNICODE; + lpsz = ::CharNext(lpsz); + break; + + // modifiers that do not affect size + case _T('F'): + case _T('N'): + case _T('L'): + lpsz = ::CharNext(lpsz); + break; + } + } + + // now should be on specifier + switch (*lpsz | nModifier) + { + // single characters + case _T('c'): + case _T('C'): + nItemLen = 2; + va_arg(argList, TCHAR); + break; + case _T('c') | FORCE_ANSI: + case _T('C') | FORCE_ANSI: + nItemLen = 2; + va_arg(argList, char); + break; + case _T('c') | FORCE_UNICODE: + case _T('C') | FORCE_UNICODE: + nItemLen = 2; + va_arg(argList, WCHAR); + break; + + // strings + case _T('s'): + { + LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR); + if (pstrNextArg == NULL) + { + nItemLen = 6; // "(null)" + } + else + { + nItemLen = lstrlen(pstrNextArg); + nItemLen = __max(1, nItemLen); + } + break; + } + + case _T('S'): + { +#ifndef _UNICODE + LPWSTR pstrNextArg = va_arg(argList, LPWSTR); + if (pstrNextArg == NULL) + { + nItemLen = 6; // "(null)" + } + else + { + nItemLen = (int)wcslen(pstrNextArg); + nItemLen = __max(1, nItemLen); + } +#else // _UNICODE + LPCSTR pstrNextArg = va_arg(argList, LPCSTR); + if (pstrNextArg == NULL) + { + nItemLen = 6; // "(null)" + } + else + { +#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) + nItemLen = ATL::lstrlenA(pstrNextArg); +#else + nItemLen = lstrlenA(pstrNextArg); +#endif + nItemLen = __max(1, nItemLen); + } +#endif // _UNICODE + break; + } + + case _T('s') | FORCE_ANSI: + case _T('S') | FORCE_ANSI: + { + LPCSTR pstrNextArg = va_arg(argList, LPCSTR); + if (pstrNextArg == NULL) + { + nItemLen = 6; // "(null)" + } + else + { +#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) + nItemLen = ATL::lstrlenA(pstrNextArg); +#else + nItemLen = lstrlenA(pstrNextArg); +#endif + nItemLen = __max(1, nItemLen); + } + break; + } + + case _T('s') | FORCE_UNICODE: + case _T('S') | FORCE_UNICODE: + { + LPWSTR pstrNextArg = va_arg(argList, LPWSTR); + if (pstrNextArg == NULL) + { + nItemLen = 6; // "(null)" + } + else + { + nItemLen = (int)wcslen(pstrNextArg); + nItemLen = __max(1, nItemLen); + } + break; + } + } + + // adjust nItemLen for strings + if (nItemLen != 0) + { + nItemLen = __max(nItemLen, nWidth); + if (nPrecision != 0) + nItemLen = __min(nItemLen, nPrecision); + } + else + { + switch (*lpsz) + { + // integers + case _T('d'): + case _T('i'): + case _T('u'): + case _T('x'): + case _T('X'): + case _T('o'): + if (nModifier & FORCE_INT64) + va_arg(argList, __int64); + else + va_arg(argList, int); + nItemLen = 32; + nItemLen = __max(nItemLen, nWidth + nPrecision); + break; + +#ifndef _ATL_USE_CSTRING_FLOAT + case _T('e'): + case _T('E'): + case _T('f'): + case _T('g'): + case _T('G'): + ATLASSERT(!"Floating point (%%e, %%E, %%f, %%g, and %%G) is not supported by the WTL::CString class."); +#ifndef _DEBUG + ::OutputDebugString(_T("Floating point (%%e, %%f, %%g, and %%G) is not supported by the WTL::CString class.")); +#ifndef _WIN32_WCE + ::DebugBreak(); +#else // CE specific + DebugBreak(); +#endif // _WIN32_WCE +#endif // !_DEBUG + break; +#else // _ATL_USE_CSTRING_FLOAT + case _T('e'): + case _T('E'): + case _T('g'): + case _T('G'): + va_arg(argList, double); + nItemLen = 128; + nItemLen = __max(nItemLen, nWidth + nPrecision); + break; + case _T('f'): + { + double f = va_arg(argList, double); + // 312 == strlen("-1+(309 zeroes).") + // 309 zeroes == max precision of a double + // 6 == adjustment in case precision is not specified, + // which means that the precision defaults to 6 + int cchLen = __max(nWidth, 312 + nPrecision + 6); + CTempBuffer buff; + LPTSTR pszTemp = buff.Allocate(cchLen); + if(pszTemp != NULL) + { + SecureHelper::sprintf_x(pszTemp, cchLen, _T("%*.*f"), nWidth, nPrecision + 6, f); + nItemLen = (int)_tcslen(pszTemp); + } + else + { + nItemLen = cchLen; + } + } + break; +#endif // _ATL_USE_CSTRING_FLOAT + + case _T('p'): + va_arg(argList, void*); + nItemLen = 32; + nItemLen = __max(nItemLen, nWidth + nPrecision); + break; + + // no output + case _T('n'): + va_arg(argList, int*); + break; + + default: + ATLASSERT(FALSE); // unknown formatting option + } + } + + // adjust nMaxLen for output nItemLen + nMaxLen += nItemLen; + } + + if(GetBuffer(nMaxLen) == NULL) + return FALSE; +#ifndef _ATL_USE_CSTRING_FLOAT + int nRet = SecureHelper::wvsprintf_x(m_pchData, GetAllocLength() + 1, lpszFormat, argListSave); +#else // _ATL_USE_CSTRING_FLOAT + int nRet = SecureHelper::vsprintf_x(m_pchData, GetAllocLength() + 1, lpszFormat, argListSave); +#endif // _ATL_USE_CSTRING_FLOAT + nRet; // ref + ATLASSERT(nRet <= GetAllocLength()); + ReleaseBuffer(); + + va_end(argListSave); + return TRUE; + } + + // formatting for localization (uses FormatMessage API) + // formatting (using FormatMessage style formatting) + BOOL __cdecl FormatMessage(LPCTSTR lpszFormat, ...) + { + // format message into temporary buffer lpszTemp + va_list argList; + va_start(argList, lpszFormat); + LPTSTR lpszTemp = NULL; + BOOL bRet = TRUE; + + if ((::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, + lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0) || (lpszTemp == NULL)) + bRet = FALSE; + + // assign lpszTemp into the resulting string and free the temporary + *this = lpszTemp; + LocalFree(lpszTemp); + va_end(argList); + return bRet; + } + + BOOL __cdecl FormatMessage(UINT nFormatID, ...) + { + // get format string from string table + CString strFormat; + BOOL bRetTmp = strFormat.LoadString(nFormatID); + bRetTmp; // ref + ATLASSERT(bRetTmp != 0); + + // format message into temporary buffer lpszTemp + va_list argList; + va_start(argList, nFormatID); + LPTSTR lpszTemp = NULL; + BOOL bRet = TRUE; + + if ((::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, + strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0) || (lpszTemp == NULL)) + bRet = FALSE; + + // assign lpszTemp into the resulting string and free lpszTemp + *this = lpszTemp; + LocalFree(lpszTemp); + va_end(argList); + return bRet; + } + + // Windows support + BOOL LoadString(UINT nID) // load from string resource (255 chars max.) + { +#ifdef _UNICODE + const int CHAR_FUDGE = 1; // one TCHAR unused is good enough +#else + const int CHAR_FUDGE = 2; // two BYTES unused for case of DBC last char +#endif + + // try fixed buffer first (to avoid wasting space in the heap) + TCHAR szTemp[256] = { 0 }; + int nCount = sizeof(szTemp) / sizeof(szTemp[0]); + int nLen = _LoadString(nID, szTemp, nCount); + if (nCount - nLen > CHAR_FUDGE) + { + *this = szTemp; + return (nLen > 0); + } + + // try buffer size of 512, then larger size until entire string is retrieved + int nSize = 256; + do + { + nSize += 256; + LPTSTR lpstr = GetBuffer(nSize - 1); + if(lpstr == NULL) + { + nLen = 0; + break; + } + nLen = _LoadString(nID, lpstr, nSize); + } while (nSize - nLen <= CHAR_FUDGE); + ReleaseBuffer(); + + return (nLen > 0); + } + +#ifndef _UNICODE + // ANSI <-> OEM support (convert string in place) + void AnsiToOem() + { + CopyBeforeWrite(); + ::AnsiToOem(m_pchData, m_pchData); + } + + void OemToAnsi() + { + CopyBeforeWrite(); + ::OemToAnsi(m_pchData, m_pchData); + } +#endif + +#ifndef _ATL_NO_COM + // OLE BSTR support (use for OLE automation) + BSTR AllocSysString() const + { +#if defined(_UNICODE) || defined(OLE2ANSI) + BSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength); +#else + int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData, + GetData()->nDataLength, NULL, NULL); + BSTR bstr = ::SysAllocStringLen(NULL, nLen); + if(bstr != NULL) + MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, bstr, nLen); +#endif + return bstr; + } + + BSTR SetSysString(BSTR* pbstr) const + { +#if defined(_UNICODE) || defined(OLE2ANSI) + ::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength); +#else + int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData, + GetData()->nDataLength, NULL, NULL); + if(::SysReAllocStringLen(pbstr, NULL, nLen)) + MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, *pbstr, nLen); +#endif + ATLASSERT(*pbstr != NULL); + return *pbstr; + } +#endif // !_ATL_NO_COM + + // Access to string implementation buffer as "C" character array + LPTSTR GetBuffer(int nMinBufLength) + { + ATLASSERT(nMinBufLength >= 0); + + if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength) + { + // we have to grow the buffer + CStringData* pOldData = GetData(); + int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it + if (nMinBufLength < nOldLen) + nMinBufLength = nOldLen; + + if(!AllocBuffer(nMinBufLength)) + return NULL; + + SecureHelper::memcpy_x(m_pchData, (nMinBufLength + 1) * sizeof(TCHAR), pOldData->data(), (nOldLen + 1) * sizeof(TCHAR)); + GetData()->nDataLength = nOldLen; + CString::Release(pOldData); + } + ATLASSERT(GetData()->nRefs <= 1); + + // return a pointer to the character storage for this string + ATLASSERT(m_pchData != NULL); + return m_pchData; + } + + void ReleaseBuffer(int nNewLength = -1) + { + CopyBeforeWrite(); // just in case GetBuffer was not called + + if (nNewLength == -1) + nNewLength = lstrlen(m_pchData); // zero terminated + + ATLASSERT(nNewLength <= GetData()->nAllocLength); + GetData()->nDataLength = nNewLength; + m_pchData[nNewLength] = _T('\0'); + } + + LPTSTR GetBufferSetLength(int nNewLength) + { + ATLASSERT(nNewLength >= 0); + + if(GetBuffer(nNewLength) == NULL) + return NULL; + + GetData()->nDataLength = nNewLength; + m_pchData[nNewLength] = _T('\0'); + return m_pchData; + } + + void FreeExtra() + { + ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength); + if (GetData()->nDataLength != GetData()->nAllocLength) + { + CStringData* pOldData = GetData(); + if(AllocBuffer(GetData()->nDataLength)) + { + SecureHelper::memcpy_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), pOldData->data(), pOldData->nDataLength * sizeof(TCHAR)); + ATLASSERT(m_pchData[GetData()->nDataLength] == _T('\0')); + CString::Release(pOldData); + } + } + ATLASSERT(GetData() != NULL); + } + + // Use LockBuffer/UnlockBuffer to turn refcounting off + LPTSTR LockBuffer() + { + LPTSTR lpsz = GetBuffer(0); + if(lpsz != NULL) + GetData()->nRefs = -1; + return lpsz; + } + + void UnlockBuffer() + { + ATLASSERT(GetData()->nRefs == -1); + if (GetData() != _atltmpDataNil) + GetData()->nRefs = 1; + } + +// Implementation +public: + ~CString() // free any attached data + { + if (GetData() != _atltmpDataNil) + { + if (InterlockedDecrement(&GetData()->nRefs) <= 0) + delete[] (BYTE*)GetData(); + } + } + + int GetAllocLength() const + { + return GetData()->nAllocLength; + } + + static BOOL __stdcall _IsValidString(LPCTSTR lpsz, int /*nLength*/ = -1) + { + return (lpsz != NULL) ? TRUE : FALSE; + } + +protected: + LPTSTR m_pchData; // pointer to ref counted string data + + // implementation helpers + CStringData* GetData() const + { + ATLASSERT(m_pchData != NULL); + return ((CStringData*)m_pchData) - 1; + } + + void Init() + { + m_pchData = _GetEmptyString().m_pchData; + } + + BOOL AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const + { + // will clone the data attached to this string + // allocating 'nExtraLen' characters + // Places results in uninitialized string 'dest' + // Will copy the part or all of original data to start of new string + + BOOL bRet = FALSE; + int nNewLen = nCopyLen + nExtraLen; + if (nNewLen == 0) + { + dest.Init(); + bRet = TRUE; + } + else if(nNewLen >= nCopyLen) + { + if(dest.AllocBuffer(nNewLen)) + { + SecureHelper::memcpy_x(dest.m_pchData, (nNewLen + 1) * sizeof(TCHAR), m_pchData + nCopyIndex, nCopyLen * sizeof(TCHAR)); + bRet = TRUE; + } + } + + return bRet; + } + + // always allocate one extra character for '\0' termination + // assumes [optimistically] that data length will equal allocation length + BOOL AllocBuffer(int nLen) + { + ATLASSERT(nLen >= 0); + ATLASSERT(nLen <= INT_MAX - 1); // max size (enough room for 1 extra) + + if (nLen == 0) + { + Init(); + } + else + { + CStringData* pData = NULL; + ATLTRY(pData = (CStringData*)new BYTE[sizeof(CStringData) + (nLen + 1) * sizeof(TCHAR)]); + if(pData == NULL) + return FALSE; + + pData->nRefs = 1; + pData->data()[nLen] = _T('\0'); + pData->nDataLength = nLen; + pData->nAllocLength = nLen; + m_pchData = pData->data(); + } + + return TRUE; + } + + // Assignment operators + // All assign a new value to the string + // (a) first see if the buffer is big enough + // (b) if enough room, copy on top of old buffer, set size and type + // (c) otherwise free old string data, and create a new one + // + // All routines return the new string (but as a 'const CString&' so that + // assigning it again will cause a copy, eg: s1 = s2 = "hi there". + // + void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData) + { + if(AllocBeforeWrite(nSrcLen)) + { + SecureHelper::memcpy_x(m_pchData, (nSrcLen + 1) * sizeof(TCHAR), lpszSrcData, nSrcLen * sizeof(TCHAR)); + GetData()->nDataLength = nSrcLen; + m_pchData[nSrcLen] = _T('\0'); + } + } + + // Concatenation + // NOTE: "operator +" is done as friend functions for simplicity + // There are three variants: + // CString + CString + // and for ? = TCHAR, LPCTSTR + // CString + ? + // ? + CString + BOOL ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data) + { + // -- master concatenation routine + // Concatenate two sources + // -- assume that 'this' is a new CString object + + BOOL bRet = TRUE; + int nNewLen = nSrc1Len + nSrc2Len; + if(nNewLen < nSrc1Len || nNewLen < nSrc2Len) + { + bRet = FALSE; + } + else if(nNewLen != 0) + { + bRet = AllocBuffer(nNewLen); + if (bRet) + { + SecureHelper::memcpy_x(m_pchData, (nNewLen + 1) * sizeof(TCHAR), lpszSrc1Data, nSrc1Len * sizeof(TCHAR)); + SecureHelper::memcpy_x(m_pchData + nSrc1Len, (nNewLen + 1 - nSrc1Len) * sizeof(TCHAR), lpszSrc2Data, nSrc2Len * sizeof(TCHAR)); + } + } + return bRet; + } + + void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData) + { + // -- the main routine for += operators + + // concatenating an empty string is a no-op! + if (nSrcLen == 0) + return; + + // if the buffer is too small, or we have a width mis-match, just + // allocate a new buffer (slow but sure) + if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength) + { + // we have to grow the buffer, use the ConcatCopy routine + CStringData* pOldData = GetData(); + if (ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData)) + { + ATLASSERT(pOldData != NULL); + CString::Release(pOldData); + } + } + else + { + // fast concatenation when buffer big enough + SecureHelper::memcpy_x(m_pchData + GetData()->nDataLength, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpszSrcData, nSrcLen * sizeof(TCHAR)); + GetData()->nDataLength += nSrcLen; + ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength); + m_pchData[GetData()->nDataLength] = _T('\0'); + } + } + + void CopyBeforeWrite() + { + if (GetData()->nRefs > 1) + { + CStringData* pData = GetData(); + Release(); + if(AllocBuffer(pData->nDataLength)) + SecureHelper::memcpy_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), pData->data(), (pData->nDataLength + 1) * sizeof(TCHAR)); + } + ATLASSERT(GetData()->nRefs <= 1); + } + + BOOL AllocBeforeWrite(int nLen) + { + BOOL bRet = TRUE; + if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength) + { + Release(); + bRet = AllocBuffer(nLen); + } + ATLASSERT(GetData()->nRefs <= 1); + return bRet; + } + + void Release() + { + if (GetData() != _atltmpDataNil) + { + ATLASSERT(GetData()->nRefs != 0); + if (InterlockedDecrement(&GetData()->nRefs) <= 0) + delete[] (BYTE*)GetData(); + Init(); + } + } + + static void PASCAL Release(CStringData* pData) + { + if (pData != _atltmpDataNil) + { + ATLASSERT(pData->nRefs != 0); + if (InterlockedDecrement(&pData->nRefs) <= 0) + delete[] (BYTE*)pData; + } + } + + static int PASCAL SafeStrlen(LPCTSTR lpsz) + { + return (lpsz == NULL) ? 0 : lstrlen(lpsz); + } + + static int __stdcall _LoadString(UINT nID, LPTSTR lpszBuf, UINT nMaxBuf) + { +#ifdef _DEBUG + // LoadString without annoying warning from the Debug kernel if the + // segment containing the string is not present + if (::FindResource(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE((nID >> 4) + 1), RT_STRING) == NULL) + { + lpszBuf[0] = _T('\0'); + return 0; // not found + } +#endif // _DEBUG + + int nLen = ::LoadString(ModuleHelper::GetResourceInstance(), nID, lpszBuf, nMaxBuf); + if (nLen == 0) + lpszBuf[0] = _T('\0'); + + return nLen; + } + + static const CString& __stdcall _GetEmptyString() + { + return *(CString*)&_atltmpPchNil; + } + +// CString conversion helpers + static int __cdecl _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count) + { + if (count == 0 && mbstr != NULL) + return 0; + + int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1, mbstr, (int)count, NULL, NULL); + ATLASSERT(mbstr == NULL || result <= (int)count); + if ((mbstr != NULL) && (result > 0)) + mbstr[result - 1] = 0; + return result; + } + + static int __cdecl _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count) + { + if (count == 0 && wcstr != NULL) + return 0; + + int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1, wcstr, (int)count); + ATLASSERT(wcstr == NULL || result <= (int)count); + if ((wcstr != NULL) && (result > 0)) + wcstr[result - 1] = 0; + return result; + } + +// Helpers to avoid CRT startup code +#ifdef _ATL_MIN_CRT + static const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch) + { + // strchr for '\0' should succeed + while (*p != 0) + { + if (*p == ch) + break; + p = ::CharNext(p); + } + return (*p == ch) ? p : NULL; + } + + static TCHAR* _cstrrev(TCHAR* pStr) + { + // optimize NULL, zero-length, and single-char case + if ((pStr == NULL) || (pStr[0] == _T('\0')) || (pStr[1] == _T('\0'))) + return pStr; + + TCHAR* p = pStr; + + while (*p != 0) + { + TCHAR* pNext = ::CharNext(p); + if(pNext > p + 1) + { + char p1 = *(char*)p; + *(char*)p = *(char*)(p + 1); + *(char*)(p + 1) = p1; + } + p = pNext; + } + + p--; + TCHAR* q = pStr; + + while (q < p) + { + TCHAR t = *q; + *q = *p; + *p = t; + q++; + p--; + } + return pStr; + } + + static const TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet) + { + int nLen = lstrlen(pCharSet); + if (nLen == 0) + return (TCHAR*)pStr; + + const TCHAR* pRet = NULL; + const TCHAR* pCur = pStr; + while((pCur = _cstrchr(pCur, *pCharSet)) != NULL) + { + if(memcmp(pCur, pCharSet, nLen * sizeof(TCHAR)) == 0) + { + pRet = pCur; + break; + } + pCur = ::CharNext(pCur); + } + return pRet; + } + + static int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet) + { + int nRet = 0; + const TCHAR* p = pStr; + while (*p != 0) + { + const TCHAR* pNext = ::CharNext(p); + if(pNext > p + 1) + { + if(_cstrchr_db(pCharSet, *p, *(p + 1)) == NULL) + break; + nRet += 2; + } + else + { + if(_cstrchr(pCharSet, *p) == NULL) + break; + nRet++; + } + p = pNext; + } + return nRet; + } + + static int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet) + { + int nRet = 0; + TCHAR* p = (TCHAR*)pStr; + while (*p != 0) + { + TCHAR* pNext = ::CharNext(p); + if(pNext > p + 1) + { + if(_cstrchr_db(pCharSet, *p, *(p + 1)) != NULL) + break; + nRet += 2; + } + else + { + if(_cstrchr(pCharSet, *p) != NULL) + break; + nRet++; + } + p = pNext; + } + return nRet; + } + + static const TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet) + { + int n = _cstrcspn(p, lpszCharSet); + return (p[n] != 0) ? &p[n] : NULL; + } + + static int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + return lstrcmp(pstrOne, pstrOther); + } + + static int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + return lstrcmpi(pstrOne, pstrOther); + } + + static int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + int nRet = CompareString(GetThreadLocale(), 0, pstrOne, -1, pstrOther, -1); + ATLASSERT(nRet != 0); + return nRet - 2; // convert to strcmp convention + } + + static int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + int nRet = CompareString(GetThreadLocale(), NORM_IGNORECASE, pstrOne, -1, pstrOther, -1); + ATLASSERT(nRet != 0); + return nRet - 2; // convert to strcmp convention + } +#else // !_ATL_MIN_CRT + static const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch) + { + return _tcschr(p, ch); + } + + static TCHAR* _cstrrev(TCHAR* pStr) + { + return _tcsrev(pStr); + } + + static const TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet) + { + return _tcsstr(pStr, pCharSet); + } + + static int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet) + { + return (int)_tcsspn(pStr, pCharSet); + } + + static int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet) + { + return (int)_tcscspn(pStr, pCharSet); + } + + static const TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet) + { + return _tcspbrk(p, lpszCharSet); + } + + static int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + return _tcscmp(pstrOne, pstrOther); + } + + static int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + return _tcsicmp(pstrOne, pstrOther); + } + +#ifndef _WIN32_WCE + static int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + return _tcscoll(pstrOne, pstrOther); + } + + static int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + return _tcsicoll(pstrOne, pstrOther); + } +#endif // !_WIN32_WCE +#endif // !_ATL_MIN_CRT + + static const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch) + { + return MinCrtHelper::_strrchr(p, ch); + } + + static int _cstrisdigit(TCHAR ch) + { + return MinCrtHelper::_isdigit(ch); + } + + static int _cstrisspace(TCHAR ch) + { + return MinCrtHelper::_isspace(ch); + } + + static int _cstrtoi(const TCHAR* nptr) + { + return MinCrtHelper::_atoi(nptr); + } + + static const TCHAR* _cstrchr_db(const TCHAR* p, TCHAR ch1, TCHAR ch2) + { + const TCHAR* lpsz = NULL; + while (*p != 0) + { + if (*p == ch1 && *(p + 1) == ch2) + { + lpsz = p; + break; + } + p = ::CharNext(p); + } + return lpsz; + } +}; + + +// Compare helpers + +inline bool __stdcall operator ==(const CString& s1, const CString& s2) +{ return s1.Compare(s2) == 0; } + +inline bool __stdcall operator ==(const CString& s1, LPCTSTR s2) +{ return s1.Compare(s2) == 0; } + +inline bool __stdcall operator ==(LPCTSTR s1, const CString& s2) +{ return s2.Compare(s1) == 0; } + +inline bool __stdcall operator !=(const CString& s1, const CString& s2) +{ return s1.Compare(s2) != 0; } + +inline bool __stdcall operator !=(const CString& s1, LPCTSTR s2) +{ return s1.Compare(s2) != 0; } + +inline bool __stdcall operator !=(LPCTSTR s1, const CString& s2) +{ return s2.Compare(s1) != 0; } + +inline bool __stdcall operator <(const CString& s1, const CString& s2) +{ return s1.Compare(s2) < 0; } + +inline bool __stdcall operator <(const CString& s1, LPCTSTR s2) +{ return s1.Compare(s2) < 0; } + +inline bool __stdcall operator <(LPCTSTR s1, const CString& s2) +{ return s2.Compare(s1) > 0; } + +inline bool __stdcall operator >(const CString& s1, const CString& s2) +{ return s1.Compare(s2) > 0; } + +inline bool __stdcall operator >(const CString& s1, LPCTSTR s2) +{ return s1.Compare(s2) > 0; } + +inline bool __stdcall operator >(LPCTSTR s1, const CString& s2) +{ return s2.Compare(s1) < 0; } + +inline bool __stdcall operator <=(const CString& s1, const CString& s2) +{ return s1.Compare(s2) <= 0; } + +inline bool __stdcall operator <=(const CString& s1, LPCTSTR s2) +{ return s1.Compare(s2) <= 0; } + +inline bool __stdcall operator <=(LPCTSTR s1, const CString& s2) +{ return s2.Compare(s1) >= 0; } + +inline bool __stdcall operator >=(const CString& s1, const CString& s2) +{ return s1.Compare(s2) >= 0; } + +inline bool __stdcall operator >=(const CString& s1, LPCTSTR s2) +{ return s1.Compare(s2) >= 0; } + +inline bool __stdcall operator >=(LPCTSTR s1, const CString& s2) +{ return s2.Compare(s1) <= 0; } + + +// CString "operator +" functions + +inline CString __stdcall operator +(const CString& string1, const CString& string2) +{ + CString s; + s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, string2.GetData()->nDataLength, string2.m_pchData); + return s; +} + +inline CString __stdcall operator +(const CString& string, TCHAR ch) +{ + CString s; + s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, 1, &ch); + return s; +} + +inline CString __stdcall operator +(TCHAR ch, const CString& string) +{ + CString s; + s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData); + return s; +} + +#ifdef _UNICODE +inline CString __stdcall operator +(const CString& string, char ch) +{ + return string + (TCHAR)ch; +} + +inline CString __stdcall operator +(char ch, const CString& string) +{ + return (TCHAR)ch + string; +} +#endif // _UNICODE + +inline CString __stdcall operator +(const CString& string, LPCTSTR lpsz) +{ + ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz)); + CString s; + s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, CString::SafeStrlen(lpsz), lpsz); + return s; +} + +inline CString __stdcall operator +(LPCTSTR lpsz, const CString& string) +{ + ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz)); + CString s; + s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength, string.m_pchData); + return s; +} + +#endif // !_WTL_NO_CSTRING + + +/////////////////////////////////////////////////////////////////////////////// +// CRecentDocumentList - MRU List Support + +#ifndef _WIN32_WCE + +#ifndef _WTL_MRUEMPTY_TEXT + #define _WTL_MRUEMPTY_TEXT _T("(empty)") +#endif + +// forward declaration +inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen); + +template +class CRecentDocumentListBase +{ +public: +// Declarations + struct _DocEntry + { + TCHAR szDocName[t_cchItemLen]; + bool operator ==(const _DocEntry& de) const + { return (lstrcmpi(szDocName, de.szDocName) == 0); } + }; + + enum + { + m_nMaxEntries_Min = 2, + m_nMaxEntries_Max = t_nLastID - t_nFirstID + 1, + m_cchMaxItemLen_Min = 6, + m_cchMaxItemLen_Max = t_cchItemLen, + m_cchItemNameLen = 11 + }; + +// Data members + ATL::CSimpleArray<_DocEntry> m_arrDocs; + int m_nMaxEntries; // default is 4 + HMENU m_hMenu; + + TCHAR m_szNoEntries[t_cchItemLen]; + + int m_cchMaxItemLen; + +// Constructor + CRecentDocumentListBase() : m_hMenu(NULL), m_nMaxEntries(4), m_cchMaxItemLen(-1) + { + // These ASSERTs verify values of the template arguments + ATLASSERT(t_cchItemLen > m_cchMaxItemLen_Min); + ATLASSERT(m_nMaxEntries_Max > m_nMaxEntries_Min); + } + +// Attributes + HMENU GetMenuHandle() const + { + return m_hMenu; + } + + void SetMenuHandle(HMENU hMenu) + { + ATLASSERT(hMenu == NULL || ::IsMenu(hMenu)); + m_hMenu = hMenu; + if(m_hMenu == NULL || (::GetMenuString(m_hMenu, t_nFirstID, m_szNoEntries, t_cchItemLen, MF_BYCOMMAND) == 0)) + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + SecureHelper::strncpy_x(m_szNoEntries, _countof(m_szNoEntries), pT->GetMRUEmptyText(), _TRUNCATE); + } + } + + int GetMaxEntries() const + { + return m_nMaxEntries; + } + + void SetMaxEntries(int nMaxEntries) + { + ATLASSERT(nMaxEntries >= m_nMaxEntries_Min && nMaxEntries <= m_nMaxEntries_Max); + if(nMaxEntries < m_nMaxEntries_Min) + nMaxEntries = m_nMaxEntries_Min; + else if(nMaxEntries > m_nMaxEntries_Max) + nMaxEntries = m_nMaxEntries_Max; + m_nMaxEntries = nMaxEntries; + } + + int GetMaxItemLength() const + { + return m_cchMaxItemLen; + } + + void SetMaxItemLength(int cchMaxLen) + { + ATLASSERT((cchMaxLen >= m_cchMaxItemLen_Min && cchMaxLen <= m_cchMaxItemLen_Max) || cchMaxLen == -1); + if(cchMaxLen != -1) + { + if(cchMaxLen < m_cchMaxItemLen_Min) + cchMaxLen = m_cchMaxItemLen_Min; + else if(cchMaxLen > m_cchMaxItemLen_Max) + cchMaxLen = m_cchMaxItemLen_Max; + } + m_cchMaxItemLen = cchMaxLen; + T* pT = static_cast(this); + pT->UpdateMenu(); + } + +// Operations + BOOL AddToList(LPCTSTR lpstrDocName) + { + _DocEntry de; + errno_t nRet = SecureHelper::strncpy_x(de.szDocName, _countof(de.szDocName), lpstrDocName, _TRUNCATE); + if(nRet != 0 && nRet != STRUNCATE) + return FALSE; + + for(int i = 0; i < m_arrDocs.GetSize(); i++) + { + if(lstrcmpi(m_arrDocs[i].szDocName, lpstrDocName) == 0) + { + m_arrDocs.RemoveAt(i); + break; + } + } + + if(m_arrDocs.GetSize() == m_nMaxEntries) + m_arrDocs.RemoveAt(0); + + BOOL bRet = m_arrDocs.Add(de); + if(bRet) + { + T* pT = static_cast(this); + bRet = pT->UpdateMenu(); + } + return bRet; + } + + // This function is deprecated because it is not safe. + // Use the version below that accepts the buffer length. +#if (_MSC_VER >= 1300) + __declspec(deprecated) +#endif + BOOL GetFromList(int /*nItemID*/, LPTSTR /*lpstrDocName*/) + { + ATLASSERT(FALSE); + return FALSE; + } + + BOOL GetFromList(int nItemID, LPTSTR lpstrDocName, int cchLength) + { + int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1; + if(nIndex < 0 || nIndex >= m_arrDocs.GetSize()) + return FALSE; + if(lstrlen(m_arrDocs[nIndex].szDocName) >= cchLength) + return FALSE; + SecureHelper::strcpy_x(lpstrDocName, cchLength, m_arrDocs[nIndex].szDocName); + + return TRUE; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + BOOL GetFromList(int nItemID, _CSTRING_NS::CString& strDocName) + { + int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1; + if(nIndex < 0 || nIndex >= m_arrDocs.GetSize()) + return FALSE; + strDocName = m_arrDocs[nIndex].szDocName; + return TRUE; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + BOOL RemoveFromList(int nItemID) + { + int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1; + BOOL bRet = m_arrDocs.RemoveAt(nIndex); + if(bRet) + { + T* pT = static_cast(this); + bRet = pT->UpdateMenu(); + } + return bRet; + } + + BOOL MoveToTop(int nItemID) + { + int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1; + if(nIndex < 0 || nIndex >= m_arrDocs.GetSize()) + return FALSE; + _DocEntry de; + de = m_arrDocs[nIndex]; + m_arrDocs.RemoveAt(nIndex); + BOOL bRet = m_arrDocs.Add(de); + if(bRet) + { + T* pT = static_cast(this); + bRet = pT->UpdateMenu(); + } + return bRet; + } + + BOOL ReadFromRegistry(LPCTSTR lpstrRegKey) + { + T* pT = static_cast(this); + CRegKeyEx rkParent; + CRegKeyEx rk; + + LONG lRet = rkParent.Open(HKEY_CURRENT_USER, lpstrRegKey); + if(lRet != ERROR_SUCCESS) + return FALSE; + lRet = rk.Open(rkParent, pT->GetRegKeyName()); + if(lRet != ERROR_SUCCESS) + return FALSE; + + DWORD dwRet = 0; + lRet = rk.QueryDWORDValue(pT->GetRegCountName(), dwRet); + if(lRet != ERROR_SUCCESS) + return FALSE; + SetMaxEntries(dwRet); + + m_arrDocs.RemoveAll(); + + TCHAR szRetString[t_cchItemLen] = { 0 }; + _DocEntry de; + + for(int nItem = m_nMaxEntries; nItem > 0; nItem--) + { + TCHAR szBuff[m_cchItemNameLen] = { 0 }; + SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem); + ULONG ulCount = t_cchItemLen; + lRet = rk.QueryStringValue(szBuff, szRetString, &ulCount); + if(lRet == ERROR_SUCCESS) + { + SecureHelper::strcpy_x(de.szDocName, _countof(de.szDocName), szRetString); + m_arrDocs.Add(de); + } + } + + rk.Close(); + rkParent.Close(); + + return pT->UpdateMenu(); + } + + BOOL WriteToRegistry(LPCTSTR lpstrRegKey) + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + CRegKeyEx rkParent; + CRegKeyEx rk; + + LONG lRet = rkParent.Create(HKEY_CURRENT_USER, lpstrRegKey); + if(lRet != ERROR_SUCCESS) + return FALSE; + lRet = rk.Create(rkParent, pT->GetRegKeyName()); + if(lRet != ERROR_SUCCESS) + return FALSE; + + lRet = rk.SetDWORDValue(pT->GetRegCountName(), m_nMaxEntries); + ATLASSERT(lRet == ERROR_SUCCESS); + + // set new values + int nItem; + for(nItem = m_arrDocs.GetSize(); nItem > 0; nItem--) + { + TCHAR szBuff[m_cchItemNameLen] = { 0 }; + SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem); + TCHAR szDocName[t_cchItemLen] = { 0 }; + GetFromList(t_nFirstID + nItem - 1, szDocName, t_cchItemLen); + lRet = rk.SetStringValue(szBuff, szDocName); + ATLASSERT(lRet == ERROR_SUCCESS); + } + + // delete unused keys + for(nItem = m_arrDocs.GetSize() + 1; nItem <= m_nMaxEntries_Max; nItem++) + { + TCHAR szBuff[m_cchItemNameLen] = { 0 }; + SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem); + rk.DeleteValue(szBuff); + } + + rk.Close(); + rkParent.Close(); + + return TRUE; + } + +// Implementation + BOOL UpdateMenu() + { + if(m_hMenu == NULL) + return FALSE; + ATLASSERT(::IsMenu(m_hMenu)); + + int nItems = ::GetMenuItemCount(m_hMenu); + int nInsertPoint = 0; + for(int i = 0; i < nItems; i++) + { + CMenuItemInfo mi; + mi.fMask = MIIM_ID; + ::GetMenuItemInfo(m_hMenu, i, TRUE, &mi); + if (mi.wID == t_nFirstID) + { + nInsertPoint = i; + break; + } + } + + ATLASSERT(nInsertPoint < nItems && "You need a menu item with an ID = t_nFirstID"); + + for(int j = t_nFirstID; j < (t_nFirstID + m_nMaxEntries); j++) + { + // keep the first one as an insertion point + if (j != t_nFirstID) + ::DeleteMenu(m_hMenu, j, MF_BYCOMMAND); + } + + TCHAR szItemText[t_cchItemLen + 6] = { 0 }; // add space for &, 2 digits, and a space + int nSize = m_arrDocs.GetSize(); + int nItem = 0; + if(nSize > 0) + { + for(nItem = 0; nItem < nSize; nItem++) + { + if(m_cchMaxItemLen == -1) + { + SecureHelper::wsprintf_x(szItemText, t_cchItemLen + 6, _T("&%i %s"), nItem + 1, m_arrDocs[nSize - 1 - nItem].szDocName); + } + else + { + TCHAR szBuff[t_cchItemLen] = { 0 }; + T* pT = static_cast(this); + pT; // avoid level 4 warning + bool bRet = pT->CompactDocumentName(szBuff, m_arrDocs[nSize - 1 - nItem].szDocName, m_cchMaxItemLen); + bRet; // avoid level 4 warning + ATLASSERT(bRet); + SecureHelper::wsprintf_x(szItemText, t_cchItemLen + 6, _T("&%i %s"), nItem + 1, szBuff); + } + + ::InsertMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION | MF_STRING, t_nFirstID + nItem, szItemText); + } + } + else // empty + { + ::InsertMenu(m_hMenu, nInsertPoint, MF_BYPOSITION | MF_STRING, t_nFirstID, m_szNoEntries); + ::EnableMenuItem(m_hMenu, t_nFirstID, MF_GRAYED); + nItem++; + } + ::DeleteMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION); + + return TRUE; + } + +// Overrideables + // override to provide a different method of compacting document names + static bool CompactDocumentName(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen) + { + return AtlCompactPath(lpstrOut, lpstrIn, cchLen); + } + + static LPCTSTR GetRegKeyName() + { + return _T("Recent Document List"); + } + + static LPCTSTR GetRegCountName() + { + return _T("DocumentCount"); + } + + static LPCTSTR GetRegItemName() + { + // Note: This string is a format string used with wsprintf(). + // Resulting formatted string must be m_cchItemNameLen or less + // characters long, including the terminating null character. + return _T("Document%i"); + } + + static LPCTSTR GetMRUEmptyText() + { + return _WTL_MRUEMPTY_TEXT; + } +}; + +class CRecentDocumentList : public CRecentDocumentListBase +{ +public: +// nothing here +}; + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CFindFile - file search helper class + +class CFindFile +{ +public: +// Data members + WIN32_FIND_DATA m_fd; + TCHAR m_lpszRoot[MAX_PATH]; + TCHAR m_chDirSeparator; + HANDLE m_hFind; + BOOL m_bFound; + +// Constructor/destructor + CFindFile() : m_hFind(NULL), m_chDirSeparator(_T('\\')), m_bFound(FALSE) + { } + + ~CFindFile() + { + Close(); + } + +// Attributes + ULONGLONG GetFileSize() const + { + ATLASSERT(m_hFind != NULL); + + ULARGE_INTEGER nFileSize = { 0 }; + + if(m_bFound) + { + nFileSize.LowPart = m_fd.nFileSizeLow; + nFileSize.HighPart = m_fd.nFileSizeHigh; + } + else + { + nFileSize.QuadPart = 0; + } + + return nFileSize.QuadPart; + } + + BOOL GetFileName(LPTSTR lpstrFileName, int cchLength) const + { + ATLASSERT(m_hFind != NULL); + if(lstrlen(m_fd.cFileName) >= cchLength) + return FALSE; + + if(m_bFound) + SecureHelper::strcpy_x(lpstrFileName, cchLength, m_fd.cFileName); + + return m_bFound; + } + + BOOL GetFilePath(LPTSTR lpstrFilePath, int cchLength) const + { + ATLASSERT(m_hFind != NULL); + + int nLen = lstrlen(m_lpszRoot); +#ifndef _WIN32_WCE + ATLASSERT(nLen > 0); + if(nLen == 0) + return FALSE; + + bool bAddSep = (m_lpszRoot[nLen - 1] != _T('\\') && m_lpszRoot[nLen - 1] !=_T('/')); +#else // CE specific + // allow diskless devices (nLen == 0) + bool bAddSep = ((nLen == 0) || (m_lpszRoot[nLen - 1] != _T('\\') && m_lpszRoot[nLen - 1] !=_T('/'))); +#endif // _WIN32_WCE + + if((lstrlen(m_lpszRoot) + (bAddSep ? 1 : 0)) >= cchLength) + return FALSE; + + SecureHelper::strcpy_x(lpstrFilePath, cchLength, m_lpszRoot); + + if(bAddSep) + { + TCHAR szSeparator[2] = { m_chDirSeparator, 0 }; + SecureHelper::strcat_x(lpstrFilePath, cchLength, szSeparator); + } + + SecureHelper::strcat_x(lpstrFilePath, cchLength, m_fd.cFileName); + + return TRUE; + } + +#ifndef _WIN32_WCE + BOOL GetFileTitle(LPTSTR lpstrFileTitle, int cchLength) const + { + ATLASSERT(m_hFind != NULL); + + TCHAR szBuff[MAX_PATH] = { 0 }; + if(!GetFileName(szBuff, MAX_PATH)) + return FALSE; + + if(lstrlen(szBuff) >= cchLength || cchLength < 1) + return FALSE; + + // find the last dot + LPTSTR pstrDot = MinCrtHelper::_strrchr(szBuff, _T('.')); + if(pstrDot != NULL) + *pstrDot = 0; + + SecureHelper::strcpy_x(lpstrFileTitle, cchLength, szBuff); + + return TRUE; + } +#endif // !_WIN32_WCE + + BOOL GetFileURL(LPTSTR lpstrFileURL, int cchLength) const + { + ATLASSERT(m_hFind != NULL); + + TCHAR szBuff[MAX_PATH] = { 0 }; + if(!GetFilePath(szBuff, MAX_PATH)) + return FALSE; + LPCTSTR lpstrFileURLPrefix = _T("file://"); + if(lstrlen(szBuff) + lstrlen(lpstrFileURLPrefix) >= cchLength) + return FALSE; + SecureHelper::strcpy_x(lpstrFileURL, cchLength, lpstrFileURLPrefix); + SecureHelper::strcat_x(lpstrFileURL, cchLength, szBuff); + + return TRUE; + } + + BOOL GetRoot(LPTSTR lpstrRoot, int cchLength) const + { + ATLASSERT(m_hFind != NULL); + if(lstrlen(m_lpszRoot) >= cchLength) + return FALSE; + + SecureHelper::strcpy_x(lpstrRoot, cchLength, m_lpszRoot); + + return TRUE; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + _CSTRING_NS::CString GetFileName() const + { + ATLASSERT(m_hFind != NULL); + + _CSTRING_NS::CString ret; + + if(m_bFound) + ret = m_fd.cFileName; + return ret; + } + + _CSTRING_NS::CString GetFilePath() const + { + ATLASSERT(m_hFind != NULL); + + _CSTRING_NS::CString strResult = m_lpszRoot; + int nLen = strResult.GetLength(); +#ifndef _WIN32_WCE + ATLASSERT(nLen > 0); + if(nLen == 0) + return strResult; + + if((strResult[nLen - 1] != _T('\\')) && (strResult[nLen - 1] != _T('/'))) +#else // CE specific + // allow diskless devices (nLen == 0) + if((nLen == 0) || ((strResult[nLen - 1] != _T('\\')) && (strResult[nLen - 1] != _T('/')))) +#endif // _WIN32_WCE + strResult += m_chDirSeparator; + strResult += GetFileName(); + return strResult; + } + +#ifndef _WIN32_WCE + _CSTRING_NS::CString GetFileTitle() const + { + ATLASSERT(m_hFind != NULL); + + _CSTRING_NS::CString strResult; + GetFileTitle(strResult.GetBuffer(MAX_PATH), MAX_PATH); + strResult.ReleaseBuffer(); + + return strResult; + } +#endif // !_WIN32_WCE + + _CSTRING_NS::CString GetFileURL() const + { + ATLASSERT(m_hFind != NULL); + + _CSTRING_NS::CString strResult("file://"); + strResult += GetFilePath(); + return strResult; + } + + _CSTRING_NS::CString GetRoot() const + { + ATLASSERT(m_hFind != NULL); + + _CSTRING_NS::CString str = m_lpszRoot; + return str; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + BOOL GetLastWriteTime(FILETIME* pTimeStamp) const + { + ATLASSERT(m_hFind != NULL); + ATLASSERT(pTimeStamp != NULL); + + if(m_bFound && pTimeStamp != NULL) + { + *pTimeStamp = m_fd.ftLastWriteTime; + return TRUE; + } + + return FALSE; + } + + BOOL GetLastAccessTime(FILETIME* pTimeStamp) const + { + ATLASSERT(m_hFind != NULL); + ATLASSERT(pTimeStamp != NULL); + + if(m_bFound && pTimeStamp != NULL) + { + *pTimeStamp = m_fd.ftLastAccessTime; + return TRUE; + } + + return FALSE; + } + + BOOL GetCreationTime(FILETIME* pTimeStamp) const + { + ATLASSERT(m_hFind != NULL); + + if(m_bFound && pTimeStamp != NULL) + { + *pTimeStamp = m_fd.ftCreationTime; + return TRUE; + } + + return FALSE; + } + + BOOL MatchesMask(DWORD dwMask) const + { + ATLASSERT(m_hFind != NULL); + + if(m_bFound) + return ((m_fd.dwFileAttributes & dwMask) != 0); + + return FALSE; + } + + BOOL IsDots() const + { + ATLASSERT(m_hFind != NULL); + + // return TRUE if the file name is "." or ".." and + // the file is a directory + + BOOL bResult = FALSE; + if(m_bFound && IsDirectory()) + { + if(m_fd.cFileName[0] == _T('.') && (m_fd.cFileName[1] == _T('\0') || (m_fd.cFileName[1] == _T('.') && m_fd.cFileName[2] == _T('\0')))) + bResult = TRUE; + } + + return bResult; + } + + BOOL IsReadOnly() const + { + return MatchesMask(FILE_ATTRIBUTE_READONLY); + } + + BOOL IsDirectory() const + { + return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); + } + + BOOL IsCompressed() const + { + return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); + } + + BOOL IsSystem() const + { + return MatchesMask(FILE_ATTRIBUTE_SYSTEM); + } + + BOOL IsHidden() const + { + return MatchesMask(FILE_ATTRIBUTE_HIDDEN); + } + + BOOL IsTemporary() const + { + return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); + } + + BOOL IsNormal() const + { + return MatchesMask(FILE_ATTRIBUTE_NORMAL); + } + + BOOL IsArchived() const + { + return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); + } + +// Operations + BOOL FindFile(LPCTSTR pstrName = NULL) + { + Close(); + + if(pstrName == NULL) + { + pstrName = _T("*.*"); + } + else if(lstrlen(pstrName) >= MAX_PATH) + { + ATLASSERT(FALSE); + return FALSE; + } + + SecureHelper::strcpy_x(m_fd.cFileName, _countof(m_fd.cFileName), pstrName); + + m_hFind = ::FindFirstFile(pstrName, &m_fd); + + if(m_hFind == INVALID_HANDLE_VALUE) + return FALSE; + +#ifndef _WIN32_WCE + bool bFullPath = (::GetFullPathName(pstrName, MAX_PATH, m_lpszRoot, NULL) != 0); +#else // CE specific + errno_t nRet = SecureHelper::strncpy_x(m_lpszRoot, _countof(m_lpszRoot), pstrName, _TRUNCATE); + bool bFullPath = (nRet == 0 || nRet == STRUNCATE); +#endif // _WIN32_WCE + + // passed name isn't a valid path but was found by the API + ATLASSERT(bFullPath); + if(!bFullPath) + { + Close(); + ::SetLastError(ERROR_INVALID_NAME); + return FALSE; + } + else + { + // find the last forward or backward whack + LPTSTR pstrBack = MinCrtHelper::_strrchr(m_lpszRoot, _T('\\')); + LPTSTR pstrFront = MinCrtHelper::_strrchr(m_lpszRoot, _T('/')); + + if(pstrFront != NULL || pstrBack != NULL) + { + if(pstrFront == NULL) + pstrFront = m_lpszRoot; + if(pstrBack == NULL) + pstrBack = m_lpszRoot; + + // from the start to the last whack is the root + + if(pstrFront >= pstrBack) + *pstrFront = _T('\0'); + else + *pstrBack = _T('\0'); + } + } + + m_bFound = TRUE; + + return TRUE; + } + + BOOL FindNextFile() + { + ATLASSERT(m_hFind != NULL); + + if(m_hFind == NULL) + return FALSE; + + if(!m_bFound) + return FALSE; + + m_bFound = ::FindNextFile(m_hFind, &m_fd); + + return m_bFound; + } + + void Close() + { + m_bFound = FALSE; + + if(m_hFind != NULL && m_hFind != INVALID_HANDLE_VALUE) + { + ::FindClose(m_hFind); + m_hFind = NULL; + } + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Global functions for stock GDI objects + +inline HPEN AtlGetStockPen(int nPen) +{ +#if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE) + ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN); +#else + ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN); +#endif + return (HPEN)::GetStockObject(nPen); +} + +inline HBRUSH AtlGetStockBrush(int nBrush) +{ +#if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE) + ATLASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH); +#else + ATLASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH); +#endif + return (HBRUSH)::GetStockObject(nBrush); +} + +inline HFONT AtlGetStockFont(int nFont) +{ +#ifndef _WIN32_WCE + ATLASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFont == DEFAULT_GUI_FONT); +#else // CE specific + ATLASSERT(nFont == SYSTEM_FONT); +#endif // _WIN32_WCE + return (HFONT)::GetStockObject(nFont); +} + +inline HPALETTE AtlGetStockPalette(int nPalette) +{ + ATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported + return (HPALETTE)::GetStockObject(nPalette); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Global function for compacting a path by replacing parts with ellipsis + +// helper for multi-byte character sets +inline bool _IsDBCSTrailByte(LPCTSTR lpstr, int nChar) +{ +#ifndef _UNICODE + int i = nChar; + for( ; i > 0; i--) + { + if(!::IsDBCSLeadByte(lpstr[i - 1])) + break; + } + return ((nChar > 0) && (((nChar - i) & 1) != 0)); +#else // _UNICODE + lpstr; nChar; + return false; +#endif // _UNICODE +} + +inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen) +{ + ATLASSERT(lpstrOut != NULL); + ATLASSERT(lpstrIn != NULL); + ATLASSERT(cchLen > 0); + + LPCTSTR szEllipsis = _T("..."); + const int cchEndEllipsis = 3; + const int cchMidEllipsis = 4; + + if(lstrlen(lpstrIn) < cchLen) + { + SecureHelper::strcpy_x(lpstrOut, cchLen, lpstrIn); + return true; + } + + lpstrOut[0] = 0; + + // check if the separator is a slash or a backslash + TCHAR chSlash = _T('\\'); + for(LPTSTR lpstr = (LPTSTR)lpstrIn; *lpstr != 0; lpstr = ::CharNext(lpstr)) + { + if((*lpstr == _T('/')) || (*lpstr == _T('\\'))) + chSlash = *lpstr; + } + + // find the filename portion of the path + LPCTSTR lpstrFileName = lpstrIn; + for(LPCTSTR pPath = lpstrIn; *pPath; pPath = ::CharNext(pPath)) + { + if((pPath[0] == _T('\\') || pPath[0] == _T(':') || pPath[0] == _T('/')) + && pPath[1] && pPath[1] != _T('\\') && pPath[1] != _T('/')) + lpstrFileName = pPath + 1; + } + int cchFileName = lstrlen(lpstrFileName); + + // handle just the filename without a path + if(lpstrFileName == lpstrIn && cchLen > cchEndEllipsis) + { + bool bRet = (SecureHelper::strncpy_x(lpstrOut, cchLen, lpstrIn, cchLen - cchEndEllipsis - 1) == 0); + if(bRet) + { +#ifndef _UNICODE + if(_IsDBCSTrailByte(lpstrIn, cchLen - cchEndEllipsis)) + lpstrOut[cchLen - cchEndEllipsis - 1] = 0; +#endif // _UNICODE + SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis); + } + return bRet; + } + + // handle just ellipsis + if((cchLen < (cchMidEllipsis + cchEndEllipsis))) + { + for(int i = 0; i < cchLen - 1; i++) + lpstrOut[i] = ((i + 1) == cchMidEllipsis) ? chSlash : _T('.'); + lpstrOut[cchLen - 1] = 0; + return true; + } + + // calc how much we have to copy + int cchToCopy = cchLen - (cchMidEllipsis + cchFileName) - 1; + + if(cchToCopy < 0) + cchToCopy = 0; + +#ifndef _UNICODE + if(cchToCopy > 0 && _IsDBCSTrailByte(lpstrIn, cchToCopy)) + cchToCopy--; +#endif // _UNICODE + + bool bRet = (SecureHelper::strncpy_x(lpstrOut, cchLen, lpstrIn, cchToCopy) == 0); + if(!bRet) + return false; + + // add ellipsis + SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis); + TCHAR szSlash[2] = { chSlash, 0 }; + SecureHelper::strcat_x(lpstrOut, cchLen, szSlash); + + // add filename (and ellipsis, if needed) + if(cchLen > (cchMidEllipsis + cchFileName)) + { + SecureHelper::strcat_x(lpstrOut, cchLen, lpstrFileName); + } + else + { + cchToCopy = cchLen - cchMidEllipsis - cchEndEllipsis - 1; +#ifndef _UNICODE + if(cchToCopy > 0 && _IsDBCSTrailByte(lpstrFileName, cchToCopy)) + cchToCopy--; +#endif // _UNICODE + bRet = (SecureHelper::strncpy_x(&lpstrOut[cchMidEllipsis], cchLen - cchMidEllipsis, lpstrFileName, cchToCopy) == 0); + if(bRet) + SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis); + } + + return bRet; +} + +}; // namespace WTL + +#endif // __ATLMISC_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlprint.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlprint.h new file mode 100644 index 0000000000000000000000000000000000000000..5dc5ab5af6973d6d9a60e01f83b812c1e2c8af9a --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlprint.h @@ -0,0 +1,1106 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLPRINT_H__ +#define __ATLPRINT_H__ + +#pragma once + +#ifdef _WIN32_WCE + #error atlprint.h is not supported on Windows CE +#endif + +#ifndef __ATLAPP_H__ + #error atlprint.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlprint.h requires atlwin.h to be included first +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CPrinterInfo +// CPrinterT +// CDevModeT +// CPrinterDC +// CPrintJobInfo +// CPrintJob +// CPrintPreview +// CPrintPreviewWindowImpl +// CPrintPreviewWindow +// CZoomPrintPreviewWindowImpl +// CZoomPrintPreviewWindow + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CPrinterInfo - This class wraps all of the PRINTER_INFO_* structures +// and provided by ::GetPrinter. + +template +class _printer_info +{ +public: + typedef void infotype; +}; + +template <> class _printer_info<1> { public: typedef PRINTER_INFO_1 infotype; }; +template <> class _printer_info<2> { public: typedef PRINTER_INFO_2 infotype; }; +template <> class _printer_info<3> { public: typedef PRINTER_INFO_3 infotype; }; +template <> class _printer_info<4> { public: typedef PRINTER_INFO_4 infotype; }; +template <> class _printer_info<5> { public: typedef PRINTER_INFO_5 infotype; }; +template <> class _printer_info<6> { public: typedef PRINTER_INFO_6 infotype; }; +template <> class _printer_info<7> { public: typedef PRINTER_INFO_7 infotype; }; +// these are not in the old (vc6.0) headers +#ifdef _ATL_USE_NEW_PRINTER_INFO +template <> class _printer_info<8> { public: typedef PRINTER_INFO_8 infotype; }; +template <> class _printer_info<9> { public: typedef PRINTER_INFO_9 infotype; }; +#endif // _ATL_USE_NEW_PRINTER_INFO + + +template +class CPrinterInfo +{ +public: +// Data members + typename _printer_info::infotype* m_pi; + +// Constructor/destructor + CPrinterInfo() : m_pi(NULL) + { } + + CPrinterInfo(HANDLE hPrinter) : m_pi(NULL) + { + GetPrinterInfo(hPrinter); + } + + ~CPrinterInfo() + { + Cleanup(); + } + +// Operations + bool GetPrinterInfo(HANDLE hPrinter) + { + Cleanup(); + return GetPrinterInfoHelper(hPrinter, (BYTE**)&m_pi, t_nInfo); + } + +// Implementation + void Cleanup() + { + delete [] (BYTE*)m_pi; + m_pi = NULL; + } + + static bool GetPrinterInfoHelper(HANDLE hPrinter, BYTE** pi, int nIndex) + { + ATLASSERT(pi != NULL); + DWORD dw = 0; + BYTE* pb = NULL; + ::GetPrinter(hPrinter, nIndex, NULL, 0, &dw); + if (dw > 0) + { + ATLTRY(pb = new BYTE[dw]); + if (pb != NULL) + { + memset(pb, 0, dw); + DWORD dwNew; + if (!::GetPrinter(hPrinter, nIndex, pb, dw, &dwNew)) + { + delete [] pb; + pb = NULL; + } + } + } + *pi = pb; + return (pb != NULL); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPrinter - Wrapper class for a HANDLE to a printer + +template +class CPrinterT +{ +public: +// Data members + HANDLE m_hPrinter; + +// Constructor/destructor + CPrinterT(HANDLE hPrinter = NULL) : m_hPrinter(hPrinter) + { } + + ~CPrinterT() + { + ClosePrinter(); + } + +// Operations + CPrinterT& operator =(HANDLE hPrinter) + { + if (hPrinter != m_hPrinter) + { + ClosePrinter(); + m_hPrinter = hPrinter; + } + return *this; + } + + bool IsNull() const { return (m_hPrinter == NULL); } + + bool OpenPrinter(HANDLE hDevNames, const DEVMODE* pDevMode = NULL) + { + bool b = false; + DEVNAMES* pdn = (DEVNAMES*)::GlobalLock(hDevNames); + if (pdn != NULL) + { + LPTSTR lpszPrinterName = (LPTSTR)pdn + pdn->wDeviceOffset; + b = OpenPrinter(lpszPrinterName, pDevMode); + ::GlobalUnlock(hDevNames); + } + return b; + } + + bool OpenPrinter(LPCTSTR lpszPrinterName, const DEVMODE* pDevMode = NULL) + { + ClosePrinter(); + PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE }; + ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs); + + return (m_hPrinter != NULL); + } + + bool OpenPrinter(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS* pprintdefs) + { + ClosePrinter(); + ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, pprintdefs); + return (m_hPrinter != NULL); + } + + bool OpenDefaultPrinter(const DEVMODE* pDevMode = NULL) + { + ClosePrinter(); + const int cchBuff = 512; + TCHAR buffer[cchBuff] = { 0 }; + ::GetProfileString(_T("windows"), _T("device"), _T(",,,"), buffer, cchBuff); + int nLen = lstrlen(buffer); + if (nLen != 0) + { + LPTSTR lpsz = buffer; + while (*lpsz) + { + if (*lpsz == _T(',')) + { + *lpsz = 0; + break; + } + lpsz = CharNext(lpsz); + } + PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE }; + ::OpenPrinter(buffer, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs); + } + return m_hPrinter != NULL; + } + + void ClosePrinter() + { + if (m_hPrinter != NULL) + { + if (t_bManaged) + ::ClosePrinter(m_hPrinter); + m_hPrinter = NULL; + } + } + + bool PrinterProperties(HWND hWnd = NULL) + { + if (hWnd == NULL) + hWnd = ::GetActiveWindow(); + return !!::PrinterProperties(hWnd, m_hPrinter); + } + + HANDLE CopyToHDEVNAMES() const + { + HANDLE h = NULL; + CPrinterInfo<5> pinfon5; + CPrinterInfo<2> pinfon2; + LPTSTR lpszPrinterName = NULL; + // Some printers fail for PRINTER_INFO_5 in some situations + if (pinfon5.GetPrinterInfo(m_hPrinter)) + lpszPrinterName = pinfon5.m_pi->pPrinterName; + else if (pinfon2.GetPrinterInfo(m_hPrinter)) + lpszPrinterName = pinfon2.m_pi->pPrinterName; + if (lpszPrinterName != NULL) + { + int nLen = sizeof(DEVNAMES) + (lstrlen(lpszPrinterName) + 1) * sizeof(TCHAR); + h = ::GlobalAlloc(GMEM_MOVEABLE, nLen); + BYTE* pv = (BYTE*)::GlobalLock(h); + DEVNAMES* pdev = (DEVNAMES*)pv; + if (pv != NULL) + { + memset(pv, 0, nLen); + pdev->wDeviceOffset = sizeof(DEVNAMES) / sizeof(TCHAR); + pv = pv + sizeof(DEVNAMES); // now points to end + SecureHelper::strcpy_x((LPTSTR)pv, lstrlen(lpszPrinterName) + 1, lpszPrinterName); + ::GlobalUnlock(h); + } + } + return h; + } + + HDC CreatePrinterDC(const DEVMODE* pdm = NULL) const + { + CPrinterInfo<5> pinfo5; + CPrinterInfo<2> pinfo2; + HDC hDC = NULL; + LPTSTR lpszPrinterName = NULL; + // Some printers fail for PRINTER_INFO_5 in some situations + if (pinfo5.GetPrinterInfo(m_hPrinter)) + lpszPrinterName = pinfo5.m_pi->pPrinterName; + else if (pinfo2.GetPrinterInfo(m_hPrinter)) + lpszPrinterName = pinfo2.m_pi->pPrinterName; + if (lpszPrinterName != NULL) + hDC = ::CreateDC(NULL, lpszPrinterName, NULL, pdm); + return hDC; + } + + HDC CreatePrinterIC(const DEVMODE* pdm = NULL) const + { + CPrinterInfo<5> pinfo5; + CPrinterInfo<2> pinfo2; + HDC hDC = NULL; + LPTSTR lpszPrinterName = NULL; + // Some printers fail for PRINTER_INFO_5 in some situations + if (pinfo5.GetPrinterInfo(m_hPrinter)) + lpszPrinterName = pinfo5.m_pi->pPrinterName; + else if (pinfo2.GetPrinterInfo(m_hPrinter)) + lpszPrinterName = pinfo2.m_pi->pPrinterName; + if (lpszPrinterName != NULL) + hDC = ::CreateIC(NULL, lpszPrinterName, NULL, pdm); + return hDC; + } + + void Attach(HANDLE hPrinter) + { + ClosePrinter(); + m_hPrinter = hPrinter; + } + + HANDLE Detach() + { + HANDLE hPrinter = m_hPrinter; + m_hPrinter = NULL; + return hPrinter; + } + + operator HANDLE() const { return m_hPrinter; } +}; + +typedef CPrinterT CPrinterHandle; +typedef CPrinterT CPrinter; + + +/////////////////////////////////////////////////////////////////////////////// +// CDevMode - Wrapper class for DEVMODE + +template +class CDevModeT +{ +public: +// Data members + HANDLE m_hDevMode; + DEVMODE* m_pDevMode; + +// Constructor/destructor + CDevModeT(HANDLE hDevMode = NULL) : m_hDevMode(hDevMode) + { + m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL; + } + + ~CDevModeT() + { + Cleanup(); + } + +// Operations + CDevModeT& operator =(HANDLE hDevMode) + { + Attach(hDevMode); + return *this; + } + + void Attach(HANDLE hDevModeNew) + { + Cleanup(); + m_hDevMode = hDevModeNew; + m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL; + } + + HANDLE Detach() + { + if (m_hDevMode != NULL) + ::GlobalUnlock(m_hDevMode); + HANDLE hDevMode = m_hDevMode; + m_hDevMode = NULL; + return hDevMode; + } + + bool IsNull() const { return (m_hDevMode == NULL); } + + bool CopyFromPrinter(HANDLE hPrinter) + { + CPrinterInfo<2> pinfo; + bool b = pinfo.GetPrinterInfo(hPrinter); + if (b) + b = CopyFromDEVMODE(pinfo.m_pi->pDevMode); + return b; + } + + bool CopyFromDEVMODE(const DEVMODE* pdm) + { + if (pdm == NULL) + return false; + int nSize = pdm->dmSize + pdm->dmDriverExtra; + HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize); + if (h != NULL) + { + void* p = ::GlobalLock(h); + SecureHelper::memcpy_x(p, nSize, pdm, nSize); + ::GlobalUnlock(h); + } + Attach(h); + return (h != NULL); + } + + bool CopyFromHDEVMODE(HANDLE hdm) + { + bool b = false; + if (hdm != NULL) + { + DEVMODE* pdm = (DEVMODE*)::GlobalLock(hdm); + b = CopyFromDEVMODE(pdm); + ::GlobalUnlock(hdm); + } + return b; + } + + HANDLE CopyToHDEVMODE() + { + if ((m_hDevMode == NULL) || (m_pDevMode == NULL)) + return NULL; + int nSize = m_pDevMode->dmSize + m_pDevMode->dmDriverExtra; + HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize); + if (h != NULL) + { + void* p = ::GlobalLock(h); + SecureHelper::memcpy_x(p, nSize, m_pDevMode, nSize); + ::GlobalUnlock(h); + } + return h; + } + + // If this devmode was for another printer, this will create a new devmode + // based on the existing devmode, but retargeted at the new printer + bool UpdateForNewPrinter(HANDLE hPrinter) + { + bool bRet = false; + LONG nLen = ::DocumentProperties(NULL, hPrinter, NULL, NULL, NULL, 0); + CTempBuffer buff; + DEVMODE* pdm = buff.AllocateBytes(nLen); + if(pdm != NULL) + { + memset(pdm, 0, nLen); + LONG l = ::DocumentProperties(NULL, hPrinter, NULL, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER); + if (l == IDOK) + bRet = CopyFromDEVMODE(pdm); + } + + return bRet; + } + + bool DocumentProperties(HANDLE hPrinter, HWND hWnd = NULL) + { + CPrinterInfo<1> pi; + pi.GetPrinterInfo(hPrinter); + if (hWnd == NULL) + hWnd = ::GetActiveWindow(); + + bool bRet = false; + LONG nLen = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, NULL, NULL, 0); + CTempBuffer buff; + DEVMODE* pdm = buff.AllocateBytes(nLen); + if(pdm != NULL) + { + memset(pdm, 0, nLen); + LONG l = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER | DM_PROMPT); + if (l == IDOK) + bRet = CopyFromDEVMODE(pdm); + } + + return bRet; + } + + operator HANDLE() const { return m_hDevMode; } + + operator DEVMODE*() const { return m_pDevMode; } + +// Implementation + void Cleanup() + { + if (m_hDevMode != NULL) + { + ::GlobalUnlock(m_hDevMode); + if(t_bManaged) + ::GlobalFree(m_hDevMode); + m_hDevMode = NULL; + } + } +}; + +typedef CDevModeT CDevModeHandle; +typedef CDevModeT CDevMode; + + +/////////////////////////////////////////////////////////////////////////////// +// CPrinterDC + +class CPrinterDC : public CDC +{ +public: +// Constructors/destructor + CPrinterDC() + { + CPrinter printer; + printer.OpenDefaultPrinter(); + Attach(printer.CreatePrinterDC()); + ATLASSERT(m_hDC != NULL); + } + + CPrinterDC(HANDLE hPrinter, const DEVMODE* pdm = NULL) + { + CPrinterHandle p; + p.Attach(hPrinter); + Attach(p.CreatePrinterDC(pdm)); + ATLASSERT(m_hDC != NULL); + } + + ~CPrinterDC() + { + DeleteDC(); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPrintJob - Wraps a set of tasks for a specific printer (StartDoc/EndDoc) +// Handles aborting, background printing + +// Defines callbacks used by CPrintJob (not a COM interface) +class ATL_NO_VTABLE IPrintJobInfo +{ +public: + virtual void BeginPrintJob(HDC hDC) = 0; // allocate handles needed, etc. + virtual void EndPrintJob(HDC hDC, bool bAborted) = 0; // free handles, etc. + virtual void PrePrintPage(UINT nPage, HDC hDC) = 0; + virtual bool PrintPage(UINT nPage, HDC hDC) = 0; + virtual void PostPrintPage(UINT nPage, HDC hDC) = 0; + // If you want per page devmodes, return the DEVMODE* to use for nPage. + // You can optimize by only returning a new DEVMODE* when it is different + // from the one for nLastPage, otherwise return NULL. + // When nLastPage==0, the current DEVMODE* will be the default passed to + // StartPrintJob. + // Note: During print preview, nLastPage will always be "0". + virtual DEVMODE* GetNewDevModeForPage(UINT nLastPage, UINT nPage) = 0; + virtual bool IsValidPage(UINT nPage) = 0; +}; + +// Provides a default implementatin for IPrintJobInfo +// Typically, MI'd into a document or view class +class ATL_NO_VTABLE CPrintJobInfo : public IPrintJobInfo +{ +public: + virtual void BeginPrintJob(HDC /*hDC*/) // allocate handles needed, etc + { + } + + virtual void EndPrintJob(HDC /*hDC*/, bool /*bAborted*/) // free handles, etc + { + } + + virtual void PrePrintPage(UINT /*nPage*/, HDC hDC) + { + m_nPJState = ::SaveDC(hDC); + } + + virtual bool PrintPage(UINT /*nPage*/, HDC /*hDC*/) = 0; + + virtual void PostPrintPage(UINT /*nPage*/, HDC hDC) + { + RestoreDC(hDC, m_nPJState); + } + + virtual DEVMODE* GetNewDevModeForPage(UINT /*nLastPage*/, UINT /*nPage*/) + { + return NULL; + } + + virtual bool IsValidPage(UINT /*nPage*/) + { + return true; + } + +// Implementation - data + int m_nPJState; +}; + + +class CPrintJob +{ +public: +// Data members + CPrinterHandle m_printer; + IPrintJobInfo* m_pInfo; + DEVMODE* m_pDefDevMode; + DOCINFO m_docinfo; + int m_nJobID; + bool m_bCancel; + bool m_bComplete; + unsigned long m_nStartPage; + unsigned long m_nEndPage; + +// Constructor/destructor + CPrintJob() : m_nJobID(0), m_bCancel(false), m_bComplete(true) + { } + + ~CPrintJob() + { + ATLASSERT(IsJobComplete()); // premature destruction? + } + +// Operations + bool IsJobComplete() const + { + return m_bComplete; + } + + bool StartPrintJob(bool bBackground, HANDLE hPrinter, DEVMODE* pDefaultDevMode, + IPrintJobInfo* pInfo, LPCTSTR lpszDocName, + unsigned long nStartPage, unsigned long nEndPage, + bool bPrintToFile = false, LPCTSTR lpstrOutputFile = NULL) + { + ATLASSERT(m_bComplete); // previous job not done yet? + if (pInfo == NULL) + return false; + + memset(&m_docinfo, 0, sizeof(m_docinfo)); + m_docinfo.cbSize = sizeof(m_docinfo); + m_docinfo.lpszDocName = lpszDocName; + m_pInfo = pInfo; + m_nStartPage = nStartPage; + m_nEndPage = nEndPage; + m_printer.Attach(hPrinter); + m_pDefDevMode = pDefaultDevMode; + m_bComplete = false; + + if(bPrintToFile) + m_docinfo.lpszOutput = (lpstrOutputFile != NULL) ? lpstrOutputFile : _T("FILE:"); + + if (!bBackground) + { + m_bComplete = true; + return StartHelper(); + } + + // Create a thread and return + DWORD dwThreadID = 0; +#if !defined(_ATL_MIN_CRT) && defined(_MT) + HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))StartProc, this, 0, (UINT*)&dwThreadID); +#else + HANDLE hThread = ::CreateThread(NULL, 0, StartProc, (void*)this, 0, &dwThreadID); +#endif + if (hThread == NULL) + return false; + + ::CloseHandle(hThread); + + return true; + } + +// Implementation + static DWORD WINAPI StartProc(void* p) + { + CPrintJob* pThis = (CPrintJob*)p; + pThis->StartHelper(); + pThis->m_bComplete = true; + return 0; + } + + bool StartHelper() + { + CDC dcPrinter; + dcPrinter.Attach(m_printer.CreatePrinterDC(m_pDefDevMode)); + if (dcPrinter.IsNull()) + return false; + + m_nJobID = ::StartDoc(dcPrinter, &m_docinfo); + if (m_nJobID <= 0) + return false; + + m_pInfo->BeginPrintJob(dcPrinter); + + // print all the pages now + unsigned long nLastPage = 0; + for (unsigned long nPage = m_nStartPage; nPage <= m_nEndPage; nPage++) + { + if (!m_pInfo->IsValidPage(nPage)) + break; + DEVMODE* pdm = m_pInfo->GetNewDevModeForPage(nLastPage, nPage); + if (pdm != NULL) + dcPrinter.ResetDC(pdm); + dcPrinter.StartPage(); + m_pInfo->PrePrintPage(nPage, dcPrinter); + if (!m_pInfo->PrintPage(nPage, dcPrinter)) + m_bCancel = true; + m_pInfo->PostPrintPage(nPage, dcPrinter); + dcPrinter.EndPage(); + if (m_bCancel) + break; + nLastPage = nPage; + } + + m_pInfo->EndPrintJob(dcPrinter, m_bCancel); + if (m_bCancel) + ::AbortDoc(dcPrinter); + else + ::EndDoc(dcPrinter); + m_nJobID = 0; + return true; + } + + // Cancels a print job. Can be called asynchronously. + void CancelPrintJob() + { + m_bCancel = true; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPrintPreview - Adds print preview support to an existing window + +class CPrintPreview +{ +public: +// Data members + IPrintJobInfo* m_pInfo; + CPrinterHandle m_printer; + CEnhMetaFile m_meta; + DEVMODE* m_pDefDevMode; + DEVMODE* m_pCurDevMode; + SIZE m_sizeCurPhysOffset; + +// Constructor + CPrintPreview() : m_pInfo(NULL), m_pDefDevMode(NULL), m_pCurDevMode(NULL) + { + m_sizeCurPhysOffset.cx = 0; + m_sizeCurPhysOffset.cy = 0; + } + +// Operations + void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pji) + { + m_printer.Attach(hPrinter); + m_pDefDevMode = pDefaultDevMode; + m_pInfo = pji; + m_nCurPage = 0; + m_pCurDevMode = NULL; + } + + void SetEnhMetaFile(HENHMETAFILE hEMF) + { + m_meta = hEMF; + } + + void SetPage(int nPage) + { + if (!m_pInfo->IsValidPage(nPage)) + return; + m_nCurPage = nPage; + m_pCurDevMode = m_pInfo->GetNewDevModeForPage(0, nPage); + if (m_pCurDevMode == NULL) + m_pCurDevMode = m_pDefDevMode; + CDC dcPrinter = m_printer.CreatePrinterDC(m_pCurDevMode); + + int iWidth = dcPrinter.GetDeviceCaps(PHYSICALWIDTH); + int iHeight = dcPrinter.GetDeviceCaps(PHYSICALHEIGHT); + int nLogx = dcPrinter.GetDeviceCaps(LOGPIXELSX); + int nLogy = dcPrinter.GetDeviceCaps(LOGPIXELSY); + + RECT rcMM = { 0, 0, ::MulDiv(iWidth, 2540, nLogx), ::MulDiv(iHeight, 2540, nLogy) }; + + m_sizeCurPhysOffset.cx = dcPrinter.GetDeviceCaps(PHYSICALOFFSETX); + m_sizeCurPhysOffset.cy = dcPrinter.GetDeviceCaps(PHYSICALOFFSETY); + + CEnhMetaFileDC dcMeta(dcPrinter, &rcMM); + m_pInfo->PrePrintPage(nPage, dcMeta); + m_pInfo->PrintPage(nPage, dcMeta); + m_pInfo->PostPrintPage(nPage, dcMeta); + m_meta.Attach(dcMeta.Close()); + } + + void GetPageRect(RECT& rc, LPRECT prc) + { + int x1 = rc.right-rc.left; + int y1 = rc.bottom - rc.top; + if ((x1 < 0) || (y1 < 0)) + return; + + CEnhMetaFileInfo emfinfo(m_meta); + ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); + + // Compute whether we are OK vertically or horizontally + int x2 = pmh->szlDevice.cx; + int y2 = pmh->szlDevice.cy; + int y1p = MulDiv(x1, y2, x2); + int x1p = MulDiv(y1, x2, y2); + ATLASSERT((x1p <= x1) || (y1p <= y1)); + if (x1p <= x1) + { + prc->left = rc.left + (x1 - x1p) / 2; + prc->right = prc->left + x1p; + prc->top = rc.top; + prc->bottom = rc.bottom; + } + else + { + prc->left = rc.left; + prc->right = rc.right; + prc->top = rc.top + (y1 - y1p) / 2; + prc->bottom = prc->top + y1p; + } + } + +// Painting helpers + void DoPaint(CDCHandle dc) + { + // this one is not used + } + + void DoPaint(CDCHandle dc, RECT& rc) + { + CEnhMetaFileInfo emfinfo(m_meta); + ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); + int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx); + int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy); + + dc.OffsetWindowOrg(-nOffsetX, -nOffsetY); + dc.PlayMetaFile(m_meta, &rc); + } + +// Implementation - data + int m_nCurPage; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPrintPreviewWindow - Implements a print preview window + +template +class ATL_NO_VTABLE CPrintPreviewWindowImpl : public ATL::CWindowImpl, public CPrintPreview +{ +public: + DECLARE_WND_CLASS_EX(NULL, CS_VREDRAW | CS_HREDRAW, -1) + + enum { m_cxOffset = 10, m_cyOffset = 10 }; + +// Constructor + CPrintPreviewWindowImpl() : m_nMaxPage(0), m_nMinPage(0) + { } + +// Operations + void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, + IPrintJobInfo* pji, int nMinPage, int nMaxPage) + { + CPrintPreview::SetPrintPreviewInfo(hPrinter, pDefaultDevMode, pji); + m_nMinPage = nMinPage; + m_nMaxPage = nMaxPage; + } + + bool NextPage() + { + if (m_nCurPage == m_nMaxPage) + return false; + SetPage(m_nCurPage + 1); + Invalidate(); + return true; + } + + bool PrevPage() + { + if (m_nCurPage == m_nMinPage) + return false; + if (m_nCurPage == 0) + return false; + SetPage(m_nCurPage - 1); + Invalidate(); + return true; + } + +// Message map and handlers + BEGIN_MSG_MAP(CPrintPreviewWindowImpl) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + END_MSG_MAP() + + LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no need for the background + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + RECT rc = { 0 }; + + if(wParam != NULL) + { + pT->DoPrePaint((HDC)wParam, rc); + pT->DoPaint((HDC)wParam, rc); + } + else + { + CPaintDC dc(m_hWnd); + pT->DoPrePaint(dc.m_hDC, rc); + pT->DoPaint(dc.m_hDC, rc); + } + + return 0; + } + +// Painting helper + void DoPrePaint(CDCHandle dc, RECT& rc) + { + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + RECT rcArea = rcClient; + T* pT = static_cast(this); + pT; // avoid level 4 warning + ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset); + if (rcArea.left > rcArea.right) + rcArea.right = rcArea.left; + if (rcArea.top > rcArea.bottom) + rcArea.bottom = rcArea.top; + GetPageRect(rcArea, &rc); + CRgn rgn1, rgn2; + rgn1.CreateRectRgnIndirect(&rc); + rgn2.CreateRectRgnIndirect(&rcClient); + rgn2.CombineRgn(rgn1, RGN_DIFF); + dc.SelectClipRgn(rgn2); + dc.FillRect(&rcClient, COLOR_BTNSHADOW); + dc.SelectClipRgn(NULL); + dc.FillRect(&rc, (HBRUSH)::GetStockObject(WHITE_BRUSH)); + } + +// Implementation - data + int m_nMinPage; + int m_nMaxPage; +}; + + +class CPrintPreviewWindow : public CPrintPreviewWindowImpl +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_PrintPreview"), CS_VREDRAW | CS_HREDRAW, -1) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CZoomPrintPreviewWindowImpl - Implements print preview window with zooming + +#ifdef __ATLSCRL_H__ + +template +class ATL_NO_VTABLE CZoomPrintPreviewWindowImpl : public CPrintPreviewWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T > +{ +public: + bool m_bSized; + + CZoomPrintPreviewWindowImpl() + { + SetScrollExtendedStyle(SCRL_DISABLENOSCROLL); + InitZoom(); + } + + // should be called to reset data members before recreating window + void InitZoom() + { + m_bSized = false; + m_nZoomMode = ZOOMMODE_OFF; + m_fZoomScaleMin = 1.0; + m_fZoomScale = 1.0; + } + + BEGIN_MSG_MAP(CZoomPrintPreviewWindowImpl) + MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor) + MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) + MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown) + MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove) + MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp) + MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) + END_MSG_MAP() + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + SIZE sizeClient = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; + POINT ptOffset = m_ptOffset; + SIZE sizeAll = m_sizeAll; + SetScrollSize(sizeClient); + if(sizeAll.cx > 0) + ptOffset.x = ::MulDiv(ptOffset.x, m_sizeAll.cx, sizeAll.cx); + if(sizeAll.cy > 0) + ptOffset.y = ::MulDiv(ptOffset.y, m_sizeAll.cy, sizeAll.cy); + SetScrollOffset(ptOffset); + CScrollImpl< T >::OnSize(uMsg, wParam, lParam, bHandled); + if(!m_bSized) + { + m_bSized = true; + T* pT = static_cast(this); + pT->ShowScrollBar(SB_HORZ, TRUE); + pT->ShowScrollBar(SB_VERT, TRUE); + } + return 0; + } + + LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + RECT rc = { 0 }; + + if(wParam != NULL) + { + CDCHandle dc = (HDC)wParam; + int nMapModeSav = dc.GetMapMode(); + dc.SetMapMode(MM_ANISOTROPIC); + SIZE szWindowExt = { 0, 0 }; + dc.SetWindowExt(m_sizeLogAll, &szWindowExt); + SIZE szViewportExt = { 0, 0 }; + dc.SetViewportExt(m_sizeAll, &szViewportExt); + POINT ptViewportOrg = { 0, 0 }; + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); + + pT->DoPrePaint(dc, rc); + pT->DoPaint(dc, rc); + + dc.SetMapMode(nMapModeSav); + dc.SetWindowExt(szWindowExt); + dc.SetViewportExt(szViewportExt); + dc.SetViewportOrg(ptViewportOrg); + } + else + { + CPaintDC dc(pT->m_hWnd); + pT->PrepareDC(dc.m_hDC); + pT->DoPrePaint(dc.m_hDC, rc); + pT->DoPaint(dc.m_hDC, rc); + } + + return 0; + } + + // Painting helpers + void DoPaint(CDCHandle dc) + { + // this one is not used + } + + void DoPrePaint(CDCHandle dc, RECT& rc) + { + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + RECT rcArea = rcClient; + T* pT = static_cast(this); + pT; // avoid level 4 warning + ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset); + if (rcArea.left > rcArea.right) + rcArea.right = rcArea.left; + if (rcArea.top > rcArea.bottom) + rcArea.bottom = rcArea.top; + GetPageRect(rcArea, &rc); + HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW)); + dc.PatBlt(rcClient.left, rcClient.top, rc.left - rcClient.left, rcClient.bottom - rcClient.top, PATCOPY); + dc.PatBlt(rc.left, rcClient.top, rc.right - rc.left, rc.top - rcClient.top, PATCOPY); + dc.PatBlt(rc.right, rcClient.top, rcClient.right - rc.right, rcClient.bottom - rcClient.top, PATCOPY); + dc.PatBlt(rc.left, rc.bottom, rc.right - rc.left, rcClient.bottom - rc.bottom, PATCOPY); + dc.SelectBrush((HBRUSH)::GetStockObject(WHITE_BRUSH)); + dc.PatBlt(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY); + dc.SelectBrush(::GetSysColorBrush(COLOR_3DDKSHADOW)); + dc.PatBlt(rc.right, rc.top + 4, 4, rc.bottom - rc.top, PATCOPY); + dc.PatBlt(rc.left + 4, rc.bottom, rc.right - rc.left, 4, PATCOPY); + dc.SelectBrush(hbrOld); + } + + void DoPaint(CDCHandle dc, RECT& rc) + { + CEnhMetaFileInfo emfinfo(m_meta); + ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); + int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx); + int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy); + + dc.OffsetWindowOrg(-nOffsetX, -nOffsetY); + dc.PlayMetaFile(m_meta, &rc); + } +}; + +class CZoomPrintPreviewWindow : public CZoomPrintPreviewWindowImpl +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_ZoomPrintPreview"), CS_VREDRAW | CS_HREDRAW, -1) +}; + +#endif // __ATLSCRL_H__ + +}; // namespace WTL + +#endif // __ATLPRINT_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlres.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlres.h new file mode 100644 index 0000000000000000000000000000000000000000..32544d7b8b0024f584ebde2d574d6fa772de3172 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlres.h @@ -0,0 +1,265 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLRES_H__ +#define __ATLRES_H__ + +#pragma once + +#if defined(_WIN32_WCE) && !defined(__ATLRESCE_H__) + #error Use atlresCE.h instead of atlres.h for Windows CE +#endif + + +#ifdef RC_INVOKED +#ifndef _INC_WINDOWS + + #define _INC_WINDOWS + + #ifndef _WIN32_WCE + #define VS_VERSION_INFO 1 + + #ifdef APSTUDIO_INVOKED + #define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols + #endif // APSTUDIO_INVOKED + + #ifndef WINVER + #define WINVER 0x0400 // default to Windows Version 4.0 + #endif // !WINVER + + #include + + // operation messages sent to DLGINIT + #define LB_ADDSTRING (WM_USER+1) + #define CB_ADDSTRING (WM_USER+3) + #endif // !_WIN32_WCE + + #ifdef APSTUDIO_INVOKED + #undef APSTUDIO_HIDDEN_SYMBOLS + #endif // APSTUDIO_INVOKED + + #ifdef IDC_STATIC + #undef IDC_STATIC + #endif // IDC_STATIC + #define IDC_STATIC (-1) + +#endif // !_INC_WINDOWS +#endif // RC_INVOKED + +#ifdef APSTUDIO_INVOKED + #define APSTUDIO_HIDDEN_SYMBOLS +#endif // APSTUDIO_INVOKED + +/////////////////////////////////////////////////////////////////////////////// +// ATL resource types + +#ifndef RC_INVOKED + #define RT_DLGINIT MAKEINTRESOURCE(240) + #define RT_TOOLBAR MAKEINTRESOURCE(241) +#endif // RC_INVOKED + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef APSTUDIO_INVOKED + #undef APSTUDIO_HIDDEN_SYMBOLS +#endif // APSTUDIO_INVOKED + +/////////////////////////////////////////////////////////////////////////////// +// Standard window components + +#define ID_SEPARATOR 0 // special separator value +#define ID_DEFAULT_PANE 0 // default status bar pane + +#ifndef RC_INVOKED // code only +// standard control bars (IDW = window ID) + #define ATL_IDW_TOOLBAR 0xE800 // main Toolbar for window + #define ATL_IDW_STATUS_BAR 0xE801 // Status bar window + #define ATL_IDW_COMMAND_BAR 0xE802 // Command bar window + +// parts of a frame window + #define ATL_IDW_CLIENT 0xE900 + #define ATL_IDW_PANE_FIRST 0xE900 // first pane (256 max) + #define ATL_IDW_PANE_LAST 0xE9FF + #define ATL_IDW_HSCROLL_FIRST 0xEA00 // first Horz scrollbar (16 max) + #define ATL_IDW_VSCROLL_FIRST 0xEA10 // first Vert scrollbar (16 max) + + #define ATL_IDW_SIZE_BOX 0xEA20 // size box for splitters + #define ATL_IDW_PANE_SAVE 0xEA21 // to shift ATL_IDW_PANE_FIRST + +// bands for a rebar + #define ATL_IDW_BAND_FIRST 0xEB00 + #define ATL_IDW_BAND_LAST 0xEBFF +#endif // !RC_INVOKED + +/////////////////////////////////////////////////////////////////////////////// +// Standard Commands + +// File commands +#define ID_FILE_NEW 0xE100 +#define ID_FILE_OPEN 0xE101 +#define ID_FILE_CLOSE 0xE102 +#define ID_FILE_SAVE 0xE103 +#define ID_FILE_SAVE_AS 0xE104 +#define ID_FILE_PAGE_SETUP 0xE105 +#define ID_FILE_PRINT_SETUP 0xE106 +#define ID_FILE_PRINT 0xE107 +#define ID_FILE_PRINT_DIRECT 0xE108 +#define ID_FILE_PRINT_PREVIEW 0xE109 +#define ID_FILE_UPDATE 0xE10A +#define ID_FILE_SAVE_COPY_AS 0xE10B +#define ID_FILE_SEND_MAIL 0xE10C + +#define ID_FILE_MRU_FIRST 0xE110 +#define ID_FILE_MRU_FILE1 0xE110 // range - 16 max +#define ID_FILE_MRU_FILE2 0xE111 +#define ID_FILE_MRU_FILE3 0xE112 +#define ID_FILE_MRU_FILE4 0xE113 +#define ID_FILE_MRU_FILE5 0xE114 +#define ID_FILE_MRU_FILE6 0xE115 +#define ID_FILE_MRU_FILE7 0xE116 +#define ID_FILE_MRU_FILE8 0xE117 +#define ID_FILE_MRU_FILE9 0xE118 +#define ID_FILE_MRU_FILE10 0xE119 +#define ID_FILE_MRU_FILE11 0xE11A +#define ID_FILE_MRU_FILE12 0xE11B +#define ID_FILE_MRU_FILE13 0xE11C +#define ID_FILE_MRU_FILE14 0xE11D +#define ID_FILE_MRU_FILE15 0xE11E +#define ID_FILE_MRU_FILE16 0xE11F +#define ID_FILE_MRU_LAST 0xE11F + +// Edit commands +#define ID_EDIT_CLEAR 0xE120 +#define ID_EDIT_CLEAR_ALL 0xE121 +#define ID_EDIT_COPY 0xE122 +#define ID_EDIT_CUT 0xE123 +#define ID_EDIT_FIND 0xE124 +#define ID_EDIT_PASTE 0xE125 +#define ID_EDIT_PASTE_LINK 0xE126 +#define ID_EDIT_PASTE_SPECIAL 0xE127 +#define ID_EDIT_REPEAT 0xE128 +#define ID_EDIT_REPLACE 0xE129 +#define ID_EDIT_SELECT_ALL 0xE12A +#define ID_EDIT_UNDO 0xE12B +#define ID_EDIT_REDO 0xE12C +#define ID_EDIT_DELETE ID_EDIT_CLEAR +#define ID_EDIT_FIND_NEXT ID_EDIT_REPEAT +#define ID_EDIT_FIND_PREVIOUS 0xE12D + +// Window commands +#define ID_WINDOW_NEW 0xE130 +#define ID_WINDOW_ARRANGE 0xE131 +#define ID_WINDOW_CASCADE 0xE132 +#define ID_WINDOW_TILE_HORZ 0xE133 +#define ID_WINDOW_TILE_VERT 0xE134 +#define ID_WINDOW_SPLIT 0xE135 +#ifndef RC_INVOKED // code only + #define ATL_IDM_WINDOW_FIRST 0xE130 + #define ATL_IDM_WINDOW_LAST 0xE13F + #define ATL_IDM_FIRST_MDICHILD 0xFF00 // window list starts here + #define ATL_IDM_LAST_MDICHILD 0xFFFD +#endif // !RC_INVOKED +// TabView +#define ID_WINDOW_TABFIRST 0xFF00 // = ATL_IDM_FIRST_MDICHILD +#define ID_WINDOW_TABLAST 0xFFFD +#define ID_WINDOW_SHOWTABLIST 0xFFFE + +// Help and App commands +#define ID_APP_ABOUT 0xE140 +#define ID_APP_EXIT 0xE141 +#define ID_HELP_INDEX 0xE142 +#define ID_HELP_FINDER 0xE143 +#define ID_HELP_USING 0xE144 +#define ID_CONTEXT_HELP 0xE145 // shift-F1 +// special commands for processing help +#define ID_HELP 0xE146 // first attempt for F1 +#define ID_DEFAULT_HELP 0xE147 // last attempt + +// Misc +#define ID_NEXT_PANE 0xE150 +#define ID_PREV_PANE 0xE151 +#define ID_PANE_CLOSE 0xE152 +#define ID_PANE_NEXT ID_NEXT_PANE +#define ID_PANE_PREVIOUS ID_PREV_PANE + +// Format +#define ID_FORMAT_FONT 0xE160 + +// Scroll +#define ID_SCROLL_UP 0xE170 +#define ID_SCROLL_DOWN 0xE171 +#define ID_SCROLL_PAGE_UP 0xE172 +#define ID_SCROLL_PAGE_DOWN 0xE173 +#define ID_SCROLL_TOP 0xE174 +#define ID_SCROLL_BOTTOM 0xE175 +#define ID_SCROLL_LEFT 0xE176 +#define ID_SCROLL_RIGHT 0xE177 +#define ID_SCROLL_PAGE_LEFT 0xE178 +#define ID_SCROLL_PAGE_RIGHT 0xE179 +#define ID_SCROLL_ALL_LEFT 0xE17A +#define ID_SCROLL_ALL_RIGHT 0xE17B + +// OLE commands +#define ID_OLE_INSERT_NEW 0xE200 +#define ID_OLE_EDIT_LINKS 0xE201 +#define ID_OLE_EDIT_CONVERT 0xE202 +#define ID_OLE_EDIT_CHANGE_ICON 0xE203 +#define ID_OLE_EDIT_PROPERTIES 0xE204 +#define ID_OLE_VERB_FIRST 0xE210 // range - 16 max +#ifndef RC_INVOKED // code only + #define ID_OLE_VERB_LAST 0xE21F +#endif // !RC_INVOKED + +// View commands (same number used as IDW used for toolbar and status bar) +#define ID_VIEW_TOOLBAR 0xE800 +#define ID_VIEW_STATUS_BAR 0xE801 +#define ID_VIEW_REFRESH 0xE803 +#define ID_VIEW_RIBBON 0xE804 + +/////////////////////////////////////////////////////////////////////////////// +// Standard control IDs + +#ifdef IDC_STATIC + #undef IDC_STATIC +#endif // IDC_STATIC +#define IDC_STATIC (-1) // all static controls + +/////////////////////////////////////////////////////////////////////////////// +// Standard string error/warnings + +// idle status bar message +#define ATL_IDS_IDLEMESSAGE 0xE001 + +#ifndef RC_INVOKED // code only + #define ATL_IDS_SCFIRST 0xEF00 +#endif // !RC_INVOKED + +#define ATL_IDS_SCSIZE 0xEF00 +#define ATL_IDS_SCMOVE 0xEF01 +#define ATL_IDS_SCMINIMIZE 0xEF02 +#define ATL_IDS_SCMAXIMIZE 0xEF03 +#define ATL_IDS_SCNEXTWINDOW 0xEF04 +#define ATL_IDS_SCPREVWINDOW 0xEF05 +#define ATL_IDS_SCCLOSE 0xEF06 +#define ATL_IDS_SCRESTORE 0xEF12 +#define ATL_IDS_SCTASKLIST 0xEF13 + +#define ATL_IDS_MDICHILD 0xEF1F +#define ATL_IDS_MRU_FILE 0xEFDA + +/////////////////////////////////////////////////////////////////////////////// +// Misc. control IDs + +// Property Sheet control id's (determined with Spy++) +#define ID_APPLY_NOW 0x3021 +#define ID_WIZBACK 0x3023 +#define ID_WIZNEXT 0x3024 +#define ID_WIZFINISH 0x3025 +#define ATL_IDC_TAB_CONTROL 0x3020 + +#endif // __ATLRES_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlresce.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlresce.h new file mode 100644 index 0000000000000000000000000000000000000000..571db3091d95eb7211a167d1aaa80e75b4639813 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlresce.h @@ -0,0 +1,90 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLRESCE_H__ +#define __ATLRESCE_H__ + +#pragma once + +#ifndef _WIN32_WCE + #error atlresCE.h is only for Windows CE +#endif + + +#ifdef RC_INVOKED +#ifndef _INC_WINDOWS + + #define VS_VERSION_INFO 1 + + #ifdef APSTUDIO_INVOKED + #define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols + #endif // APSTUDIO_INVOKED + + #ifndef WINVER + #define WINVER 0x0400 // default to Windows Version 4.0 + #endif // !WINVER + + #if !defined(WCEOLE_ENABLE_DIALOGEX) + #define DIALOGEX DIALOG DISCARDABLE + #endif + + #include + #define SHMENUBAR RCDATA + + #if defined(SHELLSDK_MODULES_AYGSHELL) + #include + #else + #define NOMENU 0xFFFF + #define IDS_SHNEW 1 + #define IDM_SHAREDNEW 10 + #define IDM_SHAREDNEWDEFAULT 11 + #endif + #ifndef I_IMAGENONE + #define I_IMAGENONE (-2) + #endif + + #include + +#endif // !_INC_WINDOWS +#endif // RC_INVOKED + +#include "atlres.h" + +#ifdef APSTUDIO_INVOKED + #undef APSTUDIO_HIDDEN_SYMBOLS +#endif // APSTUDIO_INVOKED + +// Visual Studio dialog editor bug fix +#ifndef DS_FIXEDSYS + #define DS_FIXEDSYS 0 +#endif + +#define IDC_INFOSTATIC 0xFFFE // == IDC_STATIC -1 + +/////////////////////////////////////////////////////////////////////////////// +// Smartphone and PPC 2005 Resource IDs + +// Command and associated string resource IDs +#define ID_MENU_OK 0xE790 +#define ID_MENU_CANCEL 0xE791 +#define ID_MENU 0xE792 +#define ID_ACTION 0xE793 +#define ID_VIEW_FULLSCREEN 0xE802 + +// MenuBar resource IDs +#define ATL_IDM_MENU_DONE 0xE701 +#define ATL_IDM_MENU_CANCEL 0xE702 +#define ATL_IDM_MENU_DONECANCEL 0xE703 + +// Default device MenuBar control ID and MenuBar resource ID +#define ATL_IDW_MENU_BAR 0xE802 + +// SmartPhone spinned controls ID offset for CSpinCtrl +#define ATL_IDW_SPIN_ID 9999 + +#endif // __ATLRESCE_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlribbon.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlribbon.h new file mode 100644 index 0000000000000000000000000000000000000000..bbcb7d517cd28af781f0638e4ff62f83d1acd737 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlribbon.h @@ -0,0 +1,3456 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLRIBBON_H__ +#define __ATLRIBBON_H__ + +#pragma once + +#if (_MSC_VER < 1500) + #error atlribbon.h requires Visual C++ 2008 compiler or higher +#endif + +#ifndef _UNICODE + #error atlribbon.h requires the Unicode character set +#endif + +#if !defined(NTDDI_WIN7) || (NTDDI_VERSION < NTDDI_WIN7) + #error atlribbon.h requires the Windows 7 SDK or higher +#endif + +#ifdef _WIN32_WCE + #error atlribbon.h is not supported on Windows CE +#endif + +#ifndef __ATLAPP_H__ + #error atlribbon.h requires atlapp.h to be included first +#endif + +#if (_ATL_VER < 0x0700) + #include + #pragma comment(lib, "shlwapi.lib") +#endif + +#include // for RecentDocumentList classes +#include // for Frame and UpdateUI classes +#include // required for atlctrlw.h +#include // for CCommandBarCtrl + +#if !defined(_WTL_USE_CSTRING) && !defined(__ATLSTR_H__) + #pragma warning(push) + #pragma warning(disable: 4530) // unwind semantics not enabled + #include + #pragma warning(pop) +#endif + +#include +#pragma comment(lib, "dwmapi.lib") + +#include +#include +#pragma comment(lib, "propsys.lib") + +#include // for CHARFORMAT2 + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CRibbonUpdateUI : Automatic mapping of ribbon UI elements +// +// RibbonUI::Text +// RibbonUI::CharFormat +// RibbonUI::ICtrl +// RibbonUI::CtrlImpl +// RibbonUI::CommandCtrlImpl +// RibbonUI::ItemProperty +// RibbonUI::CollectionImplBase +// RibbonUI::CollectionImpl +// RibbonUI::TextCollectionImpl +// RibbonUI::ItemCollectionImpl +// RibbonUI::ComboCollectionImpl +// RibbonUI::CommandCollectionImpl +// RibbonUI::ToolbarCollectionImpl +// RibbonUI::SimpleCollectionImpl +// RibbonUI::CollectionCtrlImpl +// RibbonUI::ToolbarGalleryCtrlImpl +// RibbonUI::SimpleCollectionCtrlImpl +// RibbonUI::RecentItemsCtrlImpl +// RibbonUI::FontCtrlImpl +// RibbonUI::ColorCtrlImpl +// RibbonUI::SpinnerCtrlImpl +// +// RibbonUI::CRibbonImpl +// CRibbonImpl::CRibbonComboCtrl +// CRibbonImpl::CRibbonItemGalleryCtrl +// CRibbonImpl::CRibbonCommandGalleryCtrl +// CRibbonImpl::CRibbonToolbarGalleryCtrl +// CRibbonImpl::CRibbonSimpleComboCtrl +// CRibbonImpl::CRibbonSimpleGalleryCtrl +// CRibbonImpl::CRibbonRecentItemsCtrl +// CRibbonImpl::CRibbonColorCtrl +// CRibbonImpl::CRibbonFontCtrl +// CRibbonImpl::CRibbonSpinnerCtrl +// CRibbonImpl::CRibbonFloatSpinnerCtrl +// CRibbonImpl::CRibbonCommandCtrl +// +// CRibbonFrameWindowImplBase +// CRibbonFrameWindowImpl +// CRibbonMDIFrameWindowImpl +// CRibbonPersist +// +// Global functions: +// RibbonUI::SetPropertyVal() +// RibbonUI::GetImage() + + +// Constants + +#ifndef RIBBONUI_MAX_TEXT + #define RIBBONUI_MAX_TEXT 128 +#endif + +#define TWIPS_PER_POINT 20 // For font size + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CRibbonUpdateUI : Automatic mapping of ribbon UI elements + +template +class CRibbonUpdateUI : public CAutoUpdateUI +{ +public: + enum + { + UPDUI_RIBBON = 0x0080, + UPDUI_PERSIST = 0x0020 + }; + + bool IsRibbonElement(const _AtlUpdateUIMap& UIMap) + { + return (UIMap.m_wType & UPDUI_RIBBON) != 0; + } + + bool IsRibbonID(UINT nID) + { + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) + return IsRibbonElement(m_arrUIMap[i]); + } + + return false; + } + +// Element + bool UIAddRibbonElement(UINT nID) + { + return UIAddElement(nID); + } + + bool UIRemoveRibbonElement(UINT nID) + { + return UIRemoveElement(nID); + } + + bool UIPersistElement(UINT nID, bool bPersist = true) + { + return bPersist ? + UIAddElement(nID) : + UIRemoveElement(nID); + } + +// methods for Ribbon elements + BOOL UISetText(int nID, LPCWSTR sText, BOOL bForceUpdate = FALSE) + { + T* pT = static_cast(this); + BOOL bRes = CUpdateUIBase::UISetText(nID, sText, bForceUpdate); + if (pT->IsRibbonUI() && IsRibbonID(nID)) + bRes = SUCCEEDED(pT->InvalidateProperty(nID, UI_PKEY_Label)); + return bRes; + } + + BOOL UISetText(int nID, UINT uIdResource, BOOL bForceUpdate = FALSE) + { + CTempBuffer sText(RIBBONUI_MAX_TEXT); + int nRet = AtlLoadString(uIdResource, sText, RIBBONUI_MAX_TEXT); + if(nRet > 0) + UISetText(nID, sText, bForceUpdate); + return (nRet > 0) ? TRUE : FALSE; + } + + LPCTSTR UIGetText(int nID) + { + T* pT = static_cast(this); + LPCTSTR sUI = CAutoUpdateUI::UIGetText(nID); + + // replace 'tab' by 'space' for RibbonUI elements + if (sUI && pT->IsRibbonUI() && IsRibbonID(nID) && wcschr(sUI, L'\t')) + { + static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 }; + wcscpy_s(sText, sUI); + WCHAR* pch = wcschr(sText, L'\t'); + if (pch != NULL) + *pch = L' '; + return sText; + } + else + { + return sUI; + } + } + + BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE) + { + T* pT = static_cast(this); + BOOL bRes = CUpdateUIBase::UIEnable(nID, bEnable, bForceUpdate); + if (pT->IsRibbonUI() && IsRibbonID(nID)) + bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_Enabled, bEnable)); + return bRes; + } + + BOOL UISetCheck(int nID, INT nCheck, BOOL bForceUpdate = FALSE) + { + if ((nCheck == 0) || (nCheck == 1)) + return UISetCheck(nID, nCheck != 0, bForceUpdate); + else + return CUpdateUIBase::UISetCheck(nID, nCheck, bForceUpdate); + } + + BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE) + { + T* pT = static_cast(this); + BOOL bRes = CUpdateUIBase::UISetCheck(nID, bCheck, bForceUpdate); + if (bRes && pT->IsRibbonUI() && IsRibbonID(nID)) + bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_BooleanValue, bCheck)); + return bRes; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// RibbonUI namespace +// + +namespace RibbonUI +{ + +// Minimal string allocation support for various PROPERTYKEY values +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + typedef _CSTRING_NS::CString Text; +#else + class Text : public std::wstring + { + public: + Text(std::wstring& s) : std::wstring(s) + { } + Text(LPCWSTR s) : std::wstring(s) + { } + Text() + { } + bool IsEmpty() + { + return empty(); + } + operator LPCWSTR() + { + return c_str(); + } + Text& operator =(LPCWSTR s) + { + return static_cast(std::wstring::operator =(s)); + } + }; +#endif + +// PROPERTYKEY enum and helpers +enum k_KEY +{ + // state + k_Enabled = 1, k_BooleanValue = 200, + // text properties + k_LabelDescription = 2, k_Keytip = 3, k_Label = 4, k_TooltipDescription = 5, k_TooltipTitle = 6, + // image properties + k_LargeImage = 7, k_LargeHighContrastImage = 8, k_SmallImage = 9, k_SmallHighContrastImage = 10, + // collection properties + k_ItemsSource = 101, k_Categories = 102, k_SelectedItem = 104, + // collection item properties + k_CommandId = 100, k_CategoryId = 103, k_CommandType = 105, k_ItemImage = 106, + // combo control property + k_StringValue = 202, + // spinner control properties + k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces, k_FormatString, k_RepresentativeString = 208, + // font control properties + k_FontProperties = 300, k_FontProperties_Family, k_FontProperties_Size, k_FontProperties_Bold, k_FontProperties_Italic = 304, + k_FontProperties_Underline = 305, k_FontProperties_Strikethrough, k_FontProperties_VerticalPositioning, k_FontProperties_ForegroundColor = 308, + k_FontProperties_BackgroundColor = 309, k_FontProperties_ForegroundColorType, k_FontProperties_BackgroundColorType, k_FontProperties_ChangedProperties = 312, + k_FontProperties_DeltaSize = 313, + // recent items properties + k_RecentItems = 350, k_Pinned = 351, + // color control properties + k_Color = 400, k_ColorType = 401, k_ColorMode, + k_ThemeColorsCategoryLabel = 403, k_StandardColorsCategoryLabel, k_RecentColorsCategoryLabel = 405, k_AutomaticColorLabel = 406, + k_NoColorLabel = 407, k_MoreColorsLabel = 408, + k_ThemeColors = 409, k_StandardColors = 410, k_ThemeColorsTooltips = 411, k_StandardColorsTooltips = 412, + // Ribbon state + k_Viewable = 1000, k_Minimized = 1001, k_QuickAccessToolbarDock = 1002, k_ContextAvailable = 1100, + // Ribbon UI colors + k_GlobalBackgroundColor = 2000, k_GlobalHighlightColor, k_GlobalTextColor = 2002 +}; + +inline k_KEY k_(REFPROPERTYKEY key) +{ + return (k_KEY)key.fmtid.Data1; +} + +// PROPERTYKEY value assignment and specializations +// +template +HRESULT SetPropertyVal(REFPROPERTYKEY key, V val, PROPVARIANT* ppv) +{ + switch (k_(key)) + { + case k_Enabled: + case k_BooleanValue: + return InitPropVariantFromBoolean(val, ppv); + default: + return UIInitPropertyFromUInt32(key, val, ppv); + } +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DOUBLE val, PROPVARIANT* ppv) +{ + return SetPropertyVal(key, (LONG)val, ppv); +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUIImage* val, PROPVARIANT* ppv) +{ + HRESULT hr = UIInitPropertyFromImage(key, val, ppv); + ATLVERIFY(val->Release() == 1); + return hr; +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUnknown* val, PROPVARIANT* ppv) +{ + return UIInitPropertyFromInterface(key, val, ppv); +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IPropertyStore* val, PROPVARIANT* ppv) +{ + return UIInitPropertyFromInterface(key, val, ppv); +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, SAFEARRAY* val, PROPVARIANT* ppv) +{ + return UIInitPropertyFromIUnknownArray(key, val, ppv); +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DECIMAL* val, PROPVARIANT* ppv) +{ + return UIInitPropertyFromDecimal(key, *val, ppv); +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, bool val, PROPVARIANT* ppv) +{ + return UIInitPropertyFromBoolean(key, val, ppv); +} + +inline HRESULT SetPropertyVal(REFPROPERTYKEY key, LPCWSTR val, PROPVARIANT* ppv) +{ + return UIInitPropertyFromString(key, val, ppv); +} + +// CharFormat helper struct for RibbonUI font control +// +struct CharFormat : CHARFORMAT2 +{ + // Default constructor + CharFormat() + { + cbSize = sizeof(CHARFORMAT2); + Reset(); + } + + // Copy constructor + CharFormat(const CharFormat& cf) + { + ::CopyMemory(this, &cf, sizeof(CHARFORMAT2)); + } + + // Assign operator + CharFormat& operator =(const CharFormat& cf) + { + ::CopyMemory(this, &cf, sizeof(CHARFORMAT2)); + return (*this); + } + + void Reset() + { + uValue = dwMask = dwEffects = 0; + PropVariantInit(&propvar); + } + + void operator <<(IPropertyStore* pStore) + { + if (pStore == NULL) + { + ATLASSERT(FALSE); + return; + } + + static void (CharFormat::*Getk_[])(IPropertyStore*) = + { + &CharFormat::Getk_Family, + &CharFormat::Getk_FontProperties_Size, + &CharFormat::Getk_MaskEffect, + &CharFormat::Getk_MaskEffect, + &CharFormat::Getk_MaskEffect, + &CharFormat::Getk_MaskEffect, + &CharFormat::Getk_VerticalPositioning, + &CharFormat::Getk_Color, + &CharFormat::Getk_Color, + &CharFormat::Getk_ColorType, + &CharFormat::Getk_ColorType, + }; + + DWORD nProps = 0; + Reset(); + + ATLVERIFY(SUCCEEDED(pStore->GetCount(&nProps))); + for (DWORD iProp = 0; iProp < nProps; iProp++) + { + PROPERTYKEY key; + ATLVERIFY(SUCCEEDED(pStore->GetAt(iProp, &key))); + ATLASSERT(k_(key) >= k_FontProperties_Family); + + if (k_(key) <= k_FontProperties_BackgroundColorType) + (this->*Getk_[k_(key) - k_FontProperties_Family])(pStore); + } + } + + void operator >>(IPropertyStore* pStore) + { + if (pStore == NULL) + { + ATLASSERT(FALSE); + return; + } + + PutFace(pStore); + PutSize(pStore); + PutMaskEffect(CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold, pStore); + PutMaskEffect(CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic, pStore); + PutMaskEffect(CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline, pStore); + PutMaskEffect(CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough, pStore); + PutVerticalPos(pStore); + PutColor(pStore); + PutBackColor(pStore); + } + +private: + PROPVARIANT propvar; + UINT uValue; + + // Getk_ functions + void Getk_Family(IPropertyStore* pStore) + { + if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Family, &propvar))) + { + PropVariantToString(propvar, szFaceName, LF_FACESIZE); + if (*szFaceName) + dwMask |= CFM_FACE; + } + } + + void Getk_FontProperties_Size(IPropertyStore* pStore) + { + if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Size, &propvar))) + { + DECIMAL decSize = { 0 }; + UIPropertyToDecimal(UI_PKEY_FontProperties_Size, propvar, &decSize); + DOUBLE dSize = 0; + VarR8FromDec(&decSize, &dSize); + if (dSize > 0) + { + dwMask |= CFM_SIZE; + yHeight = (LONG)(dSize * TWIPS_PER_POINT); + } + } + } + + template + void Getk_MaskEffect(IPropertyStore* pStore) + { + if (SUCCEEDED(pStore->GetValue(key, &propvar))) + { + UIPropertyToUInt32(key, propvar, &uValue); + if ((UI_FONTPROPERTIES)uValue != UI_FONTPROPERTIES_NOTAVAILABLE) + { + dwMask |= t_dwMask; + dwEffects |= ((UI_FONTPROPERTIES) uValue == UI_FONTPROPERTIES_SET) ? t_dwEffects : 0; + } + } + } + + void Getk_VerticalPositioning(IPropertyStore* pStore) + { + if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_VerticalPositioning, &propvar))) + { + UIPropertyToUInt32(UI_PKEY_FontProperties_VerticalPositioning, propvar, &uValue); + UI_FONTVERTICALPOSITION uVerticalPosition = (UI_FONTVERTICALPOSITION) uValue; + if ((uVerticalPosition != UI_FONTVERTICALPOSITION_NOTAVAILABLE)) + { + dwMask |= (CFM_SUPERSCRIPT | CFM_SUBSCRIPT); + if (uVerticalPosition != UI_FONTVERTICALPOSITION_NOTSET) + { + dwEffects |= (uVerticalPosition == UI_FONTVERTICALPOSITION_SUPERSCRIPT) ? CFE_SUPERSCRIPT : CFE_SUBSCRIPT; + } + } + } + } + + template + void Getk_Color(IPropertyStore* pStore) + { + UINT32 color = 0; + if (SUCCEEDED(pStore->GetValue(key, &propvar))) + { + UIPropertyToUInt32(key, propvar, &color); + dwMask |= t_dwMask; + + if (t_dwMask == CFM_COLOR) + crTextColor = color; + else + crBackColor = color; + } + } + + template + void Getk_ColorType(IPropertyStore* pStore) + { + if (SUCCEEDED(pStore->GetValue(key, &propvar))) + { + UIPropertyToUInt32(key, propvar, &uValue); + if (t_type == (UI_SWATCHCOLORTYPE)uValue) + { + dwMask |= t_dwMask; + dwEffects |= t_dwEffects; + } + } + } + + // Put functions + void PutMaskEffect(WORD dwMaskVal, WORD dwEffectVal, REFPROPERTYKEY key, IPropertyStore* pStore) + { + PROPVARIANT var; + UI_FONTPROPERTIES uProp = UI_FONTPROPERTIES_NOTAVAILABLE; + if ((dwMask & dwMaskVal) != 0) + uProp = dwEffects & dwEffectVal ? UI_FONTPROPERTIES_SET : UI_FONTPROPERTIES_NOTSET; + SetPropertyVal(key, uProp, &var); + pStore->SetValue(key, var); + } + + void PutVerticalPos(IPropertyStore* pStore) + { + PROPVARIANT var; + UI_FONTVERTICALPOSITION uProp = UI_FONTVERTICALPOSITION_NOTAVAILABLE; + + if ((dwMask & CFE_SUBSCRIPT) != 0) + { + if ((dwMask & CFM_SUBSCRIPT) && (dwEffects & CFE_SUBSCRIPT)) + uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT; + else + uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT; + } + else if ((dwMask & CFM_OFFSET) != 0) + { + if (yOffset > 0) + uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT; + else if (yOffset < 0) + uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT; + } + + SetPropertyVal(UI_PKEY_FontProperties_VerticalPositioning, uProp, &var); + pStore->SetValue(UI_PKEY_FontProperties_VerticalPositioning, var); + } + + void PutFace(IPropertyStore* pStore) + { + PROPVARIANT var; + SetPropertyVal(UI_PKEY_FontProperties_Family, + dwMask & CFM_FACE ? szFaceName : L"", &var); + pStore->SetValue(UI_PKEY_FontProperties_Family, var); + } + + void PutSize(IPropertyStore* pStore) + { + PROPVARIANT var; + DECIMAL decVal; + + if ((dwMask & CFM_SIZE) != 0) + VarDecFromR8((DOUBLE)yHeight / TWIPS_PER_POINT, &decVal); + else + VarDecFromI4(0, &decVal); + + SetPropertyVal(UI_PKEY_FontProperties_Size, &decVal, &var); + pStore->SetValue(UI_PKEY_FontProperties_Size, var); + } + + void PutColor(IPropertyStore* pStore) + { + if ((dwMask & CFM_COLOR) != 0) + { + if ((dwEffects & CFE_AUTOCOLOR) == 0) + { + SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar); + + SetPropertyVal(UI_PKEY_FontProperties_ForegroundColor, crTextColor, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_ForegroundColor, propvar); + } + else + { + SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_AUTOMATIC, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar); + } + } + } + + void PutBackColor(IPropertyStore* pStore) + { + if (((dwMask & CFM_BACKCOLOR) != 0) && ((dwEffects & CFE_AUTOBACKCOLOR) == 0)) + { + SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar); + + SetPropertyVal(UI_PKEY_FontProperties_BackgroundColor, crBackColor, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_BackgroundColor, propvar); + } + else + { + SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_NOCOLOR, &propvar); + pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar); + } + } +}; + +// IUIImage helper +// +inline IUIImage* GetImage(HBITMAP hbm, UI_OWNERSHIP owner) +{ + ATLASSERT(hbm); + IUIImage* pIUII = NULL; + ATL::CComPtr pIFB; + + if SUCCEEDED(pIFB.CoCreateInstance(CLSID_UIRibbonImageFromBitmapFactory)) + ATLVERIFY(SUCCEEDED(pIFB->CreateImage(hbm, owner, &pIUII))); + + return pIUII; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Ribbon control classes + +// RibbonUI::ICtrl abstract interface of RibbonUI::CRibbonImpl and all RibbonUI control classes +// +struct ICtrl +{ + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* pCommandExecutionProperties) = 0; + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) = 0; +}; + +// RibbonUI::CtrlImpl base class for all ribbon controls +// +template +class ATL_NO_VTABLE CtrlImpl : public ICtrl +{ +protected: + T* m_pWndRibbon; + +public: + typedef T WndRibbon; + + CtrlImpl() : m_pWndRibbon(T::pWndRibbon) + { } + + WndRibbon& GetWndRibbon() + { + return *m_pWndRibbon; + } + + static WORD GetID() + { + return t_ID; + } + + Text m_sTxt[5]; + + // Operations + HRESULT Invalidate() + { + return GetWndRibbon().InvalidateCtrl(GetID()); + } + + HRESULT Invalidate(REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY) + { + return GetWndRibbon().InvalidateProperty(GetID(), key, flags); + } + + HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sTxt, bool bUpdate = false) + { + ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription)); + + m_sTxt[k_(key) - k_LabelDescription] = sTxt; + + return bUpdate ? + GetWndRibbon().InvalidateProperty(GetID(), key) : + S_OK; + } + + // Implementation + template + HRESULT SetProperty(REFPROPERTYKEY key, V val) + { + return GetWndRibbon().SetProperty(GetID(), key, val); + } + + HRESULT OnGetText(REFPROPERTYKEY key, PROPVARIANT* ppv) + { + ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription)); + + const INT iText = k_(key) - k_LabelDescription; + if (m_sTxt[iText].IsEmpty()) + if (LPCWSTR sText = GetWndRibbon().OnRibbonQueryText(GetID(), key)) + m_sTxt[iText] = sText; + + return !m_sTxt[iText].IsEmpty() ? + SetPropertyVal(key, (LPCWSTR)m_sTxt[iText], ppv) : + S_OK; + } + + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* pCommandExecutionProperties) + { + ATLASSERT(nCmdID == t_ID); + return GetWndRibbon().DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties); + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT(nCmdID == t_ID); + + const INT iMax = k_TooltipTitle - k_LabelDescription; + const INT iVal = k_(key) - k_LabelDescription; + + return (iVal <= iMax) && (iVal >= 0) ? + OnGetText(key, ppropvarNewValue) : + GetWndRibbon().DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + } +}; + +// CommandCtrlImpl base class for most ribbon controls +// +template +class CommandCtrlImpl : public CtrlImpl +{ +public: + CBitmap m_hbm[4]; + + HRESULT SetImage(REFPROPERTYKEY key, HBITMAP hbm, bool bUpdate = false) + { + ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage)); + + m_hbm[k_(key) - k_LargeImage].Attach(hbm); + + return bUpdate ? + GetWndRibbon().InvalidateProperty(GetID(), key) : + S_OK; + } + + HRESULT OnGetImage(REFPROPERTYKEY key, PROPVARIANT* ppv) + { + ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage)); + + const INT iImage = k_(key) - k_LargeImage; + + if (m_hbm[iImage].IsNull()) + m_hbm[iImage] = GetWndRibbon().OnRibbonQueryImage(GetID(), key); + + return m_hbm[iImage].IsNull() ? + E_NOTIMPL : + SetPropertyVal(key, GetImage(m_hbm[iImage], UI_OWNERSHIP_COPY), ppv); + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT (nCmdID == GetID()); + + return (k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage) ? + OnGetImage(key, ppropvarNewValue) : + CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Ribbon collection base classes + +// ItemProperty class: ribbon callback for each item in a collection +// + +#pragma warning(push) +#pragma warning(disable: 4512) // assignment operator could not be generated + +template +class ItemProperty : public IUISimplePropertySet +{ +public: + ItemProperty(UINT i, TCollection* pCollection) : m_Index(i), m_pCollection(pCollection) + { } + + const UINT m_Index; + TCollection* m_pCollection; + + // IUISimplePropertySet method. + STDMETHODIMP GetValue(REFPROPERTYKEY key, PROPVARIANT *value) + { + return m_pCollection->OnGetItem(m_Index, key, value); + } + + // IUnknown methods. + STDMETHODIMP_(ULONG) AddRef() + { + return 1; + } + + STDMETHODIMP_(ULONG) Release() + { + return 1; + } + + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) + { + if ((iid == __uuidof(IUnknown)) || (iid == __uuidof(IUISimplePropertySet))) + { + *ppv = this; + return S_OK; + } + else + { + return E_NOINTERFACE; + } + } +}; + +#pragma warning(pop) + + +// CollectionImplBase: base class for all RibbonUI collections +// +template +class CollectionImplBase +{ + typedef CollectionImplBase thisClass; + +public: + CollectionImplBase() + { + for (int i = 0; i < t_size; i++) + m_apItems[i] = new ItemProperty(i, static_cast(this)); + } + + ~CollectionImplBase() + { + for (int i = 0; i < t_size; i++) + delete m_apItems[i]; + } + +// Data members + ItemProperty* m_apItems[t_size]; +}; + +// CollectionImpl: handles categories and collecton resizing +// +template +class CollectionImpl : public CollectionImplBase, t_items + t_categories> +{ + typedef CollectionImpl thisClass; +public: + typedef thisClass Collection; + + CollectionImpl() : m_size(t_items) + { + ::FillMemory(m_auItemCat, sizeof(m_auItemCat), 0xff); // UI_COLLECTION_INVALIDINDEX + } + + UINT32 m_auItemCat[t_items]; + Text m_asCatName[__max(t_categories, 1)]; + size_t m_size; + +// Operations + HRESULT SetItemCategory(UINT uItem, UINT uCat, bool bUpdate = false) + { + ATLASSERT((uItem < t_items) && (uCat < t_categories)); + + m_auItemCat[uItem] = uCat; + + return bUpdate ? InvalidateItems() : S_OK; + } + + HRESULT SetCategoryText(UINT uCat, LPCWSTR sText, bool bUpdate = false) + { + ATLASSERT(uCat < t_categories); + + m_asCatName[uCat] = sText; + + return bUpdate ? InvalidateCategories() : S_OK; + } + + HRESULT Resize(size_t size, bool bUpdate = false) + { + ATLASSERT(size <= t_items); + + m_size = size; + + return bUpdate ? InvalidateItems() : S_OK; + } + +// Implementation + HRESULT OnGetItem(UINT uIndex, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(uIndex < t_items + t_categories); + TCtrl* pCtrl = static_cast(this); + + return uIndex < t_items ? + pCtrl->DoGetItem(uIndex, key, value) : + pCtrl->DoGetCategory(uIndex - t_items, key, value); + } + + HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(k_(key) == k_CategoryId); + UINT32 uCat = UI_COLLECTION_INVALIDINDEX; + + if (t_categories != 0) + { + if (m_auItemCat[uItem] == UI_COLLECTION_INVALIDINDEX) + { + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + m_auItemCat[uItem] = ribbon.OnRibbonQueryItemCategory(TCtrl::GetID(), uItem); + } + uCat = m_auItemCat[uItem]; + } + + return SetPropertyVal(key, uCat, value); + } + + HRESULT DoGetCategory(UINT uCat, REFPROPERTYKEY key, PROPVARIANT *value) + { + HRESULT hr = S_OK; + + switch (k_(key)) + { + case k_Label: + if (m_asCatName[uCat].IsEmpty()) + { + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + m_asCatName[uCat] = ribbon.OnRibbonQueryCategoryText(TCtrl::GetID(), uCat); + } + hr = SetPropertyVal(key, (LPCWSTR)m_asCatName[uCat], value); + break; + case k_CategoryId: + hr = SetPropertyVal(key, uCat, value); + break; + default: + ATLASSERT(FALSE); + break; + } + + return hr; + } + + HRESULT InvalidateItems() + { + return static_cast(this)->Invalidate(UI_PKEY_ItemsSource); + } + + HRESULT InvalidateCategories() + { + return static_cast(this)->Invalidate(UI_PKEY_Categories); + } + + HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* /*ppropvarNewValue*/) + { + ATLASSERT(nCmdID == TCtrl::GetID()); + nCmdID; // avoid level 4 warning + + HRESULT hr = E_NOTIMPL; + switch (k_(key)) + { + case k_ItemsSource: + { + ATL::CComQIPtr pIUICollection(ppropvarCurrentValue->punkVal); + ATLASSERT(pIUICollection); + hr = pIUICollection->Clear(); + for (UINT i = 0; i < m_size; i++) + { + if FAILED(hr = pIUICollection->Add(m_apItems[i])) + break; + } + ATLASSERT(SUCCEEDED(hr)); + } + break; + case k_Categories: + if (t_categories != 0) + { + ATL::CComQIPtr pIUICategory(ppropvarCurrentValue->punkVal); + ATLASSERT(pIUICategory.p); + hr = pIUICategory->Clear(); + for (UINT i = t_items; i < (t_items + t_categories); i++) + { + if FAILED(hr = pIUICategory->Add(m_apItems[i])) + break; + } + ATLASSERT(SUCCEEDED(hr)); + } + break; + } + + return hr; + } +}; + +// TextCollectionImpl: handles item labels and selection +// +template +class TextCollectionImpl : public CollectionImpl +{ + typedef TextCollectionImpl thisClass; +public: + typedef thisClass TextCollection; + + TextCollectionImpl() : m_uSelected(UI_COLLECTION_INVALIDINDEX) + { } + + Text m_asText[t_items]; + UINT m_uSelected; + + // Operations + HRESULT SetItemText(UINT uItem, LPCWSTR sText, bool bUpdate = false) + { + ATLASSERT(uItem < t_items); + + m_asText[uItem] = sText; + + return bUpdate ? InvalidateItems() : S_OK; + } + + UINT GetSelected() + { + return m_uSelected; + } + + HRESULT Select(UINT uItem, bool bUpdate = false) + { + ATLASSERT((uItem < t_items) || (uItem == UI_COLLECTION_INVALIDINDEX)); + + m_uSelected = uItem; + + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + return bUpdate ? + ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_SelectedItem, uItem) : + S_OK; + } + +// Implementation + HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(uItem < t_items); + + if (k_(key) == k_Label) + { + if (m_asText[uItem].IsEmpty()) + { + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + m_asText[uItem] = ribbon.OnRibbonQueryItemText(TCtrl::GetID(), uItem); + } + return SetPropertyVal(key, (LPCWSTR)m_asText[uItem], value); + } + else + { + return Collection::DoGetItem(uItem, key, value); + } + } + + HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT(nCmdID == TCtrl::GetID()); + + if (k_(key) == k_SelectedItem) + { + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + UINT uSel = UI_COLLECTION_INVALIDINDEX; + if ((m_uSelected == UI_COLLECTION_INVALIDINDEX) && + ribbon.OnRibbonQuerySelectedItem(TCtrl::GetID(), uSel)) + m_uSelected = uSel; + + return SetPropertyVal(key, m_uSelected, ppropvarNewValue); + } + else + { + return Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + } + } +}; + +// ItemCollectionImpl: handles item image +// +template +class ItemCollectionImpl : public TextCollectionImpl +{ + typedef ItemCollectionImpl thisClass; +public: + typedef thisClass ItemCollection; + + ItemCollectionImpl() + { + ::ZeroMemory(m_aBitmap, sizeof(m_aBitmap)); + } + + CBitmap m_aBitmap[t_items]; + + // Operations + HRESULT SetItemImage(UINT uIndex, HBITMAP hbm, bool bUpdate = false) + { + ATLASSERT(uIndex < t_items); + + m_aBitmap[uIndex] = hbm; + + return bUpdate ? InvalidateItems() : S_OK; + } + +// Implementation + HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(uItem < t_items); + + if (k_(key) == k_ItemImage) + { + if (m_aBitmap[uItem].IsNull()) + { + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + m_aBitmap[uItem] = ribbon.OnRibbonQueryItemImage(TCtrl::GetID(), uItem); + } + return m_aBitmap[uItem].IsNull() ? + E_NOTIMPL : + SetPropertyVal(key, GetImage(m_aBitmap[uItem], UI_OWNERSHIP_COPY), value); + } + else + { + return TextCollection::DoGetItem(uItem, key, value); + } + } +}; + +// ComboCollectionImpl: handles combo text +// +template +class ComboCollectionImpl : public ItemCollectionImpl +{ + typedef ComboCollectionImpl thisClass; +public: + typedef thisClass ComboCollection; + + // Operations + HRESULT SetComboText(LPCWSTR sText) + { + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + return ribbon.IsRibbonUI() ? + ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_StringValue, sText) : + S_OK; + } + + LPCWSTR GetComboText() + { + static WCHAR sCombo[RIBBONUI_MAX_TEXT] = { 0 }; + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + PROPVARIANT var; + if (ribbon.IsRibbonUI()) + { + HRESULT hr = ribbon.GetIUIFrameworkPtr()->GetUICommandProperty(TCtrl::GetID(), UI_PKEY_StringValue, &var); + hr = PropVariantToString(var, sCombo, RIBBONUI_MAX_TEXT); + return sCombo; + } + return NULL; + } +}; + +// CommandCollectionImpl: handles RibbonUI command collection controls +// +template +class CommandCollectionImpl : public CollectionImpl +{ + typedef CommandCollectionImpl thisClass; +public: + typedef thisClass CommandCollection; + + CommandCollectionImpl() + { + ::ZeroMemory(m_auCmd, sizeof(m_auCmd)); + ::ZeroMemory(m_aCmdType, sizeof(m_aCmdType)); + } + + UINT32 m_auCmd[t_items]; + BYTE m_aCmdType[t_items]; + + // Operations + HRESULT SetItemCommand(UINT uItem, UINT32 uCommandID, bool bUpdate = false) + { + ATLASSERT(uItem < t_items); + + if (uCommandID == m_auCmd[uItem]) + return S_OK; + + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + + m_auCmd[uItem] = uCommandID; + if (uCommandID != 0) + ribbon.UIAddRibbonElement(uCommandID); + + return bUpdate ? InvalidateItems() : S_OK; + } + + HRESULT SetItemCommandType(UINT uItem, UI_COMMANDTYPE type, bool bUpdate = false) + { + ATLASSERT(uItem < t_items); + + m_aCmdType[uItem] = (BYTE)type; + + return bUpdate ? InvalidateItems() : S_OK; + } + +// Implementation + HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(uItem < t_items); + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + + HRESULT hr = E_FAIL; + switch (k_(key)) + { + case k_CommandId: + if (m_auCmd[uItem] == 0) + SetItemCommand(uItem, ribbon.OnRibbonQueryItemCommand(TCtrl::GetID(), uItem)); + hr = SetPropertyVal(key, m_auCmd[uItem], value); + break; + case k_CommandType: + if (m_aCmdType[uItem] == UI_COMMANDTYPE_UNKNOWN) + SetItemCommandType(uItem, ribbon.OnRibbonQueryItemCommandType(TCtrl::GetID(), uItem)); + hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value); + break; + case k_CategoryId: + default: + hr = Collection::DoGetItem(uItem, key, value); + break; + } + + return hr; + } + + HRESULT Select(UINT /*uItem*/, bool /*bUpdate*/ = false) + { + ATLASSERT(FALSE); + return S_OK; + } +}; + +// SimpleCollectionImpl: collection class for ribbon simple collection controls +// +template +class SimpleCollectionImpl : public CollectionImplBase, t_size> +{ + typedef SimpleCollectionImpl thisClass; +public: + typedef CollectionImplBase CollectionBase; + typedef thisClass SimpleCollection; + +// Implementation + HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(uItem < t_size); + TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); + + HRESULT hr = E_NOTIMPL; + switch (k_(key)) + { + case k_ItemImage: + if (HBITMAP hbm = ribbon.DefRibbonQueryItemImage(TCtrl::GetID(), uItem)) + hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), value); + break; + case k_Label: + if (LPCWSTR sText = ribbon.DefRibbonQueryItemText(TCtrl::GetID(), uItem)) + hr = SetPropertyVal(key, (LPCWSTR)sText, value); + break; + case k_CommandType: + hr = SetPropertyVal(key, t_CommandType, value); + break; + case k_CommandId: + hr = SetPropertyVal(key, ribbon.DefRibbonQueryItemCommand(TCtrl::GetID(), uItem), value); + break; + case k_CategoryId: + hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value); + break; + default: + ATLASSERT(FALSE); + break; + } + + return hr; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Ribbon collection control classes + +// CollectionCtrlImpl: specializable class for ribbon collection controls +// +template +class CollectionCtrlImpl : public CommandCtrlImpl, public TCollection +{ + typedef CollectionCtrlImpl thisClass; +public: + typedef CommandCtrlImpl CommandCtrl; + typedef TCollection Collection; + + // Implementation + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT(nCmdID == GetID()); + ATLASSERT(ppropvarNewValue); + + HRESULT hr = Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + if FAILED(hr) + hr = CommandCtrl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + + return hr; + } + + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* /*pCommandExecutionProperties*/) + { + ATLASSERT (nCmdID == GetID()); + nCmdID; // avoid level4 warning + + if (key == NULL) // gallery button pressed + { + GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX); + return S_OK; + } + + ATLASSERT(k_(*key) == k_SelectedItem); + ATLASSERT(ppropvarValue); + + HRESULT hr = S_OK; + UINT32 uSel = 0xffff; + hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel); + + if (SUCCEEDED(hr)) + { + if (GetWndRibbon().OnRibbonItemSelected(GetID(), verb, uSel)) + TCollection::Select(uSel); + } + + return hr; + } +}; + +// ToolbarGalleryCtrlImpl: base class for ribbon toolbar gallery controls +// +template +class ToolbarGalleryCtrlImpl : public CollectionCtrlImpl, t_size>> +{ +public: + ToolbarGalleryCtrlImpl() + { + CResource tbres; + ATLVERIFY(tbres.Load(RT_TOOLBAR, t_idTB)); + _AtlToolBarData* pData = (_AtlToolBarData*)tbres.Lock(); + ATLASSERT(pData); + ATLASSERT(pData->wVersion == 1); + + WORD* pItems = pData->items(); + INT j = 0; + for (int i = 0; (i < pData->wItemCount) && (j < t_size); i++) + { + if (pItems[i] != 0) + { + m_aCmdType[j] = UI_COMMANDTYPE_ACTION; + m_auCmd[j++] = pItems[i]; + } + } + + if (j < t_size) + Resize(j); + } + + HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT(uItem < m_size); + ATLASSERT(m_auCmd[uItem]); + + HRESULT hr = E_FAIL; + switch (k_(key)) + { + case k_CommandId: + hr = SetPropertyVal(key, m_auCmd[uItem], value); + break; + case k_CommandType: + hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value); + break; + case k_CategoryId: + hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value); + break; + default: + ATLASSERT(FALSE); + break; + } + + return hr; + } +}; + + +// SimpleCollectionCtrlImpl: base class for simple gallery and listbox controls +// +template +class SimpleCollectionCtrlImpl : + public CommandCtrlImpl, + public SimpleCollectionImpl, t_size, t_CommandType> +{ + typedef SimpleCollectionCtrlImpl thisClass; +public: + typedef thisClass SimpleCollection; + + SimpleCollectionCtrlImpl() : m_uSelected(0) + { } + + UINT m_uSelected; + + HRESULT Select(UINT uItem, bool bUpdate = false) + { + ATLASSERT((uItem < t_size) || (uItem == UI_COLLECTION_INVALIDINDEX)); + + m_uSelected = uItem; + + return bUpdate ? + GetWndRibbon().SetProperty(GetID(), UI_PKEY_SelectedItem, uItem) : + S_OK; + } + + // Implementation + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT(nCmdID == GetID()); + ATLASSERT(ppropvarNewValue != NULL); + + HRESULT hr = S_OK; + switch (k_(key)) + { + case k_ItemsSource: + { + ATL::CComQIPtr pIUICollection(ppropvarCurrentValue->punkVal); + ATLASSERT(pIUICollection.p); + hr = pIUICollection->Clear(); + for (UINT i = 0; i < t_size; i++) + { + if FAILED(hr = pIUICollection->Add(m_apItems[i])) + break; + } + ATLASSERT(SUCCEEDED(hr)); + } + break; + case k_SelectedItem: + hr = SetPropertyVal(UI_PKEY_SelectedItem, m_uSelected, ppropvarNewValue); + break; + default: + hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + break; + } + + return hr; + } + + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* /*pCommandExecutionProperties*/) + { + ATLASSERT (nCmdID == GetID()); + nCmdID; // avoid level 4 warning + + HRESULT hr = S_OK; + if (key == NULL) // gallery button pressed + { + GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX); + return hr; + } + ATLASSERT(k_(*key) == k_SelectedItem); + ATLASSERT(ppropvarValue); + + if SUCCEEDED(hr = UIPropertyToUInt32(*key, *ppropvarValue, &m_uSelected)) + GetWndRibbon().OnRibbonItemSelected(GetID(), verb, m_uSelected); + + return hr; + } +}; + +// RecentItemsCtrlImpl +// +template +class RecentItemsCtrlImpl : + public CtrlImpl, + public CollectionImplBase, TDocList::m_nMaxEntries_Max>, + public TDocList +{ + typedef RecentItemsCtrlImpl thisClass; +public: + typedef thisClass RecentItems; + + // Implementation + HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) + { + ATLASSERT((INT)uItem < GetMaxEntries()); + + LPCWSTR sPath = m_arrDocs[uItem].szDocName; + HRESULT hr = E_NOTIMPL; + switch (k_(key)) + { + case k_Label: + hr = SetPropertyVal(key, GetWndRibbon().OnRibbonQueryRecentItemName(sPath), value); + break; + case k_LabelDescription: + hr = SetPropertyVal(key, sPath, value); + break; + default: + ATLASSERT(FALSE); + break; + } + + return hr; + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT(nCmdID == GetID()); + ATLASSERT(ppropvarNewValue); + + HRESULT hr = S_OK; + switch (k_(key)) + { + case k_RecentItems: + if (SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, m_arrDocs.GetSize())) + { + const int iLastIndex = m_arrDocs.GetSize() - 1; + for (LONG i = 0; i <= iLastIndex; i++) + SafeArrayPutElement(psa, &i, m_apItems[iLastIndex - i]); // reverse order + + hr = SetPropertyVal(key, psa, ppropvarNewValue); + SafeArrayDestroy(psa); + } + break; + default: + hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + break; + } + + return hr; + } + + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* /*pCommandExecutionProperties*/) + { + ATLASSERT(nCmdID == GetID()); + nCmdID; // avoid level 4 warning + ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE); + verb; // avoid level 4 warning + ATLASSERT((key) && (k_(*key) == k_SelectedItem)); + ATLASSERT(ppropvarValue); + + UINT32 uSel = 0xffff; + HRESULT hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel); + if SUCCEEDED(hr) + { + ATLASSERT(uSel < (UINT)GetMaxEntries()); + GetWndRibbon().DefCommandExecute(ID_FILE_MRU_FIRST + uSel); + } + + return hr; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Ribbon stand-alone control classes + +// FontCtrlImpl +// +template +class FontCtrlImpl : public CtrlImpl +{ +public: + + CharFormat m_cf; + +// Implementation + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* pCommandExecutionProperties) + { + ATLASSERT (nCmdID == GetID()); + nCmdID; // avoid level 4 warning + ATLASSERT ((key) && (k_(*key) == k_FontProperties)); + key; // avoid level 4 warning + + HRESULT hr = E_INVALIDARG; + switch (verb) + { + case UI_EXECUTIONVERB_PREVIEW: + case UI_EXECUTIONVERB_EXECUTE: + ATLASSERT(pCommandExecutionProperties); + PROPVARIANT propvar; + + if (SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_FontProperties_ChangedProperties, &propvar))) + m_cf << ATL::CComQIPtr(propvar.punkVal); + break; + + case UI_EXECUTIONVERB_CANCELPREVIEW: + ATLASSERT(ppropvarValue); + ATL::CComPtr pStore; + + if (SUCCEEDED(hr = UIPropertyToInterface(UI_PKEY_FontProperties, *ppropvarValue, &pStore))) + m_cf << pStore; + break; + } + + if (SUCCEEDED(hr)) + GetWndRibbon().OnRibbonFontCtrlExecute(GetID(), verb, &m_cf); + else + ATLASSERT(FALSE); + + return hr; + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + if ((k_(key) == k_FontProperties) && (GetWndRibbon().OnRibbonQueryFont(t_ID, m_cf))) + { + ATL::CComQIPtr pStore(ppropvarCurrentValue->punkVal); + m_cf >> pStore; + return SetPropertyVal(key, pStore.p, ppropvarNewValue); + } + else + { + return CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + } + } +}; + +// ColorCtrlImpl +// +template +class ColorCtrlImpl : public CommandCtrlImpl +{ +public: + ColorCtrlImpl() : m_colorType(UI_SWATCHCOLORTYPE_NOCOLOR), m_color(0x800080) /*MAGENTA*/ + { } + + COLORREF m_color; + UINT32 m_colorType; // value in UI_SWATCHCOLORTYPE + Text m_sLabels[6]; // k_MoreColorsLabel to k_ThemeColorsCategoryLabel + ATL::CSimpleArray m_aColors[2]; + ATL::CSimpleArray m_aTooltips[2]; + + // Operations + HRESULT SetColor(COLORREF color, bool bUpdate = false) + { + if (m_colorType != UI_SWATCHCOLORTYPE_RGB) + SetColorType(UI_SWATCHCOLORTYPE_RGB, bUpdate); + m_color = color; + return bUpdate ? SetProperty(UI_PKEY_Color, color) : S_OK; + } + + HRESULT SetColorType(UI_SWATCHCOLORTYPE type, bool bUpdate = false) + { + m_colorType = type; + return bUpdate ? SetProperty(UI_PKEY_ColorType, type) : S_OK; + } + + HRESULT SetColorLabel(REFPROPERTYKEY key, LPCWSTR sLabel, bool bUpdate = false) + { + ATLASSERT((k_(key) >= k_ThemeColorsCategoryLabel) && (k_(key) <= k_MoreColorsLabel)); + m_sLabels[k_(key) - k_ThemeColorsCategoryLabel] = sLabel; + return bUpdate ? SetProperty(key, sLabel) : S_OK; + } + + HRESULT SetColorArray(REFPROPERTYKEY key, COLORREF* pColor, bool bUpdate = false) + { + ATLASSERT((k_(key) == k_ThemeColors) || (k_(key) == k_StandardColors)); + + const INT ic = k_(key) - k_ThemeColors; + m_aColors[ic].RemoveAll(); + while (*pColor != 0x800080) /*MAGENTA*/ + m_aColors[ic].Add(*pColor++); + + if (bUpdate) + { + PROPVARIANT var; + if SUCCEEDED(InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), m_aColors[ic].GetSize(), &var)) + return SetProperty(key, var); + else + return E_INVALIDARG; + } + else + { + return S_OK; + } + } + + HRESULT SetColorTooltips(REFPROPERTYKEY key, LPCWSTR* ppsTT, bool bUpdate = false) + { + ATLASSERT((k_(key) == k_ThemeColorsTooltips) || (k_(key) == k_StandardColorsTooltips)); + + const INT ic = k_(key) - k_ThemeColorsTooltips; + m_aTooltips[ic].RemoveAll(); + while (*ppsTT) + m_aTooltips[ic].Add(*ppsTT++); + + if (bUpdate) + { + PROPVARIANT var; + if SUCCEEDED(InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), m_aTooltips[ic].GetSize(), &var)) + return SetProperty(key, var); + else + return E_INVALIDARG; + } + else + { + return S_OK; + } + } + + // Implementation + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* pCommandExecutionProperties) + { + ATLASSERT (nCmdID == GetID()); + nCmdID; // avoid level 4 warning + ATLASSERT (key && (k_(*key) == k_ColorType)); + key; // avoid level 4 warning + ATLASSERT (ppropvarValue); + + HRESULT hr = PropVariantToUInt32(*ppropvarValue, &m_colorType); + ATLASSERT(SUCCEEDED(hr)); + + if (SUCCEEDED(hr) && (m_colorType == UI_SWATCHCOLORTYPE_RGB)) + { + ATLASSERT(pCommandExecutionProperties); + PROPVARIANT var; + if SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_Color, &var)) + hr = PropVariantToUInt32(var, &m_color); + } + + if SUCCEEDED(hr) + GetWndRibbon().OnRibbonColorCtrlExecute(GetID(), verb, (UI_SWATCHCOLORTYPE)m_colorType/*uType*/, m_color); + else + ATLASSERT(FALSE); // something was wrong + + return hr; + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT (nCmdID == GetID()); + + HRESULT hr = E_NOTIMPL; + + switch (k_(key)) + { + case k_ColorType: + hr = SetPropertyVal(key, m_colorType, ppropvarNewValue); + break; + case k_Color: + if (m_color == 0x800080) /*MAGENTA*/ + m_color = GetWndRibbon().OnRibbonQueryColor(GetID()); + hr = SetPropertyVal(key, m_color, ppropvarNewValue); + break; + case k_ColorMode: + break; + case k_ThemeColorsCategoryLabel: + case k_StandardColorsCategoryLabel: + case k_RecentColorsCategoryLabel: + case k_AutomaticColorLabel: + case k_NoColorLabel: + case k_MoreColorsLabel: + { + const UINT iLabel = k_(key) - k_ThemeColorsCategoryLabel; + if (m_sLabels[iLabel].IsEmpty()) + if (LPCWSTR psLabel = GetWndRibbon().OnRibbonQueryColorLabel(GetID(), key)) + m_sLabels[iLabel] = psLabel; + if (!m_sLabels[iLabel].IsEmpty()) + hr = SetPropertyVal(key, (LPCWSTR)m_sLabels[iLabel], ppropvarNewValue); + } + break; + case k_ThemeColors: + case k_StandardColors: + { + const INT ic = k_(key) - k_ThemeColors; + if (!m_aColors[ic].GetSize()) + if (COLORREF* pColor = GetWndRibbon().OnRibbonQueryColorArray(GetID(), key)) + SetColorArray(key, pColor); + if (INT iMax = m_aColors[ic].GetSize()) + hr = InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), iMax, ppropvarNewValue); + } + break; + case k_ThemeColorsTooltips: + case k_StandardColorsTooltips: + { + const INT ic = k_(key) - k_ThemeColorsTooltips; + if (m_aTooltips[ic].GetSize() == 0) + if (LPCWSTR* ppsTT = GetWndRibbon().OnRibbonQueryColorTooltips(GetID(), key)) + SetColorTooltips(key, ppsTT); + if (INT iMax = m_aTooltips[ic].GetSize()) + hr = InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), iMax, ppropvarNewValue); + } + break; + default: + hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + break; + } + + return hr; + } +}; + +// SpinnerCtrlImpl +// +template +class SpinnerCtrlImpl : public CtrlImpl +{ +public: + SpinnerCtrlImpl() + { + m_Values[0] = m_Values[2] = m_Values[4] = 0; + m_Values[1] = 100; + m_Values[3] = 1; + } + + V m_Values[5]; + // k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces + + Text m_FormatString; + Text m_RepresentativeString; + + // Operations + HRESULT SetDecimalPlaces(V vPlaces, bool bUpdate = false) + { + return SetValue(UI_PKEY_DecimalPlaces, vPlaces, bUpdate); + } + + HRESULT SetMin(V vMin, bool bUpdate = false) + { + return SetValue(UI_PKEY_MinValue, vMin, bUpdate); + } + + HRESULT SetMax(V vMax, bool bUpdate = false) + { + return SetValue(UI_PKEY_MaxValue, vMax, bUpdate); + } + + HRESULT SetVal(V vVal, bool bUpdate = false) + { + return SetValue(UI_PKEY_DecimalValue, vVal, bUpdate); + } + + HRESULT SetIncrement(V vIncrement, bool bUpdate = false) + { + return SetValue(UI_PKEY_Increment, vIncrement, bUpdate); + } + + HRESULT SetFormatString(LPCWSTR sFormat, bool bUpdate = false) + { + return SetText(UI_PKEY_FormatString, sFormat, bUpdate); + } + + HRESULT SetRepresentativeString(LPCWSTR sRepresentative, bool bUpdate = false) + { + return SetText(UI_PKEY_RepresentativeString, sRepresentative, bUpdate); + } + + // Implementation + HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sText, bool bUpdate = false) + { + switch (k_(key)) + { + case k_FormatString: + m_FormatString = sText; + break; + case k_RepresentativeString: + m_RepresentativeString = sText; + break; + default: + return CtrlImpl::SetText(key, sText, bUpdate); + } + + return bUpdate ? + GetWndRibbon().InvalidateProperty(GetID(), key) : + S_OK; + } + + HRESULT SetValue(REFPROPERTYKEY key, V val, bool bUpdate = false) + { + ATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue)); + + const INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue; + m_Values[iVal] = val; + + if (bUpdate) + { + if(k_(key) == k_DecimalValue) + { + DECIMAL decVal; + InitDecimal(val, &decVal); + return SetProperty(key, &decVal); + } + else + { + return GetWndRibbon().InvalidateProperty(GetID(), key); + } + } + else + { + return S_OK; + } + } + + HRESULT QueryValue(REFPROPERTYKEY key, LONG* plVal) + { + return GetWndRibbon().OnRibbonQuerySpinnerValue(GetID(), key, plVal) ? S_OK : S_FALSE; + } + + HRESULT QueryValue(REFPROPERTYKEY key, DOUBLE* pdVal) + { + return GetWndRibbon().OnRibbonQueryFloatSpinnerValue(GetID(), key, pdVal) ? S_OK : S_FALSE; + } + + HRESULT OnGetValue(REFPROPERTYKEY key, PROPVARIANT* ppv) + { + ATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue)); + + const INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue; + + QueryValue(key, m_Values + iVal); + + if (k_(key) == k_DecimalPlaces) + { + return SetPropertyVal(key, m_Values[iVal], ppv); + } + else + { + DECIMAL decVal; + InitDecimal(m_Values[iVal], &decVal); + return SetPropertyVal(key, &decVal, ppv); + } + } + + HRESULT OnGetText(REFPROPERTYKEY key, Text& sVal, PROPVARIANT* ppv) + { + if (LPCWSTR sNew = GetWndRibbon().OnRibbonQueryText(GetID(), key)) + sVal = sNew; + return SetPropertyVal(key, (LPCWSTR)sVal, ppv); + } + + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* /*pCommandExecutionProperties*/) + { + ATLASSERT (nCmdID == GetID()); + nCmdID; // avoid level 4 warning + ATLASSERT (key && (k_(*key) == k_DecimalValue)); + key; // avoid level 4 warning + ATLASSERT (verb == UI_EXECUTIONVERB_EXECUTE); + verb; // avoid level 4 warning + + DECIMAL decVal; + + HRESULT hr = UIPropertyToDecimal(UI_PKEY_DecimalValue, *ppropvarValue, &decVal); + hr = InitVal(m_Values[0], &decVal); + + GetWndRibbon().OnRibbonSpinnerCtrlExecute(GetID(), &m_Values[0]); + + return hr; + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + ATLASSERT (nCmdID == GetID()); + + HRESULT hr = E_NOTIMPL; + switch (k_(key)) + { + case k_DecimalPlaces: + case k_DecimalValue: + case k_Increment: + case k_MaxValue: + case k_MinValue: + hr = OnGetValue(key, ppropvarNewValue); + break; + case k_FormatString: + if (m_FormatString.IsEmpty()) + return OnGetText(key, m_FormatString, ppropvarNewValue); + break; + case k_RepresentativeString: + if (m_RepresentativeString.IsEmpty()) + return OnGetText(key, m_RepresentativeString, ppropvarNewValue); + break; + default: + hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + break; + } + + return hr; + } + + // decimal conversion helpers + static HRESULT InitDecimal(LONG& val, DECIMAL* pDecimal) + { + return ::VarDecFromI4(val, pDecimal); + } + + static HRESULT InitDecimal(DOUBLE& val, DECIMAL* pDecimal) + { + return ::VarDecFromR8(val, pDecimal); + } + + static HRESULT InitVal(LONG& val, const DECIMAL* pDecimal) + { + return ::VarI4FromDec(pDecimal, &val); + } + + static HRESULT InitVal(DOUBLE& val, const DECIMAL* pDecimal) + { + return ::VarR8FromDec(pDecimal, &val); + } +}; + +// CRibbonImpl Ribbon implementation class +// +template +class CRibbonImpl : + public CRibbonUpdateUI, + public ICtrl, + public IUIApplication, + public IUICommandHandler +{ + typedef CRibbonImpl thisClass; +public: + typedef thisClass Ribbon; + typedef T WndRibbon; + + CRibbonImpl() : m_bRibbonUI(false), m_hgRibbonSettings(NULL) + { +#ifdef _DEBUG + m_cRef = 1; +#endif + pWndRibbon = static_cast(this); + HRESULT hr = ::CoInitialize(NULL); + if(SUCCEEDED(hr)) + if (RunTimeHelper::IsRibbonUIAvailable()) + hr = m_pIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework); + else + ATLTRACE2(atlTraceUI, 0, _T("Ribbon UI not available\n")); + + if FAILED(hr) + ATLTRACE2(atlTraceUI, 0, _T("Ribbon construction failed\n")); + + ATLASSERT(SUCCEEDED(hr)); + } + + ~CRibbonImpl() + { + ::GlobalFree(m_hgRibbonSettings); + m_pIUIFramework.Release(); + ::CoUninitialize(); + } + + ICtrl& GetRibbonCtrl(UINT) + { + return static_cast(*this); + } + + ATL::CComPtr m_pIUIFramework; + HGLOBAL m_hgRibbonSettings; + bool m_bRibbonUI; + + bool IsRibbonUI() + { + return m_bRibbonUI; + } + + IUIFramework* GetIUIFrameworkPtr() + { + return m_pIUIFramework; + } + + template + I* GetRibbonViewPtr(UINT32 uID) + { + ATLASSERT(m_pIUIFramework); + ATL::CComPtr pI; + return m_pIUIFramework->GetView(uID, __uuidof(I), (void**) &pI) == S_OK ? + pI : + NULL; + } + + IUIRibbon* GetRibbonPtr() + { + return GetRibbonViewPtr(0); + } + + IUIContextualUI* GetMenuPtr(UINT32 uID) + { + ATLASSERT(uID); + return GetRibbonViewPtr(uID); + } + + UINT GetRibbonHeight() + { + ATLASSERT(IsRibbonUI()); + + UINT32 cy = 0; + if (ATL::CComPtr pIUIRibbon = GetRibbonPtr()) + pIUIRibbon->GetHeight(&cy); + return cy; + } + + HRESULT CreateRibbon(LPCWSTR sResName = L"APPLICATION_RIBBON") + { + T* pT = static_cast(this); + ATLASSERT(GetIUIFrameworkPtr() && !IsRibbonUI()); + ATLASSERT(pT->IsWindow()); + + HRESULT hr = m_pIUIFramework->Initialize(pT->m_hWnd, this); + + if (hr == S_OK) + hr = m_pIUIFramework->LoadUI(ModuleHelper::GetResourceInstance(), sResName); + + return hr; + } + + HRESULT DestroyRibbon() + { + T* pT = static_cast(this); + ATLASSERT(GetIUIFrameworkPtr() && IsRibbonUI()); + ATLASSERT(pT->IsWindow()); + + HRESULT hRes = m_pIUIFramework->Destroy(); + if (!RunTimeHelper::IsWin7()) + pT->SetWindowRgn(NULL, TRUE); // Vista Basic bug workaround + return hRes; + } + +// Ribbon persistency + HRESULT operator >>(IStream* pIStream) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(pIStream); + + HRESULT hr = E_FAIL; + if (ATL::CComPtr pIUIRibbon = GetRibbonPtr()) + { + const LARGE_INTEGER li0 = { 0 }; + pIStream->Seek(li0, STREAM_SEEK_SET, NULL); + hr = pIUIRibbon->SaveSettingsToStream(pIStream); + pIStream->Commit(STGC_DEFAULT); + } + + return hr; + } + + HRESULT operator <<(IStream* pIStream) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(pIStream); + + HRESULT hr = E_FAIL; + if (ATL::CComPtr pIUIRibbon = GetRibbonPtr()) + { + const LARGE_INTEGER li0 = { 0 }; + pIStream->Seek(li0, STREAM_SEEK_SET, NULL); + hr = pIUIRibbon->LoadSettingsFromStream(pIStream); + } + + return hr; + } + + void ResetRibbonSettings() + { + if (m_hgRibbonSettings != NULL) + { + ::GlobalFree(m_hgRibbonSettings); + m_hgRibbonSettings = NULL; + } + } + + HRESULT SaveRibbonSettings() + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(static_cast(this)->IsWindow()); + + HRESULT hr = E_FAIL; + ATL::CComPtr pIStream; + + if SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream)) + hr = *this >> pIStream; + + if (SUCCEEDED(hr) && (m_hgRibbonSettings == NULL)) + hr = ::GetHGlobalFromStream(pIStream, &m_hgRibbonSettings); + + if FAILED(hr) + ResetRibbonSettings(); + + return hr; + } + + HRESULT RestoreRibbonSettings() + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(m_hgRibbonSettings); + ATLASSERT(static_cast(this)->IsWindow()); + + HRESULT hr = E_FAIL; + ATL::CComPtr pIStream; + + if SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream)) + hr = *this << pIStream; + + if FAILED(hr) + ResetRibbonSettings(); + + return hr; + } + +// QAT dock states + UI_CONTROLDOCK GetQATDock() + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(IsRibbonUI()); + + UINT32 uDock = 0; + PROPVARIANT propvar; + ATL::CComQIPtrpIPS(GetRibbonPtr()); + + if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(UI_PKEY_QuickAccessToolbarDock, &propvar)) && + SUCCEEDED(UIPropertyToUInt32(UI_PKEY_QuickAccessToolbarDock, propvar, &uDock))) + return (UI_CONTROLDOCK)uDock; + + ATLASSERT(FALSE); // something was wrong + return (UI_CONTROLDOCK)0; + } + + bool SetQATDock(UI_CONTROLDOCK dockState) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(IsRibbonUI()); + + PROPVARIANT propvar; + ATLVERIFY(SUCCEEDED(SetPropertyVal(UI_PKEY_QuickAccessToolbarDock, dockState, &propvar))); + + ATL::CComQIPtrpIPS(GetRibbonPtr()); + if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(UI_PKEY_QuickAccessToolbarDock, propvar))) + { + pIPS->Commit(); + return true; + } + + ATLASSERT(FALSE); // something was wrong + return false; + } + +// Ribbon display states + bool GetRibbonDisplayState(REFPROPERTYKEY key) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(IsRibbonUI()); + ATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized)); + + PROPVARIANT propvar; + ATL::CComQIPtrpIPS(GetRibbonPtr()); + + if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar))) + { + BOOL bState = FALSE; + if SUCCEEDED(UIPropertyToBoolean(key, propvar, &bState)) + return (bState != FALSE); + } + + ATLASSERT(FALSE); // something was wrong + return false; + } + + bool SetRibbonDisplayState(REFPROPERTYKEY key, bool bState = true) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(IsRibbonUI()); + ATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized)); + + PROPVARIANT propvar; + ATLVERIFY(SUCCEEDED(SetPropertyVal(key, bState, &propvar))); + + ATL::CComQIPtrpIPS(GetRibbonPtr()); + + if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar))) + { + pIPS->Commit(); + return true; + } + + ATLASSERT(FALSE); // something was wrong + return false; + } + + bool IsRibbonMinimized() + { + return GetRibbonDisplayState(UI_PKEY_Minimized); + } + + bool MinimizeRibbon(bool bMinimize = true) + { + return SetRibbonDisplayState(UI_PKEY_Minimized, bMinimize); + } + + bool IsRibbonHidden() + { + return !GetRibbonDisplayState(UI_PKEY_Viewable); + } + + bool HideRibbon(bool bHide = true) + { + return SetRibbonDisplayState(UI_PKEY_Viewable, !bHide); + } + +// Ribbon colors + UI_HSBCOLOR GetRibbonColor(REFPROPERTYKEY key) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(IsRibbonUI()); + ATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor)); + + PROPVARIANT propvar; + ATL::CComQIPtrpIPS(GetIUIFrameworkPtr()); + + if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar))) + { + UINT32 color = 0; + if SUCCEEDED(UIPropertyToUInt32(key, propvar, &color)) + return color; + } + + ATLASSERT(FALSE); // something was wrong + return 0; + } + + bool SetRibbonColor(REFPROPERTYKEY key, UI_HSBCOLOR color) + { + ATLASSERT(GetIUIFrameworkPtr()); + ATLASSERT(IsRibbonUI()); + ATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor)); + + PROPVARIANT propvar; + ATLVERIFY(SUCCEEDED(SetPropertyVal(key, color, &propvar))); + + ATL::CComQIPtrpIPS(GetIUIFrameworkPtr()); + + if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar))) + { + pIPS->Commit(); + return true; + } + + ATLASSERT(FALSE); // something was wrong + return false; + } + +// Ribbon modes + HRESULT SetRibbonModes(INT32 iModes) + { + ATLASSERT(IsRibbonUI()); + return GetIUIFrameworkPtr()->SetModes(iModes); + } + +// Ribbon contextual tab + UI_CONTEXTAVAILABILITY GetRibbonContextAvail(UINT32 uID) + { + ATLASSERT(GetIUIFrameworkPtr()); + + PROPVARIANT propvar; + if (IsRibbonUI() && + SUCCEEDED(GetIUIFrameworkPtr()->GetUICommandProperty(uID, UI_PKEY_ContextAvailable, &propvar))) + { + UINT uav; + if (SUCCEEDED(PropVariantToUInt32(propvar, &uav))) + { + CUpdateUIBase::UIEnable(uID, uav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE); + CUpdateUIBase::UISetCheck(uID, uav == UI_CONTEXTAVAILABILITY_ACTIVE); + return (UI_CONTEXTAVAILABILITY)uav; + } + } + + return UI_CONTEXTAVAILABILITY_NOTAVAILABLE; + } + + HRESULT SetRibbonContextAvail(UINT32 uID, UI_CONTEXTAVAILABILITY cav) + { + CUpdateUIBase::UIEnable(uID, cav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE); + CUpdateUIBase::UISetCheck(uID, cav == UI_CONTEXTAVAILABILITY_ACTIVE); + + return SetProperty((WORD)uID, UI_PKEY_ContextAvailable, UINT32(cav)); + } + +// Ribbon context menu + bool HasRibbonMenu(UINT32 uID) + { + ATL::CComPtr pI = GetMenuPtr(uID); + return pI != NULL; + } + + HRESULT TrackRibbonMenu(UINT32 uID, INT32 x, INT32 y) + { + ATLASSERT(HasRibbonMenu(uID)); + + return IsRibbonUI() ? + ATL::CComPtr(GetMenuPtr(uID))->ShowAtLocation(x, y) : + E_FAIL; + } + + HRESULT TrackRibbonMenu(UINT32 uID, LPARAM lParam) + { + return TrackRibbonMenu(uID, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + } + +// Overrideables + HBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY /*key*/) + { + return DefRibbonQueryImage(nCmdID); + } + + LPCWSTR OnRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key) + { + return DefRibbonQueryText(nCmdID, key); + } + + bool OnRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key) + { + return DefRibbonQueryState(nCmdID, key); + } + + UI_CONTEXTAVAILABILITY OnRibbonQueryTabAvail(UINT nCmdID) + { + DWORD dwState = UIGetState(nCmdID); + return ((dwState & UPDUI_DISABLED) == UPDUI_DISABLED) ? + UI_CONTEXTAVAILABILITY_NOTAVAILABLE : + (((dwState & UPDUI_CHECKED) == UPDUI_CHECKED) ? + UI_CONTEXTAVAILABILITY_ACTIVE : + UI_CONTEXTAVAILABILITY_AVAILABLE); + } + + LPCWSTR OnRibbonQueryComboText(UINT32 /*uCtrlID*/) + { + return NULL; + } + + LPCWSTR OnRibbonQueryCategoryText(UINT32 /*uCtrlID*/, UINT32 /*uCat*/) + { + return L"Category"; + } + + UINT32 OnRibbonQueryItemCategory(UINT32 /*uCtrlID*/, UINT32 /*uItem*/) + { + return 0; + } + + LPCWSTR OnRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem) + { + return DefRibbonQueryItemText(uCtrlID, uItem); + } + + bool OnRibbonQuerySelectedItem(UINT32 /*uCtrlID*/, UINT32& /*uSel*/) + { + return false; + } + + HBITMAP OnRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem) + { + return DefRibbonQueryItemImage(uCtrlID, uItem); + } + + UINT32 OnRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem) + { + return DefRibbonQueryItemCommand(uCtrlID, uItem); + } + + UI_COMMANDTYPE OnRibbonQueryItemCommandType(UINT32 /*uCtrlID*/, UINT32 /*uItem*/) + { + return UI_COMMANDTYPE_ACTION; + } + + LPCWSTR OnRibbonQueryRecentItemName(LPCWSTR sPath) + { + return ::PathFindFileName(sPath); + } + + bool OnRibbonQueryFont(UINT /*nId*/, CHARFORMAT2& /*cf*/) + { + return false; + } + + bool OnRibbonQuerySpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, LONG* /*pVal*/) + { + return false; + } + + bool OnRibbonQueryFloatSpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, DOUBLE* /*pVal*/) + { + return false; + } + + COLORREF OnRibbonQueryColor(UINT /*nCmdID*/) + { + return 0x800080; /*MAGENTA*/ + } + + LPCWSTR OnRibbonQueryColorLabel(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/) + { + return NULL; + } + + COLORREF* OnRibbonQueryColorArray(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/) + { + return NULL; + } + + LPCWSTR* OnRibbonQueryColorTooltips(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/) + { + return NULL; + } + + bool OnRibbonItemSelected(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UINT32 uItem) + { + DefCommandExecute(MAKELONG(uCtrlID, verb), uItem); + return true; + } + + void OnRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color) + { + DefRibbonColorCtrlExecute(uCtrlID, verb, uType, color); + } + + void OnRibbonFontCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, CHARFORMAT2* pcf) + { + DefCommandExecute(MAKELONG(uCtrlID, verb), (LPARAM)pcf); + } + + void OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, LONG* pVal) + { + DefCommandExecute(uCtrlID, *pVal); + } + + void OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, DOUBLE* pVal) + { + DefCommandExecute(uCtrlID, (LPARAM)pVal); + } + + void OnRibbonCommandExecute(UINT32 uCmdID) + { + DefCommandExecute(uCmdID); + } + +// Default implementations + HBITMAP DefRibbonQueryImage(UINT nCmdID) + { + return AtlLoadBitmapImage(nCmdID, LR_CREATEDIBSECTION); + } + + bool DefRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key) + { + DWORD dwState = UIGetState(nCmdID); + bool bRet = false; + switch (k_(key)) + { + case k_BooleanValue: + bRet = (dwState & UPDUI_CHECKED) == UPDUI_CHECKED; + break; + case k_Enabled: + bRet = (dwState & UPDUI_DISABLED) != UPDUI_DISABLED; + break; + default: + ATLASSERT(FALSE); + break; + } + + return bRet; + } + + LPCTSTR DefRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key) + { + static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 }; + + if (k_(key) == k_Label) + return UIGetText(nCmdID); + + if (AtlLoadString(nCmdID, sText, RIBBONUI_MAX_TEXT)) + { + PWCHAR pTitle = wcschr(sText, L'\n'); + switch (k_(key)) + { + case k_Keytip: + if (PWCHAR pAmp = wcschr(sText, L'&')) + pTitle = pAmp; + if (pTitle != NULL) + *(pTitle + 2) = NULL; // fall through + case k_TooltipTitle: + return pTitle ? ++pTitle : NULL; + case k_TooltipDescription: + case k_LabelDescription: + if (pTitle != NULL) + *pTitle = NULL; + return sText; + } + } + + return NULL; + } + + LPCWSTR DefRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem) + { + return DefRibbonQueryText(uCtrlID + 1 + uItem, UI_PKEY_LabelDescription); + } + + HBITMAP DefRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem) + { + return DefRibbonQueryImage(uCtrlID + 1 + uItem); + } + + UINT32 DefRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem) + { + return uCtrlID + 1 + uItem; + } + + void DefRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color) + { + switch(uType) + { + case UI_SWATCHCOLORTYPE_RGB: + break; + case UI_SWATCHCOLORTYPE_AUTOMATIC: + color = ::GetSysColor(COLOR_WINDOWTEXT); + break; + case UI_SWATCHCOLORTYPE_NOCOLOR: + color = ::GetSysColor(COLOR_WINDOW); + break; + default: + ATLASSERT(FALSE); + break; + } + + DefCommandExecute(MAKELONG(uCtrlID, verb), color); + } + + void DefCommandExecute(UINT32 uCmd, LPARAM lParam = 0) + { + static_cast(this)->PostMessage(WM_COMMAND, uCmd, lParam); + } + +// Elements setting helpers + HRESULT InvalidateCtrl(UINT32 nID) + { + return IsRibbonUI() ? + GetIUIFrameworkPtr()->InvalidateUICommand(nID, UI_INVALIDATIONS_ALLPROPERTIES, NULL) : + E_FAIL; + } + + HRESULT InvalidateProperty(UINT32 nID, REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY) + { + return IsRibbonUI() ? + GetIUIFrameworkPtr()->InvalidateUICommand(nID, flags, &key) : + E_FAIL; + } + + template + HRESULT SetProperty(WORD wID, REFPROPERTYKEY key, V val) + { + if (IsRibbonUI()) + { + PROPVARIANT var; + if (SUCCEEDED(RibbonUI::SetPropertyVal(key, val, &var))) + { + return SetProperty(wID, key, var); + } + return E_INVALIDARG; + } + else + { + return E_FAIL; + } + } + + template <> + HRESULT SetProperty(WORD nID, REFPROPERTYKEY key, PROPVARIANT var) + { + return IsRibbonUI() ? + GetIUIFrameworkPtr()->SetUICommandProperty(nID, key, var) : + E_FAIL; + } + +// Interfaces + // IUIApplication + STDMETHODIMP OnViewChanged(UINT32, UI_VIEWTYPE, IUnknown*, UI_VIEWVERB verb, INT32) + { + switch (verb) + { + case UI_VIEWVERB_CREATE: + m_bRibbonUI = true; + if (m_hgRibbonSettings != NULL) + RestoreRibbonSettings(); + break; + case UI_VIEWVERB_SIZE: + static_cast(this)->UpdateLayout(FALSE); + break; + case UI_VIEWVERB_DESTROY: + SaveRibbonSettings(); + m_bRibbonUI = false; + break; + } + + return S_OK; + } + + STDMETHODIMP OnCreateUICommand(UINT32 nCmdID, UI_COMMANDTYPE typeID, IUICommandHandler** ppCommandHandler) + { + UIAddRibbonElement(nCmdID); + if (typeID == UI_COMMANDTYPE_CONTEXT) + CUpdateUIBase::UIEnable(nCmdID, false); + *ppCommandHandler = this; + return S_OK; + } + + STDMETHODIMP OnDestroyUICommand(UINT32 nCmdID, UI_COMMANDTYPE, IUICommandHandler*) + { + UIRemoveRibbonElement(nCmdID); + return S_OK; + } + + // IUICommandHandler + STDMETHODIMP Execute(UINT nCmdID, + UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, + const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* pCommandExecutionProperties) + { + T* pT =static_cast(this); + return pT->GetRibbonCtrl(nCmdID).DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties); + } + + STDMETHODIMP UpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) + { + T* pT =static_cast(this); + return pT->GetRibbonCtrl(nCmdID).DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); + } + +#ifdef _DEBUG + // IUnknown methods (heavyweight) + STDMETHODIMP_(ULONG) AddRef() + { + return InterlockedIncrement(&m_cRef); + } + + STDMETHODIMP_(ULONG) Release() + { + LONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) // NoOp for breakpoint + { + cRef = 0; + } + + return cRef; + } + + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) + { + if (ppv == NULL) + { + return E_POINTER; + } + else if ((iid == __uuidof(IUnknown)) || + (iid == __uuidof(IUICommandHandler)) || + (iid == __uuidof(IUIApplication))) + { + *ppv = this; + AddRef(); + return S_OK; + } + else + { + return E_NOINTERFACE; + } + } + + LONG m_cRef; +#else + // IUnknown methods (lightweight) + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) + { + if ((iid == __uuidof(IUnknown)) || + (iid == __uuidof(IUICommandHandler)) || + (iid == __uuidof(IUIApplication))) + { + *ppv = this; + return S_OK; + } + return E_NOINTERFACE; + } + ULONG STDMETHODCALLTYPE AddRef() + { + return 1; + } + ULONG STDMETHODCALLTYPE Release() + { + return 1; + } +#endif + +// CRibbonImpl ICtrl implementation + virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, + const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, + IUISimplePropertySet* /*pCommandExecutionProperties*/) + { + if (key != NULL) + { + if(k_(*key) != k_BooleanValue) + { + ATLTRACE2(atlTraceUI, 0, _T("Control ID %d is not handled\n"), nCmdID); + return E_NOTIMPL; + } + BOOL bChecked = FALSE; + ATLVERIFY(SUCCEEDED(PropVariantToBoolean(*ppropvarValue, &bChecked))); + CUpdateUIBase::UISetCheck(nCmdID, bChecked); + } + + ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE); + verb; // avoid level 4 warning + + static_cast(this)->OnRibbonCommandExecute(nCmdID); + + return S_OK; + } + + virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, + const PROPVARIANT* /*ppropvarCurrentValue*/, PROPVARIANT* ppropvarNewValue) + { + T* pT = static_cast(this); + HRESULT hr = E_NOTIMPL; + switch (k_(key)) + { + case k_LargeImage: + case k_LargeHighContrastImage: + case k_SmallImage: + case k_SmallHighContrastImage: + if (HBITMAP hbm = pT->OnRibbonQueryImage(nCmdID, key)) + hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), ppropvarNewValue); + break; + case k_Label: + case k_Keytip: + case k_TooltipTitle: + case k_TooltipDescription: + case k_LabelDescription: + if (LPCWSTR sText = pT->OnRibbonQueryText(nCmdID, key)) + hr = SetPropertyVal(key, sText, ppropvarNewValue); + break; + case k_BooleanValue: + case k_Enabled: + hr = SetPropertyVal(key, pT->OnRibbonQueryState(nCmdID, key), ppropvarNewValue); + break; + case k_ContextAvailable: + hr = SetPropertyVal(key, pT->OnRibbonQueryTabAvail(nCmdID), ppropvarNewValue); + break; + } + + return hr; + } + +// CRibbonImpl::CRibbonXXXCtrl specialized classes + //CRibbonComboCtrl + template + class CRibbonComboCtrl : public CollectionCtrlImpl, t_items, t_categories>> + { + public: + CRibbonComboCtrl() + { } + }; + + // CRibbonItemGalleryCtrl + template + class CRibbonItemGalleryCtrl : public CollectionCtrlImpl, t_items, t_categories>> + { + public: + CRibbonItemGalleryCtrl() + { } + }; + + // CRibbonCommandGalleryCtrl + template + class CRibbonCommandGalleryCtrl : public CollectionCtrlImpl, t_items, t_categories>> + { + public: + CRibbonCommandGalleryCtrl() + { } + }; + + // CRibbonToolbarGalleryCtrl + template + class CRibbonToolbarGalleryCtrl : public ToolbarGalleryCtrlImpl + { }; + + // CRibbonSimpleComboCtrl + template + class CRibbonSimpleComboCtrl : public SimpleCollectionCtrlImpl + { }; + + // CRibbonSimpleGalleryCtrl + template + class CRibbonSimpleGalleryCtrl : public SimpleCollectionCtrlImpl + { }; + + //CRibbonRecentItemsCtrl + template + class CRibbonRecentItemsCtrl : public RecentItemsCtrlImpl + { + public: + CRibbonRecentItemsCtrl() + { } + }; + + // CRibbonColorCtrl + template + class CRibbonColorCtrl : public ColorCtrlImpl + { + public: + CRibbonColorCtrl() + { } + }; + + //CRibbonFontCtrl + template + class CRibbonFontCtrl : public FontCtrlImpl + { + public: + CRibbonFontCtrl() + { } + }; + + // CRibbonSpinnerCtrl + template + class CRibbonSpinnerCtrl : public SpinnerCtrlImpl + { + public: + CRibbonSpinnerCtrl() + { } + }; + + // CRibbonFloatSpinnerCtrl + template + class CRibbonFloatSpinnerCtrl : public SpinnerCtrlImpl + { + public: + CRibbonFloatSpinnerCtrl() + { + m_Values[4] = 1; // 1 decimal + } + }; + + // CRibbonCommandCtrl + template + class CRibbonCommandCtrl : public CommandCtrlImpl + { + public: + CRibbonCommandCtrl() + { } + }; + +// Control classes access to T instance (re-initialized in constructor) + static T* pWndRibbon; +}; + +template +__declspec(selectany) T* CRibbonImpl::pWndRibbon; + +// Control map element +#pragma warning(push) +#pragma warning(disable: 4510 610 4512) // missing default constructor, can't be instatiated, assignment operator could not be generated +typedef struct +{ + UINT uID; + ICtrl& ctrl; +} _ribbonCtrl; +#pragma warning(pop) + +}; // namespace RibbonUI + + +/////////////////////////////////////////////////////////////////////////////// +// RibbonUI Control map + +// Control map macros +#define BEGIN_RIBBON_CONTROL_MAP(theClass) \ + WTL::RibbonUI::ICtrl& GetRibbonCtrl(UINT id) \ + { \ + WTL::RibbonUI::_ribbonCtrl _ctrls[] = \ + { + +#define RIBBON_CONTROL(member) {member.GetID(), static_cast(member)}, + +#define END_RIBBON_CONTROL_MAP() \ + {0, *this} \ + }; \ + int i = 0; \ + for(; i < _countof(_ctrls) - 1; i++) \ + if (_ctrls[i].uID == id) \ + break; \ + return _ctrls[i].ctrl; \ +} + +// Control message map macros +#define RIBBON_GALLERY_CONTROL_HANDLER(id, func) \ + if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (UINT)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define RIBBON_COMBO_CONTROL_HANDLER(id, func) \ + RIBBON_GALLERY_CONTROL_HANDLER(id, func) + +#define RIBBON_FONT_CONTROL_HANDLER(id, func) \ + if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (CHARFORMAT2*)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define RIBBON_COLOR_CONTROL_HANDLER(id, func) \ + if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (COLORREF)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define RIBBON_SPINNER_CONTROL_HANDLER(id, func) \ + if(uMsg == WM_COMMAND && id == wParam) \ + { \ + bHandled = TRUE; \ + lResult = func((WORD)wParam, (LONG)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define RIBBON_FLOATSPINNER_CONTROL_HANDLER(id, func) \ + if(uMsg == WM_COMMAND && id == wParam) \ + { \ + bHandled = TRUE; \ + lResult = func((WORD)wParam, (DOUBLE*)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +// Handler prototypes +/* + LRESULT OnRibbonGalleryCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled); + LRESULT OnRibbonComboCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled); + LRESULT OnRibbonFontCtrl(UI_EXECUTIONVERB verb, WORD wID, CHARFORMAT2* pcf, BOOL& bHandled); + LRESULT OnRibbonColorCtrl(UI_EXECUTIONVERB verb, WORD wID, COLORREF color, BOOL& bHandled); + LRESULT OnRibbonSpinnerCtrl(WORD wID, LONG lVal, BOOL& bHandled); + LRESULT OnRibbonFloatSpinnerCtrl(WORD wID, DOUBLE* pdVal, BOOL& bHandled); +*/ + + +/////////////////////////////////////////////////////////////////////////////// +// Ribbon frame classes + +// CRibbonFrameWindowImplBase +// +template +class ATL_NO_VTABLE CRibbonFrameWindowImplBase : public TFrameImpl, public RibbonUI::CRibbonImpl +{ + typedef TFrameImpl baseFrame; + bool m_bUseCommandBarBitmaps; + bool m_bWin7Fix; + +public: +// Construction + CRibbonFrameWindowImplBase(bool bUseCommandBarBitmaps = true) : + m_bUseCommandBarBitmaps(bUseCommandBarBitmaps), m_bWin7Fix(false) + { + __if_not_exists(T::m_CmdBar) + { + m_bUseCommandBarBitmaps = false; + } + } + +// Win7 Aero fix helpers + void ResetFrame() + { + const MARGINS margins = { 0 }; + ::DwmExtendFrameIntoClientArea(m_hWnd, &margins); + } + + INT CalcWin7Fix() + { + ResetFrame(); + RECT rc = { 0 }; + ::AdjustWindowRectEx(&rc, T::GetWndStyle(0), GetMenu() != NULL, T::GetWndExStyle(0)); + return -rc.top; + } + + bool NeedWin7Fix() + { + BOOL bComp = FALSE; + return m_bWin7Fix && RunTimeHelper::IsWin7() && SUCCEEDED(DwmIsCompositionEnabled(&bComp)) && bComp; + } + +// Operations + bool UseCommandBarBitmaps(bool bUse) + { + __if_exists(T::m_CmdBar) + { + return m_bUseCommandBarBitmaps = bUse; + } + __if_not_exists(T::m_CmdBar) + { + bUse; // avoid level 4 warning + return false; + } + } + + bool ShowRibbonUI(bool bShow, INT32 imodes = UI_MAKEAPPMODE(0), LPCWSTR sResName = L"APPLICATION_RIBBON") + { + if (!RunTimeHelper::IsRibbonUIAvailable()) + return false; + + ATLASSERT(GetIUIFrameworkPtr()); + + if (IsRibbonUI() == bShow) + return bShow; + + bool bVisible = (IsWindowVisible() != FALSE); + if(bVisible && !bShow) + SetRedraw(FALSE); + + if (bShow && ::IsWindow(m_hWndToolBar)) + { + ::ShowWindow(m_hWndToolBar, SW_HIDE); + UpdateLayout(); + } + + m_bWin7Fix = !bShow; + + HRESULT hr = bShow ? CreateRibbon(sResName) : DestroyRibbon(); + + m_bWin7Fix = SUCCEEDED(hr) && !bShow; + + if (SUCCEEDED(hr)) + { + if(::IsWindow(m_hWndToolBar) && !bShow) + { + ::ShowWindow(m_hWndToolBar, SW_SHOWNA); + UpdateLayout(); + } + else if (bShow) + { + PostMessage(WM_SIZE); + SetRibbonModes(imodes); + } + } + + if(bVisible && !bShow) + { + SetRedraw(TRUE); + RedrawWindow(NULL, NULL, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + } + + return SUCCEEDED(hr) ? bShow : !bShow; + } + +// Overrideables + HBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY key) + { + if ((key == UI_PKEY_SmallImage) && m_bUseCommandBarBitmaps) + { + if (HBITMAP hbm = GetCommandBarBitmap(nCmdID)) + return (HBITMAP)::CopyImage(hbm, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); + } + + return DefRibbonQueryImage(nCmdID); + } + + BEGIN_MSG_MAP(CRibbonFrameWindowImplBase) + if (!IsRibbonUI() && NeedWin7Fix()) + { + MESSAGE_HANDLER(WM_SIZING, OnSizing) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) + MESSAGE_HANDLER(WM_NCCALCSIZE, OnNCCalcSize) + } + CHAIN_MSG_MAP(CRibbonUpdateUI) + CHAIN_MSG_MAP(baseFrame) + END_MSG_MAP() + +// Message handlers for Win7 Aero + LRESULT OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + switch (wParam) + { + case WMSZ_TOP: + case WMSZ_TOPLEFT: + case WMSZ_TOPRIGHT: + SetWindowPos(NULL, (LPRECT)lParam, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); + break; + default: + DefWindowProc(); + break; + } + + return 1; // handled + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if (wParam != SIZE_MINIMIZED) + SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + + bHandled = FALSE; + return 1; + } + + LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam != WA_INACTIVE) + SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + + bHandled = FALSE; + return 1; + } + + LRESULT OnNCCalcSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + ATLASSERT(!IsRibbonUI() && NeedWin7Fix()); + + LRESULT lRet = DefWindowProc(); + + if(wParam) + { + LPNCCALCSIZE_PARAMS pParams = (LPNCCALCSIZE_PARAMS)lParam; + pParams->rgrc[0].top = pParams->rgrc[1].top + CalcWin7Fix(); + } + + return lRet; + } + +// Overrides + void UpdateLayout(BOOL bResizeBars = TRUE) + { + RECT rect = { 0 }; + GetClientRect(&rect); + + if (IsRibbonUI() && !IsRibbonHidden()) + { + rect.top += GetRibbonHeight(); + } + else if (!IsRibbonUI() && NeedWin7Fix()) + { + ResetFrame(); + } + + // position bars and offset their dimensions + UpdateBarsPosition(rect, bResizeBars); + + // resize client window + if(m_hWndClient != NULL) + ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOZORDER | SWP_NOACTIVATE); + } + + // Implementation + HBITMAP GetCommandBarBitmap(UINT nCmdID) + { + __if_exists (T::m_CmdBar) + { + ATLASSERT(RunTimeHelper::IsVista()); + T* pT =static_cast(this); + int nIndex = pT->m_CmdBar.m_arrCommand.Find((WORD&)nCmdID); + return (nIndex == -1) ? NULL : pT->m_CmdBar.m_arrVistaBitmap[nIndex]; + } + __if_not_exists (T::m_CmdBar) + { + nCmdID; // avoid level 4 warning + return NULL; + } + } +}; + +// CRibbonFrameWindowImpl +// +template +class ATL_NO_VTABLE CRibbonFrameWindowImpl : public CRibbonFrameWindowImplBase> +{ }; + +// CRibbonMDIFrameWindowImpl +// +template +class ATL_NO_VTABLE CRibbonMDIFrameWindowImpl : public CRibbonFrameWindowImplBase> +{ }; + + +/////////////////////////////////////////////////////////////////////////////// +// CRibbonPersist helper for RibbonUI persistency + +class CRibbonPersist +{ +public: + CRibbonPersist(LPCWSTR sAppKey) + { + ATLASSERT(sAppKey && *sAppKey); + m_Key.Create(HKEY_CURRENT_USER, sAppKey); + ATLASSERT(m_Key.m_hKey); + } + + CRegKeyEx m_Key; + + LONG Save(bool bRibbonUI, HGLOBAL hgSettings = NULL) + { + CRegKeyEx key; + const DWORD dwUI = bRibbonUI; + + LONG lRet = key.Create(m_Key, L"Ribbon"); + if(lRet != ERROR_SUCCESS) + return lRet; + + lRet = key.SetDWORDValue(L"UI", dwUI); + if(lRet != ERROR_SUCCESS) + return lRet; + + if (hgSettings != NULL) + { + LPBYTE pVal = (LPBYTE)::GlobalLock(hgSettings); + if (pVal != NULL) + { + lRet = key.SetBinaryValue(L"Settings", pVal, (ULONG)::GlobalSize(hgSettings)); + ::GlobalUnlock(hgSettings); + } + else + { + lRet = GetLastError(); + } + } + + return lRet; + } + + LONG Restore(bool& bRibbonUI, HGLOBAL& hgSettings) + { + ATLASSERT(hgSettings == NULL); + + CRegKeyEx key; + + LONG lRet = key.Open(m_Key, L"Ribbon"); + if(lRet != ERROR_SUCCESS) + return lRet; + + DWORD dwUI = 0xffff; + lRet = key.QueryDWORDValue(L"UI", dwUI); + if(lRet == ERROR_SUCCESS) + bRibbonUI = dwUI == 1; + else + return lRet; + + ULONG ulSize = 0; + lRet = key.QueryBinaryValue(L"Settings", NULL, &ulSize); + if (lRet == ERROR_SUCCESS) + { + ATLASSERT(ulSize != 0); + + hgSettings = ::GlobalAlloc(GHND, ulSize); + if (hgSettings != NULL) + { + LPBYTE pData = (LPBYTE)::GlobalLock(hgSettings); + if (pData != NULL) + { + lRet = key.QueryBinaryValue(L"Settings", pData, &ulSize); + } + else + { + lRet = GetLastError(); + ::GlobalFree(hgSettings); + hgSettings = NULL; + } + } + else + { + lRet = GetLastError(); + } + } + return lRet; + } + + LONG Delete() + { + return m_Key.DeleteSubKey(L"Ribbon"); + } +}; + +} // namespace WTL + +#endif // __ATLRIBBON_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlscrl.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlscrl.h new file mode 100644 index 0000000000000000000000000000000000000000..ae483719d150f5d6c01e163e573e1978e715caec --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlscrl.h @@ -0,0 +1,2166 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLSCRL_H__ +#define __ATLSCRL_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atlscrl.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlscrl.h requires atlwin.h to be included first +#endif + +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + #include +#endif + +#ifndef GET_WHEEL_DELTA_WPARAM + #define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CScrollImpl +// CScrollWindowImpl +// CMapScrollImpl +// CMapScrollWindowImpl +// CFSBWindowT +// CZoomScrollImpl +// CZoomScrollWindowImpl +// CScrollContainerImpl +// CScrollContainer + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CScrollImpl - Provides scrolling support to any window + +// Scroll extended styles +#define SCRL_SCROLLCHILDREN 0x00000001 +#define SCRL_ERASEBACKGROUND 0x00000002 +#define SCRL_NOTHUMBTRACKING 0x00000004 +#if (WINVER >= 0x0500) +#define SCRL_SMOOTHSCROLL 0x00000008 +#endif // (WINVER >= 0x0500) +#define SCRL_DISABLENOSCROLLV 0x00000010 +#define SCRL_DISABLENOSCROLLH 0x00000020 +#define SCRL_DISABLENOSCROLL (SCRL_DISABLENOSCROLLV | SCRL_DISABLENOSCROLLH) + + +template +class CScrollImpl +{ +public: + enum { uSCROLL_FLAGS = SW_INVALIDATE }; + + POINT m_ptOffset; + SIZE m_sizeAll; + SIZE m_sizeLine; + SIZE m_sizePage; + SIZE m_sizeClient; + int m_zDelta; // current wheel value + int m_nWheelLines; // number of lines to scroll on wheel +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + // Note that this message must be forwarded from a top level window + UINT m_uMsgMouseWheel; // MSH_MOUSEWHEEL +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + int m_zHDelta; // current horizontal wheel value + int m_nHWheelChars; // number of chars to scroll on horizontal wheel + UINT m_uScrollFlags; + DWORD m_dwExtendedStyle; // scroll specific extended styles + +// Constructor + CScrollImpl() : m_zDelta(0), m_nWheelLines(3), +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + m_uMsgMouseWheel(0U), +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + m_zHDelta(0), m_nHWheelChars(3), + m_uScrollFlags(0U), m_dwExtendedStyle(0) + { + m_ptOffset.x = 0; + m_ptOffset.y = 0; + m_sizeAll.cx = 0; + m_sizeAll.cy = 0; + m_sizePage.cx = 0; + m_sizePage.cy = 0; + m_sizeLine.cx = 0; + m_sizeLine.cy = 0; + m_sizeClient.cx = 0; + m_sizeClient.cy = 0; + + SetScrollExtendedStyle(SCRL_SCROLLCHILDREN | SCRL_ERASEBACKGROUND); + } + +// Attributes & Operations + DWORD GetScrollExtendedStyle() const + { + return m_dwExtendedStyle; + } + + DWORD SetScrollExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + // cache scroll flags + T* pT = static_cast(this); + pT; // avoid level 4 warning + m_uScrollFlags = pT->uSCROLL_FLAGS | (IsScrollingChildren() ? SW_SCROLLCHILDREN : 0) | (IsErasingBackground() ? SW_ERASE : 0); +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + m_uScrollFlags |= (IsSmoothScroll() ? SW_SMOOTHSCROLL : 0); +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) + return dwPrevStyle; + } + + // offset operations + void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + pT->AdjustScrollOffset(x, y); + + int dx = m_ptOffset.x - x; + int dy = m_ptOffset.y - y; + m_ptOffset.x = x; + m_ptOffset.y = y; + + // block: set horizontal scroll bar + { + SCROLLINFO si = { sizeof(SCROLLINFO) }; + si.fMask = SIF_POS; + if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0) + si.fMask |= SIF_DISABLENOSCROLL; + si.nPos = m_ptOffset.x; + pT->SetScrollInfo(SB_HORZ, &si, bRedraw); + } + + // block: set vertical scroll bar + { + SCROLLINFO si = { sizeof(SCROLLINFO) }; + si.fMask = SIF_POS; + if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0) + si.fMask |= SIF_DISABLENOSCROLL; + si.nPos = m_ptOffset.y; + pT->SetScrollInfo(SB_VERT, &si, bRedraw); + } + + // Move all children if needed + if(IsScrollingChildren() && (dx != 0 || dy != 0)) + { + for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT)) + { + RECT rect = { 0 }; + ::GetWindowRect(hWndChild, &rect); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1); + ::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + } + } + + if(bRedraw) + pT->Invalidate(); + } + + void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE) + { + SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw); + } + + void GetScrollOffset(POINT& ptOffset) const + { + ptOffset = m_ptOffset; + } + + // size operations + void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + m_sizeAll.cx = cx; + m_sizeAll.cy = cy; + + int x = 0; + int y = 0; + if(!bResetOffset) + { + x = m_ptOffset.x; + y = m_ptOffset.y; + pT->AdjustScrollOffset(x, y); + } + + int dx = m_ptOffset.x - x; + int dy = m_ptOffset.y - y; + m_ptOffset.x = x; + m_ptOffset.y = y; + + // block: set horizontal scroll bar + { + SCROLLINFO si = { sizeof(SCROLLINFO) }; + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0) + si.fMask |= SIF_DISABLENOSCROLL; + si.nMin = 0; + si.nMax = m_sizeAll.cx - 1; + si.nPage = m_sizeClient.cx; + si.nPos = m_ptOffset.x; + pT->SetScrollInfo(SB_HORZ, &si, bRedraw); + } + + // block: set vertical scroll bar + { + SCROLLINFO si = { sizeof(SCROLLINFO) }; + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0) + si.fMask |= SIF_DISABLENOSCROLL; + si.nMin = 0; + si.nMax = m_sizeAll.cy - 1; + si.nPage = m_sizeClient.cy; + si.nPos = m_ptOffset.y; + pT->SetScrollInfo(SB_VERT, &si, bRedraw); + } + + // Move all children if needed + if(IsScrollingChildren() && (dx != 0 || dy != 0)) + { + for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT)) + { + RECT rect = { 0 }; + ::GetWindowRect(hWndChild, &rect); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1); + ::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + } + } + + SetScrollLine(0, 0); + SetScrollPage(0, 0); + + if(bRedraw) + pT->Invalidate(); + } + + void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + SetScrollSize(size.cx, size.cy, bRedraw, bResetOffset); + } + + void GetScrollSize(SIZE& sizeWnd) const + { + sizeWnd = m_sizeAll; + } + + // line operations + void SetScrollLine(int cxLine, int cyLine) + { + ATLASSERT(cxLine >= 0 && cyLine >= 0); + ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0); + + m_sizeLine.cx = T::CalcLineOrPage(cxLine, m_sizeAll.cx, 100); + m_sizeLine.cy = T::CalcLineOrPage(cyLine, m_sizeAll.cy, 100); + } + + void SetScrollLine(SIZE sizeLine) + { + SetScrollLine(sizeLine.cx, sizeLine.cy); + } + + void GetScrollLine(SIZE& sizeLine) const + { + sizeLine = m_sizeLine; + } + + // page operations + void SetScrollPage(int cxPage, int cyPage) + { + ATLASSERT(cxPage >= 0 && cyPage >= 0); + ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0); + + m_sizePage.cx = T::CalcLineOrPage(cxPage, m_sizeAll.cx, 10); + m_sizePage.cy = T::CalcLineOrPage(cyPage, m_sizeAll.cy, 10); + } + + void SetScrollPage(SIZE sizePage) + { + SetScrollPage(sizePage.cx, sizePage.cy); + } + + void GetScrollPage(SIZE& sizePage) const + { + sizePage = m_sizePage; + } + + // commands + void ScrollLineDown() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, SB_LINEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + } + + void ScrollLineUp() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, SB_LINEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + } + + void ScrollPageDown() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, SB_PAGEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + } + + void ScrollPageUp() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, SB_PAGEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + } + + void ScrollTop() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, SB_TOP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + } + + void ScrollBottom() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, SB_BOTTOM, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + } + + void ScrollLineRight() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, SB_LINEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + } + + void ScrollLineLeft() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, SB_LINEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + } + + void ScrollPageRight() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, SB_PAGEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + } + + void ScrollPageLeft() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, SB_PAGEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + } + + void ScrollAllLeft() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, SB_TOP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + } + + void ScrollAllRight() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, SB_BOTTOM, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + } + + // scroll to make point/view/window visible + void ScrollToView(POINT pt) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + RECT rect = { pt.x, pt.y, pt.x, pt.y }; + pT->ScrollToView(rect); + } + + void ScrollToView(RECT& rect) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + RECT rcClient = { 0 }; + pT->GetClientRect(&rcClient); + + int x = m_ptOffset.x; + if(rect.left < m_ptOffset.x) + x = rect.left; + else if(rect.right > (m_ptOffset.x + rcClient.right)) + x = rect.right - rcClient.right; + + int y = m_ptOffset.y; + if(rect.top < m_ptOffset.y) + y = rect.top; + else if(rect.bottom > (m_ptOffset.y + rcClient.bottom)) + y = rect.bottom - rcClient.bottom; + + SetScrollOffset(x, y); + } + + void ScrollToView(HWND hWnd) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + RECT rect = { 0 }; + ::GetWindowRect(hWnd, &rect); + ::OffsetRect(&rect, m_ptOffset.x, m_ptOffset.y); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 2); + ScrollToView(rect); + } + + BEGIN_MSG_MAP(CScrollImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_VSCROLL, OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + MESSAGE_HANDLER(m_uMsgMouseWheel, OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_PAINT, OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) +#endif // !_WIN32_WCE + // standard scroll commands + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, OnScrollAllRight) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->GetSystemSettings(); + + bHandled = FALSE; + return 1; + } + + LRESULT OnVScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, (int)(short)LOWORD(wParam), (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + return 0; + } + + LRESULT OnHScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, (int)(short)LOWORD(wParam), (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + return 0; + } + + LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + +#if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE) + uMsg; + int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam); +#else + int zDelta = (uMsg == WM_MOUSEWHEEL) ? (int)GET_WHEEL_DELTA_WPARAM(wParam) : (int)wParam; +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE)) + int nScrollCode = (m_nWheelLines == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGEUP : SB_PAGEDOWN) : ((zDelta > 0) ? SB_LINEUP : SB_LINEDOWN); + m_zDelta += zDelta; // cumulative + int zTotal = (m_nWheelLines == WHEEL_PAGESCROLL) ? abs(m_zDelta) : abs(m_zDelta) * m_nWheelLines; + if(m_sizeAll.cy > m_sizeClient.cy) + { + for(int i = 0; i < zTotal; i += WHEEL_DELTA) + { + pT->DoScroll(SB_VERT, nScrollCode, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + pT->UpdateWindow(); + } + } + else if(m_sizeAll.cx > m_sizeClient.cx) // can't scroll vertically, scroll horizontally + { + for(int i = 0; i < zTotal; i += WHEEL_DELTA) + { + pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + pT->UpdateWindow(); + } + } + m_zDelta %= WHEEL_DELTA; + + return 0; + } + + LRESULT OnMouseHWheel(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam); + int nScrollCode = (m_nHWheelChars == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGERIGHT : SB_PAGELEFT) : ((zDelta > 0) ? SB_LINERIGHT : SB_LINELEFT); + m_zHDelta += zDelta; // cumulative + int zTotal = (m_nHWheelChars == WHEEL_PAGESCROLL) ? abs(m_zHDelta) : abs(m_zHDelta) * m_nHWheelChars; + if(m_sizeAll.cx > m_sizeClient.cx) + { + for(int i = 0; i < zTotal; i += WHEEL_DELTA) + { + pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + pT->UpdateWindow(); + } + } + m_zHDelta %= WHEEL_DELTA; + + return 0; + } + + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + GetSystemSettings(); + return 0; + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + pT->DoSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + + bHandled = FALSE; + return 1; + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + if(wParam != NULL) + { + CDCHandle dc = (HDC)wParam; + POINT ptViewportOrg = { 0, 0 }; + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); + pT->DoPaint(dc); + dc.SetViewportOrg(ptViewportOrg); + } + else + { + CPaintDC dc(pT->m_hWnd); + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y); + pT->DoPaint(dc.m_hDC); + } + return 0; + } + + // scrolling handlers + LRESULT OnScrollUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollLineUp(); + return 0; + } + + LRESULT OnScrollDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollLineDown(); + return 0; + } + + LRESULT OnScrollPageUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollPageUp(); + return 0; + } + + LRESULT OnScrollPageDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollPageDown(); + return 0; + } + + LRESULT OnScrollTop(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollTop(); + return 0; + } + + LRESULT OnScrollBottom(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollBottom(); + return 0; + } + + LRESULT OnScrollLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollLineLeft(); + return 0; + } + + LRESULT OnScrollRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollLineRight(); + return 0; + } + + LRESULT OnScrollPageLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollPageLeft(); + return 0; + } + + LRESULT OnScrollPageRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollPageRight(); + return 0; + } + + LRESULT OnScrollAllLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollAllLeft(); + return 0; + } + + LRESULT OnScrollAllRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollAllRight(); + return 0; + } + +// Overrideables + void DoPaint(CDCHandle /*dc*/) + { + // must be implemented in a derived class + ATLASSERT(FALSE); + } + +// Implementation + void DoSize(int cx, int cy) + { + m_sizeClient.cx = cx; + m_sizeClient.cy = cy; + + T* pT = static_cast(this); + + // block: set horizontal scroll bar + { + SCROLLINFO si = { sizeof(SCROLLINFO) }; + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + si.nMin = 0; + si.nMax = m_sizeAll.cx - 1; + if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0) + si.fMask |= SIF_DISABLENOSCROLL; + si.nPage = m_sizeClient.cx; + si.nPos = m_ptOffset.x; + pT->SetScrollInfo(SB_HORZ, &si, TRUE); + } + + // block: set vertical scroll bar + { + SCROLLINFO si = { sizeof(SCROLLINFO) }; + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + si.nMin = 0; + si.nMax = m_sizeAll.cy - 1; + if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0) + si.fMask |= SIF_DISABLENOSCROLL; + si.nPage = m_sizeClient.cy; + si.nPos = m_ptOffset.y; + pT->SetScrollInfo(SB_VERT, &si, TRUE); + } + + int x = m_ptOffset.x; + int y = m_ptOffset.y; + if(pT->AdjustScrollOffset(x, y)) + { + // Children will be moved in SetScrollOffset, if needed + pT->ScrollWindowEx(m_ptOffset.x - x, m_ptOffset.y - y, (m_uScrollFlags & ~SCRL_SCROLLCHILDREN)); + SetScrollOffset(x, y, FALSE); + } + } + + void DoScroll(int nType, int nScrollCode, int& cxyOffset, int cxySizeAll, int cxySizePage, int cxySizeLine) + { + T* pT = static_cast(this); + RECT rect = { 0 }; + pT->GetClientRect(&rect); + int cxyClient = (nType == SB_VERT) ? rect.bottom : rect.right; + int cxyMax = cxySizeAll - cxyClient; + + if(cxyMax < 0) // can't scroll, client area is bigger + return; + + bool bUpdate = true; + int cxyScroll = 0; + + switch(nScrollCode) + { + case SB_TOP: // top or all left + cxyScroll = cxyOffset; + cxyOffset = 0; + break; + case SB_BOTTOM: // bottom or all right + cxyScroll = cxyOffset - cxyMax; + cxyOffset = cxyMax; + break; + case SB_LINEUP: // line up or line left + if(cxyOffset >= cxySizeLine) + { + cxyScroll = cxySizeLine; + cxyOffset -= cxySizeLine; + } + else + { + cxyScroll = cxyOffset; + cxyOffset = 0; + } + break; + case SB_LINEDOWN: // line down or line right + if(cxyOffset < cxyMax - cxySizeLine) + { + cxyScroll = -cxySizeLine; + cxyOffset += cxySizeLine; + } + else + { + cxyScroll = cxyOffset - cxyMax; + cxyOffset = cxyMax; + } + break; + case SB_PAGEUP: // page up or page left + if(cxyOffset >= cxySizePage) + { + cxyScroll = cxySizePage; + cxyOffset -= cxySizePage; + } + else + { + cxyScroll = cxyOffset; + cxyOffset = 0; + } + break; + case SB_PAGEDOWN: // page down or page right + if(cxyOffset < cxyMax - cxySizePage) + { + cxyScroll = -cxySizePage; + cxyOffset += cxySizePage; + } + else + { + cxyScroll = cxyOffset - cxyMax; + cxyOffset = cxyMax; + } + break; + case SB_THUMBTRACK: + if(IsNoThumbTracking()) + break; + // else fall through + case SB_THUMBPOSITION: + { + SCROLLINFO si = { sizeof(SCROLLINFO), SIF_TRACKPOS }; + if(pT->GetScrollInfo(nType, &si)) + { + cxyScroll = cxyOffset - si.nTrackPos; + cxyOffset = si.nTrackPos; + } + } + break; + case SB_ENDSCROLL: + default: + bUpdate = false; + break; + } + + if(bUpdate && cxyScroll != 0) + { + pT->SetScrollPos(nType, cxyOffset, TRUE); + if(nType == SB_VERT) + pT->ScrollWindowEx(0, cxyScroll, m_uScrollFlags); + else + pT->ScrollWindowEx(cxyScroll, 0, m_uScrollFlags); + } + } + + static int CalcLineOrPage(int nVal, int nMax, int nDiv) + { + if(nVal == 0) + { + nVal = nMax / nDiv; + if(nVal < 1) + nVal = 1; + } + else if(nVal > nMax) + { + nVal = nMax; + } + + return nVal; + } + + bool AdjustScrollOffset(int& x, int& y) + { + int xOld = x; + int yOld = y; + + int cxMax = m_sizeAll.cx - m_sizeClient.cx; + if(x > cxMax) + x = (cxMax >= 0) ? cxMax : 0; + else if(x < 0) + x = 0; + + int cyMax = m_sizeAll.cy - m_sizeClient.cy; + if(y > cyMax) + y = (cyMax >= 0) ? cyMax : 0; + else if(y < 0) + y = 0; + + return (x != xOld || y != yOld); + } + + void GetSystemSettings() + { +#ifndef _WIN32_WCE +#ifndef SPI_GETWHEELSCROLLLINES + const UINT SPI_GETWHEELSCROLLLINES = 104; +#endif // !SPI_GETWHEELSCROLLLINES + ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &m_nWheelLines, 0); + +#ifndef SPI_GETWHEELSCROLLCHARS + const UINT SPI_GETWHEELSCROLLCHARS = 0x006C; +#endif // !SPI_GETWHEELSCROLLCHARS + ::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &m_nHWheelChars, 0); + +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + if(m_uMsgMouseWheel != 0) + m_uMsgMouseWheel = ::RegisterWindowMessage(MSH_MOUSEWHEEL); + + HWND hWndWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE); + if(::IsWindow(hWndWheel)) + { + UINT uMsgScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES); + if(uMsgScrollLines != 0) + m_nWheelLines = (int)::SendMessage(hWndWheel, uMsgScrollLines, 0, 0L); + } +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) +#endif // !_WIN32_WCE + } + + bool IsScrollingChildren() const + { + return (m_dwExtendedStyle & SCRL_SCROLLCHILDREN) != 0; + } + + bool IsErasingBackground() const + { + return (m_dwExtendedStyle & SCRL_ERASEBACKGROUND) != 0; + } + + bool IsNoThumbTracking() const + { + return (m_dwExtendedStyle & SCRL_NOTHUMBTRACKING) != 0; + } + +#if (WINVER >= 0x0500) + bool IsSmoothScroll() const + { + return (m_dwExtendedStyle & SCRL_SMOOTHSCROLL) != 0; + } +#endif // (WINVER >= 0x0500) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CScrollWindowImpl - Implements a scrollable window + +template +class ATL_NO_VTABLE CScrollWindowImpl : public ATL::CWindowImpl, public CScrollImpl< T > +{ +public: + BOOL SubclassWindow(HWND hWnd) + { +#if (_MSC_VER >= 1300) + BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + BOOL bRet = _baseClass::SubclassWindow(hWnd); +#endif // !(_MSC_VER >= 1300) + if(bRet != FALSE) + { + T* pT = static_cast(this); + pT->GetSystemSettings(); + + RECT rect = { 0 }; + GetClientRect(&rect); + pT->DoSize(rect.right, rect.bottom); + } + + return bRet; + } + + BEGIN_MSG_MAP(CScrollWindowImpl) + MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) + MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) + MESSAGE_HANDLER(WM_PAINT, CScrollImpl< T >::OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, CScrollImpl< T >::OnPaint) +#endif // !_WIN32_WCE + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) + END_MSG_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CMapScrollImpl - Provides mapping and scrolling support to any window + +#ifndef _WIN32_WCE + +template +class CMapScrollImpl : public CScrollImpl< T > +{ +public: + int m_nMapMode; + RECT m_rectLogAll; + SIZE m_sizeLogLine; + SIZE m_sizeLogPage; + +// Constructor + CMapScrollImpl() : m_nMapMode(MM_TEXT) + { + ::SetRectEmpty(&m_rectLogAll); + m_sizeLogPage.cx = 0; + m_sizeLogPage.cy = 0; + m_sizeLogLine.cx = 0; + m_sizeLogLine.cy = 0; + } + +// Attributes & Operations + // mapping mode operations + void SetScrollMapMode(int nMapMode) + { + ATLASSERT(nMapMode >= MM_MIN && nMapMode <= MM_MAX_FIXEDSCALE); + m_nMapMode = nMapMode; + } + + int GetScrollMapMode() const + { + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + return m_nMapMode; + } + + // offset operations + void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE) + { + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + POINT ptOff = { x, y }; + // block: convert logical to device units + { + CWindowDC dc(NULL); + dc.SetMapMode(m_nMapMode); + dc.LPtoDP(&ptOff); + } + CScrollImpl< T >::SetScrollOffset(ptOff, bRedraw); + } + + void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE) + { + SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw); + } + + void GetScrollOffset(POINT& ptOffset) const + { + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + ptOffset = m_ptOffset; + // block: convert device to logical units + { + CWindowDC dc(NULL); + dc.SetMapMode(m_nMapMode); + dc.DPtoLP(&ptOffset); + } + } + + // size operations + void SetScrollSize(int xMin, int yMin, int xMax, int yMax, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + ATLASSERT(xMax > xMin && yMax > yMin); + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + + ::SetRect(&m_rectLogAll, xMin, yMin, xMax, yMax); + + SIZE sizeAll = { 0 }; + sizeAll.cx = xMax - xMin + 1; + sizeAll.cy = yMax - yMin + 1; + // block: convert logical to device units + { + CWindowDC dc(NULL); + dc.SetMapMode(m_nMapMode); + dc.LPtoDP(&sizeAll); + } + CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset); + SetScrollLine(0, 0); + SetScrollPage(0, 0); + } + + void SetScrollSize(RECT& rcScroll, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + SetScrollSize(rcScroll.left, rcScroll.top, rcScroll.right, rcScroll.bottom, bRedraw, bResetOffset); + } + + void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + SetScrollSize(0, 0, cx, cy, bRedraw, bResetOffset); + } + + void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + SetScrollSize(0, 0, size.cx, size.cy, bRedraw, bResetOffset); + } + + void GetScrollSize(RECT& rcScroll) const + { + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + rcScroll = m_rectLogAll; + } + + // line operations + void SetScrollLine(int cxLine, int cyLine) + { + ATLASSERT(cxLine >= 0 && cyLine >= 0); + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + + m_sizeLogLine.cx = cxLine; + m_sizeLogLine.cy = cyLine; + SIZE sizeLine = m_sizeLogLine; + // block: convert logical to device units + { + CWindowDC dc(NULL); + dc.SetMapMode(m_nMapMode); + dc.LPtoDP(&sizeLine); + } + CScrollImpl< T >::SetScrollLine(sizeLine); + } + + void SetScrollLine(SIZE sizeLine) + { + SetScrollLine(sizeLine.cx, sizeLine.cy); + } + + void GetScrollLine(SIZE& sizeLine) const + { + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + sizeLine = m_sizeLogLine; + } + + // page operations + void SetScrollPage(int cxPage, int cyPage) + { + ATLASSERT(cxPage >= 0 && cyPage >= 0); + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + + m_sizeLogPage.cx = cxPage; + m_sizeLogPage.cy = cyPage; + SIZE sizePage = m_sizeLogPage; + // block: convert logical to device units + { + CWindowDC dc(NULL); + dc.SetMapMode(m_nMapMode); + dc.LPtoDP(&sizePage); + } + CScrollImpl< T >::SetScrollPage(sizePage); + } + + void SetScrollPage(SIZE sizePage) + { + SetScrollPage(sizePage.cx, sizePage.cy); + } + + void GetScrollPage(SIZE& sizePage) const + { + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + sizePage = m_sizeLogPage; + } + + BEGIN_MSG_MAP(CMapScrollImpl) + MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) + MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) + END_MSG_MAP() + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + if(wParam != NULL) + { + CDCHandle dc = (HDC)wParam; + int nMapModeSav = dc.GetMapMode(); + dc.SetMapMode(m_nMapMode); + POINT ptViewportOrg = { 0, 0 }; + if(m_nMapMode == MM_TEXT) + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); + else + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy, &ptViewportOrg); + POINT ptWindowOrg = { 0, 0 }; + dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top, &ptWindowOrg); + + pT->DoPaint(dc); + + dc.SetMapMode(nMapModeSav); + dc.SetViewportOrg(ptViewportOrg); + dc.SetWindowOrg(ptWindowOrg); + } + else + { + CPaintDC dc(pT->m_hWnd); + dc.SetMapMode(m_nMapMode); + if(m_nMapMode == MM_TEXT) + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y); + else + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy); + dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top); + pT->DoPaint(dc.m_hDC); + } + return 0; + } +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMapScrollWindowImpl - Implements scrolling window with mapping + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CMapScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CMapScrollImpl< T > +{ +public: + BOOL SubclassWindow(HWND hWnd) + { +#if (_MSC_VER >= 1300) + BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + BOOL bRet = _baseClass::SubclassWindow(hWnd); +#endif // !(_MSC_VER >= 1300) + if(bRet != FALSE) + { + T* pT = static_cast(this); + pT->GetSystemSettings(); + + RECT rect = { 0 }; + GetClientRect(&rect); + pT->DoSize(rect.right, rect.bottom); + } + + return bRet; + } + + BEGIN_MSG_MAP(CMapScrollWindowImpl) + MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) + MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) + MESSAGE_HANDLER(WM_PAINT, CMapScrollImpl< T >::OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, CMapScrollImpl< T >::OnPaint) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) + END_MSG_MAP() +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CFSBWindow - Use as a base instead of CWindow to get flat scroll bar support + +#if defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +template +class CFSBWindowT : public TBase, public CFlatScrollBarImpl > +{ +public: +// Constructors + CFSBWindowT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CFSBWindowT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// CWindow overrides that use flat scroll bar API +// (only those methods that are used by scroll window classes) + int SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return FlatSB_SetScrollPos(nBar, nPos, bRedraw); + } + + BOOL GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + return FlatSB_GetScrollInfo(nBar, lpScrollInfo); + } + + BOOL SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return FlatSB_SetScrollInfo(nBar, lpScrollInfo, bRedraw); + } +}; + +typedef CFSBWindowT CFSBWindow; + +#endif // defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CZoomScrollImpl - Provides zooming and scrolling support to any window + +#ifndef _WIN32_WCE + +// The zoom modes that can be set with the SetZoomMode method +enum +{ + ZOOMMODE_OFF, + ZOOMMODE_IN, // If left mouse button is clicked or dragged, zoom in on point clicked or rectangle dragged. + ZOOMMODE_OUT // If left mouse button clicked, zoom out on point clicked. +}; + +// Notification to parent that zoom scale changed as a result of user mouse action. +#define ZSN_ZOOMCHANGED (NM_FIRST - 50) + +template +class CZoomScrollImpl : public CScrollImpl< T > +{ +public: + enum { m_cxyMinZoomRect = 12 }; // min rect size to zoom in on rect. + + struct _ChildPlacement + { + HWND hWnd; + int x; + int y; + int cx; + int cy; + + bool operator ==(const _ChildPlacement& cp) const { return (memcmp(this, &cp, sizeof(_ChildPlacement)) == 0); } + }; + +// Data members + SIZE m_sizeLogAll; + SIZE m_sizeLogLine; + SIZE m_sizeLogPage; + float m_fZoomScale; + float m_fZoomScaleMin; + float m_fZoomScaleMax; + float m_fZoomDelta; // Used in ZOOMMODE_IN and ZOOMMODE_OUT on left-button click. + int m_nZoomMode; + RECT m_rcTrack; + bool m_bTracking; + + bool m_bZoomChildren; + ATL::CSimpleArray<_ChildPlacement> m_arrChildren; + +// Constructor + CZoomScrollImpl(): m_fZoomScale(1.0f), m_fZoomScaleMin(0.1f), m_fZoomScaleMax(100.0f), m_fZoomDelta(0.5f), + m_nZoomMode(ZOOMMODE_OFF), m_bTracking(false), m_bZoomChildren(false) + { + m_sizeLogAll.cx = 0; + m_sizeLogAll.cy = 0; + m_sizeLogPage.cx = 0; + m_sizeLogPage.cy = 0; + m_sizeLogLine.cx = 0; + m_sizeLogLine.cy = 0; + ::SetRectEmpty(&m_rcTrack); + } + +// Attributes & Operations + // size operations + void SetScrollSize(int cxLog, int cyLog, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + ATLASSERT(cxLog >= 0 && cyLog >= 0); + + // Set up the defaults + if((cxLog == 0) && (cyLog == 0)) + { + cxLog = 1; + cyLog = 1; + } + + m_sizeLogAll.cx = cxLog; + m_sizeLogAll.cy = cyLog; + SIZE sizeAll = { 0 }; + sizeAll.cx = (int)((float)m_sizeLogAll.cx * m_fZoomScale); + sizeAll.cy = (int)((float)m_sizeLogAll.cy * m_fZoomScale); + + CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset); + } + + void SetScrollSize(SIZE sizeLog, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + SetScrollSize(sizeLog.cx, sizeLog.cy, bRedraw, bResetOffset); + } + + void GetScrollSize(SIZE& sizeLog) const + { + sizeLog = m_sizeLogAll; + } + + // line operations + void SetScrollLine(int cxLogLine, int cyLogLine) + { + ATLASSERT(cxLogLine >= 0 && cyLogLine >= 0); + + m_sizeLogLine.cx = cxLogLine; + m_sizeLogLine.cy = cyLogLine; + + SIZE sizeLine = { 0 }; + sizeLine.cx = (int)((float)m_sizeLogLine.cx * m_fZoomScale); + sizeLine.cy = (int)((float)m_sizeLogLine.cy * m_fZoomScale); + CScrollImpl< T >::SetScrollLine(sizeLine); + } + + void SetScrollLine(SIZE sizeLogLine) + { + SetScrollLine(sizeLogLine.cx, sizeLogLine.cy); + } + + void GetScrollLine(SIZE& sizeLogLine) const + { + sizeLogLine = m_sizeLogLine; + } + + // page operations + void SetScrollPage(int cxLogPage, int cyLogPage) + { + ATLASSERT((cxLogPage >= 0) && (cyLogPage >= 0)); + + m_sizeLogPage.cx = cxLogPage; + m_sizeLogPage.cy = cyLogPage; + + SIZE sizePage = { 0 }; + sizePage.cx = (int)((float)m_sizeLogPage.cx * m_fZoomScale); + sizePage.cy = (int)((float)m_sizeLogPage.cy * m_fZoomScale); + + CScrollImpl< T >::SetScrollPage(sizePage); + } + + void SetScrollPage(SIZE sizeLogPage) + { + SetScrollPage(sizeLogPage.cx, sizeLogPage.cy); + } + + void GetScrollPage(SIZE& sizeLogPage) const + { + sizeLogPage = m_sizeLogPage; + } + + void SetZoomScale(float fZoomScale) + { + ATLASSERT(fZoomScale > 0.0f); + if(fZoomScale <= 0.0f) + return; + + m_fZoomScale = fZoomScale; + if(m_fZoomScale < m_fZoomScaleMin) + m_fZoomScale = m_fZoomScaleMin; + else if(m_fZoomScale > m_fZoomScaleMax) + m_fZoomScale = m_fZoomScaleMax; + } + + float GetZoomScale() const + { + return m_fZoomScale; + } + + void SetZoomScaleMin(float fZoomScaleMin) + { + ATLASSERT(fZoomScaleMin > 0.0f); + ATLASSERT(fZoomScaleMin <= m_fZoomScaleMax); + + m_fZoomScaleMin = fZoomScaleMin; + } + + float GetZoomScaleMin() const + { + return m_fZoomScaleMin; + } + + void SetZoomScaleMax(float fZoomScaleMax) + { + ATLASSERT(fZoomScaleMax > 0.0f); + ATLASSERT(m_fZoomScaleMin <= fZoomScaleMax); + + m_fZoomScaleMax = fZoomScaleMax; + } + + float GetZoomScaleMax() const + { + return m_fZoomScaleMax; + } + + void SetZoomDelta(float fZoomDelta) + { + ATLASSERT(fZoomDelta >= 0.0f); + + if(fZoomDelta >= 0.0f) + m_fZoomDelta = fZoomDelta; + } + + float GetZoomDelta() const + { + return m_fZoomDelta; + } + + void SetZoomMode(int nZoomMode) + { + m_nZoomMode = nZoomMode; + } + + int GetZoomMode() const + { + return m_nZoomMode; + } + + void SetZoomChildren(bool bEnable = true) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + m_bZoomChildren = bEnable; + + m_arrChildren.RemoveAll(); + if(m_bZoomChildren) + { + for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT)) + { + RECT rect = { 0 }; + ::GetWindowRect(hWndChild, &rect); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 2); + + _ChildPlacement cp = { 0 }; + cp.hWnd = hWndChild; + cp.x = rect.left; + cp.y = rect.top; + cp.cx = rect.right - rect.left; + cp.cy = rect.bottom - rect.top; + m_arrChildren.Add(cp); + } + } + } + + bool GetZoomChildren() const + { + return m_bZoomChildren; + } + + void Zoom(int x, int y, float fZoomScale) + { + if(fZoomScale <= 0.0f) + return; + + if(fZoomScale < m_fZoomScaleMin) + fZoomScale = m_fZoomScaleMin; + else if(fZoomScale > m_fZoomScaleMax) + fZoomScale = m_fZoomScaleMax; + + T* pT = static_cast(this); + POINT pt = { x, y }; + if(!pT->PtInDevRect(pt)) + return; + + pT->ViewDPtoLP(&pt); + pT->Zoom(fZoomScale, false); + pT->CenterOnLogicalPoint(pt); + } + + void Zoom(POINT pt, float fZoomScale) + { + T* pT = static_cast(this); + pT->Zoom(pt.x, pt.y, fZoomScale); + } + + void Zoom(RECT& rc) + { + T* pT = static_cast(this); + RECT rcZoom = rc; + pT->NormalizeRect(rcZoom); + SIZE size = { rcZoom.right - rcZoom.left, rcZoom.bottom - rcZoom.top }; + POINT pt = { rcZoom.left + size.cx / 2, rcZoom.top + size.cy / 2 }; + if(size.cx < m_cxyMinZoomRect || size.cy < m_cxyMinZoomRect) + { + pT->Zoom(pt, m_fZoomScale + m_fZoomDelta); + return; + } + + ATLASSERT((size.cx > 0) && (size.cy > 0)); + + float fScaleH = (float)(m_sizeClient.cx + 1) / (float)size.cx; + float fScaleV = (float)(m_sizeClient.cy + 1) / (float)size.cy; + float fZoomScale = __min(fScaleH, fScaleV) * m_fZoomScale; + pT->Zoom(pt, fZoomScale); + } + + void Zoom(float fZoomScale, bool bCenter = true) + { + if(fZoomScale <= 0.0f) + return; + + if(fZoomScale < m_fZoomScaleMin) + fZoomScale = m_fZoomScaleMin; + else if(fZoomScale > m_fZoomScaleMax) + fZoomScale = m_fZoomScaleMax; + + T* pT = static_cast(this); + POINT pt = { 0 }; + if(bCenter) + { + RECT rcClient = { 0 }; + ::GetClientRect(pT->m_hWnd, &rcClient); + pt.x = rcClient.right / 2; + pt.y = rcClient.bottom / 2; + pT->ViewDPtoLP(&pt); + } + + // Modify the Viewport extent + SIZE sizeAll = { 0 }; + sizeAll.cx = (int)((float)m_sizeLogAll.cx * fZoomScale); + sizeAll.cy = (int)((float)m_sizeLogAll.cy * fZoomScale); + + // Update scroll bars and window + CScrollImpl< T >::SetScrollSize(sizeAll); + + // Zoom all children if needed + if(m_bZoomChildren && (m_fZoomScale != fZoomScale)) + { + for(int i = 0; i < m_arrChildren.GetSize(); i++) + { + ATLASSERT(::IsWindow(m_arrChildren[i].hWnd)); + + ::SetWindowPos(m_arrChildren[i].hWnd, NULL, + (int)((float)m_arrChildren[i].x * fZoomScale + 0.5f), + (int)((float)m_arrChildren[i].y * fZoomScale + 0.5f), + (int)((float)m_arrChildren[i].cx * fZoomScale + 0.5f), + (int)((float)m_arrChildren[i].cy * fZoomScale + 0.5f), + SWP_NOZORDER | SWP_NOACTIVATE); + } + } + + // Set new zoom scale + m_fZoomScale = fZoomScale; + + if(bCenter) + pT->CenterOnLogicalPoint(pt); + } + + // Helper functions + void PrepareDC(CDCHandle dc) + { + ATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0); + dc.SetMapMode(MM_ANISOTROPIC); + dc.SetWindowExt(m_sizeLogAll); + dc.SetViewportExt(m_sizeAll); + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y); + } + + void ViewDPtoLP(LPPOINT lpPoints, int nCount = 1) + { + ATLASSERT(lpPoints); + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + CWindowDC dc(pT->m_hWnd); + pT->PrepareDC(dc.m_hDC); + dc.DPtoLP(lpPoints, nCount); + } + + void ViewLPtoDP(LPPOINT lpPoints, int nCount = 1) + { + ATLASSERT(lpPoints); + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + CWindowDC dc(pT->m_hWnd); + pT->PrepareDC(dc.m_hDC); + dc.LPtoDP(lpPoints, nCount); + } + + void ClientToDevice(POINT &pt) + { + pt.x += m_ptOffset.x; + pt.y += m_ptOffset.y; + } + + void DeviceToClient(POINT &pt) + { + pt.x -= m_ptOffset.x; + pt.y -= m_ptOffset.y; + } + + void CenterOnPoint(POINT pt) + { + T* pT = static_cast(this); + RECT rect = { 0 }; + pT->GetClientRect(&rect); + + int xOfs = pt.x - (rect.right / 2) + m_ptOffset.x; + if(xOfs < 0) + { + xOfs = 0; + } + else + { + int xMax = __max((int)(m_sizeAll.cx - rect.right), 0); + if(xOfs > xMax) + xOfs = xMax; + } + + int yOfs = pt.y - (rect.bottom / 2) + m_ptOffset.y; + if(yOfs < 0) + { + yOfs = 0; + } + else + { + int yMax = __max((int)(m_sizeAll.cy - rect.bottom), 0); + if(yOfs > yMax) + yOfs = yMax; + } + + CScrollImpl< T >::SetScrollOffset(xOfs, yOfs); + } + + void CenterOnLogicalPoint(POINT ptLog) + { + T* pT = static_cast(this); + pT->ViewLPtoDP(&ptLog); + pT->DeviceToClient(ptLog); + pT->CenterOnPoint(ptLog); + } + + BOOL PtInDevRect(POINT pt) + { + RECT rc = { 0, 0, m_sizeAll.cx, m_sizeAll.cy }; + ::OffsetRect(&rc, -m_ptOffset.x, -m_ptOffset.y); + return ::PtInRect(&rc, pt); + } + + void NormalizeRect(RECT& rc) + { + if(rc.left > rc.right) + { + int r = rc.right; + rc.right = rc.left; + rc.left = r; + } + + if(rc.top > rc.bottom) + { + int b = rc.bottom; + rc.bottom = rc.top; + rc.top = b; + } + } + + void DrawTrackRect() + { + T* pT = static_cast(this); + const SIZE sizeLines = { 2, 2 }; + RECT rc = m_rcTrack; + pT->NormalizeRect(rc); + if(!::IsRectEmpty(&rc)) + { + ::MapWindowPoints(pT->m_hWnd, NULL, (LPPOINT)&rc, 2); + CWindowDC dc(NULL); + dc.DrawDragRect(&rc, sizeLines, NULL, sizeLines); + } + } + + void NotifyParentZoomChanged() + { + T* pT = static_cast(this); + int nId = pT->GetDlgCtrlID(); + NMHDR nmhdr = { pT->m_hWnd, (UINT_PTR)nId, ZSN_ZOOMCHANGED }; + ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nId, (LPARAM)&nmhdr); + } + + BEGIN_MSG_MAP(CZoomScrollImpl) + MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) + MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) + MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) + MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) + END_MSG_MAP() + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + ATLASSERT((m_sizeLogAll.cx >= 0) && (m_sizeLogAll.cy >= 0)); + ATLASSERT((m_sizeAll.cx >= 0) && (m_sizeAll.cy >= 0)); + + if(wParam != NULL) + { + CDCHandle dc = (HDC)wParam; + int nMapModeSav = dc.GetMapMode(); + dc.SetMapMode(MM_ANISOTROPIC); + SIZE szWindowExt = { 0, 0 }; + dc.SetWindowExt(m_sizeLogAll, &szWindowExt); + SIZE szViewportExt = { 0, 0 }; + dc.SetViewportExt(m_sizeAll, &szViewportExt); + POINT ptViewportOrg = { 0, 0 }; + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); + + pT->DoPaint(dc); + + dc.SetMapMode(nMapModeSav); + dc.SetWindowExt(szWindowExt); + dc.SetViewportExt(szViewportExt); + dc.SetViewportOrg(ptViewportOrg); + } + else + { + CPaintDC dc(pT->m_hWnd); + pT->PrepareDC(dc.m_hDC); + pT->DoPaint(dc.m_hDC); + } + + return 0; + } + + LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(m_nZoomMode == ZOOMMODE_IN && !m_bTracking) + { + T* pT = static_cast(this); + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + if(pT->PtInDevRect(pt)) + { + pT->SetCapture(); + m_bTracking = true; + ::SetRect(&m_rcTrack, pt.x, pt.y, pt.x, pt.y); + } + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(m_bTracking) + { + T* pT = static_cast(this); + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + if(pT->PtInDevRect(pt)) + { + pT->DrawTrackRect(); + m_rcTrack.right = pt.x; + m_rcTrack.bottom = pt.y; + pT->DrawTrackRect(); + } + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + ::ReleaseCapture(); + if(m_nZoomMode == ZOOMMODE_OUT) + { + T* pT = static_cast(this); + pT->Zoom(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), m_fZoomScale - m_fZoomDelta); + pT->NotifyParentZoomChanged(); + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_bTracking) + { + m_bTracking = false; + T* pT = static_cast(this); + pT->DrawTrackRect(); + pT->Zoom(m_rcTrack); + pT->NotifyParentZoomChanged(); + ::SetRectEmpty(&m_rcTrack); + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if(LOWORD(lParam) == HTCLIENT && m_nZoomMode != ZOOMMODE_OFF) + { + T* pT = static_cast(this); + if((HWND)wParam == pT->m_hWnd) + { + DWORD dwPos = ::GetMessagePos(); + POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; + pT->ScreenToClient(&pt); + if(pT->PtInDevRect(pt)) + { + ::SetCursor(::LoadCursor(NULL, IDC_CROSS)); + return 1; + } + } + } + + bHandled = FALSE; + return 0; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CZoomScrollWindowImpl - Implements scrolling window with zooming + +template +class ATL_NO_VTABLE CZoomScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T > +{ +public: + BOOL SubclassWindow(HWND hWnd) + { +#if (_MSC_VER >= 1300) + BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + BOOL bRet = _baseClass::SubclassWindow(hWnd); +#endif // !(_MSC_VER >= 1300) + if(bRet != FALSE) + { + T* pT = static_cast(this); + pT->GetSystemSettings(); + + RECT rect = { 0 }; + GetClientRect(&rect); + pT->DoSize(rect.right, rect.bottom); + } + + return bRet; + } + + BEGIN_MSG_MAP(CZoomScrollWindowImpl) + MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor) + MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) + MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) + MESSAGE_HANDLER(WM_PAINT, CZoomScrollImpl< T >::OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, CZoomScrollImpl< T >::OnPaint) + MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown) + MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove) + MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp) + MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) + END_MSG_MAP() +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CScrollContainer + +template +class ATL_NO_VTABLE CScrollContainerImpl : public CScrollWindowImpl< T, TBase, TWinTraits > +{ +public: + DECLARE_WND_CLASS_EX(NULL, 0, -1) + + typedef CScrollWindowImpl< T, TBase, TWinTraits > _baseClass; + +// Data members + ATL::CWindow m_wndClient; + bool m_bAutoSizeClient; + bool m_bDrawEdgeIfEmpty; + +// Constructor + CScrollContainerImpl() : m_bAutoSizeClient(true), m_bDrawEdgeIfEmpty(false) + { + // Set CScrollWindowImpl extended style + SetScrollExtendedStyle(SCRL_SCROLLCHILDREN); + } + +// Attributes + HWND GetClient() const + { + return m_wndClient; + } + + HWND SetClient(HWND hWndClient, bool bClientSizeAsMin = true) + { + ATLASSERT(::IsWindow(m_hWnd)); + + HWND hWndOldClient = m_wndClient; + m_wndClient = hWndClient; + + SetRedraw(FALSE); + SetScrollSize(1, 1, FALSE); + + if(m_wndClient.m_hWnd != NULL) + { + m_wndClient.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE); + + if(bClientSizeAsMin) + { + RECT rect = { 0 }; + m_wndClient.GetWindowRect(&rect); + if((rect.right - rect.left) > 0 && (rect.bottom - rect.top) > 0) + SetScrollSize(rect.right - rect.left, rect.bottom - rect.top, FALSE); + } + + T* pT = static_cast(this); + pT->UpdateLayout(); + } + + SetRedraw(TRUE); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW | RDW_ALLCHILDREN); + + return hWndOldClient; + } + +// Message map and handlers + BEGIN_MSG_MAP(CScrollContainerImpl) + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + CHAIN_MSG_MAP(_baseClass) + FORWARD_NOTIFICATIONS() + ALT_MSG_MAP(1) + CHAIN_MSG_MAP_ALT(_baseClass, 1) + END_MSG_MAP() + + LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(m_wndClient.m_hWnd != NULL) + m_wndClient.SetFocus(); + + return 0; + } + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background needed + } + +// Overrides for CScrollWindowImpl + void DoSize(int cx, int cy) + { + _baseClass::DoSize(cx, cy); + + T* pT = static_cast(this); + pT->UpdateLayout(); + } + + void DoPaint(CDCHandle dc) + { + if(!m_bAutoSizeClient || m_wndClient.m_hWnd == NULL) + { + T* pT = static_cast(this); + RECT rect = { 0 }; + pT->GetContainerRect(rect); + + if(m_bDrawEdgeIfEmpty && m_wndClient.m_hWnd == NULL) + dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + + dc.FillRect(&rect, COLOR_APPWORKSPACE); + } + } + + void ScrollToView(POINT pt) + { + CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(pt); + } + + void ScrollToView(RECT& rect) + { + CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(rect); + } + + void ScrollToView(HWND hWnd) // client window coordinates + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + ATLASSERT(::IsWindow(pT->m_hWnd)); + ATLASSERT(m_wndClient.IsWindow()); + + RECT rect = { 0 }; + ::GetWindowRect(hWnd, &rect); + ::MapWindowPoints(NULL, m_wndClient.m_hWnd, (LPPOINT)&rect, 2); + ScrollToView(rect); + } + +// Implementation - overrideable methods + void UpdateLayout() + { + ATLASSERT(::IsWindow(m_hWnd)); + + if(m_bAutoSizeClient && m_wndClient.m_hWnd != NULL) + { + T* pT = static_cast(this); + RECT rect = { 0 }; + pT->GetContainerRect(rect); + + m_wndClient.SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE); + } + else + { + Invalidate(); + } + } + + void GetContainerRect(RECT& rect) + { + GetClientRect(&rect); + + if(rect.right < m_sizeAll.cx) + rect.right = m_sizeAll.cx; + + if(rect.bottom < m_sizeAll.cy) + rect.bottom = m_sizeAll.cy; + } +}; + +class CScrollContainer : public CScrollContainerImpl +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_ScrollContainer"), 0, -1) +}; + +}; // namespace WTL + +#endif // __ATLSCRL_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlsplit.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlsplit.h new file mode 100644 index 0000000000000000000000000000000000000000..00a419d494e1d18c251c0d01145e46b269ab9bbf --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlsplit.h @@ -0,0 +1,1130 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLSPLIT_H__ +#define __ATLSPLIT_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atlsplit.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlsplit.h requires atlwin.h to be included first +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CSplitterImpl +// CSplitterWindowImpl +// CSplitterWindowT - CSplitterWindow, CHorSplitterWindow + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CSplitterImpl - Provides splitter support to any window + +// Splitter panes constants +#define SPLIT_PANE_LEFT 0 +#define SPLIT_PANE_RIGHT 1 +#define SPLIT_PANE_TOP SPLIT_PANE_LEFT +#define SPLIT_PANE_BOTTOM SPLIT_PANE_RIGHT +#define SPLIT_PANE_NONE -1 + +// Splitter extended styles +#define SPLIT_PROPORTIONAL 0x00000001 +#define SPLIT_NONINTERACTIVE 0x00000002 +#define SPLIT_RIGHTALIGNED 0x00000004 +#define SPLIT_BOTTOMALIGNED SPLIT_RIGHTALIGNED +#define SPLIT_GRADIENTBAR 0x00000008 +#define SPLIT_FIXEDBARSIZE 0x00000010 + +// Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are +// mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL. +// SPLIT_GRADIENTBAR doesn't work with _ATL_NO_MSIMG + + +template +class CSplitterImpl +{ +public: + enum { m_nPanesCount = 2, m_nPropMax = 10000, m_cxyStep = 10 }; + + bool m_bVertical; + HWND m_hWndPane[m_nPanesCount]; + RECT m_rcSplitter; + int m_xySplitterPos; // splitter bar position + int m_xySplitterPosNew; // internal - new position while moving + HWND m_hWndFocusSave; + int m_nDefActivePane; + int m_cxySplitBar; // splitter bar width/height + HCURSOR m_hCursor; + int m_cxyMin; // minimum pane size + int m_cxyBarEdge; // splitter bar edge + bool m_bFullDrag; + int m_cxyDragOffset; // internal + int m_nProportionalPos; + bool m_bUpdateProportionalPos; + DWORD m_dwExtendedStyle; // splitter specific extended styles + int m_nSinglePane; // single pane mode + int m_xySplitterDefPos; // default position + bool m_bProportionalDefPos; // porportinal def pos + +// Constructor + CSplitterImpl(bool bVertical = true) : + m_bVertical(bVertical), m_xySplitterPos(-1), m_xySplitterPosNew(-1), m_hWndFocusSave(NULL), + m_nDefActivePane(SPLIT_PANE_NONE), m_cxySplitBar(4), m_hCursor(NULL), m_cxyMin(0), m_cxyBarEdge(0), + m_bFullDrag(true), m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProportionalPos(true), + m_dwExtendedStyle(SPLIT_PROPORTIONAL), m_nSinglePane(SPLIT_PANE_NONE), + m_xySplitterDefPos(-1), m_bProportionalDefPos(false) + { + m_hWndPane[SPLIT_PANE_LEFT] = NULL; + m_hWndPane[SPLIT_PANE_RIGHT] = NULL; + + ::SetRectEmpty(&m_rcSplitter); + } + +// Attributes + void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true) + { + if(lpRect == NULL) + { + T* pT = static_cast(this); + pT->GetClientRect(&m_rcSplitter); + } + else + { + m_rcSplitter = *lpRect; + } + + if(IsProportional()) + UpdateProportionalPos(); + else if(IsRightAligned()) + UpdateRightAlignPos(); + + if(bUpdate) + UpdateSplitterLayout(); + } + + void GetSplitterRect(LPRECT lpRect) const + { + ATLASSERT(lpRect != NULL); + *lpRect = m_rcSplitter; + } + + bool SetSplitterPos(int xyPos = -1, bool bUpdate = true) + { + if(xyPos == -1) // -1 == default position + { + if(m_bProportionalDefPos) + { + ATLASSERT((m_xySplitterDefPos >= 0) && (m_xySplitterDefPos <= m_nPropMax)); + + if(m_bVertical) + xyPos = ::MulDiv(m_xySplitterDefPos, m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge, m_nPropMax); + else + xyPos = ::MulDiv(m_xySplitterDefPos, m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge, m_nPropMax); + } + else if(m_xySplitterDefPos != -1) + { + xyPos = m_xySplitterDefPos; + } + else // not set, use middle position + { + if(m_bVertical) + xyPos = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2; + else + xyPos = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2; + } + } + + // Adjust if out of valid range + int cxyMax = 0; + if(m_bVertical) + cxyMax = m_rcSplitter.right - m_rcSplitter.left; + else + cxyMax = m_rcSplitter.bottom - m_rcSplitter.top; + + if(xyPos < m_cxyMin + m_cxyBarEdge) + xyPos = m_cxyMin; + else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin)) + xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin; + + // Set new position and update if requested + bool bRet = (m_xySplitterPos != xyPos); + m_xySplitterPos = xyPos; + + if(m_bUpdateProportionalPos) + { + if(IsProportional()) + StoreProportionalPos(); + else if(IsRightAligned()) + StoreRightAlignPos(); + } + else + { + m_bUpdateProportionalPos = true; + } + + if(bUpdate && bRet) + UpdateSplitterLayout(); + + return bRet; + } + + int GetSplitterPos() const + { + return m_xySplitterPos; + } + + void SetSplitterPosPct(int nPct, bool bUpdate = true) + { + ATLASSERT((nPct >= 0) && (nPct <= 100)); + + m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100); + UpdateProportionalPos(); + + if(bUpdate) + UpdateSplitterLayout(); + } + + int GetSplitterPosPct() const + { + int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); + return ((cxyTotal > 0) && (m_xySplitterPos >= 0)) ? (::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal) / 100) : -1; + } + + bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE) + { + ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT) || (nPane == SPLIT_PANE_NONE)); + if(!((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT) || (nPane == SPLIT_PANE_NONE))) + return false; + + if(nPane != SPLIT_PANE_NONE) + { + if(::IsWindowVisible(m_hWndPane[nPane]) == FALSE) + ::ShowWindow(m_hWndPane[nPane], SW_SHOW); + int nOtherPane = (nPane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT; + ::ShowWindow(m_hWndPane[nOtherPane], SW_HIDE); + if(m_nDefActivePane != nPane) + m_nDefActivePane = nPane; + } + else if(m_nSinglePane != SPLIT_PANE_NONE) + { + int nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT; + ::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW); + } + + m_nSinglePane = nPane; + UpdateSplitterLayout(); + + return true; + } + + int GetSinglePaneMode() const + { + return m_nSinglePane; + } + + DWORD GetSplitterExtendedStyle() const + { + return m_dwExtendedStyle; + } + + DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + +#ifdef _DEBUG + if(IsProportional() && IsRightAligned()) + ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\n")); +#endif // _DEBUG + + return dwPrevStyle; + } + + void SetSplitterDefaultPos(int xyPos = -1) + { + m_xySplitterDefPos = xyPos; + m_bProportionalDefPos = false; + } + + void SetSplitterDefaultPosPct(int nPct) + { + ATLASSERT((nPct >= 0) && (nPct <= 100)); + + m_xySplitterDefPos = ::MulDiv(nPct, m_nPropMax, 100); + m_bProportionalDefPos = true; + } + +// Splitter operations + void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpdate = true) + { + m_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop; + m_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom; + ATLASSERT((m_hWndPane[SPLIT_PANE_LEFT] == NULL) || (m_hWndPane[SPLIT_PANE_RIGHT] == NULL) || (m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT])); + if(bUpdate) + UpdateSplitterLayout(); + } + + bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true) + { + ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT)); + if((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT)) + return false; + + m_hWndPane[nPane] = hWnd; + ATLASSERT((m_hWndPane[SPLIT_PANE_LEFT] == NULL) || (m_hWndPane[SPLIT_PANE_RIGHT] == NULL) || (m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT])); + if(bUpdate) + UpdateSplitterLayout(); + + return true; + } + + HWND GetSplitterPane(int nPane) const + { + ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT)); + if((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT)) + return NULL; + + return m_hWndPane[nPane]; + } + + bool SetActivePane(int nPane) + { + ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT)); + if((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT)) + return false; + if((m_nSinglePane != SPLIT_PANE_NONE) && (nPane != m_nSinglePane)) + return false; + + ::SetFocus(m_hWndPane[nPane]); + m_nDefActivePane = nPane; + + return true; + } + + int GetActivePane() const + { + int nRet = SPLIT_PANE_NONE; + HWND hWndFocus = ::GetFocus(); + if(hWndFocus != NULL) + { + for(int nPane = 0; nPane < m_nPanesCount; nPane++) + { + if((hWndFocus == m_hWndPane[nPane]) || (::IsChild(m_hWndPane[nPane], hWndFocus) != FALSE)) + { + nRet = nPane; + break; + } + } + } + + return nRet; + } + + bool ActivateNextPane(bool bNext = true) + { + int nPane = m_nSinglePane; + if(nPane == SPLIT_PANE_NONE) + { + switch(GetActivePane()) + { + case SPLIT_PANE_LEFT: + nPane = SPLIT_PANE_RIGHT; + break; + case SPLIT_PANE_RIGHT: + nPane = SPLIT_PANE_LEFT; + break; + default: + nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIGHT; + break; + } + } + + return SetActivePane(nPane); + } + + bool SetDefaultActivePane(int nPane) + { + ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT)); + if((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT)) + return false; + + m_nDefActivePane = nPane; + + return true; + } + + bool SetDefaultActivePane(HWND hWnd) + { + for(int nPane = 0; nPane < m_nPanesCount; nPane++) + { + if(hWnd == m_hWndPane[nPane]) + { + m_nDefActivePane = nPane; + return true; + } + } + + return false; // not found + } + + int GetDefaultActivePane() const + { + return m_nDefActivePane; + } + + void DrawSplitter(CDCHandle dc) + { + ATLASSERT(dc.m_hDC != NULL); + if((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1)) + return; + + T* pT = static_cast(this); + if(m_nSinglePane == SPLIT_PANE_NONE) + { + pT->DrawSplitterBar(dc); + + for(int nPane = 0; nPane < m_nPanesCount; nPane++) + { + if(m_hWndPane[nPane] == NULL) + pT->DrawSplitterPane(dc, nPane); + } + } + else + { + if(m_hWndPane[m_nSinglePane] == NULL) + pT->DrawSplitterPane(dc, m_nSinglePane); + } + } + + // call to initiate moving splitter bar with keyboard + void MoveSplitterBar() + { + T* pT = static_cast(this); + + int x = 0; + int y = 0; + if(m_bVertical) + { + x = m_xySplitterPos + (m_cxySplitBar / 2) + m_cxyBarEdge; + y = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2; + } + else + { + x = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2; + y = m_xySplitterPos + (m_cxySplitBar / 2) + m_cxyBarEdge; + } + + POINT pt = { x, y }; + pT->ClientToScreen(&pt); + ::SetCursorPos(pt.x, pt.y); + + m_xySplitterPosNew = m_xySplitterPos; + pT->SetCapture(); + m_hWndFocusSave = pT->SetFocus(); + ::SetCursor(m_hCursor); + if(!m_bFullDrag) + DrawGhostBar(); + if(m_bVertical) + m_cxyDragOffset = x - m_rcSplitter.left - m_xySplitterPos; + else + m_cxyDragOffset = y - m_rcSplitter.top - m_xySplitterPos; + } + + void SetOrientation(bool bVertical, bool bUpdate = true) + { + if(m_bVertical != bVertical) + { + m_bVertical = bVertical; + + m_hCursor = ::LoadCursor(NULL, m_bVertical ? IDC_SIZEWE : IDC_SIZENS); + + T* pT = static_cast(this); + pT->GetSystemSettings(false); + + if(m_bVertical) + m_xySplitterPos = ::MulDiv(m_xySplitterPos, m_rcSplitter.right - m_rcSplitter.left, m_rcSplitter.bottom - m_rcSplitter.top); + else + m_xySplitterPos = ::MulDiv(m_xySplitterPos, m_rcSplitter.bottom - m_rcSplitter.top, m_rcSplitter.right - m_rcSplitter.left); + } + + if(bUpdate) + UpdateSplitterLayout(); + } + +// Overrideables + void DrawSplitterBar(CDCHandle dc) + { + RECT rect = { 0 }; + if(GetSplitterBarRect(&rect)) + { + dc.FillRect(&rect, COLOR_3DFACE); + +#if (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420) + if((m_dwExtendedStyle & SPLIT_GRADIENTBAR) != 0) + { + RECT rect2 = rect; + if(m_bVertical) + rect2.left = (rect.left + rect.right) / 2 - 1; + else + rect2.top = (rect.top + rect.bottom) / 2 - 1; + + dc.GradientFillRect(rect2, ::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DSHADOW), m_bVertical); + } +#endif // (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420) + + // draw 3D edge if needed + T* pT = static_cast(this); + if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0) + dc.DrawEdge(&rect, EDGE_RAISED, m_bVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM)); + } + } + + // called only if pane is empty + void DrawSplitterPane(CDCHandle dc, int nPane) + { + RECT rect = { 0 }; + if(GetSplitterPaneRect(nPane, &rect)) + { + T* pT = static_cast(this); + if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0) + dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + dc.FillRect(&rect, COLOR_APPWORKSPACE); + } + } + +// Message map and handlers + BEGIN_MSG_MAP(CSplitterImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_PAINT, OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) +#endif // !_WIN32_WCE + if(IsInteractive()) + { + MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) + MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) + MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick) + MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) + MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) + } + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->Init(); + + bHandled = FALSE; + return 1; + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + + // try setting position if not set + if((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1)) + pT->SetSplitterPos(); + + // do painting + if(wParam != NULL) + { + pT->DrawSplitter((HDC)wParam); + } + else + { + CPaintDC dc(pT->m_hWnd); + pT->DrawSplitter(dc.m_hDC); + } + + return 0; + } + + LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + if(((HWND)wParam == pT->m_hWnd) && (LOWORD(lParam) == HTCLIENT)) + { + DWORD dwPos = ::GetMessagePos(); + POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; + pT->ScreenToClient(&ptPos); + if(IsOverSplitterBar(ptPos.x, ptPos.y)) + return 1; + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + int xPos = GET_X_LPARAM(lParam); + int yPos = GET_Y_LPARAM(lParam); + if(::GetCapture() == pT->m_hWnd) + { + int xyNewSplitPos = 0; + if(m_bVertical) + xyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset; + else + xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset; + + if(xyNewSplitPos == -1) // avoid -1, that means default position + xyNewSplitPos = -2; + + if(m_xySplitterPos != xyNewSplitPos) + { + if(m_bFullDrag) + { + if(pT->SetSplitterPos(xyNewSplitPos, true)) + pT->UpdateWindow(); + } + else + { + DrawGhostBar(); + pT->SetSplitterPos(xyNewSplitPos, false); + DrawGhostBar(); + } + } + } + else // not dragging, just set cursor + { + if(IsOverSplitterBar(xPos, yPos)) + ::SetCursor(m_hCursor); + bHandled = FALSE; + } + + return 0; + } + + LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + int xPos = GET_X_LPARAM(lParam); + int yPos = GET_Y_LPARAM(lParam); + if((::GetCapture() != pT->m_hWnd) && IsOverSplitterBar(xPos, yPos)) + { + m_xySplitterPosNew = m_xySplitterPos; + pT->SetCapture(); + m_hWndFocusSave = pT->SetFocus(); + ::SetCursor(m_hCursor); + if(!m_bFullDrag) + DrawGhostBar(); + if(m_bVertical) + m_cxyDragOffset = xPos - m_rcSplitter.left - m_xySplitterPos; + else + m_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos; + } + else if((::GetCapture() == pT->m_hWnd) && !IsOverSplitterBar(xPos, yPos)) + { + ::ReleaseCapture(); + } + + bHandled = FALSE; + return 1; + } + + LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + if(::GetCapture() == pT->m_hWnd) + { + m_xySplitterPosNew = m_xySplitterPos; + ::ReleaseCapture(); + } + + bHandled = FALSE; + return 1; + } + + LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->SetSplitterPos(); // default + + return 0; + } + + LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(!m_bFullDrag) + DrawGhostBar(); + + if((m_xySplitterPosNew != -1) && (!m_bFullDrag || (m_xySplitterPos != m_xySplitterPosNew))) + { + m_xySplitterPos = m_xySplitterPosNew; + m_xySplitterPosNew = -1; + UpdateSplitterLayout(); + T* pT = static_cast(this); + pT->UpdateWindow(); + } + + if(m_hWndFocusSave != NULL) + ::SetFocus(m_hWndFocusSave); + + return 0; + } + + LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + if(::GetCapture() == pT->m_hWnd) + { + switch(wParam) + { + case VK_RETURN: + m_xySplitterPosNew = m_xySplitterPos; + case VK_ESCAPE: + ::ReleaseCapture(); + break; + case VK_LEFT: + case VK_RIGHT: + if(m_bVertical) + { + POINT pt = { 0, 0 }; + ::GetCursorPos(&pt); + int xyPos = m_xySplitterPos + ((wParam == VK_LEFT) ? -pT->m_cxyStep : pT->m_cxyStep); + int cxyMax = m_rcSplitter.right - m_rcSplitter.left; + if(xyPos < (m_cxyMin + m_cxyBarEdge)) + xyPos = m_cxyMin; + else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin)) + xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin; + pt.x += xyPos - m_xySplitterPos; + ::SetCursorPos(pt.x, pt.y); + } + break; + case VK_UP: + case VK_DOWN: + if(!m_bVertical) + { + POINT pt = { 0, 0 }; + ::GetCursorPos(&pt); + int xyPos = m_xySplitterPos + ((wParam == VK_UP) ? -pT->m_cxyStep : pT->m_cxyStep); + int cxyMax = m_rcSplitter.bottom - m_rcSplitter.top; + if(xyPos < (m_cxyMin + m_cxyBarEdge)) + xyPos = m_cxyMin; + else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin)) + xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin; + pt.y += xyPos - m_xySplitterPos; + ::SetCursorPos(pt.x, pt.y); + } + break; + default: + break; + } + } + else + { + bHandled = FALSE; + } + + return 0; + } + + LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHandled) + { + T* pT = static_cast(this); + if(::GetCapture() != pT->m_hWnd) + { + if(m_nSinglePane == SPLIT_PANE_NONE) + { + if((m_nDefActivePane == SPLIT_PANE_LEFT) || (m_nDefActivePane == SPLIT_PANE_RIGHT)) + ::SetFocus(m_hWndPane[m_nDefActivePane]); + } + else + { + ::SetFocus(m_hWndPane[m_nSinglePane]); + } + } + + bHandled = FALSE; + return 1; + } + +#ifndef _WIN32_WCE + LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); + if((lRet == MA_ACTIVATE) || (lRet == MA_ACTIVATEANDEAT)) + { + DWORD dwPos = ::GetMessagePos(); + POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; + pT->ScreenToClient(&pt); + RECT rcPane = { 0 }; + for(int nPane = 0; nPane < m_nPanesCount; nPane++) + { + if(GetSplitterPaneRect(nPane, &rcPane) && (::PtInRect(&rcPane, pt) != FALSE)) + { + m_nDefActivePane = nPane; + break; + } + } + } + + return lRet; + } +#endif // !_WIN32_WCE + + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->GetSystemSettings(true); + + return 0; + } + +// Implementation - internal helpers + void Init() + { + m_hCursor = ::LoadCursor(NULL, m_bVertical ? IDC_SIZEWE : IDC_SIZENS); + + T* pT = static_cast(this); + pT->GetSystemSettings(false); + } + + void UpdateSplitterLayout() + { + if((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1)) + return; + + T* pT = static_cast(this); + RECT rect = { 0 }; + if(m_nSinglePane == SPLIT_PANE_NONE) + { + if(GetSplitterBarRect(&rect)) + pT->InvalidateRect(&rect); + + for(int nPane = 0; nPane < m_nPanesCount; nPane++) + { + if(GetSplitterPaneRect(nPane, &rect)) + { + if(m_hWndPane[nPane] != NULL) + ::SetWindowPos(m_hWndPane[nPane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER); + else + pT->InvalidateRect(&rect); + } + } + } + else + { + if(GetSplitterPaneRect(m_nSinglePane, &rect)) + { + if(m_hWndPane[m_nSinglePane] != NULL) + ::SetWindowPos(m_hWndPane[m_nSinglePane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER); + else + pT->InvalidateRect(&rect); + } + } + } + + bool GetSplitterBarRect(LPRECT lpRect) const + { + ATLASSERT(lpRect != NULL); + if((m_nSinglePane != SPLIT_PANE_NONE) || (m_xySplitterPos == -1)) + return false; + + if(m_bVertical) + { + lpRect->left = m_rcSplitter.left + m_xySplitterPos; + lpRect->top = m_rcSplitter.top; + lpRect->right = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; + lpRect->bottom = m_rcSplitter.bottom; + } + else + { + lpRect->left = m_rcSplitter.left; + lpRect->top = m_rcSplitter.top + m_xySplitterPos; + lpRect->right = m_rcSplitter.right; + lpRect->bottom = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; + } + + return true; + } + + bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const + { + ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT)); + ATLASSERT(lpRect != NULL); + bool bRet = true; + if(m_nSinglePane != SPLIT_PANE_NONE) + { + if(nPane == m_nSinglePane) + *lpRect = m_rcSplitter; + else + bRet = false; + } + else if(nPane == SPLIT_PANE_LEFT) + { + if(m_bVertical) + { + lpRect->left = m_rcSplitter.left; + lpRect->top = m_rcSplitter.top; + lpRect->right = m_rcSplitter.left + m_xySplitterPos; + lpRect->bottom = m_rcSplitter.bottom; + } + else + { + lpRect->left = m_rcSplitter.left; + lpRect->top = m_rcSplitter.top; + lpRect->right = m_rcSplitter.right; + lpRect->bottom = m_rcSplitter.top + m_xySplitterPos; + } + } + else if(nPane == SPLIT_PANE_RIGHT) + { + if(m_bVertical) + { + lpRect->left = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; + lpRect->top = m_rcSplitter.top; + lpRect->right = m_rcSplitter.right; + lpRect->bottom = m_rcSplitter.bottom; + } + else + { + lpRect->left = m_rcSplitter.left; + lpRect->top = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; + lpRect->right = m_rcSplitter.right; + lpRect->bottom = m_rcSplitter.bottom; + } + } + else + { + bRet = false; + } + + return bRet; + } + + bool IsOverSplitterRect(int x, int y) const + { + // -1 == don't check + return ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter.right)) && + (y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.bottom))); + } + + bool IsOverSplitterBar(int x, int y) const + { + if(m_nSinglePane != SPLIT_PANE_NONE) + return false; + if((m_xySplitterPos == -1) || !IsOverSplitterRect(x, y)) + return false; + int xy = m_bVertical ? x : y; + int xyOff = m_bVertical ? m_rcSplitter.left : m_rcSplitter.top; + + return ((xy >= (xyOff + m_xySplitterPos)) && (xy < xyOff + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge)); + } + + void DrawGhostBar() + { + RECT rect = { 0 }; + if(GetSplitterBarRect(&rect)) + { + // convert client to window coordinates + T* pT = static_cast(this); + RECT rcWnd = { 0 }; + pT->GetWindowRect(&rcWnd); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcWnd, 2); + ::OffsetRect(&rect, -rcWnd.left, -rcWnd.top); + + // invert the brush pattern (looks just like frame window sizing) + CWindowDC dc(pT->m_hWnd); + CBrush brush = CDCHandle::GetHalftoneBrush(); + if(brush.m_hBrush != NULL) + { + CBrushHandle brushOld = dc.SelectBrush(brush); + dc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT); + dc.SelectBrush(brushOld); + } + } + } + + void GetSystemSettings(bool bUpdate) + { + if((m_dwExtendedStyle & SPLIT_FIXEDBARSIZE) == 0) + { +#ifndef _WIN32_WCE + m_cxySplitBar = ::GetSystemMetrics(m_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME); +#else // CE specific + m_cxySplitBar = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE); +#endif // _WIN32_WCE + } + + T* pT = static_cast(this); + if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0) + { + m_cxyBarEdge = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE); + m_cxyMin = 0; + } + else + { + m_cxyBarEdge = 0; + m_cxyMin = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE); + } + +#ifndef _WIN32_WCE + ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0); +#endif // !_WIN32_WCE + + if(bUpdate) + UpdateSplitterLayout(); + } + + bool IsProportional() const + { + return ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0); + } + + void StoreProportionalPos() + { + int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); + if(cxyTotal > 0) + m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal); + else + m_nProportionalPos = 0; + ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreProportionalPos - %i\n"), m_nProportionalPos); + } + + void UpdateProportionalPos() + { + int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); + if(cxyTotal > 0) + { + int xyNewPos = ::MulDiv(m_nProportionalPos, cxyTotal, m_nPropMax); + m_bUpdateProportionalPos = false; + T* pT = static_cast(this); + pT->SetSplitterPos(xyNewPos, false); + } + } + + bool IsRightAligned() const + { + return ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0); + } + + void StoreRightAlignPos() + { + int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); + if(cxyTotal > 0) + m_nProportionalPos = cxyTotal - m_xySplitterPos; + else + m_nProportionalPos = 0; + ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreRightAlignPos - %i\n"), m_nProportionalPos); + } + + void UpdateRightAlignPos() + { + int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); + if(cxyTotal > 0) + { + m_bUpdateProportionalPos = false; + T* pT = static_cast(this); + pT->SetSplitterPos(cxyTotal - m_nProportionalPos, false); + } + } + + bool IsInteractive() const + { + return ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CSplitterWindowImpl - Implements a splitter window + +template +class ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CSplitterImpl< T > +{ +public: + DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW) + + CSplitterWindowImpl(bool bVertical = true) : CSplitterImpl< T >(bVertical) + { } + + BOOL SubclassWindow(HWND hWnd) + { +#if (_MSC_VER >= 1300) + BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + BOOL bRet = _baseClass::SubclassWindow(hWnd); +#endif // !(_MSC_VER >= 1300) + if(bRet != FALSE) + { + T* pT = static_cast(this); + pT->Init(); + + SetSplitterRect(); + } + + return bRet; + } + + BEGIN_MSG_MAP(CSplitterWindowImpl) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_SIZE, OnSize) + CHAIN_MSG_MAP(CSplitterImpl< T >) + FORWARD_NOTIFICATIONS() + END_MSG_MAP() + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + // handled, no background painting needed + return 1; + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam != SIZE_MINIMIZED) + SetSplitterRect(); + + bHandled = FALSE; + return 1; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CSplitterWindow/CHorSplitterWindow - Implements splitter windows to be used as is + +template +class CSplitterWindowT : public CSplitterWindowImpl > +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW) + + CSplitterWindowT() : CSplitterWindowImpl >(t_bVertical) + { } +}; + +typedef CSplitterWindowT CSplitterWindow; +typedef CSplitterWindowT CHorSplitterWindow; + +}; // namespace WTL + +#endif // __ATLSPLIT_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atltheme.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atltheme.h new file mode 100644 index 0000000000000000000000000000000000000000..b453a41bccf62f603acb86ee33faf2d35a651a8a --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atltheme.h @@ -0,0 +1,1257 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLTHEME_H__ +#define __ATLTHEME_H__ + +#pragma once + +#ifdef _WIN32_WCE + #error atltheme.h is not supported on Windows CE +#endif + +#ifndef __ATLAPP_H__ + #error atltheme.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atltheme.h requires atlwin.h to be included first +#endif + +#if (_WIN32_WINNT < 0x0501) + #error atltheme.h requires _WIN32_WINNT >= 0x0501 +#endif // (_WIN32_WINNT < 0x0501) + +#if defined(_WTL_USE_VSSYM32) || (defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)) + #include +#else + #ifndef TMSCHEMA_H + #include + #endif +#endif + +#include +#pragma comment(lib, "uxtheme.lib") + +// Note: To create an application that also runs on older versions of Windows, +// use delay load of uxtheme.dll and ensure that no calls to the Theme API are +// made if theming is not supported. It is enough to check if m_hTheme is NULL. +// Example: +// if(m_hTheme != NULL) +// { +// DrawThemeBackground(dc, BP_PUSHBUTTON, PBS_NORMAL, &rect, NULL); +// DrawThemeText(dc, BP_PUSHBUTTON, PBS_NORMAL, L"Button", -1, DT_SINGLELINE | DT_CENTER | DT_VCENTER, 0, &rect); +// } +// else +// { +// dc.DrawFrameControl(&rect, DFC_BUTTON, DFCS_BUTTONPUSH); +// dc.DrawText(_T("Button"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); +// } +// +// Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib, +// and add uxtheme.dll in the Linker.Input.Delay Loaded DLLs section of the +// project properties. +#if (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD) + #pragma comment(lib, "delayimp.lib") + #pragma comment(linker, "/delayload:uxtheme.dll") +#endif // (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD) + +// Hack: Signatures in uxtheme.h changed - the only way to check which variant of uxtheme.h +// is included is to check for presence of new defines MAX_THEMECOLOR and MAX_THEMESIZE +// Note: In WinSDK 7.0 (and higher) they are defined with #if (_WIN32_WINNT >= 0x0600), +// so you have to compile with _WTL_NEW_UXTHEME defined for _WIN32_WINNT < 0x0600 +#ifndef _WTL_NEW_UXTHEME + #if defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE) + #define _WTL_NEW_UXTHEME + #endif // defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE) +#endif // _WTL_NEW_UXTHEME + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CTheme +// CThemeImpl +// +// CBufferedPaint +// CBufferedPaintImpl +// CBufferedPaintWindowImpl +// CBufferedAnimation +// CBufferedAnimationImpl +// CBufferedAnimationWindowImpl +// +// Global functions: +// AtlDrawThemeClientEdge() + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CTheme - wrapper for theme handle + +class CTheme +{ +public: +// Data members + HTHEME m_hTheme; + static int m_nIsThemingSupported; + +// Constructor + CTheme(HTHEME hTheme = NULL) : m_hTheme(hTheme) + { + IsThemingSupported(); + } + +// Operators and helpers + bool IsThemeNull() const + { + return (m_hTheme == NULL); + } + + CTheme& operator =(HTHEME hTheme) + { + m_hTheme = hTheme; + return *this; + } + + operator HTHEME() const + { + return m_hTheme; + } + + void Attach(HTHEME hTheme) + { + m_hTheme = hTheme; + } + + HTHEME Detach() + { + HTHEME hTheme = m_hTheme; + m_hTheme = NULL; + return hTheme; + } + +// Theme support helper + static bool IsThemingSupported() + { + if(m_nIsThemingSupported == -1) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CTheme::IsThemingSupported.\n")); + ATLASSERT(FALSE); + return false; + } + + if(m_nIsThemingSupported == -1) + { + HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll")); + m_nIsThemingSupported = (hThemeDLL != NULL) ? 1 : 0; + if(hThemeDLL != NULL) + ::FreeLibrary(hThemeDLL); + } + + lock.Unlock(); + } + + ATLASSERT(m_nIsThemingSupported != -1); + return (m_nIsThemingSupported == 1); + } + +// Operations and theme properties + HTHEME OpenThemeData(HWND hWnd, LPCWSTR pszClassList) + { + if(!IsThemingSupported()) + return NULL; + + ATLASSERT(m_hTheme == NULL); + m_hTheme = ::OpenThemeData(hWnd, pszClassList); + return m_hTheme; + } + + HRESULT CloseThemeData() + { + HRESULT hRet = S_FALSE; + if(m_hTheme != NULL) + { + hRet = ::CloseThemeData(m_hTheme); + if(SUCCEEDED(hRet)) + m_hTheme = NULL; + } + return hRet; + } + + HRESULT DrawThemeBackground(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, LPCRECT pClipRect = NULL) + { + ATLASSERT(m_hTheme != NULL); + return ::DrawThemeBackground(m_hTheme, hDC, nPartID, nStateID, pRect, pClipRect); + } + +// Missing in original uxtheme.h +#ifdef DTBG_CLIPRECT + HRESULT DrawThemeBackgroundEx(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, const DTBGOPTS* pOptions = NULL) + { + ATLASSERT(m_hTheme != NULL); + return ::DrawThemeBackgroundEx(m_hTheme, hDC, nPartID, nStateID, pRect, pOptions); + } +#endif // DTBG_CLIPRECT + + HRESULT DrawThemeText(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect) + { + ATLASSERT(m_hTheme != NULL); + return ::DrawThemeText(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, dwTextFlags2, pRect); + } + + HRESULT GetThemeBackgroundContentRect(HDC hDC, int nPartID, int nStateID, LPCRECT pBoundingRect, LPRECT pContentRect) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeBackgroundContentRect(m_hTheme, hDC, nPartID, nStateID, pBoundingRect, pContentRect); + } + + HRESULT GetThemeBackgroundExtent(HDC hDC, int nPartID, int nStateID, LPCRECT pContentRect, LPRECT pExtentRect) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeBackgroundExtent(m_hTheme, hDC, nPartID, nStateID, pContentRect, pExtentRect); + } + + HRESULT GetThemePartSize(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, enum THEMESIZE eSize, LPSIZE pSize) const + { + ATLASSERT(m_hTheme != NULL); +#ifdef _WTL_NEW_UXTHEME + return ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, pRect, eSize, pSize); +#else // !_WTL_NEW_UXTHEME + // Note: The cast to LPRECT is because uxtheme.h incorrectly uses it instead of LPCRECT + return ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, (LPRECT)pRect, eSize, pSize); +#endif // !_WTL_NEW_UXTHEME + } + + HRESULT GetThemeTextExtent(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, LPCRECT pBoundingRect, LPRECT pExtentRect) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeTextExtent(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, pBoundingRect, pExtentRect); + } + + HRESULT GetThemeTextMetrics(HDC hDC, int nPartID, int nStateID, PTEXTMETRICW pTextMetric) const + { + ATLASSERT(m_hTheme != NULL); +#ifdef _WTL_NEW_UXTHEME + return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, pTextMetric); +#else // !_WTL_NEW_UXTHEME + // Note: The cast to PTEXTMETRIC is because uxtheme.h incorrectly uses it instead of PTEXTMETRICW + return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, (PTEXTMETRIC)pTextMetric); +#endif // !_WTL_NEW_UXTHEME + } + + HRESULT GetThemeBackgroundRegion(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HRGN* pRegion) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeBackgroundRegion(m_hTheme, hDC, nPartID, nStateID, pRect, pRegion); + } + + HRESULT HitTestThemeBackground(HDC hDC, int nPartID, int nStateID, DWORD dwOptions, LPCRECT pRect, HRGN hrgn, POINT ptTest, WORD* pwHitTestCode) const + { + ATLASSERT(m_hTheme != NULL); + return ::HitTestThemeBackground(m_hTheme, hDC, nPartID, nStateID, dwOptions, pRect, hrgn, ptTest, pwHitTestCode); + } + + HRESULT DrawThemeEdge(HDC hDC, int nPartID, int nStateID, LPCRECT pDestRect, UINT uEdge, UINT uFlags, LPRECT pContentRect = NULL) + { + ATLASSERT(m_hTheme != NULL); + return ::DrawThemeEdge(m_hTheme, hDC, nPartID, nStateID, pDestRect, uEdge, uFlags, pContentRect); + } + + HRESULT DrawThemeIcon(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HIMAGELIST himl, int nImageIndex) + { + ATLASSERT(m_hTheme != NULL); + return ::DrawThemeIcon(m_hTheme, hDC, nPartID, nStateID, pRect, himl, nImageIndex); + } + + BOOL IsThemePartDefined(int nPartID, int nStateID) const + { + ATLASSERT(m_hTheme != NULL); + return ::IsThemePartDefined(m_hTheme, nPartID, nStateID); + } + + BOOL IsThemeBackgroundPartiallyTransparent(int nPartID, int nStateID) const + { + ATLASSERT(m_hTheme != NULL); + return ::IsThemeBackgroundPartiallyTransparent(m_hTheme, nPartID, nStateID); + } + + HRESULT GetThemeColor(int nPartID, int nStateID, int nPropID, COLORREF* pColor) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeColor(m_hTheme, nPartID, nStateID, nPropID, pColor); + } + + HRESULT GetThemeMetric(HDC hDC, int nPartID, int nStateID, int nPropID, int* pnVal) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeMetric(m_hTheme, hDC, nPartID, nStateID, nPropID, pnVal); + } + + HRESULT GetThemeString(int nPartID, int nStateID, int nPropID, LPWSTR pszBuff, int cchMaxBuffChars) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeString(m_hTheme, nPartID, nStateID, nPropID, pszBuff, cchMaxBuffChars); + } + + HRESULT GetThemeBool(int nPartID, int nStateID, int nPropID, BOOL* pfVal) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeBool(m_hTheme, nPartID, nStateID, nPropID, pfVal); + } + + HRESULT GetThemeInt(int nPartID, int nStateID, int nPropID, int* pnVal) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeInt(m_hTheme, nPartID, nStateID, nPropID, pnVal); + } + + HRESULT GetThemeEnumValue(int nPartID, int nStateID, int nPropID, int* pnVal) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeEnumValue(m_hTheme, nPartID, nStateID, nPropID, pnVal); + } + + HRESULT GetThemePosition(int nPartID, int nStateID, int nPropID, LPPOINT pPoint) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemePosition(m_hTheme, nPartID, nStateID, nPropID, pPoint); + } + + // deprecated + HRESULT GetThemeFont(int nPartID, HDC hDC, int nStateID, int nPropID, LOGFONTW* pFont) const + { + ATLASSERT(m_hTheme != NULL); +#ifdef _WTL_NEW_UXTHEME + return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont); +#else // !_WTL_NEW_UXTHEME + // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* + return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont); +#endif // !_WTL_NEW_UXTHEME + } + + HRESULT GetThemeFont(HDC hDC, int nPartID, int nStateID, int nPropID, LOGFONTW* pFont) const + { + ATLASSERT(m_hTheme != NULL); +#ifdef _WTL_NEW_UXTHEME + return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont); +#else // !_WTL_NEW_UXTHEME + // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* + return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont); +#endif // !_WTL_NEW_UXTHEME + } + + HRESULT GetThemeRect(int nPartID, int nStateID, int nPropID, LPRECT pRect) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeRect(m_hTheme, nPartID, nStateID, nPropID, pRect); + } + + HRESULT GetThemeMargins(HDC hDC, int nPartID, int nStateID, int nPropID, LPRECT pRect, PMARGINS pMargins) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeMargins(m_hTheme, hDC, nPartID, nStateID, nPropID, pRect, pMargins); + } + + HRESULT GetThemeIntList(int nPartID, int nStateID, int nPropID, INTLIST* pIntList) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeIntList(m_hTheme, nPartID, nStateID, nPropID, pIntList); + } + + HRESULT GetThemePropertyOrigin(int nPartID, int nStateID, int nPropID, enum PROPERTYORIGIN* pOrigin) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemePropertyOrigin(m_hTheme, nPartID, nStateID, nPropID, pOrigin); + } + + HRESULT GetThemeFilename(int nPartID, int nStateID, int nPropID, LPWSTR pszThemeFileName, int cchMaxBuffChars) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeFilename(m_hTheme, nPartID, nStateID, nPropID, pszThemeFileName, cchMaxBuffChars); + } + + COLORREF GetThemeSysColor(int nColorID) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeSysColor(m_hTheme, nColorID); + } + + HBRUSH GetThemeSysColorBrush(int nColorID) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeSysColorBrush(m_hTheme, nColorID); + } + + int GetThemeSysSize(int nSizeID) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeSysSize(m_hTheme, nSizeID); + } + + BOOL GetThemeSysBool(int nBoolID) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeSysBool(m_hTheme, nBoolID); + } + + HRESULT GetThemeSysFont(int nFontID, LOGFONTW* plf) const + { + ATLASSERT(m_hTheme != NULL); +#ifdef _WTL_NEW_UXTHEME + return ::GetThemeSysFont(m_hTheme, nFontID, plf); +#else // !_WTL_NEW_UXTHEME + // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* + return ::GetThemeSysFont(m_hTheme, nFontID, (LOGFONT*)plf); +#endif // !_WTL_NEW_UXTHEME + } + + HRESULT GetThemeSysString(int nStringID, LPWSTR pszStringBuff, int cchMaxStringChars) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeSysString(m_hTheme, nStringID, pszStringBuff, cchMaxStringChars); + } + + HRESULT GetThemeSysInt(int nIntID, int* pnValue) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeSysInt(m_hTheme, nIntID, pnValue); + } + +#ifdef _WTL_NEW_UXTHEME + HTHEME OpenThemeDataEx(HWND hWnd, LPCWSTR pszClassList, DWORD dwFlags) + { + if(!IsThemingSupported()) + return NULL; + + ATLASSERT(m_hTheme == NULL); + m_hTheme = ::OpenThemeDataEx(hWnd, pszClassList, dwFlags); + return m_hTheme; + } + +#if (_WIN32_WINNT >= 0x0600) + HRESULT DrawThemeTextEx(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT lpRect, const DTTOPTS* pOptions) + { + ATLASSERT(m_hTheme != NULL); + return ::DrawThemeTextEx(m_hTheme, hDC, nPartID, nStateID, pszText, cchText, dwTextFlags, lpRect, pOptions); + } + + HRESULT GetThemeTransitionDuration(int nPartID, int nFromStateID, int nToStateID, int nPropID, DWORD& dwDuration) + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeTransitionDuration(m_hTheme, nPartID, nFromStateID, nToStateID, nPropID, &dwDuration); + } +#endif // (_WIN32_WINNT >= 0x0600) +#endif // _WTL_NEW_UXTHEME + +#if (_WIN32_WINNT >= 0x0600) + HRESULT GetThemeBitmap(int nPartID, int nStateID, int nPropID, ULONG uFlags, HBITMAP& hBitmap) + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeBitmap(m_hTheme, nPartID, nStateID, nPropID, uFlags, &hBitmap); + } + + HRESULT GetThemeStream(int nPartID, int nStateID, int nPropID, VOID** ppvStream, DWORD* pcbStream, HINSTANCE hInstance) + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeStream(m_hTheme, nPartID, nStateID, nPropID, ppvStream, pcbStream, hInstance); + } +#endif // (_WIN32_WINNT >= 0x0600) + +#if (_WIN32_WINNT >= 0x0602) + HRESULT GetThemeAnimationProperty(int iStoryboardId, int iTargetId, TA_PROPERTY eProperty, VOID* pvProperty, DWORD cbSize, DWORD* pcbSizeOut) + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeAnimationProperty(m_hTheme, iStoryboardId, iTargetId, eProperty, pvProperty, cbSize, pcbSizeOut); + } + + HRESULT GetThemeAnimationTransform(int iStoryboardId, int iTargetId, DWORD dwTransformIndex, TA_TRANSFORM* pTransform, DWORD cbSize, DWORD* pcbSizeOut) + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeAnimationTransform(m_hTheme, iStoryboardId, iTargetId, dwTransformIndex, pTransform, cbSize, pcbSizeOut); + } + + HRESULT GetThemeTimingFunction(int iTimingFunctionId, TA_TIMINGFUNCTION* pTimingFunction, DWORD cbSize, DWORD* pcbSizeOut) + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeTimingFunction(m_hTheme, iTimingFunctionId, pTimingFunction, cbSize, pcbSizeOut); + } +#endif // (_WIN32_WINNT >= 0x0602) +}; + +__declspec(selectany) int CTheme::m_nIsThemingSupported = -1; + + +/////////////////////////////////////////////////////////////////////////////// +// CThemeImpl - theme support implementation + +// Derive from this class to implement window with theme support. +// Example: +// class CMyThemeWindow : public CWindowImpl, public CThemeImpl +// { +// ... +// BEGIN_MSG_MAP(CMyThemeWindow) +// CHAIN_MSG_MAP(CThemeImpl) +// ... +// END_MSG_MAP() +// ... +// }; +// +// If you set theme class list, the class will automaticaly open/close/reopen theme data. + + +// Helper for drawing theme client edge +inline bool AtlDrawThemeClientEdge(HTHEME hTheme, HWND hWnd, HRGN hRgnUpdate = NULL, HBRUSH hBrush = NULL, int nPartID = 0, int nStateID = 0) +{ + ATLASSERT(hTheme != NULL); + ATLASSERT(::IsWindow(hWnd)); + + CWindowDC dc(hWnd); + if(dc.IsNull()) + return false; + + // Get border size + int cxBorder = ::GetSystemMetrics(SM_CXBORDER); + int cyBorder = ::GetSystemMetrics(SM_CYBORDER); + if(SUCCEEDED(::GetThemeInt(hTheme, nPartID, nStateID, TMT_SIZINGBORDERWIDTH, &cxBorder))) + cyBorder = cxBorder; + + RECT rect = { 0 }; + ::GetWindowRect(hWnd, &rect); + + // Remove the client edge from the update region + int cxEdge = ::GetSystemMetrics(SM_CXEDGE); + int cyEdge = ::GetSystemMetrics(SM_CYEDGE); + ::InflateRect(&rect, -cxEdge, -cyEdge); + CRgn rgn; + rgn.CreateRectRgnIndirect(&rect); + if(rgn.IsNull()) + return false; + + if(hRgnUpdate != NULL) + rgn.CombineRgn(hRgnUpdate, rgn, RGN_AND); + + ::OffsetRect(&rect, -rect.left, -rect.top); + + ::OffsetRect(&rect, cxEdge, cyEdge); + dc.ExcludeClipRect(&rect); + ::InflateRect(&rect, cxEdge, cyEdge); + + ::DrawThemeBackground(hTheme, dc, nPartID, nStateID, &rect, NULL); + + // Use background brush too, since theme border might not cover everything + if((cxBorder < cxEdge) && (cyBorder < cyEdge)) + { + if(hBrush == NULL) +// need conditional code because types don't match in winuser.h +#ifdef _WIN64 + hBrush = (HBRUSH)::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND); +#else + hBrush = (HBRUSH)UlongToPtr(::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND)); +#endif + + ::InflateRect(&rect, cxBorder - cxEdge, cyBorder - cyEdge); + dc.FillRect(&rect, hBrush); + } + + ::DefWindowProc(hWnd, WM_NCPAINT, (WPARAM)rgn.m_hRgn, 0L); + + return true; +} + + +// Theme extended styles +#define THEME_EX_3DCLIENTEDGE 0x00000001 +#define THEME_EX_THEMECLIENTEDGE 0x00000002 + +template +class CThemeImpl : public TBase +{ +public: +// Data members + LPWSTR m_lpstrThemeClassList; + DWORD m_dwExtendedStyle; // theme specific extended styles + +// Constructor & destructor + CThemeImpl() : m_lpstrThemeClassList(NULL), m_dwExtendedStyle(0) + { } + + ~CThemeImpl() + { + delete [] m_lpstrThemeClassList; + } + +// Attributes + bool SetThemeClassList(LPCWSTR lpstrThemeClassList) + { + if(m_lpstrThemeClassList != NULL) + { + delete [] m_lpstrThemeClassList; + m_lpstrThemeClassList = NULL; + } + + if(lpstrThemeClassList == NULL) + return true; + + int cchLen = lstrlenW(lpstrThemeClassList) + 1; + ATLTRY(m_lpstrThemeClassList = new WCHAR[cchLen]); + if(m_lpstrThemeClassList == NULL) + return false; + + SecureHelper::strcpyW_x(m_lpstrThemeClassList, cchLen, lpstrThemeClassList); + + return true; + } + + bool GetThemeClassList(LPWSTR lpstrThemeClassList, int cchListBuffer) const + { + int cchLen = lstrlenW(m_lpstrThemeClassList) + 1; + if(cchListBuffer < cchLen) + return false; + + SecureHelper::strcpyW_x(lpstrThemeClassList, cchListBuffer, m_lpstrThemeClassList); + + return true; + } + + LPCWSTR GetThemeClassList() const + { + return m_lpstrThemeClassList; + } + + DWORD SetThemeExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + + return dwPrevStyle; + } + + DWORD GetThemeExtendedStyle() const + { + return m_dwExtendedStyle; + } + +// Operations + HTHEME OpenThemeData() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + ATLASSERT(m_lpstrThemeClassList != NULL); + if(m_lpstrThemeClassList == NULL) + return NULL; + CloseThemeData(); + + return TBase::OpenThemeData(pT->m_hWnd, m_lpstrThemeClassList); + } + + HTHEME OpenThemeData(LPCWSTR pszClassList) + { + if(!SetThemeClassList(pszClassList)) + return NULL; + + return OpenThemeData(); + } + + HRESULT SetWindowTheme(LPCWSTR pszSubAppName, LPCWSTR pszSubIDList) + { + if(!IsThemingSupported()) + return S_FALSE; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::SetWindowTheme(pT->m_hWnd, pszSubAppName, pszSubIDList); + } + + HTHEME GetWindowTheme() const + { + if(!IsThemingSupported()) + return NULL; + + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::GetWindowTheme(pT->m_hWnd); + } + + HRESULT EnableThemeDialogTexture(DWORD dwFlags) + { + if(!IsThemingSupported()) + return S_FALSE; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::EnableThemeDialogTexture(pT->m_hWnd, dwFlags); + } + + BOOL IsThemeDialogTextureEnabled() const + { + if(!IsThemingSupported()) + return FALSE; + + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::IsThemeDialogTextureEnabled(pT->m_hWnd); + } + + HRESULT DrawThemeParentBackground(HDC hDC, const RECT* pRect = NULL) + { + if(!IsThemingSupported()) + return S_FALSE; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); +#ifdef _WTL_NEW_UXTHEME + return ::DrawThemeParentBackground(pT->m_hWnd, hDC, pRect); +#else + return ::DrawThemeParentBackground(pT->m_hWnd, hDC, (RECT*)pRect); +#endif + } + +#if defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600) + HRESULT SetWindowThemeAttribute(WINDOWTHEMEATTRIBUTETYPE type, PVOID pvAttribute, DWORD cbAttribute) + { + if(!IsThemingSupported()) + return S_FALSE; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::SetWindowThemeAttribute(pT->m_hWnd, type, pvAttribute, cbAttribute); + } + + HRESULT SetWindowThemeNonClientAttributes(DWORD dwAttributes, DWORD dwMask) + { + if(!IsThemingSupported()) + return S_FALSE; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + WTA_OPTIONS opt = { dwAttributes, dwMask }; + return ::SetWindowThemeAttribute(pT->m_hWnd, WTA_NONCLIENT, (PVOID)&opt, sizeof(opt)); + } + + HRESULT DrawThemeParentBackgroundEx(HDC hDC, DWORD dwFlags, const RECT* lpRect = NULL) + { + if(!IsThemingSupported()) + return S_FALSE; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DrawThemeParentBackgroundEx(pT->m_hWnd, hDC, dwFlags, lpRect); + } +#endif // defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600) + +// Message map and handlers + // Note: If you handle any of these messages in your derived class, + // it is better to put CHAIN_MSG_MAP at the start of your message map. + BEGIN_MSG_MAP(CThemeImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) + MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_lpstrThemeClassList != NULL) + OpenThemeData(); + + bHandled = FALSE; + return 1; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + CloseThemeData(); + + bHandled = FALSE; + return 1; + } + + LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + CloseThemeData(); + if(m_lpstrThemeClassList != NULL) + OpenThemeData(); + + bHandled = FALSE; + return 1; + } + + LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + LRESULT lRet = 0; + bHandled = FALSE; + if(IsThemingSupported() && ((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)) + { + if((m_dwExtendedStyle & THEME_EX_3DCLIENTEDGE) != 0) + { + lRet = ::DefWindowProc(pT->m_hWnd, uMsg, wParam, lParam); + bHandled = TRUE; + } + else if((m_hTheme != NULL) && ((m_dwExtendedStyle & THEME_EX_THEMECLIENTEDGE) != 0)) + { + HRGN hRgn = (wParam != 1) ? (HRGN)wParam : NULL; + if(pT->DrawThemeClientEdge(hRgn)) + bHandled = TRUE; + } + } + + return lRet; + } + +// Drawing helper + bool DrawThemeClientEdge(HRGN hRgnUpdate) + { + T* pT = static_cast(this); + return AtlDrawThemeClientEdge(m_hTheme, pT->m_hWnd, hRgnUpdate, NULL, 0, 0); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// Buffered Paint and Animation + +#if defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600) + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedPaintBase - Buffered Paint support for othe classes + +class CBufferedPaintBase +{ +public: + static int m_nIsBufferedPaintSupported; + + CBufferedPaintBase() + { + if(IsBufferedPaintSupported()) + ATLVERIFY(SUCCEEDED(::BufferedPaintInit())); + } + + ~CBufferedPaintBase() + { + if(IsBufferedPaintSupported()) + ATLVERIFY(SUCCEEDED(::BufferedPaintUnInit())); + } + + static bool IsBufferedPaintSupported() + { + if(m_nIsBufferedPaintSupported == -1) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CBufferedPaintBase::IsBufferedPaintSupported.\n")); + ATLASSERT(FALSE); + return false; + } + + if(m_nIsBufferedPaintSupported == -1) + m_nIsBufferedPaintSupported = RunTimeHelper::IsVista() ? 1 : 0; + + lock.Unlock(); + } + + ATLASSERT(m_nIsBufferedPaintSupported != -1); + return (m_nIsBufferedPaintSupported == 1); + } +}; + +__declspec(selectany) int CBufferedPaintBase::m_nIsBufferedPaintSupported = -1; + + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedPaint - support for buffered paint functions + +class CBufferedPaint +{ +public: + HPAINTBUFFER m_hPaintBuffer; + + CBufferedPaint() : m_hPaintBuffer(NULL) + { } + + ~CBufferedPaint() + { + ATLVERIFY(SUCCEEDED(End())); + } + + bool IsNull() const + { + return (m_hPaintBuffer == NULL); + } + + HPAINTBUFFER Begin(HDC hdcTarget, const RECT* prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, HDC* phdcPaint) + { + ATLASSERT(m_hPaintBuffer == NULL); + m_hPaintBuffer = ::BeginBufferedPaint(hdcTarget, prcTarget, dwFormat, pPaintParams, phdcPaint); + return m_hPaintBuffer; + } + + HRESULT End(BOOL bUpdate = TRUE) + { + HRESULT hRet = S_FALSE; + if(m_hPaintBuffer != NULL) + { + hRet = ::EndBufferedPaint(m_hPaintBuffer, bUpdate); + m_hPaintBuffer = NULL; + } + return hRet; + } + + HRESULT GetTargetRect(LPRECT pRect) const + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::GetBufferedPaintTargetRect(m_hPaintBuffer, pRect); + } + + HDC GetTargetDC() const + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::GetBufferedPaintTargetDC(m_hPaintBuffer); + } + + HDC GetPaintDC() const + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::GetBufferedPaintDC(m_hPaintBuffer); + } + + HRESULT GetBits(RGBQUAD** ppbBuffer, int* pcxRow) const + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::GetBufferedPaintBits(m_hPaintBuffer, ppbBuffer, pcxRow); + } + + HRESULT Clear(const RECT* pRect = NULL) + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::BufferedPaintClear(m_hPaintBuffer, pRect); + } + + HRESULT SetAlpha(BYTE alpha, const RECT* pRect = NULL) + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, alpha); + } + + HRESULT MakeOpaque(const RECT* pRect = NULL) + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, 255); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedPaintImpl - provides buffered paint for any window + +template +class ATL_NO_VTABLE CBufferedPaintImpl : public CBufferedPaintBase +{ +public: + CBufferedPaint m_BufferedPaint; + BP_BUFFERFORMAT m_dwFormat; + BP_PAINTPARAMS m_PaintParams; + + CBufferedPaintImpl() : m_dwFormat(BPBF_TOPDOWNDIB) + { + memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS)); + m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS); + } + +// Message map and handlers + BEGIN_MSG_MAP(CBufferedPaintImpl) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + END_MSG_MAP() + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background needed + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + if(wParam != NULL) + { + RECT rect = { 0 }; + pT->GetClientRect(&rect); + pT->DoPaint((HDC)wParam, rect); + } + else + { + CPaintDC dc(pT->m_hWnd); + pT->DoBufferedPaint(dc.m_hDC, dc.m_ps.rcPaint); + } + + return 0; + } + +// Overrideables + void DoBufferedPaint(CDCHandle dc, RECT& rect) + { + HDC hDCPaint = NULL; + if(IsBufferedPaintSupported()) + m_BufferedPaint.Begin(dc, &rect, m_dwFormat, &m_PaintParams, &hDCPaint); + + T* pT = static_cast(this); + if(hDCPaint != NULL) + pT->DoPaint(hDCPaint, rect); + else + pT->DoPaint(dc.m_hDC, rect); + + if(IsBufferedPaintSupported()) + m_BufferedPaint.End(); + } + + void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/) + { + // must be implemented in a derived class + ATLASSERT(FALSE); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedPaintWindowImpl - implements a window that uses buffered paint + +template +class ATL_NO_VTABLE CBufferedPaintWindowImpl : + public ATL::CWindowImpl, + public CBufferedPaintImpl< T > +{ +public: + BEGIN_MSG_MAP(CBufferedPaintWindowImpl) + CHAIN_MSG_MAP(CBufferedPaintImpl< T >) + END_MSG_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedAnimation - support for buffered animation + +class CBufferedAnimation +{ +public: + HANIMATIONBUFFER m_hAnimationBuffer; + + CBufferedAnimation() : m_hAnimationBuffer(NULL) + { } + + ~CBufferedAnimation() + { + ATLVERIFY(SUCCEEDED(End())); + } + + bool IsNull() const + { + return (m_hAnimationBuffer == NULL); + } + + HANIMATIONBUFFER Begin(HWND hWnd, HDC hDCTarget, const RECT* pRectTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, BP_ANIMATIONPARAMS* pAnimationParams, HDC* phdcFrom, HDC* phdcTo) + { + ATLASSERT(m_hAnimationBuffer == NULL); + m_hAnimationBuffer = ::BeginBufferedAnimation(hWnd, hDCTarget, pRectTarget, dwFormat, pPaintParams, pAnimationParams, phdcFrom, phdcTo); + return m_hAnimationBuffer; + } + + HRESULT End(BOOL bUpdate = TRUE) + { + HRESULT hRet = S_FALSE; + if(m_hAnimationBuffer != NULL) + { + hRet = ::EndBufferedAnimation(m_hAnimationBuffer, bUpdate); + m_hAnimationBuffer = NULL; + } + return hRet; + } + + static bool IsRendering(HWND hWnd, HDC hDC) + { + return (::BufferedPaintRenderAnimation(hWnd, hDC) != FALSE); + } + + static HRESULT StopAllAnimations(HWND hWnd) + { + return ::BufferedPaintStopAllAnimations(hWnd); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedAnimationImpl - provides buffered animation support for any window + +// Note: You can either use m_State and m_NewState to store the state information +// for the animation change, or map your state to those data members. DoPaint() +// should only rely on the state information that is passed to it. + +template +class ATL_NO_VTABLE CBufferedAnimationImpl : public CBufferedPaintBase +{ +public: + BP_BUFFERFORMAT m_dwFormat; + BP_PAINTPARAMS m_PaintParams; + BP_ANIMATIONPARAMS m_AnimationParams; + + TState m_State; + TState m_NewState; + + CBufferedAnimationImpl(TState InitialState) : m_dwFormat(BPBF_TOPDOWNDIB) + { + memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS)); + m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS); + + memset(&m_AnimationParams, 0, sizeof(BP_ANIMATIONPARAMS)); + m_AnimationParams.cbSize = sizeof(BP_ANIMATIONPARAMS); + m_AnimationParams.style = BPAS_LINEAR; + m_AnimationParams.dwDuration = 500; + + T* pT = static_cast(this); + pT->SetState(InitialState); + pT->SetNewState(InitialState); + } + + DWORD GetDuration() const + { + return m_AnimationParams.dwDuration; + } + + void SetDuration(DWORD dwDuration) + { + m_AnimationParams.dwDuration = dwDuration; + } + + void DoAnimation(TState NewState, const RECT* pRect = NULL) + { + T* pT = static_cast(this); + pT->SetNewState(NewState); + + pT->InvalidateRect(pRect, FALSE); + pT->UpdateWindow(); + + pT->SetState(NewState); + } + +// Message map and handlers + BEGIN_MSG_MAP(CBufferedAnimationImpl) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + END_MSG_MAP() + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background needed + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + if(wParam != NULL) + { + RECT rect = { 0 }; + pT->GetClientRect(&rect); + pT->DoPaint((HDC)wParam, rect, m_NewState); + } + else + { + CPaintDC dc(pT->m_hWnd); + pT->DoAnimationPaint(dc.m_hDC, dc.m_ps.rcPaint); + } + + return 0; + } + +// Overrideables + void SetState(TState State) + { + m_State = State; + } + + void SetNewState(TState State) + { + m_NewState = State; + } + + bool AreStatesEqual() const + { + return (m_State == m_NewState); + } + + void DoAnimationPaint(CDCHandle dc, RECT& rect) + { + T* pT = static_cast(this); + if(IsBufferedPaintSupported() && CBufferedAnimation::IsRendering(pT->m_hWnd, dc)) + return; + + DWORD dwDurationSave = m_AnimationParams.dwDuration; + if(pT->AreStatesEqual()) + m_AnimationParams.dwDuration = 0; + + HDC hdcFrom = NULL, hdcTo = NULL; + CBufferedAnimation ba; + if(IsBufferedPaintSupported()) + ba.Begin(pT->m_hWnd, dc, &rect, m_dwFormat, &m_PaintParams, &m_AnimationParams, &hdcFrom, &hdcTo); + + if(!ba.IsNull()) + { + if(hdcFrom != NULL) + pT->DoPaint(hdcFrom, rect, m_State); + + if (hdcTo != NULL) + pT->DoPaint(hdcTo, rect, m_NewState); + } + else + { + pT->DoPaint(dc.m_hDC, rect, m_NewState); + } + + m_AnimationParams.dwDuration = dwDurationSave; + } + + void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/, TState /*State*/) + { + // must be implemented in a derived class + ATLASSERT(FALSE); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedAnimationWindowImpl - implements a window that uses buffered animation + +template +class ATL_NO_VTABLE CBufferedAnimationWindowImpl : + public ATL::CWindowImpl, + public CBufferedAnimationImpl< T, TState > +{ +public: + CBufferedAnimationWindowImpl(TState InitialState) : CBufferedAnimationImpl< T, TState >(InitialState) + { } + + typedef CBufferedAnimationImpl< T, TState > _baseBufferedAnimation; + BEGIN_MSG_MAP(CBufferedAnimationWindowImpl) + CHAIN_MSG_MAP(_baseBufferedAnimation) + END_MSG_MAP() +}; + +#endif // defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600) + +}; // namespace WTL + +#endif // __ATLTHEME_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atluser.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atluser.h new file mode 100644 index 0000000000000000000000000000000000000000..24b9bd21767e75cbd04cedf3a6a56af3aee17b9f --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atluser.h @@ -0,0 +1,1387 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLUSER_H__ +#define __ATLUSER_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atluser.h requires atlapp.h to be included first +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CMenuItemInfo +// CMenuT +// CAcceleratorT +// CIconT +// CCursorT +// CResource +// +// Global functions: +// AtlMessageBox() +// +// AtlLoadAccelerators() +// AtlLoadMenu() +// AtlLoadBitmap() +// AtlLoadSysBitmap() +// AtlLoadCursor() +// AtlLoadSysCursor() +// AtlLoadIcon() +// AtlLoadSysIcon() +// AtlLoadBitmapImage() +// AtlLoadCursorImage() +// AtlLoadIconImage() +// AtlLoadSysBitmapImage() +// AtlLoadSysCursorImage() +// AtlLoadSysIconImage() +// AtlLoadString() + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// AtlMessageBox - accepts both memory and resource based strings + +inline int AtlMessageBox(HWND hWndOwner, ATL::_U_STRINGorID message, ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uType = MB_OK | MB_ICONINFORMATION) +{ + ATLASSERT(hWndOwner == NULL || ::IsWindow(hWndOwner)); + + LPTSTR lpstrMessage = NULL; + if(IS_INTRESOURCE(message.m_lpstr)) + { + for(int nLen = 256; ; nLen *= 2) + { + ATLTRY(lpstrMessage = new TCHAR[nLen]); + if(lpstrMessage == NULL) + { + ATLASSERT(FALSE); + return 0; + } + int nRes = ::LoadString(ModuleHelper::GetResourceInstance(), LOWORD(message.m_lpstr), lpstrMessage, nLen); + if(nRes < nLen - 1) + break; + delete [] lpstrMessage; + lpstrMessage = NULL; + } + + message.m_lpstr = lpstrMessage; + } + + LPTSTR lpstrTitle = NULL; + if(IS_INTRESOURCE(title.m_lpstr) && LOWORD(title.m_lpstr) != 0) + { + for(int nLen = 256; ; nLen *= 2) + { + ATLTRY(lpstrTitle = new TCHAR[nLen]); + if(lpstrTitle == NULL) + { + ATLASSERT(FALSE); + return 0; + } + int nRes = ::LoadString(ModuleHelper::GetResourceInstance(), LOWORD(title.m_lpstr), lpstrTitle, nLen); + if(nRes < nLen - 1) + break; + delete [] lpstrTitle; + lpstrTitle = NULL; + } + + title.m_lpstr = lpstrTitle; + } + + int nRet = ::MessageBox(hWndOwner, message.m_lpstr, title.m_lpstr, uType); + + delete [] lpstrMessage; + delete [] lpstrTitle; + + return nRet; +} + + +/////////////////////////////////////////////////////////////////////////////// +// CMenu + +#if (WINVER >= 0x0500) + #ifndef MII_SIZEOF_STRUCT + #define MII_SIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) + #endif + #define MENUITEMINFO_SIZE_VERSION_400A MII_SIZEOF_STRUCT(MENUITEMINFOA, cch) + #define MENUITEMINFO_SIZE_VERSION_400W MII_SIZEOF_STRUCT(MENUITEMINFOW, cch) + #ifdef UNICODE + #define MENUITEMINFO_SIZE_VERSION_400 MENUITEMINFO_SIZE_VERSION_400W + #else + #define MENUITEMINFO_SIZE_VERSION_400 MENUITEMINFO_SIZE_VERSION_400A + #endif // !UNICODE +#endif // (WINVER >= 0x0500) + +class CMenuItemInfo : public MENUITEMINFO +{ +public: + CMenuItemInfo() + { + memset(this, 0, sizeof(MENUITEMINFO)); + cbSize = sizeof(MENUITEMINFO); +#if (WINVER >= 0x0500) + // adjust struct size if running on older version of Windows + if(AtlIsOldWindows()) + { + ATLASSERT(cbSize > MENUITEMINFO_SIZE_VERSION_400); // must be + cbSize = MENUITEMINFO_SIZE_VERSION_400; + } +#endif // (WINVER >= 0x0500) + } +}; + + +// forward declarations +template class CMenuT; +typedef CMenuT CMenuHandle; +typedef CMenuT CMenu; + + +template +class CMenuT +{ +public: +// Data members + HMENU m_hMenu; + +// Constructor/destructor/operators + CMenuT(HMENU hMenu = NULL) : m_hMenu(hMenu) + { } + + ~CMenuT() + { + if(t_bManaged && m_hMenu != NULL) + DestroyMenu(); + } + + CMenuT& operator =(HMENU hMenu) + { + Attach(hMenu); + return *this; + } + + void Attach(HMENU hMenuNew) + { + ATLASSERT(::IsMenu(hMenuNew)); + if(t_bManaged && m_hMenu != NULL && m_hMenu != hMenuNew) + ::DestroyMenu(m_hMenu); + m_hMenu = hMenuNew; + } + + HMENU Detach() + { + HMENU hMenu = m_hMenu; + m_hMenu = NULL; + return hMenu; + } + + operator HMENU() const { return m_hMenu; } + + bool IsNull() const { return (m_hMenu == NULL); } + + BOOL IsMenu() const + { + return ::IsMenu(m_hMenu); + } + +// Create/destroy methods + BOOL CreateMenu() + { + ATLASSERT(m_hMenu == NULL); + m_hMenu = ::CreateMenu(); + return (m_hMenu != NULL) ? TRUE : FALSE; + } + + BOOL CreatePopupMenu() + { + ATLASSERT(m_hMenu == NULL); + m_hMenu = ::CreatePopupMenu(); + return (m_hMenu != NULL) ? TRUE : FALSE; + } + + BOOL LoadMenu(ATL::_U_STRINGorID menu) + { + ATLASSERT(m_hMenu == NULL); + m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr); + return (m_hMenu != NULL) ? TRUE : FALSE; + } + +#ifndef _WIN32_WCE + BOOL LoadMenuIndirect(const void* lpMenuTemplate) + { + ATLASSERT(m_hMenu == NULL); + m_hMenu = ::LoadMenuIndirect(lpMenuTemplate); + return (m_hMenu != NULL) ? TRUE : FALSE; + } +#endif // !_WIN32_WCE + + BOOL DestroyMenu() + { + if (m_hMenu == NULL) + return FALSE; + BOOL bRet = ::DestroyMenu(m_hMenu); + if(bRet) + m_hMenu = NULL; + return bRet; + } + +// Menu Operations + BOOL DeleteMenu(UINT nPosition, UINT nFlags) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::DeleteMenu(m_hMenu, nPosition, nFlags); + } + + BOOL TrackPopupMenu(UINT nFlags, int x, int y, HWND hWnd, LPCRECT lpRect = NULL) + { + ATLASSERT(::IsMenu(m_hMenu)); +#ifndef _WIN32_WCE +#if (WINVER >= 0x0500) + x = _FixTrackMenuPopupX(x, y); +#endif // !(WINVER >= 0x0500) + return ::TrackPopupMenu(m_hMenu, nFlags, x, y, 0, hWnd, lpRect); +#else // CE specific + lpRect; + return ::TrackPopupMenuEx(m_hMenu, nFlags, x, y, hWnd, NULL); +#endif // _WIN32_WCE + } + + BOOL TrackPopupMenuEx(UINT uFlags, int x, int y, HWND hWnd, LPTPMPARAMS lptpm = NULL) + { + ATLASSERT(::IsMenu(m_hMenu)); +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + x = _FixTrackMenuPopupX(x, y); +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) + return ::TrackPopupMenuEx(m_hMenu, uFlags, x, y, hWnd, lptpm); + } + +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + // helper that fixes popup menu X position when it's off-screen + static int _FixTrackMenuPopupX(int x, int y) + { + POINT pt = { x, y }; + HMONITOR hMonitor = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONULL); + if(hMonitor == NULL) + { + HMONITOR hMonitorNear = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); + if(hMonitorNear != NULL) + { + MONITORINFO mi = { sizeof(MONITORINFO) }; + if(::GetMonitorInfo(hMonitorNear, &mi) != FALSE) + { + if(x < mi.rcWork.left) + x = mi.rcWork.left; + else if(x > mi.rcWork.right) + x = mi.rcWork.right; + } + } + } + + return x; + } + + BOOL GetMenuInfo(LPMENUINFO lpMenuInfo) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuInfo(m_hMenu, lpMenuInfo); + } + + BOOL SetMenuInfo(LPCMENUINFO lpMenuInfo) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::SetMenuInfo(m_hMenu, lpMenuInfo); + } +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) + +// Menu Item Operations + BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::AppendMenu(m_hMenu, nFlags, nIDNewItem, lpszNewItem); + } + + BOOL AppendMenu(UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem) + { + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(::IsMenu(hSubMenu)); + return ::AppendMenu(m_hMenu, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem); + } + +#ifndef _WIN32_WCE + BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::AppendMenu(m_hMenu, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp); + } + + BOOL AppendMenu(UINT nFlags, HMENU hSubMenu, HBITMAP hBmp) + { + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(::IsMenu(hSubMenu)); + return ::AppendMenu(m_hMenu, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp); + } +#endif // !_WIN32_WCE + + UINT CheckMenuItem(UINT nIDCheckItem, UINT nCheck) + { + ATLASSERT(::IsMenu(m_hMenu)); + return (UINT)::CheckMenuItem(m_hMenu, nIDCheckItem, nCheck); + } + + UINT EnableMenuItem(UINT nIDEnableItem, UINT nEnable) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::EnableMenuItem(m_hMenu, nIDEnableItem, nEnable); + } + +#ifndef _WIN32_WCE + BOOL HiliteMenuItem(HWND hWnd, UINT uIDHiliteItem, UINT uHilite) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::HiliteMenuItem(hWnd, m_hMenu, uIDHiliteItem, uHilite); + } + + int GetMenuItemCount() const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuItemCount(m_hMenu); + } + + UINT GetMenuItemID(int nPos) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuItemID(m_hMenu, nPos); + } + + UINT GetMenuState(UINT nID, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuState(m_hMenu, nID, nFlags); + } + + int GetMenuString(UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuString(m_hMenu, nIDItem, lpString, nMaxCount, nFlags); + } + + int GetMenuStringLen(UINT nIDItem, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuString(m_hMenu, nIDItem, NULL, 0, nFlags); + } + +#ifndef _ATL_NO_COM + BOOL GetMenuString(UINT nIDItem, BSTR& bstrText, UINT nFlags) const + { + USES_CONVERSION; + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(bstrText == NULL); + + int nLen = GetMenuStringLen(nIDItem, nFlags); + if(nLen == 0) + { + bstrText = ::SysAllocString(OLESTR("")); + return (bstrText != NULL) ? TRUE : FALSE; + } + + nLen++; // increment to include terminating NULL char + CTempBuffer buff; + LPTSTR lpszText = buff.Allocate(nLen); + if(lpszText == NULL) + return FALSE; + + if(!GetMenuString(nIDItem, lpszText, nLen, nFlags)) + return FALSE; + + bstrText = ::SysAllocString(T2OLE(lpszText)); + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#elif (_ATL_VER >= 0x0800) + int GetMenuItemCount() const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ATL::GetMenuItemCount(m_hMenu); + } + + UINT GetMenuItemID(int nPos) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ATL::GetMenuItemID(m_hMenu, nPos); + } + + UINT GetMenuState(UINT nID, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ATL::GetMenuState(m_hMenu, nID, nFlags); + } + + int GetMenuString(UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ATL::GetMenuString(m_hMenu, nIDItem, lpString, nMaxCount, nFlags); + } + + int GetMenuStringLen(UINT nIDItem, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ATL::GetMenuString(m_hMenu, nIDItem, NULL, 0, nFlags); + } +#endif // (_ATL_VER >= 0x0800) + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetMenuString(UINT nIDItem, _CSTRING_NS::CString& strText, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + + int nLen = GetMenuStringLen(nIDItem, nFlags); + if(nLen == 0) + return 0; + + nLen++; // increment to include terminating NULL char + LPTSTR lpstr = strText.GetBufferSetLength(nLen); + if(lpstr == NULL) + return 0; + int nRet = GetMenuString(nIDItem, lpstr, nLen, nFlags); + strText.ReleaseBuffer(); + return nRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + CMenuHandle GetSubMenu(int nPos) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return CMenuHandle(::GetSubMenu(m_hMenu, nPos)); + } + + BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::InsertMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem); + } + + BOOL InsertMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem) + { + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(::IsMenu(hSubMenu)); + return ::InsertMenu(m_hMenu, nPosition, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem); + } + +#ifndef _WIN32_WCE + BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::InsertMenu(m_hMenu, nPosition, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp); + } + + BOOL InsertMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, HBITMAP hBmp) + { + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(::IsMenu(hSubMenu)); + return ::InsertMenu(m_hMenu, nPosition, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp); + } + + BOOL ModifyMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::ModifyMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem); + } + + BOOL ModifyMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem) + { + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(::IsMenu(hSubMenu)); + return ::ModifyMenu(m_hMenu, nPosition, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem); + } + + BOOL ModifyMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::ModifyMenu(m_hMenu, nPosition, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp); + } + + BOOL ModifyMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, HBITMAP hBmp) + { + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(::IsMenu(hSubMenu)); + return ::ModifyMenu(m_hMenu, nPosition, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp); + } +#endif // !_WIN32_WCE + + BOOL RemoveMenu(UINT nPosition, UINT nFlags) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::RemoveMenu(m_hMenu, nPosition, nFlags); + } + +#ifndef _WIN32_WCE + BOOL SetMenuItemBitmaps(UINT nPosition, UINT nFlags, HBITMAP hBmpUnchecked, HBITMAP hBmpChecked) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::SetMenuItemBitmaps(m_hMenu, nPosition, nFlags, hBmpUnchecked, hBmpChecked); + } +#endif // !_WIN32_WCE + + BOOL CheckMenuRadioItem(UINT nIDFirst, UINT nIDLast, UINT nIDItem, UINT nFlags) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::CheckMenuRadioItem(m_hMenu, nIDFirst, nIDLast, nIDItem, nFlags); + } + + BOOL GetMenuItemInfo(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return (BOOL)::GetMenuItemInfo(m_hMenu, uItem, bByPosition, lpmii); + } + + BOOL SetMenuItemInfo(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii) + { + ATLASSERT(::IsMenu(m_hMenu)); + return (BOOL)::SetMenuItemInfo(m_hMenu, uItem, bByPosition, lpmii); + } + +#ifndef _WIN32_WCE + BOOL InsertMenuItem(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii) + { + ATLASSERT(::IsMenu(m_hMenu)); + return (BOOL)::InsertMenuItem(m_hMenu, uItem, bByPosition, lpmii); + } + + UINT GetMenuDefaultItem(BOOL bByPosition = FALSE, UINT uFlags = 0U) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuDefaultItem(m_hMenu, (UINT)bByPosition, uFlags); + } + + BOOL SetMenuDefaultItem(UINT uItem = (UINT)-1, BOOL bByPosition = FALSE) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::SetMenuDefaultItem(m_hMenu, uItem, (UINT)bByPosition); + } + + BOOL GetMenuItemRect(HWND hWnd, UINT uItem, LPRECT lprcItem) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuItemRect(hWnd, m_hMenu, uItem, lprcItem); + } + + int MenuItemFromPoint(HWND hWnd, POINT point) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::MenuItemFromPoint(hWnd, m_hMenu, point); + } + +// Context Help Functions + BOOL SetMenuContextHelpId(DWORD dwContextHelpId) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::SetMenuContextHelpId(m_hMenu, dwContextHelpId); + } + + DWORD GetMenuContextHelpId() const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuContextHelpId(m_hMenu); + } +#endif // !_WIN32_WCE +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAccelerator + +template +class CAcceleratorT +{ +public: + HACCEL m_hAccel; + +// Constructor/destructor/operators + CAcceleratorT(HACCEL hAccel = NULL) : m_hAccel(hAccel) + { } + + ~CAcceleratorT() + { + if(t_bManaged && m_hAccel != NULL) + ::DestroyAcceleratorTable(m_hAccel); + } + + CAcceleratorT& operator =(HACCEL hAccel) + { + Attach(hAccel); + return *this; + } + + void Attach(HACCEL hAccel) + { + if(t_bManaged && m_hAccel != NULL) + ::DestroyAcceleratorTable(m_hAccel); + m_hAccel = hAccel; + } + + HACCEL Detach() + { + HACCEL hAccel = m_hAccel; + m_hAccel = NULL; + return hAccel; + } + + operator HACCEL() const { return m_hAccel; } + + bool IsNull() const { return m_hAccel == NULL; } + +// Create/destroy methods + HACCEL LoadAccelerators(ATL::_U_STRINGorID accel) + { + ATLASSERT(m_hAccel == NULL); + m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), accel.m_lpstr); + return m_hAccel; + } + + HACCEL CreateAcceleratorTable(LPACCEL pAccel, int cEntries) + { + ATLASSERT(m_hAccel == NULL); + ATLASSERT(pAccel != NULL); + m_hAccel = ::CreateAcceleratorTable(pAccel, cEntries); + return m_hAccel; + } + + void DestroyObject() + { + if(m_hAccel != NULL) + { + ::DestroyAcceleratorTable(m_hAccel); + m_hAccel = NULL; + } + } + +// Operations +#ifndef _WIN32_WCE + int CopyAcceleratorTable(LPACCEL lpAccelDst, int cEntries) + { + ATLASSERT(m_hAccel != NULL); + ATLASSERT(lpAccelDst != NULL); + return ::CopyAcceleratorTable(m_hAccel, lpAccelDst, cEntries); + } + + int GetEntriesCount() const + { + ATLASSERT(m_hAccel != NULL); + return ::CopyAcceleratorTable(m_hAccel, NULL, 0); + } +#endif // !_WIN32_WCE + + BOOL TranslateAccelerator(HWND hWnd, LPMSG pMsg) + { + ATLASSERT(m_hAccel != NULL); + ATLASSERT(::IsWindow(hWnd)); + ATLASSERT(pMsg != NULL); + return ::TranslateAccelerator(hWnd, m_hAccel, pMsg); + } +}; + +typedef CAcceleratorT CAcceleratorHandle; +typedef CAcceleratorT CAccelerator; + + +/////////////////////////////////////////////////////////////////////////////// +// CIcon + +template +class CIconT +{ +public: + HICON m_hIcon; + +// Constructor/destructor/operators + CIconT(HICON hIcon = NULL) : m_hIcon(hIcon) + { } + + ~CIconT() + { + if(t_bManaged && m_hIcon != NULL) + ::DestroyIcon(m_hIcon); + } + + CIconT& operator =(HICON hIcon) + { + Attach(hIcon); + return *this; + } + + void Attach(HICON hIcon) + { + if(t_bManaged && m_hIcon != NULL) + ::DestroyIcon(m_hIcon); + m_hIcon = hIcon; + } + + HICON Detach() + { + HICON hIcon = m_hIcon; + m_hIcon = NULL; + return hIcon; + } + + operator HICON() const { return m_hIcon; } + + bool IsNull() const { return m_hIcon == NULL; } + +// Create/destroy methods + HICON LoadIcon(ATL::_U_STRINGorID icon) + { + ATLASSERT(m_hIcon == NULL); + m_hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr); + return m_hIcon; + } + + HICON LoadIcon(ATL::_U_STRINGorID icon, int cxDesired, int cyDesired, UINT fuLoad = 0) + { + ATLASSERT(m_hIcon == NULL); + m_hIcon = (HICON) ::LoadImage(ModuleHelper::GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad); + return m_hIcon; + } + +#ifndef _WIN32_WCE + HICON LoadOEMIcon(LPCTSTR lpstrIconName) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(IsOEMIcon(lpstrIconName)); + m_hIcon = ::LoadIcon(NULL, lpstrIconName); + return m_hIcon; + } + + HICON CreateIcon(int nWidth, int nHeight, BYTE cPlanes, BYTE cBitsPixel, CONST BYTE* lpbANDbits, CONST BYTE *lpbXORbits) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(lpbANDbits != NULL); + ATLASSERT(lpbXORbits != NULL); + m_hIcon = ::CreateIcon(ModuleHelper::GetResourceInstance(), nWidth, nHeight, cPlanes, cBitsPixel, lpbANDbits, lpbXORbits); + return m_hIcon; + } + + HICON CreateIconFromResource(PBYTE pBits, DWORD dwResSize, DWORD dwVersion = 0x00030000) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(pBits != NULL); + m_hIcon = ::CreateIconFromResource(pBits, dwResSize, TRUE, dwVersion); + return m_hIcon; + } + + HICON CreateIconFromResourceEx(PBYTE pbBits, DWORD cbBits, DWORD dwVersion = 0x00030000, int cxDesired = 0, int cyDesired = 0, UINT uFlags = LR_DEFAULTCOLOR) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(pbBits != NULL); + ATLASSERT(cbBits > 0); + m_hIcon = ::CreateIconFromResourceEx(pbBits, cbBits, TRUE, dwVersion, cxDesired, cyDesired, uFlags); + return m_hIcon; + } +#endif // !_WIN32_WCE + + HICON CreateIconIndirect(PICONINFO pIconInfo) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(pIconInfo != NULL); + m_hIcon = ::CreateIconIndirect(pIconInfo); + return m_hIcon; + } + +#ifndef _WIN32_WCE + HICON ExtractIcon(LPCTSTR lpszExeFileName, UINT nIconIndex) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(lpszExeFileName != NULL); + m_hIcon = ::ExtractIcon(ModuleHelper::GetModuleInstance(), lpszExeFileName, nIconIndex); + return m_hIcon; + } + + HICON ExtractAssociatedIcon(HINSTANCE hInst, LPTSTR lpIconPath, LPWORD lpiIcon) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(lpIconPath != NULL); + ATLASSERT(lpiIcon != NULL); + m_hIcon = ::ExtractAssociatedIcon(hInst, lpIconPath, lpiIcon); + return m_hIcon; + } +#endif // !_WIN32_WCE + + BOOL DestroyIcon() + { + ATLASSERT(m_hIcon != NULL); + BOOL bRet = ::DestroyIcon(m_hIcon); + if(bRet != FALSE) + m_hIcon = NULL; + return bRet; + } + +// Operations +#ifndef _WIN32_WCE + HICON CopyIcon() + { + ATLASSERT(m_hIcon != NULL); + return ::CopyIcon(m_hIcon); + } + + HICON DuplicateIcon() + { + ATLASSERT(m_hIcon != NULL); + return ::DuplicateIcon(NULL, m_hIcon); + } +#endif // !_WIN32_WCE + + BOOL DrawIcon(HDC hDC, int x, int y) + { + ATLASSERT(m_hIcon != NULL); +#ifndef _WIN32_WCE + return ::DrawIcon(hDC, x, y, m_hIcon); +#else // CE specific + return ::DrawIconEx(hDC, x, y, m_hIcon, 0, 0, 0, NULL, DI_NORMAL); +#endif // _WIN32_WCE + } + + BOOL DrawIcon(HDC hDC, POINT pt) + { + ATLASSERT(m_hIcon != NULL); +#ifndef _WIN32_WCE + return ::DrawIcon(hDC, pt.x, pt.y, m_hIcon); +#else // CE specific + return ::DrawIconEx(hDC, pt.x, pt.y, m_hIcon, 0, 0, 0, NULL, DI_NORMAL); +#endif // _WIN32_WCE + } + + BOOL DrawIconEx(HDC hDC, int x, int y, int cxWidth, int cyWidth, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) + { + ATLASSERT(m_hIcon != NULL); + return ::DrawIconEx(hDC, x, y, m_hIcon, cxWidth, cyWidth, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); + } + + BOOL DrawIconEx(HDC hDC, POINT pt, SIZE size, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) + { + ATLASSERT(m_hIcon != NULL); + return ::DrawIconEx(hDC, pt.x, pt.y, m_hIcon, size.cx, size.cy, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); + } + +#ifndef _WIN32_WCE + BOOL GetIconInfo(PICONINFO pIconInfo) const + { + ATLASSERT(m_hIcon != NULL); + ATLASSERT(pIconInfo != NULL); + return ::GetIconInfo(m_hIcon, pIconInfo); + } + +#if (_WIN32_WINNT >= 0x0600) + BOOL GetIconInfoEx(PICONINFOEX pIconInfo) const + { + ATLASSERT(m_hIcon != NULL); + ATLASSERT(pIconInfo != NULL); + return ::GetIconInfoEx(m_hIcon, pIconInfo); + } +#endif // (_WIN32_WINNT >= 0x0600) + +#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + HRESULT LoadIconMetric(ATL::_U_STRINGorID icon, int lims) + { + ATLASSERT(m_hIcon == NULL); + USES_CONVERSION; + return ::LoadIconMetric(ModuleHelper::GetResourceInstance(), T2CW(icon.m_lpstr), lims, &m_hIcon); + } + + HRESULT LoadIconWithScaleDown(ATL::_U_STRINGorID icon, int cx, int cy) + { + ATLASSERT(m_hIcon == NULL); + USES_CONVERSION; + return ::LoadIconWithScaleDown(ModuleHelper::GetResourceInstance(), T2CW(icon.m_lpstr), cx, cy, &m_hIcon); + } + + HRESULT LoadOEMIconMetric(LPCTSTR lpstrIconName, int lims) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(IsOEMIcon(lpstrIconName)); + return ::LoadIconMetric(NULL, (LPCWSTR)lpstrIconName, lims, &m_hIcon); + } + + HRESULT LoadOEMIconWithScaleDown(LPCTSTR lpstrIconName, int cx, int cy) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(IsOEMIcon(lpstrIconName)); + USES_CONVERSION; + return ::LoadIconWithScaleDown(NULL, (LPCWSTR)lpstrIconName, cx, cy, &m_hIcon); + } +#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) +#endif // !_WIN32_WCE + + // Helper +#ifndef _WIN32_WCE + static bool IsOEMIcon(LPCTSTR lpstrIconName) + { +#if (WINVER >= 0x0600) + return (lpstrIconName == IDI_APPLICATION || lpstrIconName == IDI_ASTERISK || lpstrIconName == IDI_EXCLAMATION || + lpstrIconName == IDI_HAND || lpstrIconName == IDI_QUESTION || lpstrIconName == IDI_WINLOGO || + lpstrIconName == IDI_SHIELD); +#else // !(WINVER >= 0x0600) + return (lpstrIconName == IDI_APPLICATION || lpstrIconName == IDI_ASTERISK || lpstrIconName == IDI_EXCLAMATION || + lpstrIconName == IDI_HAND || lpstrIconName == IDI_QUESTION || lpstrIconName == IDI_WINLOGO); +#endif // !(WINVER >= 0x0600) + } +#endif // !_WIN32_WCE +}; + +typedef CIconT CIconHandle; +typedef CIconT CIcon; + + +/////////////////////////////////////////////////////////////////////////////// +// CCursor + +// protect template member from a winuser.h macro +#ifdef CopyCursor + #undef CopyCursor +#endif + +template +class CCursorT +{ +public: + HCURSOR m_hCursor; + +// Constructor/destructor/operators + CCursorT(HCURSOR hCursor = NULL) : m_hCursor(hCursor) + { } + + ~CCursorT() + { + if(t_bManaged && m_hCursor != NULL) + DestroyCursor(); + } + + CCursorT& operator =(HCURSOR hCursor) + { + Attach(hCursor); + return *this; + } + + void Attach(HCURSOR hCursor) + { + if(t_bManaged && m_hCursor != NULL) + DestroyCursor(); + m_hCursor = hCursor; + } + + HCURSOR Detach() + { + HCURSOR hCursor = m_hCursor; + m_hCursor = NULL; + return hCursor; + } + + operator HCURSOR() const { return m_hCursor; } + + bool IsNull() const { return m_hCursor == NULL; } + +// Create/destroy methods + HCURSOR LoadCursor(ATL::_U_STRINGorID cursor) + { + ATLASSERT(m_hCursor == NULL); + m_hCursor = ::LoadCursor(ModuleHelper::GetResourceInstance(), cursor.m_lpstr); + return m_hCursor; + } + + HCURSOR LoadSysCursor(LPCTSTR lpstrCursorName) + { + ATLASSERT(m_hCursor == NULL); +#if (WINVER >= 0x0500) + ATLASSERT(lpstrCursorName == IDC_ARROW || lpstrCursorName == IDC_IBEAM || lpstrCursorName == IDC_WAIT || + lpstrCursorName == IDC_CROSS || lpstrCursorName == IDC_UPARROW || lpstrCursorName == IDC_SIZE || + lpstrCursorName == IDC_ICON || lpstrCursorName == IDC_SIZENWSE || lpstrCursorName == IDC_SIZENESW || + lpstrCursorName == IDC_SIZEWE || lpstrCursorName == IDC_SIZENS || lpstrCursorName == IDC_SIZEALL || + lpstrCursorName == IDC_NO || lpstrCursorName == IDC_APPSTARTING || lpstrCursorName == IDC_HELP || + lpstrCursorName == IDC_HAND); +#else // !(WINVER >= 0x0500) + ATLASSERT(lpstrCursorName == IDC_ARROW || lpstrCursorName == IDC_IBEAM || lpstrCursorName == IDC_WAIT || + lpstrCursorName == IDC_CROSS || lpstrCursorName == IDC_UPARROW || lpstrCursorName == IDC_SIZE || + lpstrCursorName == IDC_ICON || lpstrCursorName == IDC_SIZENWSE || lpstrCursorName == IDC_SIZENESW || + lpstrCursorName == IDC_SIZEWE || lpstrCursorName == IDC_SIZENS || lpstrCursorName == IDC_SIZEALL || + lpstrCursorName == IDC_NO || lpstrCursorName == IDC_APPSTARTING || lpstrCursorName == IDC_HELP); +#endif // !(WINVER >= 0x0500) + m_hCursor = ::LoadCursor(NULL, lpstrCursorName); + return m_hCursor; + } + + // deprecated + HCURSOR LoadOEMCursor(LPCTSTR lpstrCursorName) + { + return LoadSysCursor(lpstrCursorName); + } + + HCURSOR LoadCursor(ATL::_U_STRINGorID cursor, int cxDesired, int cyDesired, UINT fuLoad = 0) + { + ATLASSERT(m_hCursor == NULL); + m_hCursor = (HCURSOR) ::LoadImage(ModuleHelper::GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad); + return m_hCursor; + } + +#ifndef _WIN32_WCE + HCURSOR LoadCursorFromFile(LPCTSTR pstrFilename) + { + ATLASSERT(m_hCursor == NULL); + ATLASSERT(pstrFilename != NULL); + m_hCursor = ::LoadCursorFromFile(pstrFilename); + return m_hCursor; + } +#endif // !_WIN32_WCE + +#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) + HCURSOR CreateCursor(int xHotSpot, int yHotSpot, int nWidth, int nHeight, CONST VOID *pvANDPlane, CONST VOID *pvXORPlane) + { + ATLASSERT(m_hCursor == NULL); + m_hCursor = ::CreateCursor(ModuleHelper::GetResourceInstance(), xHotSpot, yHotSpot, nWidth, nHeight, pvANDPlane, pvXORPlane); + return m_hCursor; + } +#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) + +#ifndef _WIN32_WCE + HCURSOR CreateCursorFromResource(PBYTE pBits, DWORD dwResSize, DWORD dwVersion = 0x00030000) + { + ATLASSERT(m_hCursor == NULL); + ATLASSERT(pBits != NULL); + m_hCursor = (HCURSOR)::CreateIconFromResource(pBits, dwResSize, FALSE, dwVersion); + return m_hCursor; + } + + HCURSOR CreateCursorFromResourceEx(PBYTE pbBits, DWORD cbBits, DWORD dwVersion = 0x00030000, int cxDesired = 0, int cyDesired = 0, UINT uFlags = LR_DEFAULTCOLOR) + { + ATLASSERT(m_hCursor == NULL); + ATLASSERT(pbBits != NULL); + ATLASSERT(cbBits > 0); + m_hCursor = (HCURSOR)::CreateIconFromResourceEx(pbBits, cbBits, FALSE, dwVersion, cxDesired, cyDesired, uFlags); + return m_hCursor; + } +#endif // !_WIN32_WCE + + BOOL DestroyCursor() + { + ATLASSERT(m_hCursor != NULL); +#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) + BOOL bRet = ::DestroyCursor(m_hCursor); + if(bRet != FALSE) + m_hCursor = NULL; + return bRet; +#else // !(!defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))) + ATLTRACE2(atlTraceUI, 0, _T("Warning: This version of Windows CE does not have ::DestroyCursor()\n")); + return FALSE; +#endif // !(!defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))) + } + +// Operations +#ifndef _WIN32_WCE + HCURSOR CopyCursor() + { + ATLASSERT(m_hCursor != NULL); + return (HCURSOR)::CopyIcon((HICON)m_hCursor); + } +#endif // !_WIN32_WCE + +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + BOOL GetCursorInfo(LPCURSORINFO pCursorInfo) + { + ATLASSERT(m_hCursor != NULL); + ATLASSERT(pCursorInfo != NULL); + return ::GetCursorInfo(pCursorInfo); + } +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) +}; + +typedef CCursorT CCursorHandle; +typedef CCursorT CCursor; + + +/////////////////////////////////////////////////////////////////////////////// +// CResource - Wraps a generic Windows resource. +// Use it with custom resource types other than the +// standard RT_CURSOR, RT_BITMAP, etc. + +class CResource +{ +public: + HGLOBAL m_hGlobal; + HRSRC m_hResource; + +// Constructor/destructor + CResource() : m_hGlobal(NULL), m_hResource(NULL) + { } + + ~CResource() + { + Release(); + } + +// Load methods + bool Load(ATL::_U_STRINGorID Type, ATL::_U_STRINGorID ID) + { + ATLASSERT(m_hResource == NULL); + ATLASSERT(m_hGlobal == NULL); + + m_hResource = ::FindResource(ModuleHelper::GetResourceInstance(), ID.m_lpstr, Type.m_lpstr); + if(m_hResource == NULL) + return false; + + m_hGlobal = ::LoadResource(ModuleHelper::GetResourceInstance(), m_hResource); + if(m_hGlobal == NULL) + { + m_hResource = NULL; + return false; + } + + return true; + } + +#ifndef _WIN32_WCE + bool LoadEx(ATL::_U_STRINGorID ID, ATL::_U_STRINGorID Type, WORD wLanguage) + { + ATLASSERT(m_hResource == NULL); + ATLASSERT(m_hGlobal == NULL); + + m_hResource = ::FindResourceEx(ModuleHelper::GetResourceInstance(), Type.m_lpstr, ID.m_lpstr, wLanguage); + if(m_hResource == NULL) + return false; + + m_hGlobal = ::LoadResource(ModuleHelper::GetResourceInstance(), m_hResource); + if(m_hGlobal == NULL) + { + m_hResource = NULL; + return false; + } + + return true; + } +#endif // !_WIN32_WCE + +// Misc. operations + DWORD GetSize() const + { + ATLASSERT(m_hResource != NULL); + return ::SizeofResource(ModuleHelper::GetResourceInstance(), m_hResource); + } + + LPVOID Lock() + { + ATLASSERT(m_hResource != NULL); + ATLASSERT(m_hGlobal != NULL); + LPVOID pVoid = ::LockResource(m_hGlobal); + ATLASSERT(pVoid != NULL); + return pVoid; + } + + void Release() + { + if(m_hGlobal != NULL) + { + FreeResource(m_hGlobal); + m_hGlobal = NULL; + m_hResource = NULL; + } + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Toolbar resource descriptor + +struct _AtlToolBarData +{ + WORD wVersion; + WORD wWidth; + WORD wHeight; + WORD wItemCount; + + WORD* items() + { return (WORD*)(this+1); } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Global functions for loading resources + +inline HACCEL AtlLoadAccelerators(ATL::_U_STRINGorID table) +{ + return ::LoadAccelerators(ModuleHelper::GetResourceInstance(), table.m_lpstr); +} + +inline HMENU AtlLoadMenu(ATL::_U_STRINGorID menu) +{ + return ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr); +} + +inline HBITMAP AtlLoadBitmap(ATL::_U_STRINGorID bitmap) +{ + return ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr); +} + +#ifdef OEMRESOURCE +inline HBITMAP AtlLoadSysBitmap(ATL::_U_STRINGorID bitmap) +{ +#ifdef _DEBUG + WORD wID = LOWORD(bitmap.m_lpstr); + ATLASSERT(wID >= 32734 && wID <= 32767); +#endif // _DEBUG + return ::LoadBitmap(NULL, bitmap.m_lpstr); +} +#endif // OEMRESOURCE + +inline HCURSOR AtlLoadCursor(ATL::_U_STRINGorID cursor) +{ + return ::LoadCursor(ModuleHelper::GetResourceInstance(), cursor.m_lpstr); +} + +inline HCURSOR AtlLoadSysCursor(LPCTSTR lpCursorName) +{ +#if (WINVER >= 0x0500) + ATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCursorName == IDC_WAIT || + lpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCursorName == IDC_SIZE || + lpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCursorName == IDC_SIZENESW || + lpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCursorName == IDC_SIZEALL || + lpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpCursorName == IDC_HELP || + lpCursorName == IDC_HAND); +#else // !(WINVER >= 0x0500) + ATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCursorName == IDC_WAIT || + lpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCursorName == IDC_SIZE || + lpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCursorName == IDC_SIZENESW || + lpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCursorName == IDC_SIZEALL || + lpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpCursorName == IDC_HELP); +#endif // !(WINVER >= 0x0500) + return ::LoadCursor(NULL, lpCursorName); +} + +inline HICON AtlLoadIcon(ATL::_U_STRINGorID icon) +{ + return ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr); +} + +#ifndef _WIN32_WCE +inline HICON AtlLoadSysIcon(LPCTSTR lpIconName) +{ +#if (WINVER >= 0x0600) + ATLASSERT(lpIconName == IDI_APPLICATION || lpIconName == IDI_ASTERISK || lpIconName == IDI_EXCLAMATION || + lpIconName == IDI_HAND || lpIconName == IDI_QUESTION || lpIconName == IDI_WINLOGO || + lpIconName == IDI_SHIELD); +#else // !(WINVER >= 0x0600) + ATLASSERT(lpIconName == IDI_APPLICATION || lpIconName == IDI_ASTERISK || lpIconName == IDI_EXCLAMATION || + lpIconName == IDI_HAND || lpIconName == IDI_QUESTION || lpIconName == IDI_WINLOGO); +#endif // !(WINVER >= 0x0600) + return ::LoadIcon(NULL, lpIconName); +} +#endif // !_WIN32_WCE + +inline HBITMAP AtlLoadBitmapImage(ATL::_U_STRINGorID bitmap, UINT fuLoad = LR_DEFAULTCOLOR) +{ + return (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr, IMAGE_BITMAP, 0, 0, fuLoad); +} + +inline HCURSOR AtlLoadCursorImage(ATL::_U_STRINGorID cursor, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0) +{ + return (HCURSOR)::LoadImage(ModuleHelper::GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad); +} + +inline HICON AtlLoadIconImage(ATL::_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0) +{ + return (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad); +} + +#ifdef OEMRESOURCE +inline HBITMAP AtlLoadSysBitmapImage(WORD wBitmapID, UINT fuLoad = LR_DEFAULTCOLOR) +{ + ATLASSERT(wBitmapID >= 32734 && wBitmapID <= 32767); + ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file + return (HBITMAP)::LoadImage(NULL, MAKEINTRESOURCE(wBitmapID), IMAGE_BITMAP, 0, 0, fuLoad); +} +#endif // OEMRESOURCE + +inline HCURSOR AtlLoadSysCursorImage(ATL::_U_STRINGorID cursor, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0) +{ +#ifdef _DEBUG + WORD wID = LOWORD(cursor.m_lpstr); + ATLASSERT((wID >= 32512 && wID <= 32516) || (wID >= 32640 && wID <= 32648) || (wID == 32650) || (wID == 32651)); + ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file +#endif // _DEBUG + return (HCURSOR)::LoadImage(NULL, cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad); +} + +inline HICON AtlLoadSysIconImage(ATL::_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0) +{ +#ifdef _DEBUG + WORD wID = LOWORD(icon.m_lpstr); + ATLASSERT(wID >= 32512 && wID <= 32517); + ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file +#endif // _DEBUG + return (HICON)::LoadImage(NULL, icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad); +} + +#if (_ATL_VER < 0x0700) +inline int AtlLoadString(UINT uID, LPTSTR lpBuffer, int nBufferMax) +{ + return ::LoadString(ModuleHelper::GetResourceInstance(), uID, lpBuffer, nBufferMax); +} +#else + +using ATL::AtlLoadString; + +#endif // (_ATL_VER < 0x0700) + +#ifdef _WIN32_WCE // CE only direct access to the resource +inline LPCTSTR AtlLoadString(UINT uID) +{ + LPCTSTR s = (LPCTSTR)::LoadString(ModuleHelper::GetResourceInstance(), uID, NULL, 0); +#ifdef DEBUG // Check for null-termination + if(s != NULL) + // Note: RC -n compiles null-terminated resource strings + ATLASSERT(s[*((WORD*)s -1) - 1] == L'\0'); +#endif + return s; +} +#endif // _WIN32_WCE + +inline bool AtlLoadString(UINT uID, BSTR& bstrText) +{ + USES_CONVERSION; + ATLASSERT(bstrText == NULL); + + LPTSTR lpstrText = NULL; + int nRes = 0; + for(int nLen = 256; ; nLen *= 2) + { + ATLTRY(lpstrText = new TCHAR[nLen]); + if(lpstrText == NULL) + break; + nRes = ::LoadString(ModuleHelper::GetResourceInstance(), uID, lpstrText, nLen); + if(nRes < nLen - 1) + break; + delete [] lpstrText; + lpstrText = NULL; + } + + if(lpstrText != NULL) + { + if(nRes != 0) + bstrText = ::SysAllocString(T2OLE(lpstrText)); + delete [] lpstrText; + } + + return (bstrText != NULL) ? true : false; +} + +}; // namespace WTL + +#endif // __ATLUSER_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlwince.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlwince.h new file mode 100644 index 0000000000000000000000000000000000000000..19f9e3fb298075e2f30fe8f5510d2b266420dd48 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlwince.h @@ -0,0 +1,2981 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLWINCE_H__ +#define __ATLWINCE_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atlwince.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlwince.h requires atlwin.h to be included first +#endif + +#ifndef _WIN32_WCE + #error atlwince.h compiles under Windows CE only +#endif + +#if (_WIN32_WCE < 300) + #error atlwince.h requires Windows CE 3.0 or higher. +#endif + +#if defined(WIN32_PLATFORM_WFSP) && _MSC_VER < 1400 // EVC compiling SmartPhone code + #if (WIN32_PLATFORM_WFSP < 200) + #error atlwince.h requires Smartphone 2003 or higher + #endif +#endif // WIN32_PLATFORM_WFSP + +#if defined(WIN32_PLATFORM_PSPC) && _MSC_VER < 1400 // EVC compiling Pocket PC code + #if (WIN32_PLATFORM_PSPC < 310) + #error atlwince.h requires Pocket PC 2002 or higher + #endif +#endif // WIN32_PLATFORM_PSPC + +#if !defined(_AYGSHELL_H_) && !defined(__AYGSHELL_H__) + #error atlwince.h requires aygshell.h to be included first +#else + #if defined(WIN32_PLATFORM_WFSP) && !defined(_TPCSHELL_H_) + #error SmartPhone dialog classes require tpcshell.h to be included first + #endif +#endif + +#if (_MSC_VER >= 1400) // VS2005 + #include + #define _WTL_CE_DRA +#endif // (_MSC_VER >= 1400) + +#if !defined(_WTL_CE_NO_DIALOGS) && !defined(__ATLFRAME_H__) + #error Orientation aware dialog classes require atlframe.h to be included first +#endif + +#if !defined(_WTL_CE_NO_APPWINDOW) && !defined(__ATLFRAME_H__) + #error Application window class require atlframe.h to be included first +#endif + +#if !defined(_WTL_CE_NO_ZOOMSCROLL) && !defined(__ATLSCRL_H__) + #error ZoomScroll implementation requires atlscrl.h to be included first +#endif + +#if !defined(_WTL_CE_NO_ZOOMSCROLL) + #if !(defined(__ATLTYPES_H__) || (defined(__ATLMISC_H__) && !defined(_WTL_NO_WTYPES))) + #error ZoomScroll requires _WTL_NO_WTYPES not to be defined and either atlmisc.h or atltypes.h to be included first + #endif // !(defined(__ATLTYPES_H__) || (defined(__ATLMISC_H__) && !defined(_WTL_NO_WTYPES))) +#endif // !defined(_WTL_CE_NO_ZOOMSCROLL) + +#if !defined(WIN32_PLATFORM_WFSP) && !defined(WIN32_PLATFORM_PSPC) + #define _WTL_CE_NO_CONTROLS +#endif // !defined(WIN32_PLATFORM_WFSP) && !defined(WIN32_PLATFORM_PSPC) + +#ifndef _WTL_CE_NO_CONTROLS + #ifndef __ATLCTRLS_H__ + #error The PPC/SmartPhone controls classes require atlctrls.h to be included first + #endif + + #include + #pragma comment(lib, "htmlview.lib") + + #include + #pragma comment(lib, "voicectl.lib") + + #ifdef WIN32_PLATFORM_PSPC + #include + #pragma comment(lib, "richink.lib") + + #include + #pragma comment(lib, "inkx.lib") + + #include + #pragma comment(lib, "doclist.lib") + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CStdDialogBase : Standard PPC/SmartPhone dialog base class +// CStdDialogImplBase - Base implementation of standard dialog +// CStdDialogImpl : Standard dialog implementation +// CStdIndirectDialogImpl - implementation of standard indirect PPC/SmartPhone dialog +// CStdAxDialogImpl : Standard AxDialog implementation +// CStdSimpleDialog : Standard simple dialog +// CStdDialogResizeImplBase - Base implementation of orientation resizing standard dialog +// CStdDialogResizeImpl : Orientation resizing standard dialog implementation +// CStdAxDialogResizeImpl - implementation of orientation resizing standard AxDialog +// CStdSimpleDialogResizeImpl : Standard resizing simple dialog implementation +// CStdOrientedDialogBase - Oriented PPC standard dialog base class +// CStdOrientedDialogImplBase - Oriented PPC standard dialog base implementation +// CStdOrientedDialogImpl : Oriented PPC standard dialog implementation +// CStdAxOrientedDialogImpl - Oriented PPC standard AxDialog implementation +// CStdSimpleOrientedDialog : Standard simple orientable dialog +// +// CAppInfoBase : Helper for application state save/restore to registry +// CAppInfoT : CAppInfoBase constructed from a CAppWindow +// CAppWindowBase : Base class for PPC/SmartPhone well-behaved application window or dialog +// CAppWindow : PPC/SmartPhone well-behaved application window class +// CAppDialog : PPC/SmartPhone well-behaved application dialog class +// CAppStdDialogImplBase - Base implementation of standard application dialogs +// CAppStdDialogImpl : Implementation of standard application dialog +// CAppStdDialogResizeImpl - implementation of orientation resizing standard application dialog +// CAppStdAxDialogImpl - Implementation of standard application AxDialog +// CAppStdAxDialogResizeImpl - implementation of orientation resizing standard application AxDialog +// CAppStdOrientedDialogImpl - implementation of oriented PPC standard application dialog +// CAppStdAxOrientedDialogImpl - implementation of oriented PPC standard application AxDialog +// +// CFullScreenFrame : Full screen frame class +// +// CZoomScrollImpl : WinCE zooming implementation +// +// CBottomTabViewImpl - CBottomTabView +// CHtmlCtrlT - CHtmlCtrl +// CRichInkCtrlT - CRichInkCtrl +// CInkXCtrlT - CInkXCtrl +// CVoiceRecorderCtrlT - CVoiceRecorderCtrl +// CDocListCtrlT - CDocListCtrl +// CCapEditT - CCapEdit +// CTTStaticT - CTTStatic +// CTTButtonT - CTTButton +// +// CSpinCtrlT - CSpinCtrl : SmartPhone specific UpDown control +// CSpinned : SmartPhone association of control and Spin +// CSpinListBox : SmartPhone spinned ListBox control +// CExpandListBox : SmartPhone expandable ListBox control +// CExpandEdit : SmartPhone expandable Edit control +// CExpandCapEdit : SmartPhone expandable CapEdit control +// +// Global functions: +// AtlCreateMenuBar() +// AtlCreateEmptyMenuBar() +// AtlIsEditFocus() +// AtlActivateBackKey() + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// MenuBar creation functions for property sheets and dialogs +// Frame windows use CreateSimpleCEMenuBar + +inline HWND AtlCreateMenuBar(SHMENUBARINFO& mbi) +{ + ATLASSERT(::IsWindow(mbi.hwndParent)); + ATLVERIFY(::SHCreateMenuBar(&mbi) != FALSE); + return mbi.hwndMB; +}; + +inline HWND AtlCreateMenuBar(HWND hWnd, UINT nToolBarId = ATL_IDW_TOOLBAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0, COLORREF clrBk = 0) +{ + SHMENUBARINFO mbi = { sizeof(mbi), hWnd, dwFlags, nToolBarId, ModuleHelper::GetResourceInstance(), nBmpId, cBmpImages, 0, clrBk }; + return AtlCreateMenuBar(mbi); +} + +inline HWND AtlCreateEmptyMenuBar(HWND hWnd, bool bSip = true) +{ + SHMENUBARINFO embi = { sizeof(SHMENUBARINFO), hWnd, SHCMBF_EMPTYBAR }; + if (!bSip) + embi.dwFlags |= SHCMBF_HIDESIPBUTTON; + + return AtlCreateMenuBar(embi); +} + +/////////////////////////////////////////////////////////////////////////////// +// Helper functions for SmartPhone back key handling + +inline bool AtlIsEditFocus() +{ + ATL::CWindow wCtrl = GetFocus(); + if (wCtrl.IsWindow()) + { + TCHAR szClassName[8] = {0}; + ATLVERIFY(::GetClassName(wCtrl.m_hWnd, szClassName, 8)); + return !_tcscmp(szClassName, _T("Edit")) || !_tcscmp(szClassName, WC_CAPEDIT); + } + return false; +} + +#if defined WIN32_PLATFORM_WFSP +inline void AtlActivateBackKey(HWND hMenuBar) +{ + ATLASSERT(::IsWindow(hMenuBar)); + ::SendMessage(hMenuBar, SHCMBM_OVERRIDEKEY, VK_TBACK, + MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, SHMBOF_NODEFAULT | SHMBOF_NOTIFY)); +} +#endif // WIN32_PLATFORM_WFSP + +// --- Standard PPC/SmartPhone dialogs --- + +#ifndef _WTL_CE_NO_DIALOGS + +/////////////////////////////////////////////////////////////////////////////// +// CStdDialogBase - base class for standard PPC/SmartPhone dialogs + +#define WTL_STD_SHIDIF SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN +#define WTL_SP_SHIDIF SHIDIF_SIZEDLGFULLSCREEN + +// Title setting macros +#define WTL_DLG_TITLEHEIGHT(iHeight) static const int GetTitleHeight(){return iHeight;} +#define WTL_DLG_NOTITLE WTL_DLG_TITLEHEIGHT(0) + +/////////////////////////////////////////////////////////////////////////////// +// CStdDialogBase - Base class for standard PPC/SmartPhone dialog + +template +class CStdDialogBase +{ +public: +#ifdef WIN32_PLATFORM_PSPC +// Pocket PC only Dialog title handling + const int nTitleHeight; + + CStdDialogBase() : nTitleHeight(T::GetTitleHeight()) + { } + +// Overloads + BOOL GetClientRect(LPRECT lpRect) + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + BOOL bRes = ::GetClientRect(pT->m_hWnd, lpRect); + if (nTitleHeight) + lpRect->top += nTitleHeight + 1; + return bRes; + } + + BOOL SetWindowText(LPCTSTR lpszString) + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + BOOL bRes = ::SetWindowText(pT->m_hWnd, lpszString); + if (nTitleHeight != 0) + pT->DoPaintTitle(); + return bRes; + } + +// Overrideables + static const int GetTitleHeight() + { + #ifdef _WTL_CE_DRA + return DRA::SCALEY(24); + #else // !_WTL_CE_DRA + CWindowDC dc(NULL); + return dc.GetDeviceCaps(LOGPIXELSY) >> 2; // LOGPIXELSY * 24 / 96, + #endif // !_WTL_CE_DRA + } + + // Title painting + bool DoPaintTitle() + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + TCHAR sTitle[48] = { 0 }; + + // Preparation + CPaintDC dc(pT->m_hWnd); + CFont fontTitle = AtlCreateBoldFont(); + CFontHandle fontOld = dc.SelectFont(fontTitle); + dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHT)); + int nLen = pT->GetWindowText(sTitle, 48); + int nWidth = dc.GetDeviceCaps(HORZRES); + + // Display title text + RECT rTitle = { 0, 0, nWidth, nTitleHeight }; + dc.FillRect(&rTitle, COLOR_3DHIGHLIGHT); + #ifdef _WTL_CE_DRA + rTitle.left = DRA::SCALEX(8); + #else // !_WTL_CE_DRA + rTitle.left = nTitleHeight / 3; // 8 == 24 / 3 + #endif // !_WTL_CE_DRA + dc.DrawText(sTitle, nLen, &rTitle, DT_VCENTER | DT_SINGLELINE); + dc.SelectFont(fontOld); + + // Draw bottom line, 2 pixels thick if HI_RES_AWARE + CPenHandle penOld = dc.SelectStockPen(BLACK_PEN); + POINT line[4] = {{0, nTitleHeight}, {nWidth, nTitleHeight}, {0, nTitleHeight - 1}, {nWidth, nTitleHeight - 1}}; + + #ifdef _WTL_CE_DRA + int nSeg = DRA::SCALEY(1); + #else // !_WTL_CE_DRA + int nSeg = nTitleHeight / 24; + #endif // !_WTL_CE_DRA + + dc.Polyline(line, nSeg <= 2 ? nSeg * 2 : 4); + dc.SelectPen(penOld); + + return false; + } + + // Title preparation: move the dialog controls down to make room for title + void DialogTitleInit() + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + + ATL::CWindow wCtl = pT->GetWindow(GW_CHILD); + while (wCtl.IsWindow()) + { + RECT rCtl = { 0 }; + wCtl.GetWindowRect(&rCtl); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rCtl, 2); + ::OffsetRect(&rCtl, 0, nTitleHeight); + wCtl.MoveWindow(&rCtl, FALSE); + wCtl = wCtl.GetWindow(GW_HWNDNEXT); + } + } + + // SIP management + void DoSipInfo() + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + + SIPINFO si = {sizeof(SIPINFO)}; + SipGetInfo(&si); + if ((si.fdwFlags & SIPF_ON) ^ SIPF_ON) + si.rcVisibleDesktop.bottom = si.rcSipRect.bottom; + pT->MoveWindow(&si.rcVisibleDesktop, FALSE); + } + +// Title painting handler + LRESULT OnPaintTitle(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + return bHandled = nTitleHeight ? pT->DoPaintTitle() : FALSE; + } + +// SIP handler + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + if (wParam == SPI_SETSIPINFO) + { + pT->DoSipInfo(); + return TRUE; + } + return bHandled = FALSE; + } + +#elif defined WIN32_PLATFORM_WFSP +// SmartPhone VK_TBACK key standard management + LRESULT OnHotKey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + const UINT uModif = (UINT)LOWORD(lParam); + const UINT uVirtKey = (UINT)HIWORD(lParam); + + if(uVirtKey == VK_TBACK) + if (AtlIsEditFocus()) + ::SHSendBackToFocusWindow(uMsg, wParam, lParam); + else if (uModif & MOD_KEYUP) + pT->StdCloseDialog(IDCANCEL); + return 1; + } + + // SmartPhone MenuBar and VK_TBACK key initialization + void StdSPInit() + { + T* pT = static_cast(this); + HWND hMenuBar = ::SHFindMenuBar(pT->m_hWnd); + + if (!hMenuBar && (t_shidiFlags & SHIDIF_DONEBUTTON)) + hMenuBar = CreateMenuBar(ATL_IDM_MENU_DONE); + + if(hMenuBar != NULL) + AtlActivateBackKey(hMenuBar); + } + + void SetStaticBold() + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + + CFontHandle fontBold = AtlCreateBoldFont(pT->GetFont()); + + ATL::CWindow wCtl = pT->GetWindow(GW_CHILD); + + while (wCtl.IsWindow()) + { + if ((short int)wCtl.GetDlgCtrlID() == IDC_STATIC) + wCtl.SetFont(fontBold); + wCtl = wCtl.GetWindow(GW_HWNDNEXT); + } + } +#endif // WIN32_PLATFORM_WFSP + +// Platform dependant initialization + void StdPlatformInit() + { + T* pT = static_cast(this); +#ifdef WIN32_PLATFORM_PSPC // Pocket PC title initialization + if (nTitleHeight != 0) + pT->DialogTitleInit(); +#elif defined(WIN32_PLATFORM_WFSP) + pT->StdSPInit(); + SetStaticBold(); +#endif // WIN32_PLATFORM_WFSP + } + + // Menu bar creation + HWND CreateMenuBar(UINT uiMB = T::IDD, int nBmpImages = 0) + { + T* pT = static_cast(this); + return AtlCreateMenuBar(pT->m_hWnd, uiMB, 0, nBmpImages ? uiMB : 0, nBmpImages); + } + + // Dialog closing + void StdCloseDialog(WORD wID) + { + T* pT = static_cast(this); + if (t_bModal) + ::EndDialog(pT->m_hWnd, wID); + else + pT->DestroyWindow(); + } + + // Shell dialog layout initialization + void StdShidInit() + { + T* pT = static_cast(this); + SHINITDLGINFO shidi = { SHIDIM_FLAGS, pT->m_hWnd, t_shidiFlags }; + ::SHInitDialog(&shidi); + } + +// IDC_INFOSTATIC background setting + LRESULT OnColorStatic(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if (::GetDlgCtrlID((HWND)lParam) == IDC_INFOSTATIC) + { + ::SetBkMode((HDC)wParam, TRANSPARENT); + return (LRESULT)::GetSysColorBrush(COLOR_INFOBK); + } + return bHandled = FALSE; + } + +// Menu dialog ending + LRESULT OnMenuClose(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->StdCloseDialog((WORD)(wID - ID_MENU_OK + IDOK)); + return 0; + } + +// Standard dialog ending: may be used with any command + LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->StdCloseDialog(wID); + return 0; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CStdDialogImplBase - Base implementation of standard PPC/SmartPhone dialog + +template > +class ATL_NO_VTABLE CStdDialogImplBase : + public TBase, + public CStdDialogBase +{ +public: +#ifdef WIN32_PLATFORM_PSPC + BOOL GetClientRect(LPRECT lpRect) + { + return CStdDialogBase::GetClientRect(lpRect); + } + + BOOL SetWindowText(LPCTSTR lpszString) + { + return CStdDialogBase::SetWindowText(lpszString); + } +#endif + + BEGIN_MSG_MAP(CStdDialogImplBase) +#ifdef WIN32_PLATFORM_PSPC // Pocket PC title and SIP + MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) +#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key + MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) +#endif + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd) + COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + ATLASSERT(t_bModal == pT->m_bModal); + pT->StdPlatformInit(); + pT->StdShidInit(); + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CStdDialogImpl - implementation of standard PPC/SmartPhone dialog + +template +class ATL_NO_VTABLE CStdDialogImpl : public CStdDialogImplBase< T, t_shidiFlags, t_bModal> +{}; + +/////////////////////////////////////////////////////////////////////////////// +// CStdIndirectDialogImpl - implementation of standard indirect PPC/SmartPhone dialog + +#if defined __ATLDLGS_H__ + +template +class ATL_NO_VTABLE CStdIndirectDialogImpl : + public CIndirectDialogImpl< T, CMemDlgTemplate, CStdDialogImpl > +{ +public: + typedef CIndirectDialogImpl< T, CMemDlgTemplate, CStdDialogImpl > _baseClass; + typedef CStdDialogImpl _baseStd; + + void CheckStyle() + { + // Mobile devices don't support DLGTEMPLATEEX + ATLASSERT(!m_Template.IsTemplateEx()); + + // Standard dialogs need only DS_CENTER + DWORD &dwStyle = m_Template.GetTemplatePtr()->style; + if (dwStyle & DS_CENTER) + if(t_bModal) + { + ATLASSERT((dwStyle & WS_CHILD) != WS_CHILD); + dwStyle |= WS_POPUP; + } + else + { + if((dwStyle & WS_CHILD) != WS_CHILD) + dwStyle |= WS_POPUP; + } + } + + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL) + { + ATLASSERT(t_bModal); + + if (!m_Template.IsValid()) + CreateTemplate(); + + CheckStyle(); + + return _baseClass::DoModal(hWndParent, dwInitParam); + } + + HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL) + { + ATLASSERT(!t_bModal); + + if (!m_Template.IsValid()) + CreateTemplate(); + + CheckStyle(); + + return _baseClass::Create(hWndParent, dwInitParam); + } + + BEGIN_MSG_MAP(CStdIndirectDialogImpl) + CHAIN_MSG_MAP(_baseStd) + END_MSG_MAP() + +}; + +#endif // defined __ATLDLGS_H__ + +#ifndef _ATL_NO_HOSTING + +/////////////////////////////////////////////////////////////////////////////// +// CStdAxDialogImpl - implementation of standard PPC/SmartPhone AxDialog + +template +class ATL_NO_VTABLE CStdAxDialogImpl : public CStdDialogImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl< T > > +{}; +#endif // _ATL_NO_HOSTING + +/////////////////////////////////////////////////////////////////////////////// +// CStdSimpleDialog - standard PPC/SmartPhone simple dialog with SHIDIF_xxx flags + +template +class CStdSimpleDialog : + public ATL::CSimpleDialog, + public CStdDialogBase, t_shidiFlags> +{ +public: + typedef CStdDialogBase, t_shidiFlags> baseClass; + +#ifdef WIN32_PLATFORM_PSPC + BOOL GetClientRect(LPRECT lpRect) + { + return baseClass::GetClientRect(lpRect); + } + + BOOL SetWindowText(LPCTSTR lpszString) + { + return baseClass::SetWindowText(lpszString); + } +#endif + + BEGIN_MSG_MAP(CStdSimpleDialog) +#ifdef WIN32_PLATFORM_PSPC // Pocket PC title and SIP + MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) +#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key + MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) +#endif + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) + COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + StdPlatformInit(); + StdShidInit(); + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CStdDialogResizeImplBase - Base implementation of orientation resizing standard PPC/SmartPhone dialog + +template > +class ATL_NO_VTABLE CStdDialogResizeImplBase : + public CStdDialogImplBase< T, t_shidiFlags, t_bModal, TBase>, + public CDialogResize +{ +public: + // Note: BEGIN_DLGRESIZE_MAP is required in the derived class. + + BEGIN_MSG_MAP(CStdResizeDialogImplBase) +#ifdef WIN32_PLATFORM_PSPC // Pocket PC title + MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) +#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key + MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) +#endif + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd) + COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) + CHAIN_MSG_MAP(CDialogResize< T >) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + ATLASSERT(t_bModal == pT->m_bModal); + pT->StdPlatformInit(); + pT->DlgResize_Init(FALSE); + pT->StdShidInit(); + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CStdDialogResizeImpl - implementation of orientation resizing standard PPC/SmartPhone dialog + +template +class ATL_NO_VTABLE CStdDialogResizeImpl : public CStdDialogResizeImplBase< T, t_shidiFlags, t_bModal> +{}; + +#ifndef _ATL_NO_HOSTING + +/////////////////////////////////////////////////////////////////////////////// +// CStdAxDialogResizeImpl - implementation of orientation resizing standard PPC/SmartPhone AxDialog + +template +class ATL_NO_VTABLE CStdAxDialogResizeImpl : public CStdDialogResizeImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl > +{}; +#endif // _ATL_NO_HOSTING + +/////////////////////////////////////////////////////////////////////////////// +// CStdSimpleDialogResizeImpl - implementation of standard resizing simple dialog with SHIDIF_xxx flags + +// Usage: +// class CMyDlg : public CStdSimpleDialogResize +// { +// public: +// BEGIN_DLGRESIZE_MAP(CMyDlg) +// ... +// END_DLGRESIZE_MAP() +// }; + +template +class ATL_NO_VTABLE CStdSimpleDialogResizeImpl : + public CStdSimpleDialog, + public CDialogResize< T > +{ +public: + typedef CStdSimpleDialog::baseClass baseClass; + + BEGIN_MSG_MAP(CStdSimpleDialogResizeImpl) +#ifdef WIN32_PLATFORM_PSPC // Pocket PC title + MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) +#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key + MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) +#endif + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd) + COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) + CHAIN_MSG_MAP(CDialogResize< T >) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->StdPlatformInit(); + pT->DlgResize_Init(FALSE); + pT->StdShidInit(); + return bHandled = FALSE; + } +}; + +#if defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC) + +/////////////////////////////////////////////////////////////////////////////// +// CStdOrientedDialogBase - Oriented PPC standard dialog base class + +template +class CStdOrientedDialogBase +{ +public: +// Operation + BOOL SetOrientation(DRA::DisplayMode mode) + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + ATLASSERT(mode == DRA::GetDisplayMode()); + + // Derived dialog must enumerate TWO dialog templates with the same control ids and types ie: + // enum { IDD = IDD_MYDLG, IDD_LANDSCAPE = IDD_MYDLG_L }; + UINT iResource = (mode == DRA::Landscape)? T::IDD_LANDSCAPE : T::IDD; + + BOOL bRes = DRA::RelayoutDialog(ModuleHelper::GetResourceInstance(), pT->m_hWnd, MAKEINTRESOURCE(iResource)); + pT->OnOrientation(mode); + return bRes; + } + +// Override + void OnOrientation(DRA::DisplayMode /*mode*/) + {} + +// Message handlers + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + if (wParam == SETTINGCHANGE_RESET) + { + pT->SetOrientation(DRA::GetDisplayMode()); + pT->StdPlatformInit(); + pT->StdShidInit(); + } + else if (wParam == SPI_SETSIPINFO) + { + pT->DoSipInfo(); + return TRUE; + } + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CStdOrientedDialogImplBase - Oriented PPC standard dialog base implementation + +template > +class ATL_NO_VTABLE CStdOrientedDialogImplBase : + public CStdDialogImplBase< T, t_shidiFlags, t_bModal, TBase>, + public CStdOrientedDialogBase +{ +public: + BEGIN_MSG_MAP(CStdOrientedDialogImpl) + MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CStdOrientedDialogBase::OnSettingChange) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd) + COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); +#ifdef _DEBUG + ATLASSERT(t_bModal == pT->m_bModal); +#endif + if (DRA::GetDisplayMode() == DRA::Landscape) + pT->SetOrientation(DRA::Landscape); + pT->StdPlatformInit(); + pT->StdShidInit(); + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CStdOrientedDialogImpl - Oriented PPC standard dialog implementation + +template +class ATL_NO_VTABLE CStdOrientedDialogImpl : public CStdOrientedDialogImplBase< T, t_shidiFlags, t_bModal> +{}; + +#ifndef _ATL_NO_HOSTING +/////////////////////////////////////////////////////////////////////////////// +// CStdAxOrientedDialogImpl - Oriented PPC standard AxDialog implementation + +template +class ATL_NO_VTABLE CStdAxOrientedDialogImpl : public CStdOrientedDialogImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl > +{}; +#endif // _ATL_NO_HOSTING + +/////////////////////////////////////////////////////////////////////////////// +// CStdSimpleOrientedDialog - Standard simple orientable dialog + +template +class CStdSimpleOrientedDialog : + public CStdSimpleDialog, + public CStdOrientedDialogBase > +{ +public: + typedef CStdSimpleDialog::baseClass baseClass; + typedef CStdOrientedDialogBase > baseOriented; + + enum {IDD = t_wDlgTemplateID, IDD_LANDSCAPE = t_wDlgLandscapeID}; + + BEGIN_MSG_MAP(CStdSimpleDialog) + MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) + MESSAGE_HANDLER(WM_SETTINGCHANGE, baseOriented::OnSettingChange) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd) + COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if (DRA::GetDisplayMode() == DRA::Landscape) + SetOrientation(DRA::Landscape); + StdPlatformInit(); + StdShidInit(); + return bHandled = FALSE; + } +}; + +#endif // _WTL_CE_DRA + + +#endif // _WTL_CE_NO_DIALOGS + + +// --- PPC/SmartPhone application window and helpers --- + +#ifndef _WTL_CE_NO_APPWINDOW + +/////////////////////////////////////////////////////////////////////////////// +// CAppInfoBase - Helper for application state save/restore to registry + +class CAppInfoBase +{ +public: + CRegKeyEx m_Key; + + CAppInfoBase(ATL::_U_STRINGorID sAppKey) + { + m_Key.Create(HKEY_CURRENT_USER, sAppKey.m_lpstr); + ATLASSERT(m_Key.m_hKey); + } + + template + LONG Save(V& val, ATL::_U_STRINGorID sName) + { + return m_Key.SetBinaryValue(sName.m_lpstr, &val, sizeof(V)); + } + + template + LONG Save(int nb, V& val0, ATL::_U_STRINGorID sName) + { + return m_Key.SetBinaryValue(sName.m_lpstr, &val0, nb * sizeof(V)); + } + + template + LONG Restore(V& val, ATL::_U_STRINGorID sName) + { + ULONG bufSize = sizeof(V); + return m_Key.QueryBinaryValue(sName.m_lpstr, &val, &bufSize); + } + + template + LONG Restore(int nb, V& val0, ATL::_U_STRINGorID sName) + { + ULONG bufSize = nb * sizeof(V); + return m_Key.QueryBinaryValue(sName.m_lpstr, &val0, &bufSize); + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + LONG Save(_CSTRING_NS::CString& sval, ATL::_U_STRINGorID sName) + { + return m_Key.SetStringValue(sName.m_lpstr, sval); + } + + LONG Restore(_CSTRING_NS::CString& sval, ATL::_U_STRINGorID sName) + { + DWORD size = MAX_PATH; + LONG res = m_Key.QueryStringValue(sName.m_lpstr, sval.GetBuffer(size), &size); + sval.ReleaseBuffer(); + return res; + } +#else + #pragma message("Warning: CAppInfoBase compiles without CString support. Do not use CString in Save or Restore.") +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + LONG Save(LPCTSTR sval, ATL::_U_STRINGorID sName) + { + return m_Key.SetStringValue(sName.m_lpstr, sval); + } + + LONG Restore(LPTSTR sval, ATL::_U_STRINGorID sName, DWORD *plength) + { + return m_Key.QueryStringValue(sName.m_lpstr, sval, plength); + } + + LONG Delete(ATL::_U_STRINGorID sName) + { + return m_Key.DeleteValue(sName.m_lpstr); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAppInfoT - CAppInfoBase constructed from a class with T::GetAppKey() + +// Macro for declaring AppKey +#define DECLARE_APPKEY(uAppKey) \ + static LPCTSTR GetAppKey() \ + { \ + static LPCTSTR sAppKey = ATL::_U_STRINGorID(uAppKey).m_lpstr; \ + return sAppKey; \ + } + +template +class CAppInfoT : public CAppInfoBase +{ +public: + CAppInfoT() : CAppInfoBase(T::GetAppKey()){} +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAppWindowBase - Base class for PPC/SmartPhone "well-behaved" application window or dialog + +// Macros for declaring frame WNDCLASS and AppKey +#define DECLARE_APP_FRAME_CLASS(WndClassName, uCommonResourceID, uAppKey) \ + DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ + DECLARE_APPKEY(uAppKey) + +#define DECLARE_APP_FRAME_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd, uAppKey) \ + DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ + DECLARE_APPKEY(uAppKey) + +template +class CAppWindowBase +{ +public: + typedef class CAppInfoT< T > CAppInfo; + +#ifndef WIN32_PLATFORM_WFSP + SHACTIVATEINFO m_sai; // NoOp on SmartPhones +#endif // WIN32_PLATFORM_WFSP + + bool m_bHibernate; + + CAppWindowBase< T >() : m_bHibernate(false) + { +#ifndef WIN32_PLATFORM_WFSP + SHACTIVATEINFO sai = { sizeof(SHACTIVATEINFO) }; + m_sai = sai; +#endif // WIN32_PLATFORM_WFSP + }; + + // Same as WTL 7.1 AppWizard generated ActivatePreviousInstance + SendMessage WM_COPYDATA + static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR lpstrCmdLine, bool bDialog) + { + // requires T does DECLARE_APP_FRAME_CLASS, DECLARE_APP_FRAME_CLASS_EX or DECLARE_APP_DLG_CLASS + CFrameWndClassInfo& classInfo = T::GetWndClassInfo(); + + ATLVERIFY(::LoadString(hInstance, classInfo.m_uCommonResourceID, classInfo.m_szAutoName, sizeof(classInfo.m_szAutoName)/sizeof(classInfo.m_szAutoName[0])) != 0); + + classInfo.m_wc.lpszClassName = classInfo.m_szAutoName; + + const TCHAR* pszClass = classInfo.m_wc.lpszClassName; + + if(NULL == pszClass || '\0' == *pszClass) + { + return E_FAIL; + } + + const DWORD dRetryInterval = 100; + const int iMaxRetries = 25; + + for(int i = 0; i < iMaxRetries; ++i) + { + HANDLE hMutex = CreateMutex(NULL, FALSE, pszClass); + + DWORD dw = GetLastError(); + + if(NULL == hMutex) + { + HRESULT hr; + + switch(dw) + { + case ERROR_INVALID_HANDLE: + // A non-mutext object with this name already exists. + hr = E_INVALIDARG; + break; + default: + // This should never happen... + hr = E_FAIL; + } + + return hr; + } + + // If the mutex already exists, then there should be another instance running + if(dw == ERROR_ALREADY_EXISTS) + { + CloseHandle(hMutex); + + HWND hwnd = NULL; + if (bDialog) + hwnd = FindWindow(NULL, pszClass); + else + hwnd = FindWindow(pszClass, NULL); + + if(hwnd == NULL) + { + Sleep(dRetryInterval); + continue; + } + else + { + // Transmit our params to previous instance + if (lpstrCmdLine && *lpstrCmdLine) + { + COPYDATASTRUCT cd = { NULL, sizeof(TCHAR) * (wcslen(lpstrCmdLine) + 1), (PVOID)lpstrCmdLine }; + ::SendMessage(hwnd, WM_COPYDATA, NULL, (LPARAM)&cd); + } + // Set the previous instance as the foreground window + if(0 != SetForegroundWindow(reinterpret_cast(reinterpret_cast(hwnd) | 0x1))) + return S_FALSE; + } + } + else + { + return S_OK; + } + } + return S_OK; + } + +// Operations overriden in derived class + bool AppHibernate(bool /*bHibernate*/) + { + return false; + } + + bool AppNewInstance(LPCTSTR /*lpstrCmdLine*/) + { + return false; + } + + void AppSave() + { + } + +#ifdef WIN32_PLATFORM_WFSP + void AppBackKey() + { + ::SHNavigateBack(); + } +#endif + +// Message map and handlers + BEGIN_MSG_MAP(CAppWindowBase) + MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) +#ifdef WIN32_PLATFORM_WFSP + MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) +#else + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) +#endif // WIN32_PLATFORM_WFSP + MESSAGE_HANDLER(WM_HIBERNATE, OnHibernate) + MESSAGE_HANDLER(WM_COPYDATA, OnNewInstance) + MESSAGE_HANDLER(WM_CLOSE, OnClose) + END_MSG_MAP() + + LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + if (m_bHibernate) + m_bHibernate = pT->AppHibernate(false); +#ifndef WIN32_PLATFORM_WFSP + ::SHHandleWMActivate(pT->m_hWnd, wParam, lParam, &m_sai, 0); +#else + wParam; + lParam; +#endif // WIN32_PLATFORM_WFSP + return bHandled = FALSE; + } + +#ifdef WIN32_PLATFORM_WFSP +// SmartPhone VK_TBACK key standard management + LRESULT OnHotKey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + const UINT uModif = (UINT)LOWORD(lParam); + const UINT uVirtKey = (UINT)HIWORD(lParam); + if(uVirtKey == VK_TBACK) + if (AtlIsEditFocus()) + ::SHSendBackToFocusWindow(uMsg, wParam, lParam); + else if (uModif & MOD_KEYUP) + pT->AppBackKey(); + return 1; + } + +#else // !WIN32_PLATFORM_WFSP +// PPC SIP handling + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + bHandled = FALSE; + return ::SHHandleWMSettingChange(pT->m_hWnd, wParam, lParam, &m_sai); + } +#endif // !WIN32_PLATFORM_WFSP + + LRESULT OnHibernate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + return m_bHibernate = pT->AppHibernate(true); + } + + LRESULT OnNewInstance(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam; + return pT->AppNewInstance((LPCTSTR)pcds->lpData); + } + + LRESULT OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->AppSave(); + bHandled = FALSE; + return 1; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAppWindow - PPC/SmartPhone "well-behaved" application window class + +template +class CAppWindow : public CAppWindowBase< T > +{ +public: + // Same as WTL 7.1 AppWizard generated Run + lpstrCmdLine in CreateEx + static int AppRun(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWNORMAL) + { + CMessageLoop theLoop; + _Module.AddMessageLoop(&theLoop); + + T wndMain; + + if(wndMain.CreateEx(NULL, NULL, 0, 0, lpstrCmdLine) == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("Main window creation failed!\n")); + return 0; + } + + wndMain.ShowWindow(nCmdShow); + + int nRet = theLoop.Run(); + + _Module.RemoveMessageLoop(); + return nRet; + } + + static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR lpstrCmdLine) + { + return CAppWindowBase< T >::ActivatePreviousInstance(hInstance, lpstrCmdLine, false); + } +}; + + +#ifndef _WTL_CE_NO_DIALOGS + +/////////////////////////////////////////////////////////////////////////////// +// CAppDialog - PPC/SmartPhone "well-behaved" dialog application class + +// Macro for declaring dialog WNDCLASS and AppKey +#define DECLARE_APP_DLG_CLASS(WndClassName, uCommonResourceID, uAppKey) \ + static WTL::CFrameWndClassInfo& GetWndClassInfo() \ + { \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { 0, (WNDPROC)StartDialogProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ + }; \ + DECLARE_APPKEY(uAppKey) + +template +class CAppDialog : public CAppWindowBase< T > +{ +public: + static int AppRun(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWNORMAL) + { + CMessageLoop theLoop; + _Module.AddMessageLoop(&theLoop); + + T dlgMain; + + if(dlgMain.Create(NULL, (LPARAM)lpstrCmdLine) == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("Main dialog creation failed!\n")); + return 0; + } + + dlgMain.ShowWindow(nCmdShow); + + int nRet = theLoop.Run(); + + _Module.RemoveMessageLoop(); + return nRet; + } + + static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR lpstrCmdLine) + { + return CAppWindowBase< T >::ActivatePreviousInstance(hInstance, lpstrCmdLine, true); + }; +}; + +// PPC/SmartPhone standard application dialogs + +#ifdef WIN32_PLATFORM_WFSP +#define WTL_APP_SHIDIF WTL_SP_SHIDIF +#else +#define WTL_APP_SHIDIF WTL_STD_SHIDIF +#endif + +/////////////////////////////////////////////////////////////////////////////// +// CAppStdDialogImplBase - Base implementation of standard application dialogs + +template +class ATL_NO_VTABLE CAppStdDialogImplBase : + public TImplBase, + public CAppDialog< T > +{ +public: + WTL_DLG_NOTITLE; + + void StdCloseDialog(int nVal) + { + T* pT = static_cast(this); + if (nVal != IDCANCEL) + pT->AppSave(); + if (t_bModal == false) + { + pT->DestroyWindow(); + ::PostQuitMessage(nVal); + } + else + ::EndDialog(pT->m_hWnd, nVal); + } + + BEGIN_MSG_MAP(CAppStdDialogImplBase) + MESSAGE_HANDLER(WM_CLOSE, OnSystemClose) + CHAIN_MSG_MAP(TImplBase) + CHAIN_MSG_MAP(CAppDialog< T >) + END_MSG_MAP() + + LRESULT OnSystemClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->StdCloseDialog(IDCANCEL); + return 0; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CAppStdDialogImpl - Implementation of standard application dialog + +template +class ATL_NO_VTABLE CAppStdDialogImpl : + public CAppStdDialogImplBase, t_shidiFlags, t_bModal> +{}; + +/////////////////////////////////////////////////////////////////////////////// +// CAppStdDialogResizeImpl - implementation of orientation resizing standard application dialog + +template +class ATL_NO_VTABLE CAppStdDialogResizeImpl : + public CAppStdDialogImplBase, t_shidiFlags, t_bModal> +{}; + +#ifndef _ATL_NO_HOSTING +/////////////////////////////////////////////////////////////////////////////// +// CAppStdAxDialogImpl - Implementation of standard application AxDialog + +template +class ATL_NO_VTABLE CAppStdAxDialogImpl : + public CAppStdDialogImplBase, t_shidiFlags, t_bModal> +{}; + +/////////////////////////////////////////////////////////////////////////////// +// CAppStdAxDialogResizeImpl - implementation of orientation resizing standard application AxDialog + +template +class ATL_NO_VTABLE CAppStdAxDialogResizeImpl : + public CAppStdDialogImplBase, t_shidiFlags, t_bModal> +{}; +#endif // _ATL_NO_HOSTING + +#if defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC) +/////////////////////////////////////////////////////////////////////////////// +// CAppStdOrientedDialogImpl - implementation of oriented PPC standard application dialog + +template +class ATL_NO_VTABLE CAppStdOrientedDialogImpl : + public CAppStdDialogImplBase, t_shidiFlags, t_bModal> +{}; + +#ifndef _ATL_NO_HOSTING +/////////////////////////////////////////////////////////////////////////////// +// CAppStdAxOrientedDialogImpl - implementation of oriented PPC standard application AxDialog + +template +class ATL_NO_VTABLE CAppStdAxOrientedDialogImpl : + public CAppStdDialogImplBase, t_shidiFlags, t_bModal> +{}; +#endif // _ATL_NO_HOSTING + +#endif // defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC) + +#endif // _WTL_CE_NO_DIALOGS + +#endif // _WTL_CE_NO_APPWINDOW + + +// --- Full screen support --- + +#ifndef _WTL_CE_NO_FULLSCREEN + +/////////////////////////////////////////////////////////////////////////////// +// CFullScreenFrame - full screen frame implementation + +template +class CFullScreenFrame +{ +public: + bool m_bFullScreen; + + CFullScreenFrame() : m_bFullScreen(false) + { } + +// Operation + void SetFullScreen(bool bFull) + { + m_bFullScreen = bFull; + ShowTaskBar(!bFull, false); + ShowMenuBar(!bFull); + } + +// Manage TaskBar for modal dialogs and property sheets + template + int FSDoModal(D& dlg) + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + ATLASSERT(pT->IsWindow()); + if (m_bFullScreen) // Show taskbar if hidden + ShowTaskBar(true, false); + int iRet = dlg.DoModal(); + if (m_bFullScreen) // Hide taskbar if restored + ShowTaskBar(false); + return iRet; + } + +// Implementation + void ShowMenuBar(bool bShow) + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + ATL::CWindow MenuBar = pT->m_hWndCECommandBar; + ATLASSERT(MenuBar.IsWindow()); + MenuBar.ShowWindow(bShow ? SW_SHOWNORMAL : SW_HIDE); + pT->SizeToMenuBar(); + } + + void ShowTaskBar(bool bShow, bool bRepaint = true) + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + RECT rect = { 0 }; + SystemParametersInfo(SPI_GETWORKAREA, NULL, &rect, FALSE); + if (!bShow) + rect.top = 0; + +#ifdef WIN32_PLATFORM_PSPC // Pocket PC code + UINT uShow = t_bHasSip ? SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON : SHFS_SHOWTASKBAR | SHFS_HIDESIPBUTTON; + SHFullScreen(pT->m_hWnd, bShow ? uShow : SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON); +#elif _WIN32_WCE > 0x500 // Smartphone 2005 code + SHFullScreen(pT->m_hWnd, bShow ? SHFS_SHOWTASKBAR : SHFS_HIDETASKBAR); +#else // Smartphone 2003 + HWND hTaskBar = FindWindow(_T("tray"), NULL); + ATLASSERT(::IsWindow(hTaskBar)); + ::ShowWindow(hTaskBar, bShow ? SW_SHOW : SW_HIDE); +#endif // WIN32_PLATFORM_PSPC + + pT->MoveWindow(&rect, bRepaint); + } + +// Message map and handler + BEGIN_MSG_MAP(CFullScreenFrame) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) + MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) + END_MSG_MAP() + + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifndef SETTINGCHANGE_RESET // not defined for PPC 2002 + #define SETTINGCHANGE_RESET SPI_SETWORKAREA +#endif + if (m_bFullScreen && (wParam == SETTINGCHANGE_RESET)) + SetFullScreen(m_bFullScreen); + return bHandled = FALSE; + } + + LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if (m_bFullScreen) + { + ShowTaskBar(!wParam); + ShowMenuBar(!wParam); + } + return bHandled = FALSE; + } +}; + +#endif // _WTL_CE_NO_FULLSCREEN + + +// --- WinCE zoom support --- + +#ifndef _WTL_CE_NO_ZOOMSCROLL + +/////////////////////////////////////////////////////////////////////////////// +// CZoomScrollImpl - WinCE zooming implementation on top of CScrollImpl + +template +class CZoomScrollImpl: public CScrollImpl< T > +{ +public: +// Data members + _WTYPES_NS::CSize m_sizeTrue; + double m_fzoom; + +// Creation + CZoomScrollImpl() : m_sizeTrue(0), m_fzoom(1.) + { } + +// Zoom operations and access + void SetZoomScrollSize(_WTYPES_NS::CSize sizeTrue, double fzoom = 1., BOOL bRedraw = TRUE) + { + ATLASSERT(fzoom > 0.); + m_sizeTrue = sizeTrue; + m_fzoom = fzoom; + + CScrollImpl< T >::SetScrollSize(sizeTrue / fzoom, bRedraw); + } + + void SetZoomScrollSize(int cx, int cy, double fzoom=1., BOOL bRedraw = TRUE) + { + SetZoomScrollSize(_WTYPES_NS::CSize(cx, cy), fzoom, bRedraw); + } + + void SetZoom(double fzoom, BOOL bRedraw = TRUE) + { + _WTYPES_NS::CPoint ptCenter = WndtoTrue(m_sizeClient / 2); + _WTYPES_NS::CSize sizePage = GetScrollPage(); + _WTYPES_NS::CSize sizeLine = GetScrollLine(); + + SetZoomScrollSize(GetScrollSize(), fzoom, bRedraw); + + SetScrollLine(sizeLine); + SetScrollPage(sizePage); + _WTYPES_NS::CPoint ptOffset = ptCenter - (m_sizeClient / 2) * fzoom; + SetScrollOffset(ptOffset, bRedraw); + } + + double GetZoom() + { + return m_fzoom; + } + +// CScrollImpl overrides + void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE) + { + CScrollImpl< T >::SetScrollOffset((int)(x / m_fzoom), (int)(y / m_fzoom), bRedraw); + } + + void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE) + { + SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw); + } + + void GetScrollOffset(POINT& ptOffset) + { + ptOffset.x = (LONG)(m_ptOffset.x * m_fzoom); + ptOffset.y = (LONG)(m_ptOffset.y * m_fzoom); + } + + void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE) + { + SetZoomScrollSize(cx, cy, GetZoom(), bRedraw); + } + + void SetScrollSize(SIZE sizeTrue, BOOL bRedraw = TRUE) + { + SetZoomScrollSize(sizeTrue, GetZoom(), bRedraw); + } + + void GetScrollSize(SIZE& sizeTrue) const + { + sizeTrue = m_sizeTrue; + } + + void SetScrollPage(int cxPage, int cyPage) + { + SetScrollPage(_WTYPES_NS::CSize(cxPage, cyPage)); + } + + void SetScrollPage(SIZE sizePage) + { + CScrollImpl< T >::SetScrollPage(sizePage / m_fzoom); + } + + void GetScrollPage(SIZE& sizePage) const + { + sizePage = m_sizePage * m_fzoom; + } + + void SetScrollLine(int cxLine, int cyLine) + { + SetScrollLine(_WTYPES_NS::CSize(cxLine, cyLine)); + } + + void SetScrollLine(SIZE sizeLine) + { + CScrollImpl< T >::SetScrollLine(sizeLine / m_fzoom); + } + + void GetScrollLine(SIZE& sizeLine) const + { + sizeLine = m_sizeLine * m_fzoom; + } + +// Data access complements + _WTYPES_NS::CSize GetScrollSize() + { + return m_sizeTrue; + } + + _WTYPES_NS::CSize GetScrollPage() + { + return m_sizePage * m_fzoom; + } + + _WTYPES_NS::CSize GetScrollLine() + { + return m_sizeLine * m_fzoom; + } + + _WTYPES_NS::CPoint GetScrollOffset() + { + return (_WTYPES_NS::CSize)m_ptOffset * m_fzoom; + } + +// Helper coordinate functions + _WTYPES_NS::CPoint WndtoTrue(CPoint ptW) + { + return (_WTYPES_NS::CSize)ptW * GetZoom() + GetScrollOffset(); + } + + void WndtoTrue(LPPOINT aptW, int nPts) // in place coord transformation + { + for (int i = 0 ; i < nPts ; i++) + aptW[i] = WndtoTrue(aptW[i]); + } + + void WndtoTrue(LPRECT prectW) // in place coord transformation + { + WndtoTrue((LPPOINT)prectW, 2); + } + + _WTYPES_NS::CPoint TruetoWnd(CPoint ptT) + { + return (ptT - GetScrollOffset()) / GetZoom(); + } + + void TruetoWnd(LPPOINT aptT, int nPts) // in place coord transformation + { + for (int i = 0 ; i < nPts ; i++) + aptT[i] = TruetoWnd(aptT[i]); + } + + void TruetoWnd(LPRECT prectT) // in place coord transformation + { + TruetoWnd((LPPOINT)prectT, 2); + } + +// Drawing operations : assume adequate setting of data members + BOOL Draw(HBITMAP hbm, HDC hdestDC, DWORD dwROP = SRCCOPY) + { + CDC memDC = CreateCompatibleDC(hdestDC); + CBitmapHandle bmpOld = memDC.SelectBitmap(hbm); + BOOL bRes = Draw(memDC, hdestDC, dwROP); + memDC.SelectBitmap(bmpOld); + return bRes; + } + + BOOL Draw(HDC hsourceDC, HDC hdestDC, DWORD dwROP = SRCCOPY) + { + CDCHandle destDC = hdestDC; + destDC.SetViewportOrg(0,0); + _WTYPES_NS::CPoint ptOffset = GetScrollOffset(); + _WTYPES_NS::CSize sizeZClient = m_sizeClient * GetZoom(); + return destDC.StretchBlt(0, 0, m_sizeClient.cx, m_sizeClient.cy, hsourceDC, ptOffset.x, ptOffset.y, sizeZClient.cx, sizeZClient.cy, dwROP); + } + +#ifdef _IMAGING_H + BOOL Draw(IImage* pIImage, HDC hdestDC) + { + CDCHandle destDC = hdestDC; + destDC.SetViewportOrg(0,0); + return SUCCEEDED(pIImage->Draw(destDC, _WTYPES_NS::CRect(-_WTYPES_NS::CPoint(m_ptOffset), m_sizeAll), NULL)); + } +#endif + +// Message map and handlers + BEGIN_MSG_MAP(CZoomScrollImpl< T >) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) + CHAIN_MSG_MAP(CScrollImpl< T >) + END_MSG_MAP() + + LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + if ((GetScrollExtendedStyle() & SCRL_ERASEBACKGROUND)) + { + _WTYPES_NS::CRect rect; + pT->GetClientRect(rect); + _WTYPES_NS::CSize sizeClient=rect.Size(); + + if (m_sizeAll.cx < sizeClient.cx || m_sizeAll.cy < sizeClient.cy) + { + CDCHandle hdc = (HDC)wParam; + HBRUSH hbr = GetSysColorBrush((int)T::GetWndClassInfo().m_wc.hbrBackground - 1); + + if (m_sizeAll.cx < sizeClient.cx) + { + _WTYPES_NS::CRect rectBG(_WTYPES_NS::CPoint(m_sizeAll.cx, 0), sizeClient); + hdc.FillRect(rectBG, hbr); + } + + if (m_sizeAll.cy < sizeClient.cy) + { + _WTYPES_NS::CRect rectBG(_WTYPES_NS::CPoint(0, m_sizeAll.cy), sizeClient); + hdc.FillRect(rectBG, hbr); + } + } + } + else + { + bHandled = FALSE; + } + + return 1; + } +}; + +#endif // _WTL_CE_NO_ZOOMSCROLL + +#ifndef _WTL_CE_NO_CONTROLS + +// --- PPC bottom TabView control --- + +#if defined(__ATLCTRLX_H__) && defined(WIN32_PLATFORM_PSPC) + +/////////////////////////////////////////////////////////////////////////////// +// CBottomTabViewImpl + +template +class ATL_NO_VTABLE CBottomTabViewImpl : public CTabViewImpl +{ +public: + DECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE) + +// Implementation overrideables + bool CreateTabControl() + { + m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | TCS_BOTTOM, 0, m_nTabID); + + ATLASSERT(m_tab.m_hWnd != NULL); + if(m_tab.m_hWnd == NULL) + return false; + + m_tab.SendMessage(CCM_SETVERSION, COMCTL32_VERSION); + m_tab.SetItemExtra(sizeof(TABVIEWPAGE)); + + T* pT = static_cast(this); + m_cyTabHeight = pT->CalcTabHeight(); + + return true; + } + + int CalcTabHeight() + { + int nCount = m_tab.GetItemCount(); + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_TEXT; + tcix.tciheader.pszText = _T("NS"); + int nIndex = m_tab.InsertItem(nCount, tcix); + + RECT rect = { 0 }; + SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0); + RECT rcWnd = rect; + + m_tab.AdjustRect(FALSE, &rect); + rcWnd.top = rect.bottom; + ::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetExStyle()); + m_tab.DeleteItem(nIndex); + + return rcWnd.bottom - rcWnd.top; + } + + void UpdateLayout() + { + RECT rect = { 0 }; + GetClientRect(&rect); + + if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0)) + m_tab.SetWindowPos(NULL, 0, rect.bottom - m_cyTabHeight, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER /*| SWP_SHOWWINDOW*/); + + if(m_nActivePage != -1) + ::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, 0, rect.right - rect.left, rect.bottom - m_cyTabHeight, SWP_NOZORDER); + } + +}; + +class CBottomTabView : public CBottomTabViewImpl +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_BottomTabView"), 0, COLOR_APPWORKSPACE) +}; + +#endif // defined(__ATLCTRLX_H__) && defined(WIN32_PLATFORM_PSPC) + + +// --- PPC/SmartPhone controls --- + +//////////////////////////////////////////////////////////////////////////////// +// These are wrapper classes for the Pocket PC 2002/2003 and SmartPhone 2003 controls +// To implement a window based on a control, use following: +// Example: Implementing a window based on a Html control +// +// class CMyHtml : CWindowImpl +// { +// public: +// BEGIN_MSG_MAP(CMyHtml) +// // put your message handler entries here +// END_MSG_MAP() +// }; +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// CHtmlCtrl + +template +class CHtmlCtrlT : public TBase +{ +public: +// Constructors + CHtmlCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CHtmlCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + ATLASSERT(hWnd != NULL); // Did you remember to call InitHTMLControl(hInstance) ?? + return hWnd; + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_HTML; + } + +#if (_WIN32_WCE >= 400) + void AddStyle(LPCWSTR pszStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ADDSTYLE, 0, (LPARAM)pszStyle); + } +#endif // (_WIN32_WCE >= 400) + + void AddText(BOOL bPlainText, LPCSTR pszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ADDTEXT, (WPARAM)bPlainText, (LPARAM)pszText); + } + + void AddHTML(LPCSTR pszHTML) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ADDTEXT, (WPARAM)FALSE, (LPARAM)pszHTML); + } + + void AddText(BOOL bPlainText, LPCWSTR pszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ADDTEXTW, (WPARAM)bPlainText, (LPARAM)pszText); + } + + void AddHTML(LPCWSTR pszHTML) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ADDTEXTW, (WPARAM)FALSE, (LPARAM)pszHTML); + } + + void Anchor(LPCSTR pszAnchor) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ANCHOR, 0, (LPARAM)pszAnchor); + } + + void Anchor(LPCWSTR pszAnchor) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ANCHORW, 0, (LPARAM)pszAnchor); + } + +#if (_WIN32_WCE >= 420) + void GetBrowserDispatch(IDispatch** ppDispatch) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(ppDispatch); + ATLASSERT(*ppDispatch==NULL); + ::SendMessage(m_hWnd, DTM_BROWSERDISPATCH, 0, (LPARAM)ppDispatch); + } + void GetDocumentDispatch(IDispatch** ppDispatch) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(ppDispatch); + ATLASSERT(*ppDispatch==NULL); + ::SendMessage(m_hWnd, DTM_DOCUMENTDISPATCH , 0, (LPARAM)ppDispatch); + } +#endif // (_WIN32_WCE >= 420) + + void Clear() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_CLEAR, 0, 0L); + } + + void EnableClearType(BOOL bEnable = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ENABLECLEARTYPE, 0, (LPARAM)bEnable); + } + + void EnableContextMenu(BOOL bEnable = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ENABLECONTEXTMENU, 0, (LPARAM)bEnable); + } + + void EnableScripting(BOOL bEnable = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ENABLESCRIPTING, 0, (LPARAM)bEnable); + } + + void EnableShrink(BOOL bEnable = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ENABLESHRINK, 0, (LPARAM)bEnable); + } + + void EndOfSource() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ENDOFSOURCE, 0, 0L); + } + + void ImageFail(DWORD dwCookie) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_IMAGEFAIL, 0, (LPARAM)dwCookie); + } + + int GetLayoutHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DTM_LAYOUTHEIGHT, 0, 0L); + } + + int GetLayoutWidth() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DTM_LAYOUTWIDTH, 0, 0L); + } + + void Navigate(LPCTSTR pstrURL, UINT uFlags = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrURL); + ::SendMessage(m_hWnd, DTM_NAVIGATE, (WPARAM)uFlags, (LPARAM)pstrURL); + } + + void SelectAll() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_SELECTALL, 0, 0L); + } + + void SetImage(INLINEIMAGEINFO* pImageInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pImageInfo); + ::SendMessage(m_hWnd, DTM_SETIMAGE, 0, (LPARAM)pImageInfo); + } + + void ZoomLevel(int iLevel) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ZOOMLEVEL, 0, (LPARAM)iLevel); + } + +#if (_WIN32_WCE >= 400) + void Stop() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_STOP, 0, 0L); + } +#endif // (_WIN32_WCE >= 400) + + void GetScriptDispatch(IDispatch** ppDispatch) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(ppDispatch); + ATLASSERT(*ppDispatch==NULL); + ::SendMessage(m_hWnd, DTM_SCRIPTDISPATCH, 0, (LPARAM)ppDispatch); + } +}; + +typedef CHtmlCtrlT CHtmlCtrl; + + +#ifdef WIN32_PLATFORM_PSPC + +/////////////////////////////////////////////////////////////////////////////// +// CRichInkCtrl + +template +class CRichInkCtrlT : public TBase +{ +public: +// Constructors + CRichInkCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CRichInkCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + ATLASSERT(hWnd != NULL); // Did you remember to call InitRichInkDLL() ?? + return hWnd; + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_RICHINK; + } + + BOOL CanPaste(UINT uFormat = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANPASTE, (WPARAM)uFormat, 0L); + } + + BOOL CanRedo() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANREDO, 0, 0L); + } + + BOOL CanUndo() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L); + } + + void ClearAll(BOOL bRepaint = TRUE) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_CLEARALL, (WPARAM)bRepaint, 0L); + } + + BOOL GetModify() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L); + } + + UINT GetPageStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETPAGESTYLE, 0, 0L); + } + + UINT GetPenMode() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETPENMODE, 0, 0L); + } + + UINT GetViewStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETVIEW, 0, 0L); + } + + UINT GetWrapMode() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETWRAPMODE, 0, 0L); + } + + UINT GetZoomPercent() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETZOOMPERCENT, 0, 0L); + } + + void InsertLinks(LPWSTR lpString, int cchLength = -1) + { + ATLASSERT(::IsWindow(m_hWnd)); + if(cchLength == -1) + cchLength = lstrlen(lpString); + ::SendMessage(m_hWnd, EM_INSERTLINKS, (WPARAM)cchLength, (LPARAM)lpString); + } + + void RedoEvent() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_REDOEVENT, 0, 0L); + } + + UINT SetInkLayer(UINT uLayer) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_SETINKLAYER, (WPARAM)uLayer, 0L); + } + + void SetPageStyle(UINT uStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETPAGESTYLE, (WPARAM)uStyle, 0L); + } + + void SetPenMode(UINT uMode) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETPENMODE, (WPARAM)uMode, 0L); + } + + void SetViewStyle(UINT uStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETVIEW, (WPARAM)uStyle, 0L); + } + + void SetViewAttributes(VIEWATTRIBUTES* pAttribs) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pAttribs); + ::SendMessage(m_hWnd, EM_SETVIEWATTRIBUTES, 0, (LPARAM)pAttribs); + } + + void SetWrapMode(UINT uMode) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETWRAPMODE, (WPARAM)uMode, 0L); + } + + void SetZoomPercent(UINT uPercent) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETZOOMPERCENT, (WPARAM)uPercent, 0L); + } + + LONG StreamIn(UINT uFormat, EDITSTREAM& es) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_STREAMIN, (WPARAM)uFormat, (LPARAM)&es); + } + + LONG StreamOut(UINT uFormat, EDITSTREAM& es) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_STREAMOUT, (WPARAM)uFormat, (LPARAM)&es); + } + + void UndoEvent() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_UNDOEVENT, 0, 0L); + } + + void Undo() + { + UndoEvent(); + } + +// Standard EM_xxx messages + DWORD GetSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW); + return (DWORD)::SendMessage(m_hWnd, EM_GETSEL, 0, 0L); + } + + void GetSel(int& nStartChar, int& nEndChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW); + ::SendMessage(m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); + } + + void SetSel(int nStartChar, int nEndChar) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW); + ::SendMessage(m_hWnd, EM_SETSEL, nStartChar, nEndChar); + } + + void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW); + ::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM)bCanUndo, (LPARAM)lpszNewText); + } + + void SetModify(BOOL bModified = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETMODIFY, (WPARAM)bModified, 0L); + } + + int GetTextLength() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, WM_GETTEXTLENGTH, 0, 0L); + } + +// Clipboard operations + void Clear() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L); + } + + void Copy() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_COPY, 0, 0L); + } + + void Cut() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CUT, 0, 0L); + } + + void Paste() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_PASTE, 0, 0L); + } +}; + +typedef CRichInkCtrlT CRichInkCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CInkXCtrl + +template +class CInkXCtrlT : public TBase +{ +public: +// Constructors + CInkXCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CInkXCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + ATLASSERT(hWnd != NULL); // Did you remember to call InitInkX() ?? + return hWnd; + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_INKX; + } + + static UINT GetHotRecordingMessage() + { + return ::RegisterWindowMessage(szHotRecording); + } + + void ClearAll() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IM_CLEARALL, 0, 0L); + } + + int GetData(BYTE* lpBuffer, INT cbBuffer) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpBuffer); + return (int)::SendMessage(m_hWnd, IM_GETDATA, (WPARAM)cbBuffer, (LPARAM)lpBuffer); + } + + int GetDataLen() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, IM_GETDATALEN, 0, 0L); + } + + CRichInkCtrl GetRichInk() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HWND)::SendMessage(m_hWnd, IM_GETRICHINK, 0, 0L); + } + + BOOL IsRecording() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, IM_RECORDING, 0, 0L); + } + + void ReInit() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IM_REINIT, 0, 0L); + } + + void SetData(const BYTE* lpInkData, INT cbInkData) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpInkData); + ::SendMessage(m_hWnd, IM_SETDATA, (WPARAM)cbInkData, (LPARAM)lpInkData); + } + + void VoicePlay() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IM_VOICE_PLAY, 0, 0L); + } + + BOOL IsVoicePlaying() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, IM_VOICE_PLAYING, 0, 0L); + } + + BOOL VoiceRecord() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, IM_VOICE_RECORD, 0, 0L); + } + + void VoiceStop() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IM_VOICE_STOP, 0, 0L); + } + + void ShowVoiceBar(BOOL bShow = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IM_VOICEBAR, (WPARAM)bShow, 0L); + } +}; + +typedef CInkXCtrlT CInkXCtrl; + +#endif // WIN32_PLATFORM_PSPC + + +/////////////////////////////////////////////////////////////////////////////// +// CVoiceRecorderCtrl + +template +class CVoiceRecorderCtrlT : public TBase +{ +public: +// Constructors + CVoiceRecorderCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CVoiceRecorderCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, const POINT pt, LPTSTR pstrFileName, UINT nID, DWORD dwStyle = 0) + { + ATLASSERT(pstrFileName != NULL); + CM_VOICE_RECORDER cmvr = { 0 }; + cmvr.cb = sizeof(CM_VOICE_RECORDER); + cmvr.dwStyle = dwStyle; + cmvr.xPos = pt.x; + cmvr.yPos = pt.y; + cmvr.hwndParent = hWndParent; + cmvr.id = nID; + cmvr.lpszRecordFileName = pstrFileName; + m_hWnd = VoiceRecorder_Create(&cmvr); + return m_hWnd; + } + + HWND Create(LPCM_VOICE_RECORDER pAttribs) + { + ATLASSERT(pAttribs); + m_hWnd = VoiceRecorder_Create(pAttribs); + return m_hWnd; + } + +// Attributes + void Record() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, VRM_RECORD, 0, 0L); + } + + void Play() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, VRM_PLAY, 0, 0L); + } + + void Stop() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, VRM_STOP, 0, 0L); + } + + void Cancel() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, VRM_CANCEL, 0, 0L); + } + + void Done() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, VRM_OK, 0, 0L); + } +}; + +typedef CVoiceRecorderCtrlT CVoiceRecorderCtrl; + + +#ifdef WIN32_PLATFORM_PSPC + +/////////////////////////////////////////////////////////////////////////////// +// CDocListCtrl + +template +class CDocListCtrlT : public TBase +{ +public: +// Attributes + DOCLISTCREATE m_dlc; + TCHAR m_szPath[MAX_PATH]; + +// Constructors + CDocListCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CDocListCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, WORD wId, LPCTSTR pszFolder = NULL, LPCTSTR pstrFilter = NULL, + WORD wFilterIndex = 0, DWORD dwFlags = DLF_SHOWEXTENSION) + { + ATLASSERT(pstrFilter != NULL); // It seems to need a filter badly!! + ::ZeroMemory(&m_dlc, sizeof(DOCLISTCREATE)); + ::ZeroMemory(m_szPath, sizeof(m_szPath)); + if(pszFolder != NULL) + SecureHelper::strncpy_x(m_szPath, MAX_PATH, pszFolder, MAX_PATH - 1); + m_dlc.dwStructSize = sizeof(DOCLISTCREATE); + m_dlc.hwndParent = hWndParent; + m_dlc.pszFolder = m_szPath; + m_dlc.pstrFilter = pstrFilter; + m_dlc.wFilterIndex = wFilterIndex; + m_dlc.wId = wId; + m_dlc.dwFlags = dwFlags; + m_hWnd = DocList_Create(&m_dlc); + return m_hWnd; + } + + HWND Create(DOCLISTCREATE* pDlc) + { + m_dlc = *pDlc; + m_hWnd = DocList_Create(&m_dlc); + return m_hWnd; + } + +// Attributes + void DeleteSel() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_DELETESEL, 0, 0L); + } + + void DisableUpdates() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_DISABLEUPDATES, 0, 0L); + } + + void EnableUpdates() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_ENABLEUPDATES, 0, 0L); + } + + int GetFilterIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DLM_GETFILTERINDEX, 0, 0L); + } + + int GetItemCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DLM_GETITEMCOUNT, 0, 0L); + } + + int GetNextItem(int iIndex, DWORD dwRelation = LVNI_ALL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DLM_GETNEXTITEM, (WPARAM)iIndex, (LPARAM)dwRelation); + } + + int GetFirstItem(DWORD dwRelation = LVNI_ALL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DLM_GETNEXTITEM, (WPARAM)-1, (LPARAM)dwRelation); + } + + BOOL GetNextWave(int* pIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pIndex); + return (BOOL)::SendMessage(m_hWnd, DLM_GETNEXTWAVE, 0, (LPARAM)pIndex); + } + + BOOL GetPrevWave(int* pIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pIndex); + return (BOOL)::SendMessage(m_hWnd, DLM_GETPREVWAVE, 0, (LPARAM)pIndex); + } + + int GetSelCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DLM_GETSELCOUNT, 0, 0L); + } + + BOOL GetSelPathName(LPTSTR pstrPath, int cchMax) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrPath); + return (BOOL)::SendMessage(m_hWnd, DLM_GETSELPATHNAME, (WPARAM)cchMax, (LPARAM)pstrPath); + } + + void ReceiveIR(LPCTSTR pstrPath) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrPath); + ::SendMessage(m_hWnd, DLM_RECEIVEIR, 0, (LPARAM)pstrPath); + } + + void Refresh() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_REFRESH, 0, 0L); + } + + BOOL RenameMoveSelectedItems() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DLM_RENAMEMOVE, 0, 0L); + } + + int SelectAll() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DLM_SELECTALL, 0, 0L); + } + + HRESULT SelectItem(LPCTSTR pstrPath, BOOL bVisible = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrPath); + return (HRESULT)::SendMessage(m_hWnd, DLM_SELECTITEM, (WPARAM)bVisible, (LPARAM)pstrPath); + } + + void SendEMail(LPCTSTR pstrAttachment) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_SENDEMAIL, 0, (LPARAM)pstrAttachment); + } + + void SendIR(LPCTSTR pstrPath) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_SENDIR, 0, (LPARAM)pstrPath); + } + + HRESULT SetFilterIndex(int iIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HRESULT)::SendMessage(m_hWnd, DLM_SETFILTERINDEX, (WPARAM)iIndex, 0L); + } + + void SetFolder(LPCTSTR pstrPath) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrPath); + ::SendMessage(m_hWnd, DLM_SETFOLDER, 0, (LPARAM)pstrPath); + } + + BOOL SetItemState(int iIndex, const LVITEM* pItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pItem); + return (BOOL)::SendMessage(m_hWnd, DLM_SETITEMSTATE, (WPARAM)iIndex, (LPARAM)pItem); + } + + BOOL SetItemState(int iIndex, UINT uState, UINT uMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.stateMask = uMask; + lvi.state = uState; + return (BOOL)::SendMessage(m_hWnd, DLM_SETITEMSTATE, (WPARAM)iIndex, (LPARAM)&lvi); + } + + void SetOneItem(int iIndex, LPCVOID pPA) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_SETONEITEM, (WPARAM)iIndex, (LPARAM)pPA); + } + + void SetSelect(int iIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_SETSELECT, (WPARAM)iIndex, 0L); + } + + void SetSelPathName(LPCTSTR pstrPath) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrPath); + ::SendMessage(m_hWnd, DLM_SETSELPATHNAME, 0, (LPARAM)pstrPath); + } + + BOOL SetSortOrder() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DLM_SETSORTORDER, 0, 0L); + } + + HRESULT Update() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HRESULT)::SendMessage(m_hWnd, DLM_UPDATE, 0, 0L); + } + + BOOL ValidateFolder() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DLM_VALIDATEFOLDER, 0, 0L); + } + +// Functions + BOOL GetFirstSelectedWaveFile(int* pIndex, LPTSTR szPath, const size_t cchPath) + { + ATLASSERT(::IsWindow(m_hWnd)); + return DocList_GetFirstSelectedWaveFile(m_hWnd, pIndex, szPath, cchPath); + } + + BOOL GetNextSelectedWaveFile(int* pIndex, LPTSTR szPath, const size_t cchPath) + { + ATLASSERT(::IsWindow(m_hWnd)); + return DocList_GetNextSelectedWaveFile(m_hWnd, pIndex, szPath, cchPath); + } +}; + +typedef CDocListCtrlT CDocListCtrl; + +#endif // WIN32_PLATFORM_PSPC + + +/////////////////////////////////////////////////////////////////////////////// +// CCapEdit + +template +class CCapEditT : public TBase +{ +public: +// Constructors + CCapEditT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CCapEditT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = /*TBase*/CWindow::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + ATLASSERT(hWnd != NULL); // Did you remember to call SHInitExtraControls() ?? + return hWnd; + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_CAPEDIT; + } +}; + +typedef CCapEditT CCapEdit; + +/////////////////////////////////////////////////////////////////////////////// +// CTTStatic + +#ifndef WIN32_PLATFORM_WFSP // Tooltips not supported on SmartPhone + +template +class CTTStaticT : public TBase +{ +public: +// Constructors + CTTStaticT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CTTStaticT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = TBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + ATLASSERT(hWnd != NULL); // Did you remember to call SHInitExtraControls() ?? + return hWnd; + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_TSTATIC; + } + +// Operations + BOOL SetToolTipText(LPCTSTR pstrTipText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrTipText); + ATLASSERT(lstrlen(pstrTipText) <= 253); + CTempBuffer buff; + int cchLen = lstrlen(pstrTipText) + 3; + LPTSTR pstr = buff.Allocate(cchLen); + if(pstr == NULL) + return FALSE; + SecureHelper::strcpy_x(pstr, cchLen, _T("~~")); + SecureHelper::strcat_x(pstr, cchLen, pstrTipText); + return SetWindowText(pstr); + } +}; + +typedef CTTStaticT CTTStatic; + + +/////////////////////////////////////////////////////////////////////////////// +// CTTButton + +template +class CTTButtonT : public TBase +{ +public: +// Constructors + CTTButtonT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CTTButtonT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = TBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + ATLASSERT(hWnd != NULL); // Did you remember to call SHInitExtraControls() ?? + return hWnd; + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_TBUTTON; + } + +// Operations + BOOL SetToolTipText(LPCTSTR pstrTipText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrTipText); + ATLASSERT(lstrlen(pstrTipText) <= 253); + CTempBuffer buff; + int cchLen = lstrlen(pstrTipText) + 3; + LPTSTR pstr = buff.Allocate(cchLen); + if(pstr == NULL) + return FALSE; + SecureHelper::strcpy_x(pstr, cchLen, _T("~~")); + SecureHelper::strcat_x(pstr, cchLen, pstrTipText); + return SetWindowText(pstr); + } +}; + +typedef CTTButtonT CTTButton; + +#endif // !WIN32_PLATFORM_WFSP + + +// --- SmartPhone specific controls --- + +#ifdef WIN32_PLATFORM_WFSP + +/////////////////////////////////////////////////////////////////////////////// +// CSpinCtrlT - CSpinCtrl : SmartPhone adapted UpDown control + +template +class CSpinCtrlT : public CUpDownCtrlT< TBase > +{ +public: +// Constructors + CSpinCtrlT(HWND hWnd = NULL) : CUpDownCtrlT< TBase >(hWnd) + { } + + CSpinCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, HWND hBuddy, DWORD dwStyle, int nID, LPCTSTR szExpandedName = NULL) + { + ATLASSERT(::IsWindow(hWndParent)); + CUpDownCtrlT< TBase >::Create(hWndParent, NULL, szExpandedName, dwStyle, 0, nID, NULL); + ATLASSERT(m_hWnd != NULL); // Did you remember to call AtlInitCommonControls(ICC_UPDOWN_CLASS)? + if (hBuddy != NULL) + { + ATLASSERT(::IsWindow(hBuddy)); + SetBuddy(hBuddy); + } + return m_hWnd; + } +}; + +typedef CSpinCtrlT CSpinCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CSpinned - SmartPhone association of control and Spin + +template +class CSpinned : public TBase +{ +public: + CSpinCtrl m_SpinCtrl; + DWORD m_dwSpinnedStyle; + +// Constructors + CSpinned(HWND hWnd = NULL) : TBase(hWnd) + { + m_dwSpinnedStyle = WS_VISIBLE | UDS_ALIGNRIGHT | UDS_EXPANDABLE; + + if (t_bExpandOnly == true) + m_dwSpinnedStyle |= UDS_NOSCROLL; + else + m_dwSpinnedStyle |= UDS_HORZ | UDS_ARROWKEYS | UDS_SETBUDDYINT | UDS_WRAP; + + if (hWnd != NULL) + AttachOrCreateSpinCtrl(); + } + + CSpinned& operator =(HWND hWnd) + { + Attach(hWnd); + return *this; + } + + void Attach(HWND hWnd) + { + ATLASSERT(!IsWindow()); + TBase* pT = static_cast(this); + pT->m_hWnd = hWnd; + if (hWnd != NULL) + AttachOrCreateSpinCtrl(); + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szExpandedName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + + TBase* pT = static_cast(this); + TBase::Create(hWndParent, rect, NULL, dwStyle, dwExStyle, MenuOrID, lpCreateParam); + ATLASSERT(pT->m_hWnd != NULL); + + m_SpinCtrl.Create(hWndParent, pT->m_hWnd, m_dwSpinnedStyle, ATL_IDW_SPIN_ID + (int)MenuOrID.m_hMenu, szExpandedName); + + ATLASSERT(m_SpinCtrl.m_hWnd != NULL); // Did you remember to call AtlInitCommonControls(ICC_UPDOWN_CLASS)? + + return pT->m_hWnd; + } + +// Attributes + CSpinCtrl& GetSpinCtrl() + { + return m_SpinCtrl; + } + +// Implementation + // Attach our existing SpinCtrl or create one + bool AttachOrCreateSpinCtrl() + { + TBase* pT = static_cast(this); + + HWND hSpin = ::GetDlgItem(pT->GetParent(), ATL_IDW_SPIN_ID + pT->GetDlgCtrlID()); + + if (hSpin != NULL) + { + m_SpinCtrl.Attach(hSpin); +#ifdef DEBUG + TCHAR sClassName[16] = { 0 }; + ::GetClassName(hSpin, sClassName, 16); + ATLASSERT(!_tcscmp(sClassName, UPDOWN_CLASS)); + ATLASSERT(m_SpinCtrl.GetBuddy().m_hWnd == pT->m_hWnd); +#endif // DEBUG + } + else + { + m_SpinCtrl.Create(pT->GetParent(), pT->m_hWnd, m_dwSpinnedStyle, ATL_IDW_SPIN_ID + pT->GetDlgCtrlID()); + } + + return m_SpinCtrl.m_hWnd != NULL; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CSpinListBox - SmartPhone spinned ListBox control +// CExpandListBox - SmartPhone expandable ListBox control +// CExpandEdit - SmartPhone expandable Edit control +// CExpandCapEdit - SmartPhone expandable CapEdit control + +typedef CSpinned CSpinListBox; +typedef CSpinned CExpandListBox; +typedef CSpinned CExpandEdit; +typedef CSpinned CExpandCapEdit; + +#endif // WIN32_PLATFORM_WFSP + +#endif // _WTL_CE_NO_CONTROLS + +}; // namespace WTL + +#endif // __ATLWINCE_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/WTL/atlwinx.h b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlwinx.h new file mode 100644 index 0000000000000000000000000000000000000000..e6873a3f0a6684d5af9f61560996c3327c9d191f --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/WTL/atlwinx.h @@ -0,0 +1,522 @@ +// Windows Template Library - WTL version 9.10 +// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Microsoft Public License (http://opensource.org/licenses/MS-PL) +// which can be found in the file MS-PL.txt at the root folder. + +#ifndef __ATLWINX_H__ +#define __ATLWINX_H__ + +#pragma once + +#ifndef __ATLAPP_H__ + #error atlwinx.h requires atlapp.h to be included first +#endif + +#if (_ATL_VER >= 0x0700) + #include +#endif // (_ATL_VER >= 0x0700) + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// _U_RECT +// _U_MENUorID +// _U_STRINGorID + + +/////////////////////////////////////////////////////////////////////////////// +// Command Chaining Macros + +#define CHAIN_COMMANDS(theChainClass) \ + if(uMsg == WM_COMMAND) \ + CHAIN_MSG_MAP(theChainClass) + +#define CHAIN_COMMANDS_ALT(theChainClass, msgMapID) \ + if(uMsg == WM_COMMAND) \ + CHAIN_MSG_MAP_ALT(theChainClass, msgMapID) + +#define CHAIN_COMMANDS_MEMBER(theChainMember) \ + if(uMsg == WM_COMMAND) \ + CHAIN_MSG_MAP_MEMBER(theChainMember) + +#define CHAIN_COMMANDS_ALT_MEMBER(theChainMember, msgMapID) \ + if(uMsg == WM_COMMAND) \ + CHAIN_MSG_MAP_ALT_MEMBER(theChainMember, msgMapID) + + +/////////////////////////////////////////////////////////////////////////////// +// Macros for parent message map to selectively reflect control messages + +// NOTE: ReflectNotifications is a member of ATL's CWindowImplRoot +// (and overridden in 2 cases - CContainedWindowT and CAxHostWindow) +// Since we can't modify ATL, we'll provide the needed additions +// in a separate function (that is not a member of CWindowImplRoot) + +namespace WTL +{ + +inline LRESULT WtlReflectNotificationsFiltered(HWND hWndParent, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled, + UINT uMsgFilter = WM_NULL, UINT_PTR idFromFilter = 0, HWND hWndChildFilter = NULL) +{ + if((uMsgFilter != WM_NULL) && (uMsgFilter != uMsg)) + { + // The notification message doesn't match the filter. + bHandled = FALSE; + return 1; + } + + HWND hWndChild = NULL; + UINT_PTR idFrom = 0; + + switch(uMsg) + { + case WM_COMMAND: + if(lParam != NULL) // not from a menu + { + hWndChild = (HWND)lParam; + idFrom = (UINT_PTR)LOWORD(wParam); + } + break; + case WM_NOTIFY: + hWndChild = ((LPNMHDR)lParam)->hwndFrom; + idFrom = ((LPNMHDR)lParam)->idFrom; + break; +#ifndef _WIN32_WCE + case WM_PARENTNOTIFY: + switch(LOWORD(wParam)) + { + case WM_CREATE: + case WM_DESTROY: + hWndChild = (HWND)lParam; + idFrom = (UINT_PTR)HIWORD(wParam); + break; + default: + hWndChild = ::GetDlgItem(hWndParent, HIWORD(wParam)); + idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); + break; + } + break; +#endif // !_WIN32_WCE + case WM_DRAWITEM: + if(wParam) // not from a menu + { + hWndChild = ((LPDRAWITEMSTRUCT)lParam)->hwndItem; + idFrom = (UINT_PTR)wParam; + } + break; + case WM_MEASUREITEM: + if(wParam) // not from a menu + { + hWndChild = ::GetDlgItem(hWndParent, ((LPMEASUREITEMSTRUCT)lParam)->CtlID); + idFrom = (UINT_PTR)wParam; + } + break; + case WM_COMPAREITEM: + if(wParam) // not from a menu + { + hWndChild = ((LPCOMPAREITEMSTRUCT)lParam)->hwndItem; + idFrom = (UINT_PTR)wParam; + } + break; + case WM_DELETEITEM: + if(wParam) // not from a menu + { + hWndChild = ((LPDELETEITEMSTRUCT)lParam)->hwndItem; + idFrom = (UINT_PTR)wParam; + } + break; + case WM_VKEYTOITEM: + case WM_CHARTOITEM: + case WM_HSCROLL: + case WM_VSCROLL: + hWndChild = (HWND)lParam; + idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); + break; + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORMSGBOX: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: + hWndChild = (HWND)lParam; + idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); + break; + default: + break; + } + + if((hWndChild == NULL) || + ((hWndChildFilter != NULL) && (hWndChildFilter != hWndChild))) + { + // Either hWndChild isn't valid, or + // hWndChild doesn't match the filter. + bHandled = FALSE; + return 1; + } + + if((idFromFilter != 0) && (idFromFilter != idFrom)) + { + // The dialog control id doesn't match the filter. + bHandled = FALSE; + return 1; + } + + ATLASSERT(::IsWindow(hWndChild)); + LRESULT lResult = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam); + if((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC)) + { + // Try to prevent problems with WM_CTLCOLOR* messages when + // the message wasn't really handled + bHandled = FALSE; + } + + return lResult; +} + +}; // namespace WTL + +// Try to prevent problems with WM_CTLCOLOR* messages when +// the message wasn't really handled +#define REFLECT_NOTIFICATIONS_EX() \ +{ \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC)) \ + bHandled = FALSE; \ + if(bHandled) \ + return TRUE; \ +} + +#define REFLECT_NOTIFICATIONS_MSG_FILTERED(uMsgFilter) \ + { \ + bHandled = TRUE; \ + lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, NULL); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFICATIONS_ID_FILTERED(idFromFilter) \ + { \ + bHandled = TRUE; \ + lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, idFromFilter, NULL); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFICATIONS_HWND_FILTERED(hWndChildFilter) \ + { \ + bHandled = TRUE; \ + lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, 0, hWndChildFilter); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFICATIONS_MSG_ID_FILTERED(uMsgFilter, idFromFilter) \ + { \ + bHandled = TRUE; \ + lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, idFromFilter, NULL); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFICATIONS_MSG_HWND_FILTERED(uMsgFilter, hWndChildFilter) \ + { \ + bHandled = TRUE; \ + lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, hWndChildFilter); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_COMMAND(id, code) \ + if(uMsg == WM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_COMMAND_ID(id) \ + if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_COMMAND_CODE(code) \ + if(uMsg == WM_COMMAND && code == HIWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_COMMAND_RANGE(idFirst, idLast) \ + if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_COMMAND_RANGE_CODE(idFirst, idLast, code) \ + if(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFY(id, cd) \ + if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFY_ID(id) \ + if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFY_CODE(cd) \ + if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFY_RANGE(idFirst, idLast) \ + if(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFY_RANGE_CODE(idFirst, idLast, cd) \ + if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + + +/////////////////////////////////////////////////////////////////////////////// +// Reflected message handler macros for message maps (for ATL 3.0) + +#if (_ATL_VER < 0x0700) + +#define REFLECTED_COMMAND_HANDLER(id, code, func) \ + if(uMsg == OCM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_COMMAND_ID_HANDLER(id, func) \ + if(uMsg == OCM_COMMAND && id == LOWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_COMMAND_CODE_HANDLER(code, func) \ + if(uMsg == OCM_COMMAND && code == HIWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_COMMAND_RANGE_HANDLER(idFirst, idLast, func) \ + if(uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_COMMAND_RANGE_CODE_HANDLER(idFirst, idLast, code, func) \ + if(uMsg == OCM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_NOTIFY_HANDLER(id, cd, func) \ + if(uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \ + { \ + bHandled = TRUE; \ + lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_NOTIFY_ID_HANDLER(id, func) \ + if(uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ + { \ + bHandled = TRUE; \ + lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_NOTIFY_CODE_HANDLER(cd, func) \ + if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ + { \ + bHandled = TRUE; \ + lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_NOTIFY_RANGE_HANDLER(idFirst, idLast, func) \ + if(uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_NOTIFY_RANGE_CODE_HANDLER(idFirst, idLast, cd, func) \ + if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#endif // (_ATL_VER < 0x0700) + + +/////////////////////////////////////////////////////////////////////////////// +// Dual argument helper classes (for ATL 3.0) + +#if (_ATL_VER < 0x0700) + +namespace ATL +{ + +class _U_RECT +{ +public: + _U_RECT(LPRECT lpRect) : m_lpRect(lpRect) + { } + _U_RECT(RECT& rc) : m_lpRect(&rc) + { } + LPRECT m_lpRect; +}; + +class _U_MENUorID +{ +public: + _U_MENUorID(HMENU hMenu) : m_hMenu(hMenu) + { } + _U_MENUorID(UINT nID) : m_hMenu((HMENU)LongToHandle(nID)) + { } + HMENU m_hMenu; +}; + +class _U_STRINGorID +{ +public: + _U_STRINGorID(LPCTSTR lpString) : m_lpstr(lpString) + { } + _U_STRINGorID(UINT nID) : m_lpstr(MAKEINTRESOURCE(nID)) + { } + LPCTSTR m_lpstr; +}; + +}; // namespace ATL + +#endif // (_ATL_VER < 0x0700) + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// Forward notifications support for message maps (for ATL 3.0) + +#if (_ATL_VER < 0x0700) + +// forward notifications support +#define FORWARD_NOTIFICATIONS() \ + { \ + bHandled = TRUE; \ + lResult = WTL::Atl3ForwardNotifications(m_hWnd, uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +static LRESULT Atl3ForwardNotifications(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + LRESULT lResult = 0; + switch(uMsg) + { + case WM_COMMAND: + case WM_NOTIFY: +#ifndef _WIN32_WCE + case WM_PARENTNOTIFY: +#endif // !_WIN32_WCE + case WM_DRAWITEM: + case WM_MEASUREITEM: + case WM_COMPAREITEM: + case WM_DELETEITEM: + case WM_VKEYTOITEM: + case WM_CHARTOITEM: + case WM_HSCROLL: + case WM_VSCROLL: + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORMSGBOX: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: + lResult = ::SendMessage(::GetParent(hWnd), uMsg, wParam, lParam); + break; + default: + bHandled = FALSE; + break; + } + return lResult; +} + +#endif // (_ATL_VER < 0x0700) + +}; // namespace WTL + +#endif // __ATLWINX_H__ diff --git a/ZbaSDK/SampleCode/PluginWinExe/res/PluginWinExe.ico b/ZbaSDK/SampleCode/PluginWinExe/res/PluginWinExe.ico new file mode 100644 index 0000000000000000000000000000000000000000..7ce0295ee953658e7ecb40daba245179328ecda0 Binary files /dev/null and b/ZbaSDK/SampleCode/PluginWinExe/res/PluginWinExe.ico differ diff --git a/ZbaSDK/SampleCode/PluginWinExe/resource.h b/ZbaSDK/SampleCode/PluginWinExe/resource.h new file mode 100644 index 0000000000000000000000000000000000000000..a1bd7a457630d654c9dd6b3bb1b89198f96bbb24 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by PluginWinExe.rc +// +#define IDD_ABOUTBOX 100 +#define IDR_MAINFRAME 128 +#define IDD_MAINDLG 129 +#define IDC_EDIT_CONTENT 1000 +#define IDC_EDIT_LOG 1001 +#define IDC_WEB_BROWSER 1002 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32775 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/ZbaSDK/SampleCode/PluginWinExe/stdafx.cpp b/ZbaSDK/SampleCode/PluginWinExe/stdafx.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f1693ad9b12e3aca38ae884073b2666c08b1842 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/stdafx.cpp @@ -0,0 +1,9 @@ +// stdafx.cpp : source file that includes just the standard includes +// PluginWinExe.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +#if (_ATL_VER < 0x0700) +#include +#endif //(_ATL_VER < 0x0700) diff --git a/ZbaSDK/SampleCode/PluginWinExe/stdafx.h b/ZbaSDK/SampleCode/PluginWinExe/stdafx.h new file mode 100644 index 0000000000000000000000000000000000000000..a98bccce4db56ea7c43a1ae15d2b244dda8d9ec1 --- /dev/null +++ b/ZbaSDK/SampleCode/PluginWinExe/stdafx.h @@ -0,0 +1,53 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +// Change these values to use different versions +#define WINVER 0x0502 +#define _WIN32_WINNT 0x0502 +#define _WIN32_IE 0x0600 +#define _RICHEDIT_VER 0x0500 + +#include +/// 定义使用ATL的CString +#define _CSTRING_NS ATL +/// 不适用WTL的类型 +#define _WTL_NO_WTYPES +#include + +extern CAppModule _Module; + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#if defined _M_IX86 + #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_IA64 + #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_X64 + #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#else + #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") +#endif + +using namespace ATL; + +#pragma warning( disable : 4100 ) +#pragma warning( disable : 4510 ) +#pragma warning( disable : 4610 ) +#pragma warning( disable : 4206 ) + +#import "..\\Bin\\ZbaEngine.dll" no_namespace, raw_interfaces_only, raw_native_types, named_guids +#import "..\\Bin\\ZbaBase.dll" no_namespace, raw_interfaces_only, raw_native_types, named_guids