├── .clang-format ├── .editorconfig ├── .gitignore ├── .gitmodules ├── .tgitconfig ├── README.md ├── SendMessage.sln ├── azure-pipelines.yml ├── default.build ├── default.build.user.tmpl ├── src ├── AboutDlg.cpp ├── AboutDlg.h ├── AccessibleName.h ├── MainDlg.cpp ├── MainDlg.h ├── SendMessage.cpp ├── SendMessage.h ├── SendMessage.rc ├── SendMessage.rc2 ├── SendMessage.vcxproj ├── SendMessage.vcxproj.filters ├── WinMessage.cpp ├── WinMessage.h ├── WindowTreeDlg.cpp ├── WindowTreeDlg.h ├── XMLite.cpp ├── XMLite.h ├── auto_buffer.h ├── compatibility.manifest ├── last │ └── version.h ├── resource.h ├── resources │ ├── SendMessage.ico │ ├── searchw.cur │ ├── searchw.ico │ └── windowmessages.xml ├── stdafx.cpp ├── stdafx.h └── version.in ├── tools ├── checkyear.js └── coverity.bat ├── version.build.in └── versioninfo.build /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: AcrossEmptyLinesAndComments 6 | AlignConsecutiveBitFields: AcrossEmptyLinesAndComments 7 | AlignConsecutiveDeclarations: AcrossEmptyLinesAndComments 8 | AlignConsecutiveMacros: AcrossEmptyLinesAndComments 9 | AlignEscapedNewlines: Right 10 | AlignOperands: true 11 | AlignTrailingComments: true 12 | AllowAllParametersOfDeclarationOnNextLine: true 13 | AllowShortBlocksOnASingleLine: false 14 | AllowShortCaseLabelsOnASingleLine: false 15 | AllowShortFunctionsOnASingleLine: All 16 | AllowShortIfStatementsOnASingleLine: false 17 | AllowShortLoopsOnASingleLine: false 18 | AlwaysBreakAfterDefinitionReturnType: None 19 | AlwaysBreakAfterReturnType: None 20 | AlwaysBreakBeforeMultilineStrings: false 21 | AlwaysBreakTemplateDeclarations: false 22 | BinPackArguments: true 23 | BinPackParameters: true 24 | BraceWrapping: 25 | AfterClass: true 26 | AfterControlStatement: true 27 | AfterEnum: true 28 | AfterFunction: true 29 | AfterNamespace: true 30 | AfterObjCDeclaration: true 31 | AfterStruct: true 32 | AfterUnion: true 33 | BeforeCatch: true 34 | BeforeElse: true 35 | IndentBraces: false 36 | SplitEmptyFunction: true 37 | SplitEmptyRecord: true 38 | SplitEmptyNamespace: true 39 | BreakBeforeBinaryOperators: None 40 | BreakBeforeBraces: Custom 41 | BreakBeforeInheritanceComma: true 42 | BreakBeforeTernaryOperators: true 43 | BreakConstructorInitializersBeforeComma: true 44 | BreakConstructorInitializers: BeforeColon 45 | BreakAfterJavaFieldAnnotations: false 46 | BreakStringLiterals: true 47 | ColumnLimit: 0 48 | CommentPragmas: '^ IWYU pragma:' 49 | CompactNamespaces: false 50 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 51 | ConstructorInitializerIndentWidth: 4 52 | ContinuationIndentWidth: 4 53 | Cpp11BracedListStyle: true 54 | DerivePointerAlignment: true 55 | DisableFormat: false 56 | ExperimentalAutoDetectBinPacking: false 57 | FixNamespaceComments: true 58 | ForEachMacros: 59 | - foreach 60 | - Q_FOREACH 61 | - BOOST_FOREACH 62 | IncludeCategories: 63 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 64 | Priority: 2 65 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 66 | Priority: 3 67 | - Regex: '.*' 68 | Priority: 1 69 | IncludeIsMainRegex: '(Test)?$' 70 | IndentCaseLabels: true 71 | #IndentPPDirectives: AfterHash 72 | IndentWidth: 4 73 | IndentWrappedFunctionNames: true 74 | JavaScriptQuotes: Leave 75 | JavaScriptWrapImports: true 76 | KeepEmptyLinesAtTheStartOfBlocks: false 77 | MacroBlockBegin: "^\ 78 | BEGIN_MSG_MAP|\ 79 | BEGIN_MESSAGE_MAP|\ 80 | BEGIN_MSG_MAP_EX|\ 81 | BEGIN_MESSAGE_MAP_EX|\ 82 | BEGIN_SAFE_MSG_MAP_EX|\ 83 | CR_BEGIN_MSG_MAP_EX|\ 84 | IPC_BEGIN_MESSAGE_MAP|\ 85 | IPC_BEGIN_MESSAGE_MAP_WITH_PARAM|\ 86 | IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN|\ 87 | IPC_STRUCT_BEGIN|\ 88 | IPC_STRUCT_BEGIN_WITH_PARENT|\ 89 | IPC_STRUCT_TRAITS_BEGIN|\ 90 | POLPARAMS_BEGIN|\ 91 | PPAPI_BEGIN_MESSAGE_MAP$" 92 | MacroBlockEnd: "^\ 93 | CR_END_MSG_MAP|\ 94 | END_MSG_MAP|\ 95 | END_MESSAGE_MAP|\ 96 | IPC_END_MESSAGE_MAP|\ 97 | IPC_PROTOBUF_MESSAGE_TRAITS_END|\ 98 | IPC_STRUCT_END|\ 99 | IPC_STRUCT_TRAITS_END|\ 100 | POLPARAMS_END|\ 101 | PPAPI_END_MESSAGE_MAP$" 102 | MaxEmptyLinesToKeep: 1 103 | NamespaceIndentation: None 104 | ObjCBlockIndentWidth: 2 105 | ObjCSpaceAfterProperty: false 106 | ObjCSpaceBeforeProtocolList: true 107 | PenaltyBreakAssignment: 2 108 | PenaltyBreakBeforeFirstCallParameter: 19 109 | PenaltyBreakComment: 300 110 | PenaltyBreakFirstLessLess: 120 111 | PenaltyBreakString: 1000 112 | PenaltyExcessCharacter: 1000000 113 | PenaltyReturnTypeOnItsOwnLine: 60 114 | PointerAlignment: Left 115 | ReflowComments: true 116 | SortIncludes: false 117 | SortUsingDeclarations: true 118 | SpaceAfterCStyleCast: false 119 | SpaceAfterTemplateKeyword: true 120 | SpaceBeforeAssignmentOperators: true 121 | SpaceBeforeParens: ControlStatements 122 | SpaceInEmptyParentheses: false 123 | SpacesBeforeTrailingComments: 1 124 | SpacesInAngles: false 125 | SpacesInContainerLiterals: false 126 | SpacesInCStyleCastParentheses: false 127 | SpacesInParentheses: false 128 | SpacesInSquareBrackets: false 129 | Standard: Cpp11 130 | TabWidth: 4 131 | UseTab: Never 132 | ... 133 | 134 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{cpp,cxx,h,hpp,c,txt,build}] 2 | end_of_line = crlf 3 | indent_style = space 4 | indent_size = 4 5 | charset = utf-8-bom 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /default.build.user 2 | /src/SendMessage.vcxproj.user 3 | /src/version.h 4 | /version.build 5 | /bin 6 | /obj 7 | /.vs 8 | /signinfo.txt 9 | /_ReSharper.Caches 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "sktoolslib"] 2 | path = sktoolslib 3 | url = https://github.com/stefankueng/sktoolslib.git 4 | -------------------------------------------------------------------------------- /.tgitconfig: -------------------------------------------------------------------------------- 1 | [hook "precommit"] 2 | cmdline = WScript %root%\\\\tools\\\\checkyear.js 3 | wait = true 4 | show = false 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SendMessage 2 | SendMessage is a little tool to send Windows messages to any window. 3 | 4 | [![Build Status](https://tortoisesvn.visualstudio.com/tortoisesvnGitHub/_apis/build/status/stefankueng.sendmessage)](https://tortoisesvn.visualstudio.com/tortoisesvnGitHub/_build/latest?definitionId=9) 5 | 6 | Ever wondered how you should test whether your application correctly 7 | responds to certain system messages like WM_ENDSESSION or WM_POWERBROADCAST? 8 | Of course you can test your application by actually triggering those messages, 9 | but especially the WM_ENDSESSION message and its purpose makes it impossible 10 | to attach a debugger to your application once Windows sends you that message. 11 | 12 | With this tool, you can send that message and any other message you 13 | like to your application window. And you can do that while you have 14 | a debugger attached to your application! 15 | 16 | Please visit the [homepage](https://tools.stefankueng.com/SendMessage.html) of SendMessage for more information. 17 | -------------------------------------------------------------------------------- /SendMessage.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Version 17 3 | VisualStudioVersion = 17.0.32002.185 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SendMessage", "src\SendMessage.vcxproj", "{D1CCDBC4-3C7C-4E14-B980-73FCF457A4C1}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Win32 = Debug|Win32 10 | Debug|x64 = Debug|x64 11 | Release|Win32 = Release|Win32 12 | Release|x64 = Release|x64 13 | EndGlobalSection 14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 15 | {D1CCDBC4-3C7C-4E14-B980-73FCF457A4C1}.Debug|Win32.ActiveCfg = Debug|Win32 16 | {D1CCDBC4-3C7C-4E14-B980-73FCF457A4C1}.Debug|Win32.Build.0 = Debug|Win32 17 | {D1CCDBC4-3C7C-4E14-B980-73FCF457A4C1}.Debug|x64.ActiveCfg = Debug|x64 18 | {D1CCDBC4-3C7C-4E14-B980-73FCF457A4C1}.Debug|x64.Build.0 = Debug|x64 19 | {D1CCDBC4-3C7C-4E14-B980-73FCF457A4C1}.Release|Win32.ActiveCfg = Release|Win32 20 | {D1CCDBC4-3C7C-4E14-B980-73FCF457A4C1}.Release|Win32.Build.0 = Release|Win32 21 | {D1CCDBC4-3C7C-4E14-B980-73FCF457A4C1}.Release|x64.ActiveCfg = Release|x64 22 | {D1CCDBC4-3C7C-4E14-B980-73FCF457A4C1}.Release|x64.Build.0 = Release|x64 23 | EndGlobalSection 24 | GlobalSection(SolutionProperties) = preSolution 25 | HideSolutionNode = FALSE 26 | EndGlobalSection 27 | GlobalSection(ExtensibilityGlobals) = postSolution 28 | SolutionGuid = {498585C1-D9A2-4A0F-8BB1-AA5B4670C34C} 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # .NET Desktop 2 | # Build and run tests for .NET Desktop or Windows classic desktop solutions. 3 | # Add steps that publish symbols, save build artifacts, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net 5 | 6 | pool: 7 | vmImage: 'VS2017-Win2016' 8 | 9 | variables: 10 | solution: '**/*.sln' 11 | buildPlatform: 'x64' 12 | buildConfiguration: 'Release' 13 | 14 | steps: 15 | - task: NuGetToolInstaller@0 16 | 17 | - task: NuGetCommand@2 18 | inputs: 19 | restoreSolution: '$(solution)' 20 | 21 | - task: VSBuild@1 22 | inputs: 23 | solution: '$(solution)' 24 | platform: '$(buildPlatform)' 25 | configuration: '$(buildConfiguration)' 26 | 27 | - task: VSTest@2 28 | inputs: 29 | platform: '$(buildPlatform)' 30 | configuration: '$(buildConfiguration)' 31 | -------------------------------------------------------------------------------- /default.build: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Sets the environment up to build the debug versions. 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Cleans every subproject. 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | Sets the version information as properties, env variables 52 | and sets up the different version specific files. 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Builds SendMessage. 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /default.build.user.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | You must first call "%VS140COMNTOOLS%\vsvars32.bat" 24 | 25 | 26 | 27 | 28 | 34 | 35 | 36 | 37 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 52 | 53 | 54 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/AboutDlg.cpp: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2010-2013, 2018, 2021 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #include "stdafx.h" 21 | #include "resource.h" 22 | #include "AboutDlg.h" 23 | #include "version.h" 24 | #include 25 | 26 | CAboutDlg::CAboutDlg(HWND hParent) 27 | : m_hParent(hParent) 28 | { 29 | } 30 | 31 | CAboutDlg::~CAboutDlg() 32 | { 33 | } 34 | 35 | LRESULT CAboutDlg::DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 36 | { 37 | UNREFERENCED_PARAMETER(lParam); 38 | switch (uMsg) 39 | { 40 | case WM_INITDIALOG: { 41 | InitDialog(hwndDlg, IDI_SENDMESSAGE); 42 | TCHAR buf[MAX_PATH] = {0}; 43 | _stprintf_s(buf, _countof(buf), _T("SendMessage version %ld.%ld.%ld.%ld"), SM_VERMAJOR, SM_VERMINOR, SM_VERMICRO, SM_VERBUILD); 44 | SetDlgItemText(*this, IDC_VERSIONINFO, buf); 45 | SetDlgItemText(*this, IDC_DATE, _T(SM_VERDATE)); 46 | m_link.ConvertStaticToHyperlink(hwndDlg, IDC_WEBLINK, L"https://tools.stefankueng.com"); 47 | } 48 | return TRUE; 49 | case WM_COMMAND: 50 | return DoCommand(LOWORD(wParam), HIWORD(wParam)); 51 | default: 52 | return FALSE; 53 | } 54 | } 55 | 56 | LRESULT CAboutDlg::DoCommand(int id, int /*msg*/) 57 | { 58 | switch (id) 59 | { 60 | case IDOK: 61 | // fall through 62 | case IDCANCEL: 63 | EndDialog(*this, id); 64 | break; 65 | } 66 | return 1; 67 | } 68 | -------------------------------------------------------------------------------- /src/AboutDlg.h: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2010, 2021 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #pragma once 21 | #include "BaseDialog.h" 22 | #include "hyperlink.h" 23 | 24 | class CAboutDlg : public CDialog 25 | { 26 | public: 27 | CAboutDlg(HWND hParent); 28 | ~CAboutDlg() override; 29 | 30 | protected: 31 | LRESULT CALLBACK DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) override; 32 | LRESULT DoCommand(int id, int msg); 33 | 34 | private: 35 | HWND m_hParent; 36 | CHyperLink m_link; 37 | }; 38 | -------------------------------------------------------------------------------- /src/AccessibleName.h: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2018 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #pragma once 21 | #pragma comment(lib, "Oleacc.lib") 22 | class CAccessibleName 23 | { 24 | BSTR m_str; 25 | public: 26 | explicit CAccessibleName(HWND hwnd): m_str(NULL) 27 | { 28 | IAccessible *lpAccessible = NULL; 29 | if (SUCCEEDED(AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, IID_IAccessible, (void **)&lpAccessible))) 30 | { 31 | VARIANT varChild; 32 | varChild.vt = VT_I4; 33 | varChild.lVal = 0; 34 | lpAccessible->get_accName(varChild, &m_str); 35 | lpAccessible->Release(); 36 | } 37 | } 38 | ~CAccessibleName() 39 | { 40 | SysFreeString(m_str); 41 | } 42 | LPCWSTR c_str() const 43 | { 44 | return m_str ? m_str : L""; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /src/MainDlg.cpp: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2010, 2012-2015, 2018-2019, 2021 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #include "stdafx.h" 21 | #include "resource.h" 22 | #include "MainDlg.h" 23 | 24 | #include 25 | 26 | #include "AboutDlg.h" 27 | #include "WindowTreeDlg.h" 28 | #include "WinMessage.h" 29 | #include "AccessibleName.h" 30 | #include "StringUtils.h" 31 | 32 | CMainDlg::CMainDlg(HWND hParent) 33 | : m_hParent(hParent) 34 | , m_bStartSearchWindow(false) 35 | , m_hwndFoundWindow(nullptr) 36 | , m_hRectanglePen(nullptr) 37 | { 38 | } 39 | 40 | CMainDlg::~CMainDlg() 41 | { 42 | } 43 | 44 | LRESULT CMainDlg::DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 45 | { 46 | UNREFERENCED_PARAMETER(lParam); 47 | switch (uMsg) 48 | { 49 | case WM_INITDIALOG: { 50 | InitDialog(hwndDlg, IDI_SENDMESSAGE); 51 | 52 | // add an "About" entry to the system menu 53 | HMENU hSysMenu = GetSystemMenu(hwndDlg, FALSE); 54 | if (hSysMenu) 55 | { 56 | int menuItemsCount = GetMenuItemCount(hSysMenu); 57 | if (menuItemsCount > 2) 58 | { 59 | InsertMenu(hSysMenu, menuItemsCount - 2, MF_STRING | MF_BYPOSITION, ID_ABOUTBOX, _T("&About SendMessage...")); 60 | InsertMenu(hSysMenu, menuItemsCount - 2, MF_SEPARATOR | MF_BYPOSITION, NULL, nullptr); 61 | } 62 | else 63 | { 64 | AppendMenu(hSysMenu, MF_SEPARATOR, NULL, nullptr); 65 | AppendMenu(hSysMenu, MF_STRING, ID_ABOUTBOX, _T("&About SendMessage...")); 66 | } 67 | 68 | MENUITEMINFO stItem; 69 | stItem.cbSize = sizeof(MENUITEMINFO); 70 | stItem.fMask = MIIM_STRING; 71 | stItem.dwTypeData = (LPTSTR)TEXT("Always On Top"); 72 | SetMenuItemInfo(hSysMenu, SC_MAXIMIZE, FALSE, &stItem); 73 | } 74 | m_link.ConvertStaticToHyperlink(hwndDlg, IDC_ABOUTLINK, _T("")); 75 | 76 | m_hRectanglePen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0)); 77 | 78 | // now fill the window message combo box 79 | for (size_t i = 0; i < WinMessages::Instance().GetCount(); ++i) 80 | { 81 | WinMessage msg = WinMessages::Instance().At(i); 82 | LRESULT index = SendDlgItemMessage(*this, IDC_MESSAGE, CB_ADDSTRING, 0, reinterpret_cast(msg.messagename.c_str())); 83 | SendDlgItemMessage(*this, IDC_MESSAGE, CB_SETITEMDATA, index, msg.message); 84 | } 85 | 86 | WINDOWPLACEMENT wpl = {0}; 87 | DWORD size = sizeof(wpl); 88 | if (SHGetValue(HKEY_CURRENT_USER, _T("Software\\SendMessage"), _T("windowpos"), REG_NONE, &wpl, &size) == ERROR_SUCCESS) 89 | SetWindowPlacement(*this, &wpl); 90 | else 91 | ShowWindow(*this, SW_SHOW); 92 | 93 | ExtendFrameIntoClientArea(IDC_SENDGROUP, IDC_SENDGROUP, IDC_SENDGROUP, IDC_SENDGROUP); 94 | m_aerocontrols.SubclassControl(GetDlgItem(*this, IDC_SEARCHW)); 95 | m_aerocontrols.SubclassControl(GetDlgItem(*this, IDC_ABOUTLINK)); 96 | m_aerocontrols.SubclassControl(GetDlgItem(*this, IDC_POS)); 97 | m_aerocontrols.SubclassControl(GetDlgItem(*this, IDC_STATIC_X_POS)); 98 | m_aerocontrols.SubclassControl(GetDlgItem(*this, IDC_STATIC_Y_POS)); 99 | m_aerocontrols.SubclassControl(GetDlgItem(*this, IDC_EDIT_STATUS)); 100 | m_aerocontrols.SubclassControl(GetDlgItem(*this, IDC_WINDOWTREE)); 101 | m_aerocontrols.SubclassControl(GetDlgItem(*this, IDOK)); 102 | 103 | if (HWND hCmdShow = GetDlgItem(*this, IDC_CMDSHOW)) 104 | { 105 | ComboBox_AddString(hCmdShow, TEXT("SW_HIDE")); 106 | ComboBox_AddString(hCmdShow, TEXT("SW_SHOWNORMAL")); 107 | ComboBox_AddString(hCmdShow, TEXT("SW_SHOWMINIMIZED")); 108 | ComboBox_AddString(hCmdShow, TEXT("SW_SHOWMAXIMIZED")); 109 | ComboBox_AddString(hCmdShow, TEXT("SW_SHOWNOACTIVATE")); 110 | ComboBox_AddString(hCmdShow, TEXT("SW_SHOW")); 111 | ComboBox_AddString(hCmdShow, TEXT("SW_MINIMIZE")); 112 | ComboBox_AddString(hCmdShow, TEXT("SW_SHOWMINNOACTIVE")); 113 | ComboBox_AddString(hCmdShow, TEXT("SW_SHOWNA")); 114 | ComboBox_AddString(hCmdShow, TEXT("SW_RESTORE")); 115 | ComboBox_AddString(hCmdShow, TEXT("SW_SHOWDEFAULT")); 116 | ComboBox_AddString(hCmdShow, TEXT("SW_FORCEMINIMIZE")); 117 | ComboBox_SetCurSel(hCmdShow, 0); 118 | } 119 | } 120 | return FALSE; 121 | case WM_COMMAND: 122 | return DoCommand(LOWORD(wParam), HIWORD(wParam)); 123 | case WM_SYSCOMMAND: 124 | switch (wParam & 0xFFF0) 125 | { 126 | case ID_ABOUTBOX: 127 | CAboutDlg(*this).DoModal(hResource, IDD_ABOUTBOX, *this); 128 | break; 129 | case SC_MINIMIZE: 130 | SetWindowLongPtr(hwndDlg, GWL_STYLE, GetWindowLongPtr(hwndDlg, GWL_STYLE) & ~WS_MAXIMIZE); 131 | break; 132 | case SC_MAXIMIZE: 133 | SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 134 | return TRUE; 135 | case SC_RESTORE: 136 | if (!IsIconic(hwndDlg)) 137 | { 138 | SetWindowPos(hwndDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 139 | return TRUE; 140 | } 141 | break; 142 | } 143 | break; 144 | case WM_WINDOWPOSCHANGED: 145 | if (GetWindowLongPtr(hwndDlg, GWL_EXSTYLE) & WS_EX_TOPMOST) 146 | SetWindowLongPtr(hwndDlg, GWL_STYLE, GetWindowLongPtr(hwndDlg, GWL_STYLE) | WS_MAXIMIZE); 147 | else 148 | SetWindowLongPtr(hwndDlg, GWL_STYLE, GetWindowLongPtr(hwndDlg, GWL_STYLE) & ~WS_MAXIMIZE); 149 | break; 150 | case WM_MOUSEMOVE: 151 | if (m_bStartSearchWindow) 152 | DoMouseMove(uMsg, wParam, lParam); 153 | break; 154 | case WM_LBUTTONUP: 155 | if (m_bStartSearchWindow) 156 | DoMouseUp(uMsg, wParam, lParam); 157 | break; 158 | case WM_SETCURSOR: 159 | if (m_bStartSearchWindow) 160 | { 161 | SetCursor(LoadCursor(hResource, MAKEINTRESOURCE(IDC_SEARCHW))); 162 | return TRUE; 163 | } 164 | break; 165 | default: 166 | return FALSE; 167 | } 168 | return FALSE; 169 | } 170 | 171 | LRESULT CMainDlg::DoCommand(int id, int msg) 172 | { 173 | switch (id) 174 | { 175 | case IDOK: 176 | case IDCANCEL: 177 | DeleteObject(m_hRectanglePen); 178 | EndDialog(*this, id); 179 | break; 180 | case IDC_SEARCHW: 181 | SearchWindow(); 182 | break; 183 | case IDC_WINDOWTREE: { 184 | CWindowTreeDlg treeDlg(*this, GetSelectedHandle()); 185 | if (treeDlg.DoModal(hResource, IDD_WINDOWSTREE, *this) == IDOK) 186 | { 187 | m_hwndFoundWindow = treeDlg.GetSelectedWindow(); 188 | DisplayInfoOnFoundWindow(m_hwndFoundWindow); 189 | TCHAR szText[256]; 190 | _stprintf_s(szText, _countof(szText), _T("0x%p"), m_hwndFoundWindow); 191 | SetDlgItemText(*this, IDC_WINDOW, szText); 192 | } 193 | } 194 | break; 195 | case IDC_SENDMESSAGE: 196 | case IDC_POSTMESSAGE: 197 | if (!SendPostMessage(id)) 198 | { 199 | SetDlgItemText(*this, IDC_ERROR, _T("Message not recognized")); 200 | } 201 | break; 202 | case IDC_PINWINDOW: 203 | case IDC_UNPINWINDOW: 204 | if (HWND hWnd = GetSelectedHandle()) 205 | { 206 | HWND hWndInsertAfter = id == IDC_PINWINDOW ? HWND_TOPMOST : HWND_NOTOPMOST; 207 | int res = SetWindowPos(hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 208 | TCHAR buf[MAX_PATH]{}; 209 | _stprintf_s(buf, _countof(buf), _T("0x%08x (%d)"), res, res); 210 | SetDlgItemText(*this, IDC_RETVALUE, buf); 211 | SetDlgItemText(*this, IDC_ERROR, _T("")); 212 | } 213 | else 214 | { 215 | SetDlgItemText(*this, IDC_RETVALUE, _T("")); 216 | SetDlgItemText(*this, IDC_ERROR, _T("Window not found")); 217 | } 218 | break; 219 | case IDC_SHOWWINDOW: 220 | if (HWND hWnd = GetSelectedHandle()) 221 | { 222 | int nCmdShow = ComboBox_GetCurSel(GetDlgItem(*this, IDC_CMDSHOW)); 223 | int res = ShowWindow(hWnd, nCmdShow); 224 | TCHAR buf[MAX_PATH]{}; 225 | _stprintf_s(buf, _countof(buf), _T("0x%08x (%d)"), res, res); 226 | SetDlgItemText(*this, IDC_RETVALUE, buf); 227 | SetDlgItemText(*this, IDC_ERROR, _T("")); 228 | } 229 | else 230 | { 231 | SetDlgItemText(*this, IDC_RETVALUE, _T("")); 232 | SetDlgItemText(*this, IDC_ERROR, _T("Window not found")); 233 | } 234 | break; 235 | case IDC_ABOUTLINK: { 236 | CAboutDlg dlgAbout(*this); 237 | dlgAbout.DoModal(hResource, IDD_ABOUTBOX, *this); 238 | } 239 | break; 240 | case IDC_MESSAGE: { 241 | switch (msg) 242 | { 243 | case CBN_EDITCHANGE: 244 | case CBN_SELCHANGE: { 245 | // the selected window message has changed, adjust the wparam and lparam comboboxes 246 | LRESULT selIndex = SendDlgItemMessage(*this, IDC_MESSAGE, CB_GETCURSEL, 0, 0); 247 | SendDlgItemMessage(*this, IDC_WPARAM, CB_RESETCONTENT, 0, 0); 248 | SendDlgItemMessage(*this, IDC_LPARAM, CB_RESETCONTENT, 0, 0); 249 | if (selIndex != CB_ERR) 250 | { 251 | LRESULT textlen = SendDlgItemMessage(*this, IDC_MESSAGE, CB_GETLBTEXTLEN, selIndex, 0); 252 | auto textbuf = std::make_unique(textlen + 1); 253 | SendDlgItemMessage(*this, IDC_MESSAGE, CB_GETLBTEXT, selIndex, reinterpret_cast(textbuf.get())); 254 | for (size_t i = 0; i < WinMessages::Instance().GetCount(); ++i) 255 | { 256 | WinMessage wmsg = WinMessages::Instance().At(i); 257 | if (wmsg.messagename.compare(textbuf.get()) == 0) 258 | { 259 | for (size_t j = 0; j < wmsg.wparams.size(); ++j) 260 | { 261 | std::wstring desc = std::get<0>(wmsg.wparams[j]); 262 | LRESULT index = SendDlgItemMessage(*this, IDC_WPARAM, CB_ADDSTRING, 0, reinterpret_cast(desc.c_str())); 263 | SendDlgItemMessage(*this, IDC_WPARAM, CB_SETITEMDATA, index, std::get<1>(wmsg.wparams[j])); 264 | } 265 | for (size_t j = 0; j < wmsg.lparams.size(); ++j) 266 | { 267 | std::wstring desc = std::get<0>(wmsg.lparams[j]); 268 | LRESULT index = SendDlgItemMessage(*this, IDC_LPARAM, CB_ADDSTRING, 0, reinterpret_cast(desc.c_str())); 269 | SendDlgItemMessage(*this, IDC_LPARAM, CB_SETITEMDATA, index, std::get<1>(wmsg.lparams[j])); 270 | } 271 | } 272 | } 273 | } 274 | } 275 | break; 276 | } 277 | } 278 | break; 279 | } 280 | return 1; 281 | } 282 | 283 | void CMainDlg::SaveWndPosition() 284 | { 285 | WINDOWPLACEMENT wpl = {0}; 286 | wpl.length = sizeof(WINDOWPLACEMENT); 287 | GetWindowPlacement(*this, &wpl); 288 | SHSetValue(HKEY_CURRENT_USER, _T("Software\\SendMessage"), _T("windowpos"), REG_NONE, &wpl, sizeof(wpl)); 289 | } 290 | 291 | bool CMainDlg::PreTranslateMessage(MSG* pMsg) 292 | { 293 | if (pMsg->message == WM_KEYDOWN) 294 | { 295 | } 296 | return false; 297 | } 298 | 299 | bool CMainDlg::SearchWindow() 300 | { 301 | m_bStartSearchWindow = true; 302 | SetCapture(*this); 303 | 304 | return true; 305 | } 306 | 307 | bool CMainDlg::DoMouseMove(UINT /*message*/, WPARAM /*wParam*/, LPARAM /*lParam*/) 308 | { 309 | POINT screenpoint{}; 310 | HWND hwndFoundWindow = nullptr; 311 | TCHAR szText[256]{}; 312 | 313 | // Must use GetCursorPos() instead of calculating from "lParam". 314 | GetCursorPos(&screenpoint); 315 | 316 | // Display global positioning in the dialog box. 317 | _stprintf_s(szText, _countof(szText), _T("%d"), screenpoint.x); 318 | SetDlgItemText(*this, IDC_STATIC_X_POS, szText); 319 | 320 | _stprintf_s(szText, _countof(szText), _T("%d"), screenpoint.y); 321 | SetDlgItemText(*this, IDC_STATIC_Y_POS, szText); 322 | 323 | // Determine the window that lies underneath the mouse cursor. 324 | hwndFoundWindow = WindowFromPoint(screenpoint); 325 | 326 | if (CheckWindowValidity(hwndFoundWindow)) 327 | { 328 | // We have just found a new window. 329 | 330 | // If there was a previously found window, we must instruct it to refresh itself. 331 | // This is done to remove any highlighting effects drawn by us. 332 | if (m_hwndFoundWindow) 333 | { 334 | RefreshWindow(m_hwndFoundWindow); 335 | } 336 | 337 | m_hwndFoundWindow = hwndFoundWindow; 338 | 339 | // Display some information on this found window. 340 | DisplayInfoOnFoundWindow(hwndFoundWindow); 341 | 342 | // We now highlight the found window. 343 | HighlightFoundWindow(m_hwndFoundWindow); 344 | } 345 | SetCursor(LoadCursor(hResource, MAKEINTRESOURCE(IDC_SEARCHW))); 346 | 347 | return true; 348 | } 349 | 350 | bool CMainDlg::DoMouseUp(UINT /*message*/, WPARAM /*wParam*/, LPARAM /*lParam*/) 351 | { 352 | // If there was a found window, refresh it so that its highlighting is erased. 353 | if (m_hwndFoundWindow) 354 | { 355 | RefreshWindow(m_hwndFoundWindow); 356 | } 357 | 358 | ReleaseCapture(); 359 | 360 | m_bStartSearchWindow = false; 361 | 362 | if (m_hwndFoundWindow == nullptr) 363 | return false; 364 | if (IsWindow(m_hwndFoundWindow) == FALSE) 365 | return false; 366 | if (m_hwndFoundWindow == *this) 367 | return false; 368 | 369 | HWND hwndTemp = GetParent(m_hwndFoundWindow); 370 | if (hwndTemp == *this) 371 | return false; 372 | 373 | hwndTemp = GetParent(hwndTemp); 374 | if (hwndTemp == *this) 375 | return false; 376 | 377 | TCHAR szText[256]{}; 378 | _stprintf_s(szText, _countof(szText), _T("0x%p"), m_hwndFoundWindow); 379 | SetDlgItemText(*this, IDC_WINDOW, szText); 380 | 381 | return true; 382 | } 383 | 384 | bool CMainDlg::CheckWindowValidity(HWND hwndToCheck) 385 | { 386 | HWND hwndTemp = nullptr; 387 | 388 | // The window must not be NULL. 389 | if (hwndToCheck == nullptr) 390 | { 391 | return false; 392 | } 393 | 394 | // Ensure that the window is not the current one which has already been found. 395 | if (hwndToCheck == m_hwndFoundWindow) 396 | { 397 | return false; 398 | } 399 | 400 | // It must also be a valid window as far as the OS is concerned. 401 | if (IsWindow(hwndToCheck) == FALSE) 402 | { 403 | return false; 404 | } 405 | 406 | // It must also not be the main window itself. 407 | if (hwndToCheck == *this) 408 | { 409 | return false; 410 | } 411 | 412 | // It also must not be one of the dialog box's children... 413 | hwndTemp = GetParent(hwndToCheck); 414 | if (hwndTemp == *this) 415 | { 416 | return false; 417 | } 418 | hwndTemp = GetParent(hwndTemp); 419 | if (hwndTemp == *this) 420 | { 421 | return false; 422 | } 423 | 424 | return true; 425 | } 426 | 427 | bool CMainDlg::DisplayInfoOnFoundWindow(HWND hwndFoundWindow) 428 | { 429 | RECT rect{}; // Rectangle area of the found window. 430 | TCHAR szClassName[100]{}; 431 | 432 | // Get the screen coordinates of the rectangle of the found window. 433 | GetWindowRect(hwndFoundWindow, &rect); 434 | 435 | // Get the class name of the found window. 436 | GetClassName(hwndFoundWindow, szClassName, _countof(szClassName)); 437 | 438 | // Display some information on the found window. 439 | auto sText = CStringUtils::Format(L"Window Handle == 0x%p\r\nClass Name : %s\r\nAccessible Name : %s\r\nRECT == { Left: %d, Top: %d, Right: %d, Bottom: %d } [ %d x %d ]\r\n", 440 | hwndFoundWindow, 441 | szClassName, 442 | CAccessibleName(hwndFoundWindow).c_str(), 443 | rect.left, 444 | rect.top, 445 | rect.right, 446 | rect.bottom, 447 | rect.right - rect.left, 448 | rect.bottom - rect.top); 449 | 450 | SetDlgItemText(*this, IDC_EDIT_STATUS, sText.c_str()); 451 | 452 | return true; 453 | } 454 | 455 | bool CMainDlg::RefreshWindow(HWND hwndWindowToBeRefreshed) 456 | { 457 | InvalidateRect(hwndWindowToBeRefreshed, nullptr, TRUE); 458 | UpdateWindow(hwndWindowToBeRefreshed); 459 | RedrawWindow(hwndWindowToBeRefreshed, nullptr, nullptr, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); 460 | 461 | return true; 462 | } 463 | 464 | bool CMainDlg::HighlightFoundWindow(HWND hwndFoundWindow) const 465 | { 466 | HDC hWindowDC = nullptr; // The DC of the found window. 467 | RECT rect{}; // Rectangle area of the found window. 468 | 469 | GetWindowRect(hwndFoundWindow, &rect); 470 | hWindowDC = GetWindowDC(hwndFoundWindow); 471 | 472 | if (hWindowDC) 473 | { 474 | HGDIOBJ hPrevPen = SelectObject(hWindowDC, m_hRectanglePen); // Handle of the existing pen in the DC of the found window. 475 | HGDIOBJ hPrevBrush = SelectObject(hWindowDC, GetStockObject(HOLLOW_BRUSH)); // Handle of the existing brush in the DC of the found window. 476 | 477 | // Draw a rectangle in the DC covering the entire window area of the found window. 478 | Rectangle(hWindowDC, 1, 1, rect.right - rect.left - 2, rect.bottom - rect.top - 2); 479 | 480 | SelectObject(hWindowDC, hPrevPen); 481 | SelectObject(hWindowDC, hPrevBrush); 482 | ReleaseDC(hwndFoundWindow, hWindowDC); 483 | } 484 | 485 | return true; 486 | } 487 | 488 | HWND CMainDlg::GetSelectedHandle() 489 | { 490 | TCHAR buf[MAX_PATH]{}; 491 | 492 | ::GetDlgItemText(*this, IDC_WINDOW, buf, _countof(buf)); 493 | 494 | TCHAR* endptr = nullptr; 495 | return reinterpret_cast(_tcstoui64(buf, &endptr, 0)); 496 | } 497 | 498 | bool CMainDlg::SendPostMessage(UINT id) 499 | { 500 | HWND hTargetWnd = GetSelectedHandle(); 501 | if (hTargetWnd == nullptr) 502 | return false; 503 | SetDlgItemText(*this, IDC_RETVALUE, _T("")); 504 | 505 | UINT msg = 0; 506 | WPARAM wparam = 0; 507 | LPARAM lparam = 0; 508 | TCHAR buf[MAX_PATH]{}; 509 | TCHAR* endptr = nullptr; 510 | 511 | ::GetDlgItemText(*this, IDC_MESSAGE, buf, _countof(buf)); 512 | msg = _tcstol(buf, &endptr, 0); 513 | if (msg == 0) 514 | { 515 | LRESULT selIndex = SendDlgItemMessage(*this, IDC_MESSAGE, CB_GETCURSEL, 0, 0); 516 | if (selIndex != CB_ERR) 517 | msg = static_cast(SendDlgItemMessage(*this, IDC_MESSAGE, CB_GETITEMDATA, selIndex, 0)); 518 | } 519 | if (msg == 0) 520 | { 521 | msg = WinMessages::Instance().ParseMsg(buf); 522 | } 523 | DWORD err = 0; 524 | if (msg == 0) 525 | { 526 | err = ::GetLastError(); 527 | } 528 | 529 | if (!err) 530 | { 531 | ::GetDlgItemText(*this, IDC_WPARAM, buf, _countof(buf)); 532 | wparam = static_cast(_tcstol(buf, &endptr, 0)); 533 | if (wparam == 0) 534 | { 535 | LRESULT selIndex = SendDlgItemMessage(*this, IDC_WPARAM, CB_GETCURSEL, 0, 0); 536 | if (selIndex != CB_ERR) 537 | wparam = SendDlgItemMessage(*this, IDC_WPARAM, CB_GETITEMDATA, selIndex, 0); 538 | } 539 | 540 | ::GetDlgItemText(*this, IDC_LPARAM, buf, _countof(buf)); 541 | lparam = static_cast(_tcstol(buf, &endptr, 0)); 542 | if (lparam == 0) 543 | { 544 | LRESULT selIndex = SendDlgItemMessage(*this, IDC_LPARAM, CB_GETCURSEL, 0, 0); 545 | if (selIndex != CB_ERR) 546 | lparam = SendDlgItemMessage(*this, IDC_LPARAM, CB_GETITEMDATA, selIndex, 0); 547 | } 548 | 549 | LRESULT res = 0; 550 | if (id == IDC_SENDMESSAGE) 551 | { 552 | res = SendMessage(hTargetWnd, msg, wparam, lparam); 553 | } 554 | else 555 | { 556 | res = PostMessage(hTargetWnd, msg, wparam, lparam); 557 | } 558 | _stprintf_s(buf, _countof(buf), _T("0x%08Ix (%Id)"), res, res); 559 | SetDlgItemText(*this, IDC_RETVALUE, buf); 560 | 561 | err = GetLastError(); 562 | } 563 | 564 | if (err) 565 | { 566 | LPVOID lpMsgBuf = nullptr; 567 | LPVOID lpDisplayBuf = nullptr; 568 | 569 | if (FormatMessage( 570 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 571 | FORMAT_MESSAGE_FROM_SYSTEM | 572 | FORMAT_MESSAGE_IGNORE_INSERTS, 573 | nullptr, 574 | err, 575 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 576 | reinterpret_cast(&lpMsgBuf), 577 | 0, 578 | nullptr)) 579 | { 580 | lpDisplayBuf = LocalAlloc(LMEM_ZEROINIT, (lstrlen(static_cast(lpMsgBuf)) + 40LL) * sizeof(TCHAR)); 581 | if (lpDisplayBuf) 582 | { 583 | _stprintf_s(static_cast(lpDisplayBuf), LocalSize(lpDisplayBuf) / sizeof(TCHAR), _T("error %lu: %s"), err, (LPTSTR)lpMsgBuf); 584 | SetDlgItemText(*this, IDC_ERROR, static_cast(lpDisplayBuf)); 585 | LocalFree(lpDisplayBuf); 586 | } 587 | 588 | LocalFree(lpMsgBuf); 589 | } 590 | } 591 | else 592 | SetDlgItemText(*this, IDC_ERROR, _T("")); 593 | 594 | return true; 595 | } 596 | -------------------------------------------------------------------------------- /src/MainDlg.h: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2010, 2012-2013, 2021 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #pragma once 21 | #include "BaseDialog.h" 22 | #include "AeroControls.h" 23 | #include "HyperLink.h" 24 | #include 25 | 26 | #define ID_ABOUTBOX 0x0010 27 | 28 | /** 29 | * main dialog. 30 | */ 31 | class CMainDlg : public CDialog 32 | { 33 | public: 34 | CMainDlg(HWND hParent); 35 | ~CMainDlg(void) override; 36 | 37 | protected: 38 | LRESULT CALLBACK DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) override; 39 | LRESULT DoCommand(int id, int msg); 40 | bool PreTranslateMessage(MSG* pMsg) override; 41 | 42 | void SaveWndPosition(); 43 | bool SearchWindow(); 44 | bool DoMouseMove(UINT message, WPARAM wParam, LPARAM lParam); 45 | bool DoMouseUp(UINT message, WPARAM wParam, LPARAM lParam); 46 | bool CheckWindowValidity(HWND hwndToCheck); 47 | bool DisplayInfoOnFoundWindow(HWND hwndFoundWindow); 48 | static bool RefreshWindow(HWND hwndWindowToBeRefreshed); 49 | bool HighlightFoundWindow(HWND hwndFoundWindow) const; 50 | bool SendPostMessage(UINT id); 51 | HWND GetSelectedHandle(); 52 | 53 | private: 54 | HWND m_hParent; 55 | CHyperLink m_link; 56 | AeroControlBase m_aerocontrols; 57 | bool m_bStartSearchWindow; 58 | HWND m_hwndFoundWindow; 59 | HPEN m_hRectanglePen; 60 | }; 61 | -------------------------------------------------------------------------------- /src/SendMessage.cpp: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2010, 2012-2013, 2018, 2021 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #include "stdafx.h" 21 | #include "SendMessage.h" 22 | #include "MainDlg.h" 23 | #include "AboutDlg.h" 24 | #include "WinMessage.h" 25 | #include "CmdLineParser.h" 26 | #include "SmartHandle.h" 27 | #include "AccessibleName.h" 28 | #include 29 | #include 30 | 31 | // Global Variables: 32 | HINSTANCE hInst = nullptr; // current instance 33 | std::wstring windowTitle; 34 | std::wstring windowClass; 35 | std::wstring windowAccessiblename; 36 | std::wstring windowProcessname; 37 | 38 | BOOL CALLBACK ChildWindowEnumerator(HWND hwnd, LPARAM lParam) 39 | { 40 | auto* pSet = reinterpret_cast*>(lParam); 41 | 42 | if (!windowTitle.empty()) 43 | { 44 | TCHAR buf[4096]{}; 45 | GetWindowText(hwnd, buf, _countof(buf)); 46 | if (windowTitle.substr(0, 4096).compare(buf) != 0) 47 | return TRUE; 48 | } 49 | if (!windowClass.empty()) 50 | { 51 | TCHAR szClassName[100]{}; 52 | GetClassName(hwnd, szClassName, _countof(szClassName)); 53 | if (windowClass.compare(szClassName) != 0) 54 | return TRUE; 55 | } 56 | if (!windowAccessiblename.empty()) 57 | { 58 | if (windowAccessiblename.compare(CAccessibleName(hwnd).c_str()) != 0) 59 | return TRUE; 60 | } 61 | if (!windowProcessname.empty()) 62 | { 63 | DWORD pid = 0; 64 | GetWindowThreadProcessId(hwnd, &pid); 65 | if (pid) 66 | { 67 | CAutoGeneralHandle hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); 68 | if (hProc) 69 | { 70 | TCHAR szProcName[MAX_PATH] = {0}; 71 | TCHAR* pProcName = szProcName; 72 | if (GetProcessImageFileName(hProc, szProcName, _countof(szProcName))) 73 | { 74 | pProcName = _tcsrchr(szProcName, '\\'); 75 | if (pProcName) 76 | pProcName++; 77 | else 78 | pProcName = szProcName; 79 | if (windowProcessname.compare(pProcName) != 0) 80 | return TRUE; 81 | } 82 | } 83 | } 84 | } 85 | 86 | pSet->insert(hwnd); 87 | 88 | return TRUE; 89 | } 90 | 91 | BOOL CALLBACK WindowEnumerator(HWND hwnd, LPARAM lParam) 92 | { 93 | auto* pSet = reinterpret_cast*>(lParam); 94 | 95 | bool bMatches = true; 96 | if (!windowTitle.empty()) 97 | { 98 | TCHAR buf[4096]{}; 99 | GetWindowText(hwnd, buf, _countof(buf)); 100 | if (windowTitle.substr(0, 4096).compare(buf) != 0) 101 | bMatches = false; 102 | } 103 | if (!windowClass.empty()) 104 | { 105 | TCHAR szClassName[100] = {0}; 106 | GetClassName(hwnd, szClassName, _countof(szClassName)); 107 | if (windowClass.compare(szClassName) != 0) 108 | bMatches = false; 109 | } 110 | if (!windowAccessiblename.empty()) 111 | { 112 | if (windowAccessiblename.compare(CAccessibleName(hwnd).c_str()) != 0) 113 | bMatches = false; 114 | } 115 | if (!windowProcessname.empty()) 116 | { 117 | DWORD pid = 0; 118 | GetWindowThreadProcessId(hwnd, &pid); 119 | if (pid) 120 | { 121 | CAutoGeneralHandle hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); 122 | if (hProc) 123 | { 124 | TCHAR szProcName[MAX_PATH] = {0}; 125 | TCHAR* pProcName = szProcName; 126 | if (GetProcessImageFileName(hProc, szProcName, _countof(szProcName))) 127 | { 128 | pProcName = _tcsrchr(szProcName, '\\'); 129 | if (pProcName) 130 | pProcName++; 131 | else 132 | pProcName = szProcName; 133 | if (windowProcessname.compare(pProcName) != 0) 134 | bMatches = false; 135 | } 136 | else 137 | bMatches = false; 138 | } 139 | else 140 | bMatches = false; 141 | } 142 | else 143 | bMatches = false; 144 | } 145 | if (bMatches) 146 | pSet->insert(hwnd); 147 | 148 | if (windowProcessname.empty() || !windowTitle.empty() || !windowClass.empty() || !windowAccessiblename.empty()) 149 | EnumChildWindows(hwnd, ChildWindowEnumerator, lParam); 150 | 151 | return TRUE; 152 | } 153 | 154 | int APIENTRY _tWinMain(HINSTANCE hInstance, 155 | HINSTANCE hPrevInstance, 156 | LPTSTR lpCmdLine, 157 | int nCmdShow) 158 | { 159 | UNREFERENCED_PARAMETER(hPrevInstance); 160 | UNREFERENCED_PARAMETER(lpCmdLine); 161 | UNREFERENCED_PARAMETER(nCmdShow); 162 | 163 | ::OleInitialize(nullptr); 164 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 165 | // we need some of the common controls 166 | INITCOMMONCONTROLSEX icex{}; 167 | icex.dwSize = sizeof(INITCOMMONCONTROLSEX); 168 | icex.dwICC = ICC_LINK_CLASS | ICC_LISTVIEW_CLASSES | ICC_PAGESCROLLER_CLASS | ICC_PROGRESS_CLASS | ICC_STANDARD_CLASSES | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES | ICC_WIN95_CLASSES; 169 | InitCommonControlsEx(&icex); 170 | 171 | CCmdLineParser parser(lpCmdLine); 172 | 173 | INT_PTR ret = 0; 174 | if (parser.HasKey(_T("about")) || parser.HasKey(_T("?")) || parser.HasKey(_T("help"))) 175 | { 176 | CAboutDlg aboutDlg(nullptr); 177 | ret = aboutDlg.DoModal(hInstance, IDD_ABOUTBOX, nullptr, NULL); 178 | } 179 | else if (parser.HasKey(L"message")) 180 | { 181 | UINT msg = 0; 182 | WPARAM wParam = 0; 183 | LPARAM lParam = 0; 184 | 185 | if (parser.HasVal(L"message")) 186 | { 187 | msg = WinMessages::Instance().ParseMsg(parser.GetVal(L"message")); 188 | } 189 | if (parser.HasVal(L"wparam")) 190 | wParam = parser.GetLongVal(L"wparam"); 191 | if (parser.HasVal(L"lparam")) 192 | lParam = (LPARAM)parser.GetLongLongVal(L"lparam"); 193 | 194 | bool bSend = !parser.HasKey(L"post"); 195 | 196 | std::set hwndset; 197 | 198 | if (parser.HasVal(L"windowhandle")) 199 | hwndset.insert(reinterpret_cast(parser.GetLongLongVal(L"windowhandle"))); 200 | else 201 | { 202 | if (parser.HasVal(L"windowtitle")) 203 | windowTitle = parser.GetVal(L"windowtitle"); 204 | if (parser.HasVal(L"windowclass")) 205 | windowClass = parser.GetVal(L"windowclass"); 206 | if (parser.HasVal(L"accessiblename")) 207 | windowAccessiblename = parser.GetVal(L"accessiblename"); 208 | if (parser.HasVal(L"processname")) 209 | windowProcessname = parser.GetVal(L"processname"); 210 | 211 | EnumWindows(WindowEnumerator, reinterpret_cast(&hwndset)); 212 | } 213 | 214 | for (auto it = hwndset.cbegin(); it != hwndset.cend(); ++it) 215 | { 216 | if (bSend) 217 | ret = static_cast(SendMessage(*it, msg, wParam, lParam)); 218 | else 219 | ret = PostMessage(*it, msg, wParam, lParam); 220 | } 221 | } 222 | else 223 | { 224 | CMainDlg mainDlg(nullptr); 225 | ret = mainDlg.DoModal(hInstance, IDD_MAINDLG, nullptr, IDR_MAINDLG); 226 | } 227 | 228 | ::CoUninitialize(); 229 | ::OleUninitialize(); 230 | return static_cast(ret); 231 | } 232 | -------------------------------------------------------------------------------- /src/SendMessage.h: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2010, 2018 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #pragma once 21 | 22 | #include "resource.h" 23 | -------------------------------------------------------------------------------- /src/SendMessage.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #pragma code_page(65001) 4 | 5 | #include "resource.h" 6 | 7 | #define APSTUDIO_READONLY_SYMBOLS 8 | ///////////////////////////////////////////////////////////////////////////// 9 | // 10 | // Generated from the TEXTINCLUDE 2 resource. 11 | // 12 | #define APSTUDIO_HIDDEN_SYMBOLS 13 | #include "windows.h" 14 | #undef APSTUDIO_HIDDEN_SYMBOLS 15 | #ifndef APSTUDIO_INVOKED 16 | #include "SendMessage.rc2" 17 | #endif 18 | ///////////////////////////////////////////////////////////////////////////// 19 | #undef APSTUDIO_READONLY_SYMBOLS 20 | 21 | ///////////////////////////////////////////////////////////////////////////// 22 | // English (United States) resources 23 | 24 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 25 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | // 29 | // Icon 30 | // 31 | 32 | // Icon with lowest ID value placed first to ensure application icon 33 | // remains consistent on all systems. 34 | IDI_SENDMESSAGE ICON "resources\\SendMessage.ico" 35 | IDI_SEARCHW ICON "resources\\searchw.ico" 36 | 37 | ///////////////////////////////////////////////////////////////////////////// 38 | // 39 | // Cursor 40 | // 41 | 42 | IDC_SEARCHW CURSOR "resources\\searchw.cur" 43 | 44 | ///////////////////////////////////////////////////////////////////////////// 45 | // 46 | // TEXT 47 | // 48 | 49 | IDR_WINDOWMESSAGESXML TEXT "resources\\windowmessages.xml" 50 | 51 | 52 | ///////////////////////////////////////////////////////////////////////////// 53 | // 54 | // Dialog 55 | // 56 | 57 | IDD_ABOUTBOX DIALOGEX 0, 0, 267, 67 58 | STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU 59 | CAPTION "About SendMessage" 60 | FONT 8, "MS Shell Dlg", 0, 0, 0x1 61 | BEGIN 62 | ICON IDI_SENDMESSAGE,IDC_STATIC,14,14,20,20 63 | LTEXT "",IDC_VERSIONINFO,42,14,218,8,SS_NOPREFIX 64 | LTEXT "",IDC_DATE,42,26,114,8 65 | DEFPUSHBUTTON "OK",IDOK,210,46,50,14,WS_GROUP 66 | LTEXT "Visit our website",IDC_WEBLINK,41,52,53,8 67 | END 68 | 69 | IDD_MAINDLG DIALOGEX 0, 0, 400, 187 70 | STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU 71 | EXSTYLE WS_EX_TOPMOST 72 | CAPTION "SendMessage" 73 | FONT 8, "MS Shell Dlg", 400, 0, 0x1 74 | BEGIN 75 | DEFPUSHBUTTON "&Quit",IDOK,343,166,50,14 76 | ICON IDI_SEARCHW,IDC_SEARCHW,7,7,20,20,SS_NOTIFY | SS_CENTERIMAGE 77 | LTEXT "Pos:",IDC_POS,34,7,15,8 78 | LTEXT "0",IDC_STATIC_X_POS,57,7,15,8 79 | LTEXT "0",IDC_STATIC_Y_POS,75,7,17,8 80 | LTEXT "",IDC_EDIT_STATUS,72,18,321,50 81 | GROUPBOX "Send Message",IDC_SENDGROUP,7,76,386,84 82 | LTEXT "Window:",IDC_STATIC,12,92,36,8 83 | LTEXT "Message:",IDC_STATIC,12,109,32,8 84 | LTEXT "WPARAM:",IDC_STATIC,12,125,34,8 85 | LTEXT "LPARAM:",IDC_STATIC,12,140,30,8 86 | PUSHBUTTON "SendMessage",IDC_SENDMESSAGE,198,89,75,14 87 | PUSHBUTTON "PostMessage",IDC_POSTMESSAGE,198,108,75,14 88 | LTEXT "Return value:",IDC_STATIC,281,92,45,8 89 | EDITTEXT IDC_RETVALUE,280,104,106,8,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP 90 | LTEXT "&About SendMessage",IDC_ABOUTLINK,319,0,81,8 91 | EDITTEXT IDC_WINDOW,72,90,115,14,ES_AUTOHSCROLL 92 | COMBOBOX IDC_MESSAGE,72,107,115,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP 93 | COMBOBOX IDC_WPARAM,72,123,115,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP 94 | COMBOBOX IDC_LPARAM,72,139,115,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP 95 | LTEXT "",IDC_ERROR,281,122,105,30 96 | PUSHBUTTON "Windows",IDC_WINDOWTREE,7,39,50,14 97 | PUSHBUTTON "Pin",IDC_PINWINDOW,198,127,35,14 98 | PUSHBUTTON "UnPin",IDC_UNPINWINDOW,238,127,35,14 99 | LTEXT "nCmdShow:",IDC_STATIC,12,169,41,8 100 | PUSHBUTTON "ShowWindow",IDC_SHOWWINDOW,198,166,75,14 101 | COMBOBOX IDC_CMDSHOW,72,167,115,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP 102 | END 103 | 104 | IDD_WINDOWSTREE DIALOGEX 0, 0, 315, 261 105 | STYLE DS_SETFONT | DS_FIXEDSYS | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME 106 | CAPTION "Windows" 107 | FONT 8, "MS Shell Dlg", 400, 0, 0x1 108 | BEGIN 109 | LTEXT "Filter",IDC_STATIC,8,10,17,8 110 | EDITTEXT IDC_FILTER,36,7,272,14,ES_AUTOHSCROLL 111 | CONTROL "",IDC_WINDOWTREE,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP,7,26,301,204 112 | DEFPUSHBUTTON "OK",IDOK,205,240,50,14 113 | PUSHBUTTON "Cancel",IDCANCEL,258,240,50,14 114 | PUSHBUTTON "Refresh",IDC_REFRESH,147,240,50,14 115 | END 116 | 117 | 118 | ///////////////////////////////////////////////////////////////////////////// 119 | // 120 | // DESIGNINFO 121 | // 122 | 123 | #ifdef APSTUDIO_INVOKED 124 | GUIDELINES DESIGNINFO 125 | BEGIN 126 | IDD_ABOUTBOX, DIALOG 127 | BEGIN 128 | LEFTMARGIN, 7 129 | RIGHTMARGIN, 260 130 | TOPMARGIN, 7 131 | BOTTOMMARGIN, 60 132 | END 133 | 134 | IDD_MAINDLG, DIALOG 135 | BEGIN 136 | LEFTMARGIN, 7 137 | RIGHTMARGIN, 393 138 | VERTGUIDE, 12 139 | VERTGUIDE, 34 140 | VERTGUIDE, 72 141 | VERTGUIDE, 187 142 | VERTGUIDE, 198 143 | VERTGUIDE, 273 144 | TOPMARGIN, 7 145 | BOTTOMMARGIN, 180 146 | HORZGUIDE, 76 147 | HORZGUIDE, 160 148 | END 149 | 150 | IDD_WINDOWSTREE, DIALOG 151 | BEGIN 152 | LEFTMARGIN, 7 153 | RIGHTMARGIN, 308 154 | TOPMARGIN, 7 155 | BOTTOMMARGIN, 254 156 | END 157 | END 158 | #endif // APSTUDIO_INVOKED 159 | 160 | 161 | #ifdef APSTUDIO_INVOKED 162 | ///////////////////////////////////////////////////////////////////////////// 163 | // 164 | // TEXTINCLUDE 165 | // 166 | 167 | 1 TEXTINCLUDE 168 | BEGIN 169 | "resource.h\0" 170 | END 171 | 172 | 2 TEXTINCLUDE 173 | BEGIN 174 | "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" 175 | "#include ""windows.h""\r\n" 176 | "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" 177 | "#ifndef APSTUDIO_INVOKED\r\n" 178 | "#include ""SendMessage.rc2""\r\n" 179 | "#endif\0" 180 | END 181 | 182 | 3 TEXTINCLUDE 183 | BEGIN 184 | "\r\n" 185 | "\0" 186 | END 187 | 188 | #endif // APSTUDIO_INVOKED 189 | 190 | #endif // English (United States) resources 191 | ///////////////////////////////////////////////////////////////////////////// 192 | 193 | 194 | 195 | #ifndef APSTUDIO_INVOKED 196 | ///////////////////////////////////////////////////////////////////////////// 197 | // 198 | // Generated from the TEXTINCLUDE 3 resource. 199 | // 200 | 201 | 202 | ///////////////////////////////////////////////////////////////////////////// 203 | #endif // not APSTUDIO_INVOKED 204 | 205 | -------------------------------------------------------------------------------- /src/SendMessage.rc2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefankueng/sendmessage/9c546bc59fb5473646b93d05b69923d9a5de5245/src/SendMessage.rc2 -------------------------------------------------------------------------------- /src/SendMessage.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {D1CCDBC4-3C7C-4E14-B980-73FCF457A4C1} 23 | Win32Proj 24 | SendMessage 25 | 26 | 27 | 28 | Application 29 | Unicode 30 | v143 31 | 32 | 33 | Application 34 | Unicode 35 | v143 36 | 37 | 38 | Application 39 | true 40 | Unicode 41 | v143 42 | 43 | 44 | Application 45 | true 46 | Unicode 47 | v143 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | true 67 | $(SolutionDir)bin\$(Configuration)\$(Platform)\ 68 | $(SolutionDir)obj\$(Configuration)\$(Platform)\ 69 | false 70 | 71 | 72 | true 73 | $(SolutionDir)bin\$(Configuration)\$(Platform)\ 74 | $(SolutionDir)obj\$(Configuration)\$(Platform)\ 75 | false 76 | $(ProjectName)64 77 | 78 | 79 | false 80 | $(SolutionDir)bin\$(Configuration)\$(Platform)\ 81 | $(SolutionDir)obj\$(Configuration)\$(Platform)\ 82 | false 83 | 84 | 85 | false 86 | $(SolutionDir)bin\$(Configuration)\$(Platform)\ 87 | $(SolutionDir)obj\$(Configuration)\$(Platform)\ 88 | false 89 | $(ProjectName)64 90 | 91 | 92 | 93 | ..\sktoolslib;last 94 | EnableFastChecks 95 | EditAndContinue 96 | false 97 | true 98 | false 99 | Disabled 100 | Use 101 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 102 | MultiThreadedDebug 103 | Level4 104 | stdcpp20 105 | 106 | 107 | true 108 | Windows 109 | Psapi.lib;comctl32.lib;%(AdditionalDependencies) 110 | 111 | 112 | last 113 | 114 | 115 | true 116 | 117 | 118 | 119 | 120 | ..\sktoolslib;last 121 | EnableFastChecks 122 | ProgramDatabase 123 | false 124 | false 125 | Disabled 126 | Use 127 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 128 | MultiThreadedDebug 129 | Level4 130 | stdcpp20 131 | 132 | 133 | true 134 | Windows 135 | Psapi.lib;comctl32.lib;%(AdditionalDependencies) 136 | 137 | 138 | last 139 | 140 | 141 | true 142 | 143 | 144 | 145 | 146 | ..\sktoolslib;last 147 | ProgramDatabase 148 | NoExtensions 149 | true 150 | true 151 | true 152 | MaxSpeed 153 | Use 154 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 155 | MultiThreaded 156 | Level4 157 | stdcpp20 158 | 159 | 160 | true 161 | true 162 | true 163 | true 164 | Windows 165 | Psapi.lib;comctl32.lib;%(AdditionalDependencies) 166 | false 167 | 168 | 169 | last 170 | 171 | 172 | true 173 | 174 | 175 | 176 | 177 | ..\sktoolslib;last 178 | ProgramDatabase 179 | true 180 | true 181 | true 182 | MaxSpeed 183 | Use 184 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 185 | MultiThreaded 186 | Level4 187 | stdcpp20 188 | 189 | 190 | true 191 | true 192 | true 193 | true 194 | Windows 195 | Psapi.lib;comctl32.lib;%(AdditionalDependencies) 196 | 197 | 198 | last 199 | 200 | 201 | true 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | Create 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | Designer 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | -------------------------------------------------------------------------------- /src/SendMessage.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 6 | h;hpp;hxx;hm;inl;inc;xsd 7 | 8 | 9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 11 | 12 | 13 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 14 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 15 | 16 | 17 | {fc6ae0b6-4b38-49c1-ac99-5379a4821f54} 18 | 19 | 20 | {a6a0cbfc-4cb9-481d-b366-cfb8e263ecdf} 21 | 22 | 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | sktoolslib 50 | 51 | 52 | sktoolslib 53 | 54 | 55 | sktoolslib 56 | 57 | 58 | sktoolslib 59 | 60 | 61 | sktoolslib 62 | 63 | 64 | sktoolslib 65 | 66 | 67 | sktoolslib 68 | 69 | 70 | sktoolslib 71 | 72 | 73 | sktoolslib 74 | 75 | 76 | sktoolslib 77 | 78 | 79 | sktoolslib 80 | 81 | 82 | sktoolslib 83 | 84 | 85 | sktoolslib 86 | 87 | 88 | sktoolslib 89 | 90 | 91 | Header Files 92 | 93 | 94 | 95 | 96 | Source Files 97 | 98 | 99 | Source Files 100 | 101 | 102 | Source Files 103 | 104 | 105 | Source Files 106 | 107 | 108 | Source Files 109 | 110 | 111 | Source Files 112 | 113 | 114 | sktoolslib 115 | 116 | 117 | sktoolslib 118 | 119 | 120 | sktoolslib 121 | 122 | 123 | sktoolslib 124 | 125 | 126 | sktoolslib 127 | 128 | 129 | sktoolslib 130 | 131 | 132 | sktoolslib 133 | 134 | 135 | sktoolslib 136 | 137 | 138 | sktoolslib 139 | 140 | 141 | sktoolslib 142 | 143 | 144 | sktoolslib 145 | 146 | 147 | sktoolslib 148 | 149 | 150 | Source Files 151 | 152 | 153 | 154 | 155 | Resource Files 156 | 157 | 158 | Resource Files 159 | 160 | 161 | Resource Files 162 | 163 | 164 | Resource Files 165 | 166 | 167 | Resource Files 168 | 169 | 170 | Build 171 | 172 | 173 | Build 174 | 175 | 176 | Build 177 | 178 | 179 | Build 180 | 181 | 182 | 183 | 184 | Resource Files 185 | 186 | 187 | 188 | 189 | Resource Files 190 | 191 | 192 | -------------------------------------------------------------------------------- /src/WinMessage.cpp: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2013, 2015, 2021 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | #include "stdafx.h" 20 | #include "WinMessage.h" 21 | #include "resource.h" 22 | 23 | extern HINSTANCE hInst; 24 | 25 | UINT WinMessages::GetApiMessageCode(LPCTSTR text) const 26 | { 27 | for (const auto& it : m_messages) 28 | { 29 | if (_wcsicmp(it.messagename.c_str(), text) == 0) 30 | return it.message; 31 | } 32 | return 0; 33 | } 34 | 35 | UINT WinMessages::ParseMsg(LPCTSTR text) const 36 | { 37 | UINT msg = 0; 38 | TCHAR* endptr = nullptr; 39 | 40 | msg = _tcstol(text, &endptr, 0); 41 | if (msg == 0) 42 | { 43 | // Find API Message 44 | msg = GetApiMessageCode(text); 45 | } 46 | if (msg == 0) 47 | { 48 | // Get custom message 49 | msg = ::RegisterWindowMessage(text); 50 | } 51 | return msg; 52 | } 53 | 54 | WinMessages& WinMessages::Instance() 55 | { 56 | static WinMessages instance; 57 | if (!instance.m_bInit) 58 | instance.Init(); 59 | return instance; 60 | } 61 | 62 | void WinMessages::Init() 63 | { 64 | m_xmlResource.Open(hInst, MAKEINTRESOURCE(IDR_WINDOWMESSAGESXML), _T("TEXT"), CResourceTextFile::ConvertToUnicode); 65 | m_xml.Load(m_xmlResource.GetTextBuffer()); 66 | // now fill the window message combo box 67 | XNodes childs = m_xml.GetChilds(_T("Message")); 68 | for (size_t i = 0; i < childs.size(); ++i) 69 | { 70 | WinMessage msg; 71 | msg.messagename = childs[i]->GetAttrValue(_T("description")); 72 | TCHAR* endptr = nullptr; 73 | msg.message = _tcstol(childs[i]->GetAttrValue(_T("value")), &endptr, 0); 74 | 75 | XNodes wparams = childs[i]->GetChilds(_T("wparam")); 76 | for (size_t j = 0; j < wparams.size(); ++j) 77 | { 78 | std::wstring desc = wparams[j]->GetAttrValue(_T("description")); 79 | WPARAM m = _tcstol(wparams[j]->GetAttrValue(_T("value")), &endptr, 0); 80 | msg.wparams.push_back(std::make_tuple(desc, m)); 81 | } 82 | XNodes lparams = childs[i]->GetChilds(_T("lparam")); 83 | for (size_t j = 0; j < lparams.size(); ++j) 84 | { 85 | std::wstring desc = lparams[j]->GetAttrValue(_T("description")); 86 | UINT m = _tcstol(lparams[j]->GetAttrValue(_T("value")), &endptr, 0); 87 | msg.lparams.push_back(std::make_tuple(desc, m)); 88 | } 89 | 90 | m_messages.push_back(msg); 91 | } 92 | m_bInit = true; 93 | } 94 | -------------------------------------------------------------------------------- /src/WinMessage.h: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2013, 2015, 2021 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | #pragma once 20 | #include "ResourceTextFile.h" 21 | #include "XMLite.h" 22 | 23 | struct WinMessage 24 | { 25 | std::wstring messagename; 26 | UINT message; 27 | std::vector> wparams; 28 | std::vector> lparams; 29 | }; 30 | 31 | class WinMessages 32 | { 33 | private: 34 | WinMessages() 35 | : m_bInit(false) 36 | { 37 | } 38 | ~WinMessages() 39 | { 40 | } 41 | 42 | public: 43 | static WinMessages& Instance(); 44 | 45 | size_t GetCount() const { return m_messages.size(); } 46 | WinMessage At(size_t index) const { return m_messages[index]; } 47 | UINT ParseMsg(LPCTSTR text) const; 48 | UINT GetApiMessageCode(LPCTSTR text) const; 49 | 50 | private: 51 | void Init(); 52 | bool m_bInit; 53 | CResourceTextFile m_xmlResource; 54 | XNode m_xml; 55 | 56 | std::vector m_messages; 57 | }; 58 | -------------------------------------------------------------------------------- /src/WindowTreeDlg.cpp: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2010, 2012, 2014-2015, 2021 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #include "stdafx.h" 21 | #include "resource.h" 22 | #include "WindowTreeDlg.h" 23 | #include 24 | #include 25 | 26 | CWindowTreeDlg::CWindowTreeDlg(HWND hParent, HWND actualHandle) 27 | : m_hParent(hParent) 28 | , m_lastTreeItem(nullptr) 29 | , m_selectedWindow(actualHandle) 30 | { 31 | } 32 | 33 | CWindowTreeDlg::~CWindowTreeDlg() 34 | { 35 | } 36 | 37 | LRESULT CWindowTreeDlg::DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 38 | { 39 | UNREFERENCED_PARAMETER(lParam); 40 | switch (uMsg) 41 | { 42 | case WM_INITDIALOG: { 43 | InitDialog(hwndDlg, IDI_SENDMESSAGE); 44 | 45 | m_resizer.Init(hwndDlg); 46 | m_resizer.AddControl(hwndDlg, IDC_FILTER, RESIZER_TOPLEFTRIGHT); 47 | m_resizer.AddControl(hwndDlg, IDC_WINDOWTREE, RESIZER_TOPLEFTBOTTOMRIGHT); 48 | m_resizer.AddControl(hwndDlg, IDC_REFRESH, RESIZER_BOTTOMRIGHT); 49 | m_resizer.AddControl(hwndDlg, IDOK, RESIZER_BOTTOMRIGHT); 50 | m_resizer.AddControl(hwndDlg, IDCANCEL, RESIZER_BOTTOMRIGHT); 51 | 52 | ExtendFrameIntoClientArea(IDC_WINDOWTREE, IDC_WINDOWTREE, IDC_WINDOWTREE, IDC_WINDOWTREE); 53 | m_aeroControls.SubclassControl(GetDlgItem(*this, IDC_REFRESH)); 54 | m_aeroControls.SubclassControl(GetDlgItem(*this, IDOK)); 55 | m_aeroControls.SubclassControl(GetDlgItem(*this, IDCANCEL)); 56 | if (m_dwm.IsDwmCompositionEnabled()) 57 | m_resizer.UseSizeGrip(false); 58 | 59 | RefreshTree(); 60 | } 61 | return FALSE; 62 | case WM_DESTROY: 63 | KillTimer(*this, 0); 64 | break; 65 | case WM_TIMER: 66 | KillTimer(*this, 0); 67 | RefreshTree(); 68 | return TRUE; 69 | case WM_COMMAND: 70 | return DoCommand(LOWORD(wParam), HIWORD(wParam)); 71 | case WM_SIZE: { 72 | m_resizer.DoResize(LOWORD(lParam), HIWORD(lParam)); 73 | } 74 | break; 75 | case WM_GETMINMAXINFO: { 76 | MINMAXINFO* mmi = reinterpret_cast(lParam); 77 | mmi->ptMinTrackSize.x = m_resizer.GetDlgRect()->right; 78 | mmi->ptMinTrackSize.y = m_resizer.GetDlgRect()->bottom; 79 | return 0; 80 | } 81 | default: 82 | return FALSE; 83 | } 84 | return FALSE; 85 | } 86 | 87 | LRESULT CWindowTreeDlg::DoCommand(int id, int msg) 88 | { 89 | switch (id) 90 | { 91 | case IDOK: 92 | m_selectedWindow = GetSelectedWindowHandle(); 93 | [[fallthrough]]; 94 | case IDCANCEL: 95 | EndDialog(*this, id); 96 | break; 97 | case IDC_FILTER: 98 | switch (msg) 99 | { 100 | case EN_CHANGE: 101 | SetTimer(*this, 0, 500, nullptr); 102 | } 103 | break; 104 | case IDC_REFRESH: 105 | RefreshTree(); 106 | break; 107 | } 108 | return 1; 109 | } 110 | 111 | bool CWindowTreeDlg::PreTranslateMessage(MSG* pMsg) 112 | { 113 | if (pMsg->message == WM_KEYDOWN) 114 | { 115 | } 116 | return false; 117 | } 118 | 119 | bool CWindowTreeDlg::RefreshTree() 120 | { 121 | auto hTree = GetDlgItem(*this, IDC_WINDOWTREE); 122 | SendMessage(hTree, WM_SETREDRAW, FALSE, 0); 123 | TreeView_DeleteAllItems(hTree); 124 | m_lastTreeItem = TVI_ROOT; 125 | EnumWindows(WindowEnumerator, reinterpret_cast(this)); 126 | SendMessage(hTree, WM_SETREDRAW, TRUE, 0); 127 | SelectTreeItem(m_selectedWindow); 128 | return true; 129 | } 130 | 131 | BOOL CWindowTreeDlg::WindowEnumerator(HWND hwnd, LPARAM lParam) 132 | { 133 | auto* pThis = reinterpret_cast(lParam); 134 | 135 | TCHAR buf[4096]{}; 136 | GetWindowString(hwnd, buf, _countof(buf)); 137 | 138 | TCHAR filter[MAX_PATH]{}; 139 | ::GetDlgItemText(*pThis, IDC_FILTER, filter, _countof(filter)); 140 | if (filter[0] == '\0' || StrStrI(buf, filter) != nullptr) 141 | { 142 | TVINSERTSTRUCT is = {nullptr}; 143 | is.hParent = TVI_ROOT; 144 | is.hInsertAfter = TVI_SORT; 145 | is.itemex.mask = TVIF_TEXT | TVIF_PARAM; 146 | is.itemex.pszText = buf; 147 | is.itemex.lParam = reinterpret_cast(hwnd); 148 | 149 | pThis->m_lastTreeItem = TreeView_InsertItem(GetDlgItem(*pThis, IDC_WINDOWTREE), &is); 150 | } 151 | else 152 | { 153 | pThis->m_lastTreeItem = TVI_ROOT; 154 | } 155 | EnumChildWindows(hwnd, ChildWindowEnumerator, lParam); 156 | return TRUE; 157 | } 158 | 159 | BOOL CWindowTreeDlg::ChildWindowEnumerator(HWND hwnd, LPARAM lParam) 160 | { 161 | auto* pThis = reinterpret_cast(lParam); 162 | 163 | TCHAR buf[4096]{}; 164 | GetWindowString(hwnd, buf, _countof(buf)); 165 | 166 | TCHAR filter[MAX_PATH]{}; 167 | ::GetDlgItemText(*pThis, IDC_FILTER, filter, _countof(filter)); 168 | if (filter[0] == '\0' || (StrStrI(buf, filter) != nullptr && GetDlgItem(*pThis, IDC_FILTER) != hwnd)) 169 | { 170 | TVINSERTSTRUCT is = {nullptr}; 171 | is.hParent = pThis->m_lastTreeItem; 172 | is.hInsertAfter = TVI_SORT; 173 | is.itemex.mask = TVIF_TEXT | TVIF_PARAM; 174 | is.itemex.pszText = buf; 175 | is.itemex.lParam = reinterpret_cast(hwnd); 176 | 177 | TreeView_InsertItem(GetDlgItem(*pThis, IDC_WINDOWTREE), &is); 178 | } 179 | return TRUE; 180 | } 181 | 182 | void CWindowTreeDlg::GetWindowString(HWND hwnd, TCHAR* buf, int bufsize) 183 | { 184 | TCHAR tmpbuf[4096] = {0}; 185 | TCHAR szClassName[100] = {0}; 186 | TCHAR szProcName[MAX_PATH] = {0}; 187 | TCHAR* pProcName = szProcName; 188 | 189 | GetWindowText(hwnd, tmpbuf, _countof(tmpbuf)); 190 | if (GetClassName(hwnd, szClassName, _countof(szClassName)) == 0) 191 | szClassName[0] = 0; 192 | DWORD pid = 0; 193 | GetWindowThreadProcessId(hwnd, &pid); 194 | if (pid) 195 | { 196 | HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); 197 | if (hProc) 198 | { 199 | if (GetProcessImageFileName(hProc, szProcName, _countof(szProcName))) 200 | { 201 | pProcName = _tcsrchr(szProcName, '\\'); 202 | if (pProcName) 203 | pProcName++; 204 | else 205 | pProcName = szProcName; 206 | } 207 | CloseHandle(hProc); 208 | } 209 | } 210 | _sntprintf_s(buf, bufsize, _TRUNCATE, _T("Window 0x%p : Process \"%s\" : class \"%s\" : title \"%s\""), hwnd, pProcName, szClassName, tmpbuf); 211 | } 212 | 213 | HWND CWindowTreeDlg::GetSelectedWindowHandle() 214 | { 215 | HTREEITEM selItem = TreeView_GetSelection(GetDlgItem(*this, IDC_WINDOWTREE)); 216 | if (selItem == nullptr) 217 | return nullptr; 218 | 219 | TVITEM tvi = {0}; 220 | tvi.hItem = selItem; 221 | tvi.mask = TVIF_PARAM; 222 | TreeView_GetItem(GetDlgItem(*this, IDC_WINDOWTREE), &tvi); 223 | return reinterpret_cast(tvi.lParam); 224 | } 225 | 226 | void CWindowTreeDlg::SelectTreeItem(HWND windowHwnd) 227 | { 228 | HWND windowTreeHwnd = GetDlgItem(*this, IDC_WINDOWTREE); 229 | HTREEITEM actualItem = TreeView_GetFirstVisible(windowTreeHwnd); 230 | 231 | // Search by the item into the list 232 | while (actualItem != nullptr) 233 | { 234 | TVITEM tvi = {0}; 235 | tvi.hItem = actualItem; 236 | tvi.mask = TVIF_PARAM; 237 | TreeView_GetItem(windowTreeHwnd, &tvi); 238 | 239 | // If it is the item, select it and break the search 240 | if (reinterpret_cast(tvi.lParam) == windowHwnd) 241 | { 242 | TreeView_SelectItem(windowTreeHwnd, actualItem); 243 | break; 244 | } 245 | 246 | // Find the next item in the TreeView 247 | HTREEITEM nextItem = TreeView_GetChild(windowTreeHwnd, actualItem); 248 | if (nextItem == nullptr) 249 | nextItem = TreeView_GetNextSibling(windowTreeHwnd, actualItem); 250 | 251 | HTREEITEM parentItem = actualItem; 252 | while ((nextItem == nullptr) && (parentItem != nullptr)) 253 | { 254 | parentItem = TreeView_GetParent(windowTreeHwnd, parentItem); 255 | nextItem = TreeView_GetNextSibling(windowTreeHwnd, parentItem); 256 | } 257 | actualItem = nextItem; 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /src/WindowTreeDlg.h: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2010, 2012, 2021 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #pragma once 21 | #include "BaseDialog.h" 22 | #include "AeroControls.h" 23 | #include "DlgResizer.h" 24 | 25 | /** 26 | * dialog showing a tree of all windows 27 | */ 28 | class CWindowTreeDlg : public CDialog 29 | { 30 | public: 31 | CWindowTreeDlg(HWND hParent, HWND actualHandle); 32 | ~CWindowTreeDlg() override; 33 | 34 | HWND GetSelectedWindow() const { return m_selectedWindow; } 35 | 36 | protected: 37 | LRESULT CALLBACK DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) override; 38 | LRESULT DoCommand(int id, int msg); 39 | bool PreTranslateMessage(MSG* pMsg) override; 40 | static void GetWindowString(HWND hwnd, TCHAR* buf, int bufsize); 41 | bool RefreshTree(); 42 | static BOOL CALLBACK WindowEnumerator(HWND hwnd, LPARAM lParam); 43 | static BOOL CALLBACK ChildWindowEnumerator(HWND hwnd, LPARAM lParam); 44 | HWND GetSelectedWindowHandle(); 45 | void SelectTreeItem(HWND windowHwnd); 46 | 47 | private: 48 | HWND m_hParent; 49 | AeroControlBase m_aeroControls; 50 | CDlgResizer m_resizer; 51 | HTREEITEM m_lastTreeItem; 52 | HWND m_selectedWindow; 53 | }; 54 | -------------------------------------------------------------------------------- /src/XMLite.cpp: -------------------------------------------------------------------------------- 1 | // XMLite.cpp: implementation of the XMLite class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | 5 | // ReSharper disable All 6 | #include "stdafx.h" 7 | #include "XMLite.h" 8 | #include "auto_buffer.h" 9 | #include 10 | #include 11 | #include 12 | 13 | static const TCHAR chXMLTagOpen = '<'; 14 | static const TCHAR chXMLTagClose = '>'; 15 | static const TCHAR chXMLTagPre = '/'; 16 | static const TCHAR chXMLEscape = '\\'; // for value field escape 17 | 18 | static const TCHAR szXMLPIOpen[] = _T(""); 20 | static const TCHAR szXMLCommentOpen[] = _T(""); 22 | static const TCHAR szXMLCDATAOpen[] = _T(""); 24 | 25 | static const XENTITY x_EntityTable[] = { 26 | { '&', _T("&"), 5 } , 27 | { '\"', _T("""), 6 } , 28 | { '\'', _T("'"), 6 } , 29 | { '<', _T("<"), 4 } , 30 | { '>', _T(">"), 4 } 31 | }; 32 | 33 | PARSEINFO piDefault; 34 | DISP_OPT optDefault; 35 | XENTITYS entityDefault((LPXENTITY)x_EntityTable, sizeof(x_EntityTable)/sizeof(x_EntityTable[0]) ); 36 | 37 | LPTSTR _tcschrs( LPCTSTR psz, LPCTSTR pszchs ) 38 | { 39 | while( psz && *psz ) 40 | { 41 | if( _tcschr( pszchs, *psz ) ) 42 | return (LPTSTR)psz; 43 | psz++; 44 | } 45 | return NULL; 46 | } 47 | 48 | LPTSTR _tcsskip( LPCTSTR psz ) 49 | { 50 | //while( psz && *psz == ' ' && *psz == 13 && *psz == 10 ) psz++; 51 | while( psz && isspace(*psz) ) psz++; 52 | 53 | return (LPTSTR)psz; 54 | } 55 | 56 | LPTSTR _tcsechr( LPCTSTR psz, int ch, int escape ) 57 | { 58 | LPTSTR pch = (LPTSTR)psz; 59 | 60 | while( pch && *pch ) 61 | { 62 | if( escape != 0 && *pch == escape ) 63 | pch++; 64 | else 65 | if( *pch == ch ) 66 | return (LPTSTR)pch; 67 | pch++; 68 | } 69 | return pch; 70 | } 71 | 72 | int _tcselen( int escape, LPTSTR srt, LPTSTR end = NULL ) 73 | { 74 | int len = 0; 75 | LPTSTR pch = srt; 76 | if( end==NULL ) end = (LPTSTR)sizeof(long); 77 | LPTSTR prev_escape = NULL; 78 | while( pch && *pch && pch des[i] ) 157 | return 1; 158 | return -1; 159 | } 160 | 161 | LPTSTR _tcsenistr( LPCTSTR psz, LPCTSTR str, int len, int escape ) 162 | { 163 | LPTSTR pch = (LPTSTR)psz; 164 | LPTSTR prev_escape = NULL; 165 | 166 | while( pch && *pch ) 167 | { 168 | if( escape != 0 && *pch == escape && prev_escape == NULL ) 169 | prev_escape = pch; 170 | else 171 | { 172 | prev_escape = NULL; 173 | if( _tcsenicmp( pch, str, len, escape ) == 0 ) 174 | return (LPTSTR)pch; 175 | } 176 | pch++; 177 | } 178 | return pch; 179 | } 180 | 181 | LPTSTR _tcseistr( LPCTSTR psz, LPCTSTR str, int escape ) 182 | { 183 | size_t len = _tcslen( str ); 184 | return _tcsenistr( psz, str, (int)len, escape ); 185 | } 186 | 187 | void _SetString( LPTSTR psz, LPTSTR end, std::wstring* ps, bool trim = FALSE, int escape = 0 ) 188 | { 189 | //trim 190 | if( trim ) 191 | { 192 | while( psz && psz < end && _istspace(*psz) ) psz++; 193 | while( (end-1) && psz < (end-1) && _istspace(*(end-1)) ) end--; 194 | } 195 | size_t len = end - psz; 196 | if( len <= 0 ) return; 197 | if( escape ) 198 | { 199 | len = _tcselen( escape, psz, end ); 200 | auto_buffer pss (len + 1); 201 | _tcsecpy( pss, escape, psz, end ); 202 | ps->assign(pss); 203 | } 204 | else 205 | { 206 | auto_buffer pss (len + 1); 207 | memcpy( pss, psz, len*sizeof(TCHAR) ); 208 | pss[len] = '\0'; 209 | ps->assign(pss); 210 | } 211 | } 212 | 213 | _tagXMLNode::~_tagXMLNode() 214 | { 215 | Close(); 216 | } 217 | 218 | void _tagXMLNode::Close() 219 | { 220 | for( size_t i = 0 ; i < childs.size(); i ++) 221 | { 222 | LPXNode p = childs[i]; 223 | if( p ) 224 | { 225 | delete p; childs[i] = NULL; 226 | } 227 | } 228 | childs.clear(); 229 | 230 | for( size_t i = 0 ; i < attrs.size(); i ++) 231 | { 232 | LPXAttr p = attrs[i]; 233 | if( p ) 234 | { 235 | delete p; attrs[i] = NULL; 236 | } 237 | } 238 | attrs.clear(); 239 | } 240 | 241 | LPTSTR _tagXMLNode::LoadAttributes( LPCTSTR pszAttrs , LPPARSEINFO pi /*= &piDefault*/) 242 | { 243 | LPTSTR xml = (LPTSTR)pszAttrs; 244 | 245 | while( xml && *xml ) 246 | { 247 | if(( xml = _tcsskip( xml ) ) != NULL) 248 | { 249 | // close tag 250 | if( *xml == chXMLTagClose || *xml == chXMLTagPre ) 251 | // wel-formed tag 252 | return xml; 253 | 254 | // XML Attr Name 255 | TCHAR* pEnd = _tcspbrk( xml, _T(" =") ); 256 | if( pEnd == NULL ) 257 | { 258 | // error 259 | if( pi->error_occur == false ) 260 | { 261 | pi->error_occur = true; 262 | pi->error_pointer = xml; 263 | pi->error_code = PIE_ATTR_NO_VALUE; 264 | 265 | auto_buffer sbuf (100 + name.size()); 266 | _stprintf_s(sbuf, 100 + name.size(), _T("<%s> attribute has error "), name.c_str()); 267 | pi->error_string = sbuf.get(); 268 | } 269 | return NULL; 270 | } 271 | 272 | LPXAttr attr = new XAttr; 273 | attr->parent = this; 274 | 275 | // XML Attr Name 276 | _SetString( xml, pEnd, &attr->name ); 277 | 278 | // add new attribute 279 | attrs.push_back( attr ); 280 | xml = pEnd; 281 | 282 | // XML Attr Value 283 | if( ( xml = _tcsskip( xml ) ) != NULL ) 284 | { 285 | //if( xml = _tcschr( xml, '=' ) ) 286 | if( *xml == '=' ) 287 | { 288 | if( ( xml = _tcsskip( ++xml ) ) != NULL ) 289 | { 290 | // if " or ' 291 | // or none quote 292 | int quote = *xml; 293 | if( quote == '"' || quote == '\'' ) 294 | pEnd = _tcsechr( ++xml, quote, chXMLEscape ); 295 | else 296 | { 297 | //attr= value> 298 | // none quote mode 299 | //pEnd = _tcsechr( xml, ' ', '\\' ); 300 | pEnd = _tcsepbrk( xml, _T(" >"), chXMLEscape ); 301 | } 302 | 303 | bool trim = pi->trim_value; 304 | TCHAR escape = pi->escape_value; 305 | //_SetString( xml, pEnd, &attr->value, trim, chXMLEscape ); 306 | _SetString( xml, pEnd, &attr->value, trim, escape ); 307 | xml = pEnd; 308 | // ATTRVALUE 309 | if( pi->entity_value && pi->entities ) 310 | attr->value = pi->entities->Ref2Entity(attr->value.c_str()); 311 | 312 | if( quote == '"' || quote == '\'' ) 313 | xml++; 314 | } 315 | } 316 | } 317 | } 318 | } 319 | 320 | // not wel-formed tag 321 | return NULL; 322 | } 323 | 324 | LPTSTR _tagXMLNode::LoadAttributes( LPCTSTR pszAttrs, LPCTSTR pszEnd, LPPARSEINFO pi /*= &piDefault*/ ) 325 | { 326 | LPTSTR xml = (LPTSTR)pszAttrs; 327 | 328 | while( xml && *xml ) 329 | { 330 | if( ( xml = _tcsskip( xml ) ) != NULL ) 331 | { 332 | // close tag 333 | if( xml >= pszEnd ) 334 | // wel-formed tag 335 | return xml; 336 | 337 | // XML Attr Name 338 | TCHAR* pEnd = _tcspbrk( xml, _T(" =") ); 339 | if( pEnd == NULL ) 340 | { 341 | // error 342 | if( pi->error_occur == false ) 343 | { 344 | pi->error_occur = true; 345 | pi->error_pointer = xml; 346 | pi->error_code = PIE_ATTR_NO_VALUE; 347 | auto_buffer sbuf (100 + name.size()); 348 | _stprintf_s(sbuf, 100 + name.size(), _T("<%s> attribute has error "), name.c_str()); 349 | pi->error_string = sbuf.get(); 350 | } 351 | return NULL; 352 | } 353 | 354 | LPXAttr attr = new XAttr; 355 | attr->parent = this; 356 | 357 | // XML Attr Name 358 | _SetString( xml, pEnd, &attr->name ); 359 | 360 | // add new attribute 361 | attrs.push_back( attr ); 362 | xml = pEnd; 363 | 364 | // XML Attr Value 365 | if( ( xml = _tcsskip( xml ) ) != NULL ) 366 | { 367 | //if( xml = _tcschr( xml, '=' ) ) 368 | if( *xml == '=' ) 369 | { 370 | if( ( xml = _tcsskip( ++xml ) ) != NULL ) 371 | { 372 | // if " or ' 373 | // or none quote 374 | int quote = *xml; 375 | if( quote == '"' || quote == '\'' ) 376 | pEnd = _tcsechr( ++xml, quote, chXMLEscape ); 377 | else 378 | { 379 | //attr= value> 380 | // none quote mode 381 | //pEnd = _tcsechr( xml, ' ', '\\' ); 382 | pEnd = _tcsepbrk( xml, _T(" >"), chXMLEscape ); 383 | } 384 | 385 | bool trim = pi->trim_value; 386 | TCHAR escape = pi->escape_value; 387 | //_SetString( xml, pEnd, &attr->value, trim, chXMLEscape ); 388 | _SetString( xml, pEnd, &attr->value, trim, escape ); 389 | xml = pEnd; 390 | // ATTRVALUE 391 | if( pi->entity_value && pi->entities ) 392 | attr->value = pi->entities->Ref2Entity(attr->value.c_str()); 393 | 394 | if( quote == '"' || quote == '\'' ) 395 | xml++; 396 | } 397 | } 398 | } 399 | } 400 | } 401 | 402 | // not wel-formed tag 403 | return NULL; 404 | } 405 | 406 | LPTSTR _tagXMLNode::LoadProcessingInstrunction( LPCTSTR pszXml, LPPARSEINFO pi /*= &piDefault*/ ) 407 | { 408 | // find the end of pi 409 | LPTSTR end = _tcsenistr( pszXml, szXMLPIClose, sizeof(szXMLPIClose)-1, pi ? pi->escape_value : 0 ); 410 | if( end == NULL ) 411 | return NULL; 412 | 413 | // process pi 414 | if( doc ) 415 | { 416 | LPTSTR xml = (LPTSTR)pszXml; 417 | 418 | LPXNode node = new XNode; 419 | node->parent = this; 420 | node->doc = doc; 421 | node->type = XNODE_PI; 422 | 423 | xml += _countof(szXMLPIOpen) - 1; 424 | TCHAR* pTagEnd = _tcspbrk( xml, _T(" ?>") ); 425 | _SetString( xml, pTagEnd, &node->name ); 426 | xml = pTagEnd; 427 | 428 | node->LoadAttributes( xml, end, pi ); 429 | 430 | doc->childs.push_back( node ); 431 | } 432 | 433 | end += _countof(szXMLPIClose) - 1; 434 | return end; 435 | } 436 | 437 | LPTSTR _tagXMLNode::LoadComment( LPCTSTR pszXml, LPPARSEINFO pi /*= &piDefault*/ ) 438 | { 439 | // find the end of comment 440 | LPTSTR end = _tcsenistr( pszXml, szXMLCommentClose, sizeof(szXMLCommentClose)-1, pi ? pi->escape_value : 0 ); 441 | if( end == NULL ) 442 | return NULL; 443 | 444 | // process comment 445 | LPXNode par = parent; 446 | if( parent == NULL && doc ) 447 | par = (LPXNode)&doc; 448 | if( par ) 449 | { 450 | LPTSTR xml = (LPTSTR)pszXml; 451 | xml += _countof(szXMLCommentOpen) - 1; 452 | 453 | LPXNode node = new XNode; 454 | node->parent = this; 455 | node->doc = doc; 456 | node->type = XNODE_COMMENT; 457 | node->name = _T("#COMMENT"); 458 | _SetString( xml, end, &node->value, FALSE ); 459 | 460 | par->childs.push_back( node ); 461 | } 462 | 463 | end += _countof(szXMLCommentClose) - 1; 464 | return end; 465 | } 466 | 467 | LPTSTR _tagXMLNode::LoadCDATA( LPCTSTR pszXml, LPPARSEINFO pi /*= &piDefault*/ ) 468 | { 469 | // find the end of CDATA 470 | LPTSTR end = _tcsenistr( pszXml, szXMLCDATAClose, sizeof(szXMLCDATAClose)-1, pi ? pi->escape_value : 0 ); 471 | if( end == NULL ) 472 | return NULL; 473 | 474 | // process CDATA 475 | LPXNode par = parent; 476 | if( parent == NULL && doc ) 477 | par = (LPXNode)&doc; 478 | if( par ) 479 | { 480 | LPTSTR xml = (LPTSTR)pszXml; 481 | xml += _countof(szXMLCDATAOpen) - 1; 482 | 483 | LPXNode node = new XNode; 484 | node->parent = this; 485 | node->doc = doc; 486 | node->type = XNODE_CDATA; 487 | node->name = _T("#CDATA"); 488 | _SetString( xml, end, &node->value, FALSE ); 489 | 490 | par->childs.push_back( node ); 491 | } 492 | 493 | end += _countof(szXMLCDATAClose) - 1; 494 | return end; 495 | } 496 | 497 | LPTSTR LoadOtherNodes( LPXNode node, bool* pbRet, LPCTSTR pszXml, LPPARSEINFO pi /*= &piDefault*/ ) 498 | { 499 | LPTSTR xml = (LPTSTR)pszXml; 500 | bool do_other_type = true; 501 | *pbRet = false; 502 | 503 | while( xml && do_other_type ) 504 | { 505 | do_other_type = false; 506 | 507 | xml = _tcsskip( xml ); 508 | LPTSTR prev = xml; 509 | // is PI( Processing Instruction ) Node? 510 | if( _tcsnicmp( xml, szXMLPIOpen, sizeof(szXMLPIOpen)-1 ) == 0 ) 511 | { 512 | // processing instrunction parse 513 | // return pointer is next node of pi 514 | xml = node->LoadProcessingInstrunction( xml, pi ); 515 | //if( xml == NULL ) 516 | // return NULL; 517 | // restart xml parse 518 | } 519 | 520 | if( xml != prev ) 521 | do_other_type = true; 522 | xml = _tcsskip( xml ); 523 | prev = xml; 524 | 525 | // is comment Node? 526 | if( _tcsnicmp( xml, szXMLCommentOpen, sizeof(szXMLCommentOpen)-1 ) == 0 ) 527 | { 528 | // processing comment parse 529 | // return pointer is next node of comment 530 | xml = node->LoadComment( xml, pi ); 531 | // comment node is terminal node 532 | if( node->parent && node->parent->type != XNODE_DOC 533 | && xml != prev ) 534 | { 535 | *pbRet = true; 536 | return xml; 537 | } 538 | // restart xml parse when this node is root doc node 539 | } 540 | 541 | if( xml != prev ) 542 | do_other_type = true; 543 | 544 | xml = _tcsskip( xml ); 545 | prev = xml; 546 | // is CDATA Node? 547 | if( _tcsnicmp( xml, szXMLCDATAOpen, sizeof(szXMLCDATAOpen)-1 ) == 0 ) 548 | { 549 | // processing CDATA parse 550 | // return pointer is next node of CDATA 551 | xml = node->LoadCDATA( xml, pi ); 552 | // CDATA node is terminal node 553 | if( node->parent && node->parent->type != XNODE_DOC 554 | && xml != prev ) 555 | { 556 | *pbRet = true; 557 | return xml; 558 | } 559 | // restart xml parse when this node is root doc node 560 | } 561 | 562 | if( xml != prev ) 563 | do_other_type = true; 564 | } 565 | 566 | return xml; 567 | } 568 | 569 | LPTSTR _tagXMLNode::Load( LPCTSTR pszXml, LPPARSEINFO pi /*= &piDefault*/ ) 570 | { 571 | // Close it 572 | Close(); 573 | 574 | LPTSTR xml = (LPTSTR)pszXml; 575 | 576 | xml = _tcschr( xml, chXMLTagOpen ); 577 | if( xml == NULL ) 578 | return NULL; 579 | 580 | // Close Tag 581 | if( *(xml+1) == chXMLTagPre ) // (pi, comment, CDATA etc) 585 | bool bRet = false; 586 | LPTSTR ret = NULL; 587 | ret = LoadOtherNodes( this, &bRet, xml, pi ); 588 | if( ret != NULL ) 589 | xml = ret; 590 | if( bRet ) 591 | return xml; 592 | 593 | // XML Node Tag Name Open 594 | xml++; 595 | TCHAR* pTagEnd = _tcspbrk( xml, _T(" />\t\r\n") ); 596 | _SetString( xml, pTagEnd, &name ); 597 | xml = pTagEnd; 598 | // Generate XML Attributte List 599 | if( ( xml = LoadAttributes( xml, pi ) ) != NULL ) 600 | { 601 | // alone tag 602 | if( *xml == chXMLTagPre ) 603 | { 604 | xml++; 605 | if( *xml == chXMLTagClose ) 606 | // wel-formed tag 607 | return ++xml; 608 | else 609 | { 610 | // error: 611 | if( pi->error_occur == false ) 612 | { 613 | pi->error_occur = true; 614 | pi->error_pointer = xml; 615 | pi->error_code = PIE_ALONE_NOT_CLOSED; 616 | pi->error_string = _T("Element must be closed."); 617 | } 618 | // not wel-formed tag 619 | return NULL; 620 | } 621 | } 622 | else 623 | // open/close tag ... 624 | // ^- current pointer 625 | { 626 | // if text value is not exist, then assign value 627 | //if( this->value.IsEmpty() || this->value == _T("") ) 628 | if( XIsEmptyString( value.c_str() ) ) 629 | { 630 | // Text Value 631 | TCHAR* pEnd = _tcsechr( ++xml, chXMLTagOpen, chXMLEscape ); 632 | if( pEnd == NULL ) 633 | { 634 | if( pi->error_occur == false ) 635 | { 636 | pi->error_occur = true; 637 | pi->error_pointer = xml; 638 | pi->error_code = PIE_NOT_CLOSED; 639 | auto_buffer sbuf (100 + name.size() + value.size()); 640 | _stprintf_s(sbuf, 100 + name.size() + value.size(), _T("%s must be closed with "), name.c_str(), value.c_str()); 641 | pi->error_string = sbuf.get(); 642 | } 643 | // error cos not exist CloseTag 644 | return NULL; 645 | } 646 | 647 | bool trim = pi->trim_value; 648 | TCHAR escape = pi->escape_value; 649 | //_SetString( xml, pEnd, &value, trim, chXMLEscape ); 650 | _SetString( xml, pEnd, &value, trim, escape ); 651 | 652 | xml = pEnd; 653 | // TEXTVALUE reference 654 | if( pi->entity_value && pi->entities ) 655 | value = pi->entities->Ref2Entity(value.c_str()); 656 | } 657 | 658 | // generate child nodes 659 | while( xml && *xml ) 660 | { 661 | LPXNode node = new XNode; 662 | node->parent = this; 663 | node->doc = doc; 664 | node->type = type; 665 | 666 | xml = node->Load( xml,pi ); 667 | if( node->name.empty() == FALSE ) 668 | { 669 | childs.push_back( node ); 670 | 671 | } 672 | else 673 | { 674 | delete node; 675 | } 676 | 677 | // open/close tag ... 678 | // ^- current pointer 679 | // CloseTag case 680 | if( xml && *xml && *(xml+1) && *xml == chXMLTagOpen && *(xml+1) == chXMLTagPre ) 681 | { 682 | // 683 | xml+=2; // C 684 | 685 | if( ( xml = _tcsskip( xml ) ) != NULL ) 686 | { 687 | std::wstring closename; 688 | TCHAR* pEnd = _tcspbrk( xml, _T(" >") ); 689 | if( pEnd == NULL ) 690 | { 691 | if( pi->error_occur == false ) 692 | { 693 | pi->error_occur = true; 694 | pi->error_pointer = xml; 695 | pi->error_code = PIE_NOT_CLOSED; 696 | auto_buffer sbuf (100 + name.size() + value.size()); 697 | _stprintf_s(sbuf, 100 + name.size() + value.size(), _T("%s must be closed with "), name.c_str(), value.c_str()); 698 | pi->error_string = sbuf.get(); 699 | } 700 | // error 701 | return NULL; 702 | } 703 | _SetString( xml, pEnd, &closename ); 704 | if( closename == this->name ) 705 | { 706 | // wel-formed open/close 707 | xml = pEnd+1; 708 | // return '>' or ' ' after pointer 709 | return xml; 710 | } 711 | else 712 | { 713 | xml = pEnd+1; 714 | // 2004.6.15 - example alone tag 715 | // now it can parse with attribute 'force_arse' 716 | if( pi->force_parse == false ) 717 | { 718 | // not welformed open/close 719 | if( pi->error_occur == false ) 720 | { 721 | pi->error_occur = true; 722 | pi->error_pointer = xml; 723 | pi->error_code = PIE_NOT_NESTED; 724 | auto_buffer sbuf (100 + name.size() + closename.size()); 725 | _stprintf_s(sbuf, 100 + name.size(), _T("'<%s> ... ' is not wel-formed."), name.c_str(), closename.c_str()); 726 | pi->error_string = sbuf.get(); 727 | } 728 | return NULL; 729 | } 730 | } 731 | } 732 | } 733 | else // Alone child Tag Loaded 734 | // else ÇØ¾ßÇÏ´ÂÁö ¸»¾Æ¾ßÇÏ´ÂÁö Àǽɰ£´Ù. 735 | { 736 | 737 | //if( xml && this->value.IsEmpty() && *xml !=chXMLTagOpen ) 738 | if( xml && XIsEmptyString( value.c_str() ) && *xml !=chXMLTagOpen ) 739 | { 740 | // Text Value 741 | TCHAR* pEnd = _tcsechr( xml, chXMLTagOpen, chXMLEscape ); 742 | if( pEnd == NULL ) 743 | { 744 | // error cos not exist CloseTag 745 | if( pi->error_occur == false ) 746 | { 747 | pi->error_occur = true; 748 | pi->error_pointer = xml; 749 | pi->error_code = PIE_NOT_CLOSED; 750 | auto_buffer sbuf (100 + name.size() + value.size()); 751 | _stprintf_s(sbuf, 100 + name.size() + value.size(), _T("%s must be closed with "), name.c_str(), value.c_str()); 752 | pi->error_string = sbuf.get(); 753 | } 754 | return NULL; 755 | } 756 | 757 | bool trim = pi->trim_value; 758 | TCHAR escape = pi->escape_value; 759 | //_SetString( xml, pEnd, &value, trim, chXMLEscape ); 760 | _SetString( xml, pEnd, &value, trim, escape ); 761 | 762 | xml = pEnd; 763 | //TEXTVALUE 764 | if( pi->entity_value && pi->entities ) 765 | value = pi->entities->Ref2Entity(value.c_str()); 766 | } 767 | } 768 | } 769 | } 770 | } 771 | 772 | return xml; 773 | } 774 | 775 | LPTSTR _tagXMLDocument::Load( LPCTSTR pszXml, LPPARSEINFO pi /*= NULL*/ ) 776 | { 777 | LPXNode node = new XNode; 778 | node->parent = (LPXNode)this; 779 | node->type = XNODE_ELEMENT; 780 | node->doc = this; 781 | LPTSTR end; 782 | 783 | if( pi == NULL ) 784 | pi = &parse_info; 785 | 786 | if( (end = node->Load( pszXml, pi )) == NULL ) 787 | { 788 | delete node; 789 | return NULL; 790 | } 791 | 792 | childs.push_back( node ); 793 | 794 | // Load Other Node after (pi, comment, CDATA etc) 795 | LPTSTR ret; 796 | bool bRet = false; 797 | ret = LoadOtherNodes( node, &bRet, end, pi ); 798 | if( ret != NULL ) 799 | end = ret; 800 | 801 | return end; 802 | } 803 | 804 | LPXNode _tagXMLDocument::GetRoot() 805 | { 806 | XNodes::iterator it = childs.begin(); 807 | for( ; it != childs.end() ; ++(it) ) 808 | { 809 | LPXNode node = *it; 810 | if( node->type == XNODE_ELEMENT ) 811 | return node; 812 | } 813 | return NULL; 814 | } 815 | 816 | std::wstring _tagXMLAttr::GetXML( LPDISP_OPT opt /*= &optDefault*/ ) 817 | { 818 | std::wostringstream os; 819 | //os << (LPCTSTR)name << "='" << (LPCTSTR)value << "' "; 820 | 821 | os << (LPCTSTR)name.c_str() << _T("=") << (TCHAR)opt->value_quotation_mark 822 | << (LPCTSTR)(opt->reference_value&&opt->entities?opt->entities->Entity2Ref(value.c_str()).c_str():value.c_str()) 823 | << (TCHAR)opt->value_quotation_mark << _T(" "); 824 | return os.str(); 825 | } 826 | 827 | std::wstring _tagXMLNode::GetXML( LPDISP_OPT opt /*= &optDefault*/ ) 828 | { 829 | std::wostringstream os; 830 | 831 | // tab 832 | if( opt && opt->newline ) 833 | { 834 | os << "\r\n"; 835 | for( int i = 0 ; i < opt->tab_base ; i++) 836 | os << '\t'; 837 | } 838 | 839 | if( type == XNODE_DOC ) 840 | { 841 | for( size_t i = 0 ; i < childs.size(); i++ ) 842 | os << (LPCTSTR)childs[i]->GetXML( opt ).c_str(); 843 | return os.str(); 844 | } 845 | else 846 | if( type == XNODE_PI ) 847 | { 848 | // GetXML(opt).c_str(); 855 | } 856 | //?> 857 | os << szXMLPIClose; 858 | return os.str(); 859 | } 860 | else 861 | if( type == XNODE_COMMENT ) 862 | { 863 | // <--comment 864 | os << szXMLCommentOpen << (LPCTSTR)value.c_str(); 865 | //--> 866 | os << szXMLCommentClose; 867 | return os.str(); 868 | } 869 | else 870 | if( type == XNODE_CDATA ) 871 | { 872 | // <--comment 873 | os << szXMLCDATAOpen << (LPCTSTR)value.c_str(); 874 | //--> 875 | os << szXMLCDATAClose; 876 | return os.str(); 877 | } 878 | 879 | // GetXML(opt).c_str(); 887 | } 888 | 889 | if( childs.empty() && value.empty() ) 890 | { 891 | // alone tag 892 | os << "/>"; 893 | } 894 | else 895 | { 896 | // and get child 897 | os << '>'; 898 | if( opt && opt->newline && !childs.empty() ) 899 | { 900 | opt->tab_base++; 901 | } 902 | 903 | for( size_t i = 0 ; i < childs.size(); i++ ) 904 | os << (LPCTSTR)childs[i]->GetXML( opt ).c_str(); 905 | 906 | // Text Value 907 | if( value != _T("") ) 908 | { 909 | if( opt && opt->newline && !childs.empty() ) 910 | { 911 | if( opt && opt->newline ) 912 | os << _T("\r\n"); 913 | if( opt ) 914 | for( int i = 0 ; i < opt->tab_base ; i++) 915 | os << '\t'; 916 | } 917 | if( opt ) 918 | os << (LPCTSTR)(opt->reference_value&&opt->entities?opt->entities->Entity2Ref(value.c_str()).c_str():value.c_str()); 919 | } 920 | 921 | // CloseTag 922 | if( opt && opt->newline && !childs.empty() ) 923 | { 924 | os << "\r\n"; 925 | for( int i = 0 ; i < opt->tab_base-1 ; i++) 926 | os << '\t'; 927 | } 928 | os << "'; 929 | 930 | if( opt && opt->newline ) 931 | { 932 | if( !childs.empty() ) 933 | opt->tab_base--; 934 | } 935 | } 936 | 937 | return os.str(); 938 | } 939 | 940 | std::wstring _tagXMLNode::GetText( LPDISP_OPT opt /*= &optDefault*/ ) 941 | { 942 | std::wostringstream os; 943 | 944 | if( type == XNODE_DOC ) 945 | { 946 | for( size_t i = 0 ; i < childs.size(); i++ ) 947 | os << (LPCTSTR)childs[i]->GetText( opt ).c_str(); 948 | } 949 | else 950 | if( type == XNODE_PI ) 951 | { 952 | // no text 953 | } 954 | else 955 | if( type == XNODE_COMMENT ) 956 | { 957 | // no text 958 | } 959 | else 960 | if( type == XNODE_CDATA ) 961 | { 962 | os << (LPCTSTR)value.c_str(); 963 | } 964 | else 965 | if( type == XNODE_ELEMENT ) 966 | { 967 | if( childs.empty() && value.empty() ) 968 | { 969 | // no text 970 | } 971 | else 972 | { 973 | // childs text 974 | for( size_t i = 0 ; i < childs.size(); i++ ) 975 | os << (LPCTSTR)childs[i]->GetText().c_str(); 976 | 977 | // Text Value 978 | os << (LPCTSTR)(opt->reference_value&&opt->entities?opt->entities->Entity2Ref(value.c_str()).c_str():value.c_str()); 979 | } 980 | } 981 | 982 | return os.str(); 983 | } 984 | 985 | LPXAttr _tagXMLNode::GetAttr( LPCTSTR attrname ) 986 | { 987 | for( size_t i = 0 ; i < attrs.size(); i++ ) 988 | { 989 | LPXAttr attr = attrs[i]; 990 | if( attr ) 991 | { 992 | if( attr->name == attrname ) 993 | return attr; 994 | } 995 | } 996 | return NULL; 997 | } 998 | 999 | XAttrs _tagXMLNode::GetAttrs( LPCTSTR nam ) 1000 | { 1001 | XAttrs attr; 1002 | for( size_t i = 0 ; i < attr.size(); i++ ) 1003 | { 1004 | LPXAttr att = attr[i]; 1005 | if( att ) 1006 | { 1007 | if( att->name == nam ) 1008 | attr.push_back( att ); 1009 | } 1010 | } 1011 | return attr; 1012 | } 1013 | 1014 | LPCTSTR _tagXMLNode::GetAttrValue( LPCTSTR attrname ) 1015 | { 1016 | LPXAttr attr = GetAttr( attrname ); 1017 | return attr ? (LPCTSTR)attr->value.c_str() : NULL; 1018 | } 1019 | 1020 | XNodes _tagXMLNode::GetChilds() 1021 | { 1022 | return childs; 1023 | } 1024 | 1025 | XNodes _tagXMLNode::GetChilds( LPCTSTR nam ) 1026 | { 1027 | XNodes nodes; 1028 | for( size_t i = 0 ; i < childs.size(); i++ ) 1029 | { 1030 | LPXNode node = childs[i]; 1031 | if( node ) 1032 | { 1033 | if( node->name == nam ) 1034 | nodes.push_back( node ); 1035 | } 1036 | } 1037 | return nodes; 1038 | } 1039 | 1040 | LPXNode _tagXMLNode::GetChild( int i ) 1041 | { 1042 | if( i >= 0 && i < (int)childs.size() ) 1043 | return childs[i]; 1044 | return NULL; 1045 | } 1046 | 1047 | size_t _tagXMLNode::GetChildCount() 1048 | { 1049 | return childs.size(); 1050 | } 1051 | 1052 | LPXNode _tagXMLNode::GetChild( LPCTSTR nam ) 1053 | { 1054 | for( size_t i = 0 ; i < childs.size(); i++ ) 1055 | { 1056 | LPXNode node = childs[i]; 1057 | if( node ) 1058 | { 1059 | if( node->name == nam ) 1060 | return node; 1061 | } 1062 | } 1063 | return NULL; 1064 | } 1065 | 1066 | LPCTSTR _tagXMLNode::GetChildValue( LPCTSTR nam ) 1067 | { 1068 | LPXNode node = GetChild( nam ); 1069 | return (node != NULL)? (LPCTSTR)node->value.c_str() : NULL; 1070 | } 1071 | 1072 | std::wstring _tagXMLNode::GetChildText( LPCTSTR nam, LPDISP_OPT opt /*= &optDefault*/ ) 1073 | { 1074 | LPXNode node = GetChild( nam ); 1075 | return (node != NULL)? node->GetText(opt) : _T(""); 1076 | } 1077 | 1078 | LPXAttr _tagXMLNode::GetChildAttr( LPCTSTR nam, LPCTSTR attrname ) 1079 | { 1080 | LPXNode node = GetChild(nam); 1081 | return node ? node->GetAttr(attrname) : NULL; 1082 | } 1083 | 1084 | LPCTSTR _tagXMLNode::GetChildAttrValue( LPCTSTR nam, LPCTSTR attrname ) 1085 | { 1086 | LPXAttr attr = GetChildAttr( nam, attrname ); 1087 | return attr ? (LPCTSTR)attr->value.c_str() : NULL; 1088 | } 1089 | 1090 | LPXNode _tagXMLNode::Find( LPCTSTR nam ) 1091 | { 1092 | XNodes::iterator it = childs.begin(); 1093 | for( ; it != childs.end(); ++(it)) 1094 | { 1095 | LPXNode child = *it; 1096 | if( child->name == nam ) 1097 | return child; 1098 | 1099 | XNodes::iterator childit = child->childs.begin(); 1100 | for( ; childit != child->childs.end(); ++(childit)) 1101 | { 1102 | LPXNode find = child->Find( nam ); 1103 | if( find != NULL ) 1104 | return find; 1105 | } 1106 | } 1107 | 1108 | return NULL; 1109 | } 1110 | 1111 | XNodes::iterator _tagXMLNode::GetChildIterator( LPXNode node ) 1112 | { 1113 | XNodes::iterator it = childs.begin(); 1114 | for( ; it != childs.end() ; ++(it) ) 1115 | { 1116 | if( *it == node ) 1117 | return it; 1118 | } 1119 | return childs.end(); 1120 | } 1121 | 1122 | LPXNode _tagXMLNode::AppendChild( LPCTSTR nam /*= NULL*/, LPCTSTR val /*= NULL*/ ) 1123 | { 1124 | return AppendChild( CreateNode( nam, val ) ); 1125 | } 1126 | 1127 | LPXNode _tagXMLNode::AppendChild( LPXNode node ) 1128 | { 1129 | node->parent = this; 1130 | node->doc = doc; 1131 | childs.push_back( node ); 1132 | return node; 1133 | } 1134 | 1135 | bool _tagXMLNode::RemoveChild( LPXNode node ) 1136 | { 1137 | XNodes::iterator it = GetChildIterator( node ); 1138 | if( it != childs.end() ) 1139 | { 1140 | delete *it; 1141 | childs.erase( it ); 1142 | return true; 1143 | } 1144 | return false; 1145 | } 1146 | 1147 | LPXAttr _tagXMLNode::GetAttr( int i ) 1148 | { 1149 | if( i >= 0 && i < (int)attrs.size() ) 1150 | return attrs[i]; 1151 | return NULL; 1152 | } 1153 | 1154 | XAttrs::iterator _tagXMLNode::GetAttrIterator( LPXAttr attr ) 1155 | { 1156 | XAttrs::iterator it = attrs.begin(); 1157 | for( ; it != attrs.end() ; ++(it) ) 1158 | { 1159 | if( *it == attr ) 1160 | return it; 1161 | } 1162 | return attrs.end(); 1163 | } 1164 | 1165 | LPXAttr _tagXMLNode::AppendAttr( LPXAttr attr ) 1166 | { 1167 | attr->parent = this; 1168 | attrs.push_back( attr ); 1169 | return attr; 1170 | } 1171 | 1172 | bool _tagXMLNode::RemoveAttr( LPXAttr attr ) 1173 | { 1174 | XAttrs::iterator it = GetAttrIterator( attr ); 1175 | if( it != attrs.end() ) 1176 | { 1177 | delete *it; 1178 | attrs.erase( it ); 1179 | return true; 1180 | } 1181 | return false; 1182 | } 1183 | 1184 | LPXNode _tagXMLNode::CreateNode( LPCTSTR nam /*= NULL*/, LPCTSTR val /*= NULL*/ ) 1185 | { 1186 | LPXNode node = new XNode; 1187 | node->name = nam; 1188 | node->value = val; 1189 | return node; 1190 | } 1191 | 1192 | LPXAttr _tagXMLNode::CreateAttr( LPCTSTR nam /*= NULL*/, LPCTSTR val /*= NULL*/ ) 1193 | { 1194 | LPXAttr attr = new XAttr; 1195 | attr->name = nam; 1196 | attr->value = val; 1197 | return attr; 1198 | } 1199 | 1200 | LPXAttr _tagXMLNode::AppendAttr( LPCTSTR nam /*= NULL*/, LPCTSTR val /*= NULL*/ ) 1201 | { 1202 | return AppendAttr( CreateAttr( nam, val ) ); 1203 | } 1204 | 1205 | LPXNode _tagXMLNode::DetachChild( LPXNode node ) 1206 | { 1207 | XNodes::iterator it = GetChildIterator( node ); 1208 | if( it != childs.end() ) 1209 | { 1210 | childs.erase( it ); 1211 | return node; 1212 | } 1213 | return NULL; 1214 | } 1215 | 1216 | LPXAttr _tagXMLNode::DetachAttr( LPXAttr attr ) 1217 | { 1218 | XAttrs::iterator it = GetAttrIterator( attr ); 1219 | if( it != attrs.end() ) 1220 | { 1221 | attrs.erase( it ); 1222 | return attr; 1223 | } 1224 | return NULL; 1225 | } 1226 | 1227 | void _tagXMLNode::CopyNode( LPXNode node ) 1228 | { 1229 | Close(); 1230 | 1231 | doc = node->doc; 1232 | parent = node->parent; 1233 | name = node->name; 1234 | value = node->value; 1235 | type = node->type; 1236 | 1237 | // copy attributes 1238 | for( size_t i = 0 ; i < node->attrs.size(); i++) 1239 | { 1240 | LPXAttr attr = node->attrs[i]; 1241 | if( attr ) 1242 | AppendAttr( attr->name.c_str(), attr->value.c_str() ); 1243 | } 1244 | } 1245 | 1246 | void _tagXMLNode::_CopyBranch( LPXNode node ) 1247 | { 1248 | CopyNode( node ); 1249 | 1250 | for( size_t i = 0 ; i < node->childs.size(); i++) 1251 | { 1252 | LPXNode child = node->childs[i]; 1253 | if( child ) 1254 | { 1255 | LPXNode mychild = new XNode; 1256 | mychild->CopyNode( child ); 1257 | AppendChild( mychild ); 1258 | 1259 | mychild->_CopyBranch( child ); 1260 | } 1261 | } 1262 | } 1263 | 1264 | LPXNode _tagXMLNode::AppendChildBranch( LPXNode node ) 1265 | { 1266 | LPXNode child = new XNode; 1267 | child->CopyBranch( node ); 1268 | 1269 | return AppendChild( child ); 1270 | } 1271 | 1272 | void _tagXMLNode::CopyBranch( LPXNode branch ) 1273 | { 1274 | Close(); 1275 | 1276 | _CopyBranch( branch ); 1277 | } 1278 | 1279 | 1280 | _tagXMLEntitys::_tagXMLEntitys( LPXENTITY entities, int count ) 1281 | { 1282 | for( int i = 0; i < count; i++) 1283 | push_back( entities[i] ); 1284 | } 1285 | 1286 | LPXENTITY _tagXMLEntitys::GetEntity( int entity ) 1287 | { 1288 | for( size_t i = 0 ; i < size(); i ++ ) 1289 | { 1290 | if( at(i).entity == entity ) 1291 | return LPXENTITY(&at(i)); 1292 | } 1293 | return NULL; 1294 | } 1295 | 1296 | LPXENTITY _tagXMLEntitys::GetEntity( LPTSTR entity ) 1297 | { 1298 | for( size_t i = 0 ; i < size(); i ++ ) 1299 | { 1300 | LPTSTR ref = (LPTSTR)at(i).ref; 1301 | LPTSTR ps = entity; 1302 | while( ref && *ref ) 1303 | if( *ref++ != *ps++ ) 1304 | break; 1305 | if( ref && !*ref ) // found! 1306 | return LPXENTITY(&at(i)); 1307 | } 1308 | return NULL; 1309 | } 1310 | 1311 | size_t _tagXMLEntitys::GetEntityCount( LPCTSTR str ) 1312 | { 1313 | int nCount = 0; 1314 | LPTSTR ps = (LPTSTR)str; 1315 | while( ps && *ps ) 1316 | if( GetEntity( *ps++ ) ) nCount ++; 1317 | return nCount; 1318 | } 1319 | 1320 | size_t _tagXMLEntitys::Ref2Entity( LPCTSTR estr, LPTSTR str, size_t strlen ) 1321 | { 1322 | LPTSTR pes = (LPTSTR)estr; 1323 | LPTSTR ps = str; 1324 | LPTSTR ps_end = ps+strlen; 1325 | while( pes && *pes && ps < ps_end ) 1326 | { 1327 | LPXENTITY ent = GetEntity( pes ); 1328 | if( ent ) 1329 | { 1330 | // copy entity meanning char 1331 | *ps = ent->entity; 1332 | pes += ent->ref_len; 1333 | } 1334 | else 1335 | *ps = *pes++; // default character copy 1336 | ps++; 1337 | } 1338 | *ps = '\0'; 1339 | 1340 | // total copied characters 1341 | return ps-str; 1342 | } 1343 | 1344 | size_t _tagXMLEntitys::Entity2Ref( LPCTSTR str, LPTSTR estr, size_t estrlen ) 1345 | { 1346 | LPTSTR ps = (LPTSTR)str; 1347 | LPTSTR pes = (LPTSTR)estr; 1348 | LPTSTR pes_end = pes+estrlen; 1349 | while( ps && *ps && pes < pes_end ) 1350 | { 1351 | LPXENTITY ent = GetEntity( *ps ); 1352 | if( ent ) 1353 | { 1354 | // copy entity string 1355 | LPTSTR ref = (LPTSTR)ent->ref; 1356 | while( ref && *ref ) 1357 | *pes++ = *ref++; 1358 | } 1359 | else 1360 | *pes++ = *ps; // default character copy 1361 | ps++; 1362 | } 1363 | *pes = '\0'; 1364 | 1365 | // total copied characters 1366 | return pes-estr; 1367 | } 1368 | 1369 | std::wstring _tagXMLEntitys::Ref2Entity( LPCTSTR estr ) 1370 | { 1371 | std::wstring es; 1372 | if( estr ) 1373 | { 1374 | size_t len = _tcslen(estr); 1375 | auto_buffer esbuf (len + 1); 1376 | if( esbuf ) 1377 | { 1378 | Ref2Entity( estr, esbuf, len ); 1379 | es = esbuf.get(); 1380 | } 1381 | } 1382 | return es; 1383 | } 1384 | 1385 | std::wstring _tagXMLEntitys::Entity2Ref( LPCTSTR str ) 1386 | { 1387 | std::wstring s; 1388 | if( str ) 1389 | { 1390 | size_t nEntityCount = GetEntityCount(str); 1391 | if( nEntityCount == 0 ) 1392 | return std::wstring(str); 1393 | size_t len = _tcslen(str) + nEntityCount*10 ; 1394 | auto_buffer sbuf (len + 1); 1395 | if( sbuf ) 1396 | { 1397 | Entity2Ref( str, sbuf, len ); 1398 | s = sbuf.get(); 1399 | } 1400 | } 1401 | return s; 1402 | } 1403 | 1404 | std::wstring XRef2Entity( LPCTSTR estr ) 1405 | { 1406 | return entityDefault.Ref2Entity( estr ); 1407 | } 1408 | 1409 | std::wstring XEntity2Ref( LPCTSTR str ) 1410 | { 1411 | return entityDefault.Entity2Ref( str ); 1412 | } 1413 | -------------------------------------------------------------------------------- /src/XMLite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "StringUtils.h" 3 | #include 4 | #include 5 | #include 6 | 7 | struct _tagXMLAttr; 8 | typedef _tagXMLAttr XAttr, *LPXAttr; 9 | typedef std::vector XAttrs; 10 | 11 | struct _tagXMLNode; 12 | typedef _tagXMLNode XNode, *LPXNode; 13 | typedef std::vector XNodes, *LPXNodes; 14 | 15 | struct _tagXMLDocument; 16 | typedef struct _tagXMLDocument XDoc, *LPXDoc; 17 | 18 | // Entity Encode/Decode Support 19 | typedef struct _tagXmlEntity 20 | { 21 | TCHAR entity; // entity ( & " ' < > ) 22 | TCHAR ref[10]; // entity reference ( & " etc ) 23 | int ref_len; // entity reference length 24 | }XENTITY,*LPXENTITY; 25 | 26 | typedef struct _tagXMLEntitys : public std::vector 27 | { 28 | LPXENTITY GetEntity( int entity ); 29 | LPXENTITY GetEntity( LPTSTR entity ); 30 | size_t GetEntityCount( LPCTSTR str ); 31 | size_t Ref2Entity( LPCTSTR estr, LPTSTR str, size_t strlen ); 32 | size_t Entity2Ref( LPCTSTR str, LPTSTR estr, size_t estrlen ); 33 | std::wstring Ref2Entity( LPCTSTR estr ); 34 | std::wstring Entity2Ref( LPCTSTR str ); 35 | 36 | _tagXMLEntitys(){}; 37 | _tagXMLEntitys( LPXENTITY entities, int count ); 38 | }XENTITYS,*LPXENTITYS; 39 | extern XENTITYS entityDefault; 40 | std::wstring XRef2Entity( LPCTSTR estr ); 41 | std::wstring XEntity2Ref( LPCTSTR str ); 42 | 43 | typedef enum 44 | { 45 | PIE_PARSE_WELFORMED = 0, 46 | PIE_ALONE_NOT_CLOSED, 47 | PIE_NOT_CLOSED, 48 | PIE_NOT_NESTED, 49 | PIE_ATTR_NO_VALUE 50 | }PCODE; 51 | 52 | // Parse info. 53 | typedef struct _tagParseInfo 54 | { 55 | bool trim_value; // [set] do trim when parse? 56 | bool entity_value; // [set] do convert from reference to entity? ( < -> < ) 57 | LPXENTITYS entities; // [set] entity table for entity decode 58 | TCHAR escape_value; // [set] escape value (default '\\') 59 | bool force_parse; // [set] force parse even if xml is not welformed 60 | 61 | LPTSTR xml; // [get] xml source 62 | bool error_occur; // [get] is occurance of error? 63 | LPTSTR error_pointer; // [get] error position of xml source 64 | PCODE error_code; // [get] error code 65 | std::wstring error_string; // [get] error string 66 | 67 | LPXDoc doc; 68 | _tagParseInfo() { trim_value = false; entity_value = true; force_parse = false; entities = &entityDefault; xml = NULL; doc = NULL; error_occur = false; error_pointer = NULL; error_code = PIE_PARSE_WELFORMED; escape_value = '\\'; } 69 | }PARSEINFO,*LPPARSEINFO; 70 | extern PARSEINFO piDefault; 71 | 72 | // display optional environment 73 | typedef struct _tagDispOption 74 | { 75 | bool newline; // newline when new tag 76 | bool reference_value; // do convert from entity to reference ( < -> < ) 77 | TCHAR value_quotation_mark; // val="" (default value quotation mark " 78 | LPXENTITYS entities; // entity table for entity encode 79 | 80 | int tab_base; // internal usage 81 | _tagDispOption() { newline = true; reference_value = true; entities = &entityDefault; tab_base = 0; value_quotation_mark = '"'; } 82 | }DISP_OPT, *LPDISP_OPT; 83 | extern DISP_OPT optDefault; 84 | 85 | // XAttr : Attribute Implementation 86 | typedef struct _tagXMLAttr 87 | { 88 | std::wstring name; 89 | std::wstring value; 90 | 91 | _tagXMLNode* parent; 92 | 93 | std::wstring GetXML( LPDISP_OPT opt = &optDefault ); 94 | }XAttr, *LPXAttr; 95 | 96 | typedef enum 97 | { 98 | XNODE_ELEMENT, // general node '...' or 99 | XNODE_PI, // 100 | XNODE_COMMENT, // 101 | XNODE_CDATA, // 102 | XNODE_DOC, // internal virtual root 103 | }NODE_TYPE; 104 | 105 | // XMLNode structure 106 | typedef struct _tagXMLNode 107 | { 108 | // name and value 109 | std::wstring name; 110 | std::wstring value; 111 | 112 | // internal variables 113 | LPXNode parent; // parent node 114 | XNodes childs; // child node 115 | XAttrs attrs; // attributes 116 | NODE_TYPE type; // node type 117 | LPXDoc doc; // document 118 | 119 | // Load/Save XML 120 | LPTSTR Load( LPCTSTR pszXml, LPPARSEINFO pi = &piDefault ); 121 | std::wstring GetXML( LPDISP_OPT opt = &optDefault ); 122 | std::wstring GetText( LPDISP_OPT opt = &optDefault ); 123 | 124 | // internal load functions 125 | LPTSTR LoadAttributes( LPCTSTR pszAttrs, LPPARSEINFO pi = &piDefault ); 126 | LPTSTR LoadAttributes( LPCTSTR pszAttrs, LPCTSTR pszEnd, LPPARSEINFO pi = &piDefault ); 127 | LPTSTR LoadProcessingInstrunction( LPCTSTR pszXml, LPPARSEINFO pi = &piDefault ); 128 | LPTSTR LoadComment( LPCTSTR pszXml, LPPARSEINFO pi = &piDefault ); 129 | LPTSTR LoadCDATA( LPCTSTR pszXml, LPPARSEINFO pi = &piDefault ); 130 | 131 | // in own attribute list 132 | LPXAttr GetAttr( LPCTSTR attrname ); 133 | LPCTSTR GetAttrValue( LPCTSTR attrname ); 134 | XAttrs GetAttrs( LPCTSTR name ); 135 | 136 | // in one level child nodes 137 | LPXNode GetChild( LPCTSTR name ); 138 | LPCTSTR GetChildValue( LPCTSTR name ); 139 | std::wstring GetChildText( LPCTSTR name, LPDISP_OPT opt = &optDefault ); 140 | XNodes GetChilds( LPCTSTR name ); 141 | XNodes GetChilds(); 142 | 143 | LPXAttr GetChildAttr( LPCTSTR name, LPCTSTR attrname ); 144 | LPCTSTR GetChildAttrValue( LPCTSTR name, LPCTSTR attrname ); 145 | 146 | // search node 147 | LPXNode Find( LPCTSTR name ); 148 | 149 | // modify DOM 150 | size_t GetChildCount(); 151 | LPXNode GetChild( int i ); 152 | XNodes::iterator GetChildIterator( LPXNode node ); 153 | LPXNode CreateNode( LPCTSTR name = NULL, LPCTSTR value = NULL ); 154 | LPXNode AppendChild( LPCTSTR name = NULL, LPCTSTR value = NULL ); 155 | LPXNode AppendChild( LPXNode node ); 156 | bool RemoveChild( LPXNode node ); 157 | LPXNode DetachChild( LPXNode node ); 158 | 159 | // node/branch copy 160 | void CopyNode( LPXNode node ); 161 | void CopyBranch( LPXNode branch ); 162 | void _CopyBranch( LPXNode node ); 163 | LPXNode AppendChildBranch( LPXNode node ); 164 | 165 | // modify attribute 166 | LPXAttr GetAttr( int i ); 167 | XAttrs::iterator GetAttrIterator( LPXAttr node ); 168 | LPXAttr CreateAttr( LPCTSTR anem = NULL, LPCTSTR value = NULL ); 169 | LPXAttr AppendAttr( LPCTSTR name = NULL, LPCTSTR value = NULL ); 170 | LPXAttr AppendAttr( LPXAttr attr ); 171 | bool RemoveAttr( LPXAttr attr ); 172 | LPXAttr DetachAttr( LPXAttr attr ); 173 | 174 | // operator overloads 175 | LPXNode operator [] ( int i ) { return GetChild(i); } 176 | XNode& operator = ( XNode& node ) { CopyBranch(&node); return *this; } 177 | 178 | _tagXMLNode() { parent = NULL; doc = NULL; type = XNODE_ELEMENT; } 179 | ~_tagXMLNode(); 180 | 181 | void Close(); 182 | }XNode, *LPXNode; 183 | 184 | // XMLDocument structure 185 | typedef struct _tagXMLDocument : public XNode 186 | { 187 | PARSEINFO parse_info; 188 | 189 | _tagXMLDocument() { parent = NULL; doc = this; type = XNODE_DOC; } 190 | 191 | LPTSTR Load( LPCTSTR pszXml, LPPARSEINFO pi = NULL ); 192 | LPXNode GetRoot(); 193 | 194 | }XDoc, *LPXDoc; 195 | 196 | // Helper Funtion 197 | inline long XStr2Int( LPCTSTR str, long default_value = 0 ) 198 | { 199 | return ( str && *str ) ? _ttol(str) : default_value; 200 | } 201 | 202 | inline bool XIsEmptyString( LPCTSTR str ) 203 | { 204 | std::wstring s(str); 205 | CStringUtils::trim(s); 206 | 207 | return ( s.empty() || s == _T("") ); 208 | } 209 | -------------------------------------------------------------------------------- /src/auto_buffer.h: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2010 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #pragma once 21 | 22 | /** 23 | * A simplified analog to std::auto_ptr<> that encapsulates 24 | * an array allocated dynamically via new[]. 25 | * 26 | * Use this where you could not use a std::auto_ptr<> (works 27 | * for single elements only) nor a std::vector<> (no guarantees 28 | * w.r.t. to internal organization, i.e. no access to mem buffer). 29 | */ 30 | 31 | template 32 | class auto_buffer 33 | { 34 | private: 35 | 36 | T* buffer; 37 | 38 | /// no copy nor assignment 39 | 40 | auto_buffer(const auto_buffer&); 41 | auto_buffer& operator=(const auto_buffer&); 42 | 43 | public: 44 | 45 | explicit auto_buffer (size_t size = 0) throw() 46 | : buffer (size == 0 ? NULL : new T[size]) 47 | { 48 | } 49 | 50 | ~auto_buffer() 51 | { 52 | delete[] buffer; 53 | } 54 | 55 | operator T*() const throw() 56 | { 57 | return buffer; 58 | } 59 | 60 | operator void*() const throw() 61 | { 62 | return buffer; 63 | } 64 | 65 | operator bool() const throw() 66 | { 67 | return buffer != NULL; 68 | } 69 | 70 | T* operator->() const throw() 71 | { 72 | return buffer; 73 | } 74 | 75 | T *get() const throw() 76 | { 77 | return buffer; 78 | } 79 | 80 | T* release() throw() 81 | { 82 | T* temp = buffer; 83 | buffer = NULL; 84 | return temp; 85 | } 86 | 87 | void reset (size_t newSize = 0) 88 | { 89 | delete[] buffer; 90 | buffer = (newSize == 0 ? NULL : new T[newSize]); 91 | } 92 | }; 93 | -------------------------------------------------------------------------------- /src/compatibility.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/last/version.h: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2018 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #pragma once 21 | 22 | // this file is used if the NAnt script didn't run and 23 | // didn't create the real version.h file. 24 | // only needed if users don't need correct version info 25 | // or for the continuous integration servers where NAnt and TGit isn't available 26 | 27 | #define FILEVER 1, 0, 0, 0 28 | #define PRODUCTVER 1, 0, 0, 0 29 | #define STRFILEVER "1.0.0.0\0" 30 | #define STRPRODUCTVER "1.0.0.0\0" 31 | 32 | #define SM_VERMAJOR 1 33 | #define SM_VERMINOR 0 34 | #define SM_VERMICRO 0 35 | #define SM_VERBUILD 0 36 | #define SM_VERDATE "2000/01/01 00:00:00" 37 | -------------------------------------------------------------------------------- /src/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by SendMessage.rc 4 | // 5 | #define IDC_MYICON 2 6 | #define IDD_SENDMESSAGE_DIALOG 102 7 | #define IDD_ABOUTBOX 103 8 | #define IDM_ABOUT 104 9 | #define IDI_SENDMESSAGE 107 10 | #define IDC_SENDMESSAGE 109 11 | #define IDR_MAINFRAME 128 12 | #define IDD_MAINDLG 129 13 | #define IDR_ACCELERATOR1 130 14 | #define IDR_MAINDLG 130 15 | #define IDI_SEARCHW 131 16 | #define IDR_WINDOWMESSAGESXML 133 17 | #define IDD_WINDOWSTREE 134 18 | #define IDC_WEBLINK 1000 19 | #define IDC_VERSIONINFO 1001 20 | #define IDC_DATE 1002 21 | #define IDC_SEARCHW 1003 22 | #define IDC_STATIC_X_POS 1004 23 | #define IDC_STATIC_Y_POS 1005 24 | #define IDC_EDIT_STATUS 1006 25 | #define IDC_WINDOW 1007 26 | #define IDC_MESSAGE 1008 27 | #define IDC_WPARAM 1009 28 | #define IDC_LPARAM 1010 29 | #define IDC_POSTMESSAGE 1012 30 | #define IDC_RETVALUE 1013 31 | #define IDC_SENDGROUP 1014 32 | #define IDC_ABOUTLINK 1015 33 | #define IDC_POS 1016 34 | #define IDC_PINWINDOW 1017 35 | #define IDC_UNPINWINDOW 1018 36 | #define IDC_SHOWWINDOW 1019 37 | #define IDC_CMDSHOW 1020 38 | #define IDC_ERROR 1024 39 | #define IDC_WINDOWTREE 1025 40 | #define IDC_REFRESH 1026 41 | #define IDC_FILTER 1027 42 | #define IDC_STATIC -1 43 | 44 | // Next default values for new objects 45 | // 46 | #ifdef APSTUDIO_INVOKED 47 | #ifndef APSTUDIO_READONLY_SYMBOLS 48 | #define _APS_NO_MFC 1 49 | #define _APS_NEXT_RESOURCE_VALUE 135 50 | #define _APS_NEXT_COMMAND_VALUE 32772 51 | #define _APS_NEXT_CONTROL_VALUE 1028 52 | #define _APS_NEXT_SYMED_VALUE 110 53 | #endif 54 | #endif 55 | -------------------------------------------------------------------------------- /src/resources/SendMessage.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefankueng/sendmessage/9c546bc59fb5473646b93d05b69923d9a5de5245/src/resources/SendMessage.ico -------------------------------------------------------------------------------- /src/resources/searchw.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefankueng/sendmessage/9c546bc59fb5473646b93d05b69923d9a5de5245/src/resources/searchw.cur -------------------------------------------------------------------------------- /src/resources/searchw.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefankueng/sendmessage/9c546bc59fb5473646b93d05b69923d9a5de5245/src/resources/searchw.ico -------------------------------------------------------------------------------- /src/resources/windowmessages.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | -------------------------------------------------------------------------------- /src/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2010 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #include "stdafx.h" 21 | -------------------------------------------------------------------------------- /src/stdafx.h: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2010 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #pragma once 21 | 22 | 23 | // Including SDKDDKVer.h defines the highest available Windows platform. 24 | 25 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 26 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 27 | 28 | #include 29 | 30 | 31 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 32 | // Windows Header Files: 33 | #include 34 | #include 35 | #include 36 | 37 | // C RunTime Header Files 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | 44 | #pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 45 | -------------------------------------------------------------------------------- /src/version.in: -------------------------------------------------------------------------------- 1 | // SendMessage - a tool to send custom messages 2 | 3 | // Copyright (C) 2010-2012 - Stefan Kueng 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or (at your option) any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software Foundation, 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | 20 | #pragma once 21 | 22 | #define FILEVER $MajorVersion$, $MinorVersion$, $MicroVersion$, $WCREV$ 23 | #define PRODUCTVER $MajorVersion$, $MinorVersion$, $MicroVersion$, $WCREV$ 24 | #define STRFILEVER "$MajorVersion$.$MinorVersion$.$MicroVersion$.$WCREV$\0" 25 | #define STRPRODUCTVER "$MajorVersion$.$MinorVersion$.$MicroVersion$.$WCREV$\0" 26 | 27 | #define SM_VERMAJOR $MajorVersion$ 28 | #define SM_VERMINOR $MinorVersion$ 29 | #define SM_VERMICRO $MicroVersion$ 30 | #define SM_VERBUILD $WCREV$ 31 | #define SM_VERDATE "$WCDATE$" 32 | -------------------------------------------------------------------------------- /tools/checkyear.js: -------------------------------------------------------------------------------- 1 | /* This script is a local pre-commit hook script. 2 | * It's used to check whether the copyright year of modified files has been 3 | * bumped up to the current year. 4 | * 5 | * Only *.cpp, *.h and *.idl files are checked 6 | * 7 | * Set the local hook scripts like this (pre-commit hook): 8 | * WScript path/to/this/script/file.js 9 | * and set "Wait for the script to finish" 10 | */ 11 | 12 | var forReading = 1; 13 | var objArgs = WScript.Arguments; 14 | var num = objArgs.length; 15 | 16 | if (num !== 4 && num !== 3) 17 | { 18 | WScript.Echo("Usage: [CScript | WScript] checkyear.js path/to/pathsfile depth path/to/messagefile path/to/CWD"); 19 | WScript.Quit(1); 20 | } 21 | 22 | var currentyear = new Date().getFullYear(); 23 | var re = new RegExp('^(\\\/\\\/|#) Copyright.+(' + currentyear + ')(.*)'); 24 | var basere = /^\/\/ Copyright(.*)/; 25 | var filere = /(\.cpp$)|(\.h$)|(\.idl$)/; 26 | 27 | // readFileLines 28 | function readPaths(path) 29 | { 30 | var retPaths = []; 31 | var fileSystem = new ActiveXObject("Scripting.FileSystemObject"); 32 | 33 | if (fileSystem.FileExists(path)) 34 | { 35 | var textFile = fileSystem.OpenTextFile(path, forReading); 36 | 37 | while (!textFile.AtEndOfStream) 38 | { 39 | var line = textFile.ReadLine(); 40 | 41 | retPaths.push(line); 42 | } 43 | textFile.Close(); 44 | } 45 | return retPaths; 46 | } 47 | 48 | var found = true; 49 | var files = readPaths(objArgs(0)); 50 | var fileIndex = files.length; 51 | var errorMessage = ""; 52 | 53 | while (fileIndex--) 54 | { 55 | var f = files[fileIndex]; 56 | var fso = new ActiveXObject("Scripting.FileSystemObject"); 57 | 58 | if (f.match(filere) !== null) 59 | { 60 | if (fso.FileExists(f)) 61 | { 62 | var a = fso.OpenTextFile(f, forReading, false); 63 | var copyrightFound = false; 64 | var yearFound = false; 65 | 66 | while (!a.AtEndOfStream && !yearFound) 67 | { 68 | var r = a.ReadLine(); 69 | var rv = r.match(basere); 70 | 71 | if (rv !== null) 72 | { 73 | rv = r.match(re); 74 | if (rv !== null) 75 | { 76 | yearFound = true; 77 | } 78 | 79 | copyrightFound = true; 80 | } 81 | } 82 | a.Close(); 83 | 84 | if (copyrightFound && !yearFound) 85 | { 86 | if (errorMessage !== "") 87 | { 88 | errorMessage += "\n"; 89 | } 90 | errorMessage += f; 91 | found = false; 92 | } 93 | } 94 | } 95 | } 96 | 97 | if (found === false) 98 | { 99 | errorMessage = "the file(s):\n" + errorMessage + "\nhave not the correct copyright year!"; 100 | WScript.stderr.writeLine(errorMessage); 101 | } 102 | 103 | WScript.Quit(!found); 104 | -------------------------------------------------------------------------------- /tools/coverity.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | pushd %~dp0 5 | 6 | rem you can set the COVDIR variable to your coverity path 7 | if not defined COVDIR set "COVDIR=C:\cov-analysis" 8 | if defined COVDIR if not exist "%COVDIR%" ( 9 | echo. 10 | echo ERROR: Coverity not found in "%COVDIR%" 11 | goto End 12 | ) 13 | 14 | rem add the tools paths in PATH 15 | set "NANT_PATH=C:\nant\bin" 16 | set "PERL_PATH=C:\Perl\perl\bin" 17 | set "PYTHON_PATH=C:\Python27" 18 | set "PATH=%NANT_PATH%;%PERL_PATH%;%PYTHON_PATH%;%PATH%" 19 | 20 | 21 | :cleanup 22 | if exist "cov-int" rd /q /s "cov-int" 23 | if exist "SendMessage.lzma" del "SendMessage.lzma" 24 | if exist "SendMessage.tar" del "SendMessage.tar" 25 | if exist "SendMessage.tgz" del "SendMessage.tgz" 26 | 27 | 28 | :main 29 | call "%VS140COMNTOOLS%\vsvars32.bat" 30 | if %ERRORLEVEL% neq 0 ( 31 | echo vsvars32.bat call failed. 32 | goto End 33 | ) 34 | 35 | rem the actual coverity command 36 | title "%COVDIR%\bin\cov-build.exe" --dir "cov-int" nant -buildfile:..\default.build SendMessage 37 | "%COVDIR%\bin\cov-build.exe" --dir "cov-int" nant -buildfile:..\default.build SendMessage 38 | 39 | 40 | :tar 41 | rem try the tar tool in case it's in PATH 42 | set PATH=C:\MSYS\bin;%PATH% 43 | tar --version 1>&2 2>nul || (echo. & echo ERROR: tar not found & goto SevenZip) 44 | title Creating "SendMessage.lzma"... 45 | tar caf "SendMessage.lzma" "cov-int" 46 | goto End 47 | 48 | 49 | :SevenZip 50 | call :SubDetectSevenzipPath 51 | 52 | rem Coverity is totally bogus with lzma... 53 | rem And since I cannot replicate the arguments with 7-Zip, just use tar/gzip. 54 | if exist "%SEVENZIP%" ( 55 | title Creating "SendMessage.tar"... 56 | "%SEVENZIP%" a -ttar "SendMessage.tar" "cov-int" 57 | "%SEVENZIP%" a -tgzip "SendMessage.tgz" "SendMessage.tar" 58 | if exist "SendMessage.tar" del "SendMessage.tar" 59 | goto End 60 | ) 61 | 62 | 63 | :SubDetectSevenzipPath 64 | for %%g in (7z.exe) do (set "SEVENZIP_PATH=%%~$path:g") 65 | if exist "%SEVENZIP_PATH%" (set "SEVENZIP=%SEVENZIP_PATH%" & exit /b) 66 | 67 | for %%g in (7za.exe) do (set "SEVENZIP_PATH=%%~$path:g") 68 | if exist "%SEVENZIP_PATH%" (set "SEVENZIP=%SEVENZIP_PATH%" & exit /b) 69 | 70 | for /f "tokens=2*" %%a in ( 71 | 'reg query "HKLM\SOFTWARE\7-Zip" /v "path" 2^>nul ^| find "REG_SZ" ^|^| 72 | reg query "HKLM\SOFTWARE\Wow6432Node\7-Zip" /v "path" 2^>nul ^| find "REG_SZ"') do set "SEVENZIP=%%b\7z.exe" 73 | exit /b 74 | 75 | 76 | :End 77 | popd 78 | echo. & echo Press any key to close this window... 79 | pause >nul 80 | endlocal 81 | exit /b 82 | -------------------------------------------------------------------------------- /version.build.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /versioninfo.build: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | --------------------------------------------------------------------------------