├── .gitattributes ├── .gitignore ├── LICENSE ├── NOTICE ├── README.md ├── bin └── ckrctxt.exe ├── ckrctxt.sln ├── ckrctxt.vcxproj ├── ckrctxt.vcxproj.filters └── src ├── RcTextChecker.cpp ├── RcTextChecker.h ├── RcTextReader.cpp ├── RcTextReader.h ├── TextDlg.cpp ├── TextDlg.h ├── TextEntity.cpp ├── TextEntity.h ├── TextMeasurer.cpp ├── TextMeasurer.h ├── TextReporter.cpp ├── TextReporter.h ├── TextSize.h ├── ckrctxt.rc ├── compatibility.manifest ├── dpi_aware.manifest ├── resource.h ├── stdafx.cpp ├── stdafx.h └── targetver.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # Visual Studio 31 | *.aps 32 | *.bat 33 | *.db 34 | *.opendb 35 | *.opensdf 36 | *.sdf 37 | *.suo 38 | *.user 39 | .vs/** 40 | !bin/* 41 | build.* 42 | Debug 43 | Release 44 | ipch 45 | 46 | # ========================= 47 | # Operating System Files 48 | # ========================= 49 | 50 | # OSX 51 | # ========================= 52 | 53 | .DS_Store 54 | .AppleDouble 55 | .LSOverride 56 | 57 | # Thumbnails 58 | ._* 59 | 60 | # Files that might appear in the root of a volume 61 | .DocumentRevisions-V100 62 | .fseventsd 63 | .Spotlight-V100 64 | .TemporaryItems 65 | .Trashes 66 | .VolumeIcon.icns 67 | 68 | # Directories potentially created on remote AFP share 69 | .AppleDB 70 | .AppleDesktop 71 | Network Trash Folder 72 | Temporary Items 73 | .apdisk 74 | 75 | # Windows 76 | # ========================= 77 | 78 | # Windows image file caches 79 | Thumbs.db 80 | ehthumbs.db 81 | 82 | # Folder config file 83 | Desktop.ini 84 | 85 | # Recycle Bin used on file shares 86 | $RECYCLE.BIN/ 87 | 88 | # Windows Installer files 89 | *.cab 90 | *.msi 91 | *.msm 92 | *.msp 93 | 94 | # Windows shortcuts 95 | *.lnk 96 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2016 Caphyon Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ckrctxt :: RC Text Bounds Checker 2 | ================================= 3 | 4 | `ckrctxt` is a simple tool that can check if any static *text block* (single or multi line) from a Visual Studio [resource file (RC)][RC] doesn't fit on given rectangle **size**. 5 | On application UI the text appears truncated or *clipped*. 6 | 7 | I assume most software developers write Win32 applications to be [High DPI][hidpi] aware. 8 | Otherwise, it would be immediately visible if an application is [not ready for High DPI][issues] because everything appears blury and text is pixelated. 9 | 10 | From all [High DPI issues][issues], this tool is a solution for the most subtle one: [Clipped UI elements or text][clipped]. 11 | 12 | A dialog created with Visual Studio resource editor usually looks fine on standard DPI. 13 | However, after changing the Windows display DPI to other standard configuration (125%, 150%, 200% and up to 500% on Windows 10) you might notice that the full text doesn't fit anymore. 14 | 15 | `ckrctxt` tool was created to automatically detect such problems at build for [Advanced Installer][advinst]. 16 | 17 | [advinst]: http://www.advancedinstaller.com/ 18 | [hidpi]: https://msdn.microsoft.com/en-us/library/dd464646.aspx 19 | [issues]: https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266.aspx#appendix_c_common_high_dpi_issues 20 | [clipped]: https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266.aspx#clipped_ui_elements_or_text 21 | [RC]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa380599.aspx 22 | 23 | 24 | ### Build automation 25 | 26 | An integration into any build system will basically execute: 27 | 28 | ckrctxt --file [path-to-project].rc 29 | 30 | Performance: it can scan a RC file with 40k lines, from which 4.5k text blocks to analyse in just *~300ms*. 31 | 32 | 33 | ### Command line options 34 | 35 | Usage: ckrctxt [options] 36 | 37 | Options: 38 | -q, --quiet no output, just return the counter 39 | --no-header do not show header for current DPI 40 | -f, --file NAME Resource Script file name or path 41 | 42 | 43 | Examples 44 | -------- 45 | 46 | Single line text found at 150% display DPI: 47 | 48 | display dpi: 144|144 (150%) 49 | 50 | Dialog ID: IDD_EDIT_BUILD 51 | ------------------------------- 52 | 15225: LTEXT "Version:" 53 | - detected text size: (59,19)px 54 | - detected rect size: (25,8)du -> (56,19)px 55 | + minimum required rectangle size: (26,8)du 56 | 57 | 15227: LTEXT "Build:" 58 | - detected text size: (41,19)px 59 | - detected rect size: (16,8)du -> (36,19)px 60 | + minimum required rectangle size: (18,8)du 61 | 62 | Dialog ID: IDD_FORM_CREATE_FILE 63 | ------------------------------- 64 | 17156: CONTROL "Create file with encoding:" 65 | - detected text size: (181,19)px 66 | - detected rect size: (90,10)du -> (178,24)px 67 | + minimum required rectangle size: (93,10)du 68 | 69 | Quick indication: the *CONTROL* element on line *17156* from *IDD_FORM_CREATE_FILE* dialog should have *93du* width. 70 | 71 | Multi line text found at 150% display DPI: 72 | 73 | display dpi: 144|144 (150%) 74 | 75 | Dialog ID: IDD_WIZARD_INSTALL 76 | ------------------------------- 77 | 17246: CONTROL "The XYZ will not be installed by default. 78 | The user can choose to install it from ... 79 | or by selecting ..." 80 | - detected text size: (377,52)px 81 | - detected rect size: (267,29)du -> (383,47)px 82 | + minimum required rectangle size: (263,32)du [MULTILINE] 83 | 84 | Quick indication: the *CONTROL* element on line *17246* from *IDD_WIZARD_INSTALL* dialog should be extended to four lines (*32du*). 85 | 86 | Full description: 87 | 88 | - the multi line text from this checkbox fits in a rectangle of (377,52) pixels 89 | - the rectangle of this *CONTROL* element is (267,29) dialog units, converted to pixels this is (383,47) 90 | - the required text height is 52px, but the rectangle height is 47px 91 | - the solution is to modify the rectangle height to 52px, aproximated to 32du 92 | 93 | 94 | Implementation limits 95 | --------------------- 96 | 97 | At this time, the internal parser searches only for these text [elements][ID]: 98 | 99 | - `[LCR]TEXT` 100 | - `[DEF]PUSHBUTTON` 101 | - `CONTROL` (check, 3state, radio) 102 | - `RADIOBUTTON` 103 | 104 | [ID]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa381043.aspx 105 | -------------------------------------------------------------------------------- /bin/ckrctxt.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Caphyon/ckrctxt/cfbc031664eeadc7f2ceebaf15031ad6060d7b68/bin/ckrctxt.exe -------------------------------------------------------------------------------- /ckrctxt.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 14 3 | VisualStudioVersion = 14.0.24720.0 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ckrctxt", "ckrctxt.vcxproj", "{BB0D725B-F417-4C61-8942-5B40F0125F27}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|x86 = Debug|x86 10 | Release|x86 = Release|x86 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {BB0D725B-F417-4C61-8942-5B40F0125F27}.Debug|x86.ActiveCfg = Debug|Win32 14 | {BB0D725B-F417-4C61-8942-5B40F0125F27}.Debug|x86.Build.0 = Debug|Win32 15 | {BB0D725B-F417-4C61-8942-5B40F0125F27}.Release|x86.ActiveCfg = Release|Win32 16 | {BB0D725B-F417-4C61-8942-5B40F0125F27}.Release|x86.Build.0 = Release|Win32 17 | EndGlobalSection 18 | GlobalSection(SolutionProperties) = preSolution 19 | HideSolutionNode = FALSE 20 | EndGlobalSection 21 | EndGlobal 22 | -------------------------------------------------------------------------------- /ckrctxt.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Create 33 | Create 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | {BB0D725B-F417-4C61-8942-5B40F0125F27} 46 | Win32Proj 47 | ckrctxt 48 | 49 | 50 | 51 | Application 52 | true 53 | Unicode 54 | v140 55 | 56 | 57 | Application 58 | false 59 | true 60 | Unicode 61 | v140 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | 81 | Use 82 | Level4 83 | Disabled 84 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 85 | ProgramDatabase 86 | true 87 | true 88 | false 89 | $(ProjectDir);../../third-party 90 | MultiThreadedDebug 91 | 92 | 93 | Console 94 | true 95 | 96 | 97 | 98 | 99 | src/compatibility.manifest;src/dpi_aware.manifest 100 | 101 | 102 | 103 | 104 | Level4 105 | Use 106 | MaxSpeed 107 | true 108 | true 109 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 110 | ProgramDatabase 111 | true 112 | true 113 | false 114 | $(ProjectDir);../../third-party 115 | AnySuitable 116 | Speed 117 | true 118 | MultiThreaded 119 | 120 | 121 | Console 122 | true 123 | true 124 | true 125 | 126 | 127 | 128 | 129 | src/compatibility.manifest;src/dpi_aware.manifest 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /ckrctxt.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {824f8c77-0d5e-4d27-b524-87c59b38ee8d} 18 | 19 | 20 | 21 | 22 | Header Files 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 | Resource Files 44 | 45 | 46 | win 47 | 48 | 49 | win 50 | 51 | 52 | 53 | 54 | Resource Files 55 | 56 | 57 | 58 | 59 | win 60 | 61 | 62 | Source Files 63 | 64 | 65 | Source Files 66 | 67 | 68 | Source Files 69 | 70 | 71 | Source Files 72 | 73 | 74 | Source Files 75 | 76 | 77 | Source Files 78 | 79 | 80 | 81 | 82 | win 83 | 84 | 85 | win 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/RcTextChecker.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "stdafx.h" 16 | #include "RcTextChecker.h" 17 | #include "RcTextReader.h" 18 | #include "TextDlg.h" 19 | #include "TextEntity.h" 20 | #include "TextSize.h" 21 | #include "TextMeasurer.h" 22 | #include "TextReporter.h" 23 | 24 | using namespace std; 25 | 26 | int RcTextChecker::Run(const wstring & aFilename, bool quiet) const 27 | { 28 | // open resource script file 29 | RcTextReader rsfile(aFilename); 30 | if ( !rsfile.IsOpen() ) 31 | { 32 | wcout << L"Err: resource script file '" << aFilename 33 | << L"' was not found or could not be opened!" << endl << endl; 34 | return -1; 35 | } 36 | 37 | TextEntity textEnt; // one text block from resource script file 38 | TextMeasurer textMsr; 39 | TextReporter textRep( wcout, rsfile.GetCodepage() ); 40 | 41 | int count = 0; 42 | while (true) 43 | { 44 | rsfile >> textEnt; 45 | if ( !rsfile.HasFoundText() ) 46 | break; 47 | 48 | // compute text block size (px) 49 | textMsr.ComputeSize(textEnt); 50 | 51 | // text doesn't fit in rectangle area 52 | if ( textMsr.IsResizeNeeded() ) 53 | { 54 | if (!quiet) 55 | textRep << textMsr.GetRealSize(); 56 | ++count; 57 | } 58 | } 59 | 60 | return count; 61 | } 62 | 63 | //---------------------------------------------------------------------------- 64 | // Global helper functions. 65 | 66 | void usage(char * aMsg = nullptr); 67 | void printDPI(); 68 | 69 | int _tmain(int argc, _TCHAR ** argv) 70 | { 71 | if (argc < 3) 72 | { 73 | usage( "Err: expected at least two arguments!" ); 74 | return -1; 75 | } 76 | 77 | bool quiet = false; 78 | bool showdpi = true; 79 | wstring rsname; // resource script file name 80 | for (int i = 1; i < argc; ++i) // read command arguments 81 | { 82 | wstring argvi( argv[i] ); 83 | if ( (argvi == L"-f") || (argvi == L"--file") ) 84 | { 85 | if (++i < argc) 86 | rsname = wstring( argv[i] ); 87 | } 88 | else if ( (argvi == L"-q") || (argvi == L"--quiet") ) 89 | quiet = true; 90 | else if (argvi == L"--no-header") 91 | showdpi = false; 92 | else 93 | wcout << L"Err: unknown argument: " << argv[i] << endl; 94 | } 95 | 96 | // check if we've got a name 97 | if ( rsname.empty() ) 98 | { 99 | cout << endl; 100 | usage(); 101 | return -1; 102 | } 103 | 104 | // DPI header 105 | if (!quiet && showdpi) 106 | printDPI(); 107 | 108 | DWORD start = ::GetTickCount(); 109 | RcTextChecker batch; 110 | int count = batch.Run(rsname, quiet); 111 | DWORD finish = ::GetTickCount(); 112 | 113 | // display summary 114 | if (!quiet && (count > 0)) 115 | cout << "No. of detected problems: " << count 116 | << " (in " << (finish - start) << "ms)" << endl << endl; 117 | 118 | return count; 119 | } 120 | 121 | // show all supported arguments 122 | void usage(char * aMsg) 123 | { 124 | if (nullptr != aMsg) 125 | cout << aMsg << endl 126 | << endl; 127 | 128 | cout << "Usage: ckrctxt [options]" << endl 129 | << endl 130 | << "Options:" << endl 131 | << "-q, --quiet no output, just return the counter" << endl 132 | << "--no-header do not show header for current DPI" << endl 133 | << "-f, --file NAME Resource Script file name or path" << endl 134 | << endl; 135 | } 136 | 137 | // show current DPI settings 138 | void printDPI() 139 | { 140 | int dpiY = ::GetDeviceCaps(::GetDC(NULL), LOGPIXELSY); 141 | int dpiX = ::GetDeviceCaps(::GetDC(NULL), LOGPIXELSX); 142 | cout << "display dpi: " << dpiX << "|" << dpiY 143 | << " (" << ::MulDiv(dpiY, 100, 96) << "%)" 144 | << endl << endl; 145 | } 146 | -------------------------------------------------------------------------------- /src/RcTextChecker.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | /** 18 | * Check and report the required size for all nonconforming 19 | * text blocks read from a Visual Studio resource script file. 20 | * 21 | * @author Teodor MICU 22 | */ 23 | class RcTextChecker 24 | { 25 | public: 26 | /** 27 | * Run batch... 28 | * 29 | * @return detected number of text blocks that don't fit on rectangle area 30 | */ 31 | int Run(const std::wstring & aFilename, bool quiet = false) const; 32 | }; 33 | -------------------------------------------------------------------------------- /src/RcTextReader.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "stdafx.h" 16 | #include "RcTextReader.h" 17 | #include "TextEntity.h" 18 | 19 | using namespace std; 20 | 21 | namespace 22 | { 23 | // NAME DIALOGEX 0, 0, 340, 180 24 | const wregex kDlgExp(L"^([^ ]+) DIALOGEX [0-9]+, [0-9]+, [0-9]+, [0-9]+$"); 25 | 26 | // LTEXT "Text",ID_TEXT,53,25,156,24[,FLAGS] 27 | const wregex kTxtExp(L"^ +([LCR]TEXT) +\"(.+)\",([^,]+)," 28 | L"(\\d+),(\\d+),(\\d+),(\\d+)(?:,(.*))?$"); 29 | 30 | // CONTROL "Run as..",ID_RUN,"Button",FLAGS,30,190,81,10 31 | const wregex kCtlExp(L"^ +(CONTROL) +\"(.+)\",([^,]+),\"([A-Za-z]+)\",([^,]*)," 32 | L"(\\d+),(\\d+),(\\d+),(\\d+)$"); 33 | 34 | // RADIOBUTTON "Use..",IDC_USE,30,48,142,10[,FLAGS] 35 | const wregex kRbtExp(L"^ +(RADIOBUTTON) +\"(.+)\",([^,]+)," 36 | L"(\\d+),(\\d+),(\\d+),(\\d+).*$"); 37 | 38 | // [DEF]PUSHBUTTON "OK",ID_OK,103,47,50,16[,FLAGS] 39 | const wregex kBtnExp(L"^ +((?:DEF)?PUSHBUTTON) +\"(.+)\",([^,]+)," 40 | L"(\\d+),(\\d+),(\\d+),(\\d+)(?:,(.*))?$"); 41 | } 42 | 43 | //---------------------------------------------------------------------------- 44 | // Class definition - RcTextReader public methods. 45 | 46 | RcTextReader::RcTextReader(const wstring & aFilename) 47 | : mIStream(aFilename), mCodepage(CODEPAGE_ENGLISH), mFound(false), mLineNr(0) 48 | { 49 | // detect ANSI code page 50 | string cp = DotCodepage(aFilename); 51 | if (CODEPAGE_ENGLISH != mCodepage) // custom ANSI encoding 52 | mIStream.imbue( std::locale(cp) ); 53 | } 54 | 55 | bool RcTextReader::IsOpen() const 56 | { 57 | return mIStream.is_open(); 58 | } 59 | 60 | UINT RcTextReader::GetCodepage() const 61 | { 62 | return mCodepage; 63 | } 64 | 65 | bool RcTextReader::HasFoundText() const 66 | { 67 | return mFound; 68 | } 69 | 70 | RcTextReader & RcTextReader::operator>>(TextEntity & aTextEnt) 71 | { 72 | wstring line; // first line read 73 | wstring line23; // (optional) extra lines read 74 | TextEntity::TypeCode code = TextEntity::OTHER; 75 | 76 | wsmatch mr; // match results 77 | 78 | mFound = false; 79 | while ( mIStream.good() ) 80 | { 81 | // get first line, might be a sequence of two or three 82 | getline(mIStream, line); 83 | ++mLineNr; 84 | 85 | // empty line, or one CR (#13) 86 | if (line.size() <= 1) 87 | continue; 88 | 89 | // update current dialog name 90 | if (L' ' != line[0]) // not a SPACE 91 | { 92 | if ( regex_match(line, mr, kDlgExp) ) 93 | mDlgName = mr[1]; 94 | 95 | // all TEXT lines start with four spaces 96 | continue; 97 | } 98 | 99 | // get next lines, one CONTROL line might be split in multiple lines 100 | while ( (L',' == line[line.size()-1]) || 101 | (L'|' == line[line.size()-1]) ) 102 | { 103 | getline(mIStream, line23); 104 | ++mLineNr; 105 | 106 | wstring::size_type first = line23.find_first_not_of(L" \t"); 107 | wstring::size_type last = line23.find_last_not_of(L" \t\r"); 108 | line.append( line23.substr(first, last-first+1) ); 109 | } 110 | 111 | // detect type 112 | if ( regex_match(line, mr, kTxtExp) ) 113 | code = TextEntity::TEXT; 114 | else if ( regex_match(line, mr, kBtnExp) ) 115 | code = TextEntity::PUSHBUTTON; 116 | else if ( regex_match(line, mr, kCtlExp) ) 117 | code = TextEntity::CONTROLBUTTON; 118 | else if ( regex_match(line, mr, kRbtExp) ) 119 | code = TextEntity::RADIOBUTTON; 120 | else 121 | continue; 122 | 123 | // ignore these small buttons (resized and repositioned in code) 124 | if ( (TextEntity::PUSHBUTTON == code) && (L"..." == mr[2]) ) 125 | continue; 126 | 127 | // ignore (on purpose) truncated static text 128 | if ( (TextEntity::TEXT == code) && (mr[8].matched) ) 129 | { 130 | if ( wstring::npos != mr[8].str().find(L"ELLIPSIS") ) 131 | continue; 132 | } 133 | 134 | mFound = true; 135 | break; 136 | } // end while 137 | 138 | // stop processing if no text block was found 139 | if (!mFound) 140 | return *this; 141 | 142 | aTextEnt.mText = mr[2]; 143 | aTextEnt.mType = mr[1]; 144 | 145 | // TODO: SS_NOPREFIX flag -> no escape 146 | // "" is an escape sequence 147 | aTextEnt.ReplaceAll(L"\"\"", L"\""); 148 | 149 | // && is an escape sequence 150 | aTextEnt.ReplaceAll(L"&&", L"&"); 151 | 152 | // remove & from text string if followed by an alpha 153 | wstring::size_type amppos = aTextEnt.mText.find(L"&"); 154 | if ( (amppos < aTextEnt.mText.size()) && 155 | isalpha(aTextEnt.mText[amppos+1]) ) 156 | aTextEnt.mText.erase(amppos, 1); 157 | 158 | aTextEnt.mMultiLine = true; // TEXT does word wrap by default 159 | switch (code) 160 | { 161 | case TextEntity::CONTROLBUTTON: 162 | // must have at least 9 values (+1) 163 | assert(mr.size() >= 10); 164 | 165 | // multiline control button 166 | if ( (L"Button" == mr[4]) && 167 | (wstring::npos == mr[5].str().find(L"BS_MULTILINE")) ) 168 | { 169 | aTextEnt.mMultiLine = false; 170 | } 171 | // multiline static text 172 | else if ( (L"Static"== mr[4]) && 173 | (wstring::npos != mr[5].str().find(L"SS_LEFTNOWORDWRAP")) ) 174 | { 175 | code = TextEntity::TEXT; 176 | aTextEnt.mMultiLine = false; 177 | } 178 | 179 | aTextEnt.mRc.left = stoi( mr[6] ); // X 180 | aTextEnt.mRc.top = stoi( mr[7] ); // Y 181 | aTextEnt.mRc.right = stoi( mr[8] ); // Width 182 | aTextEnt.mRc.bottom = stoi( mr[9] ); // Height 183 | break; 184 | 185 | case TextEntity::RADIOBUTTON: 186 | case TextEntity::PUSHBUTTON: 187 | // multiline push button 188 | if ( (mr.size() < 9) || 189 | (wstring::npos == mr[8].str().find(L"BS_MULTILINE")) ) 190 | aTextEnt.mMultiLine = false; 191 | // NO break; 192 | 193 | case TextEntity::TEXT: 194 | // must have at least 7 values (+1) 195 | assert(mr.size() >= 8); 196 | 197 | aTextEnt.mRc.left = stoi( mr[4] ); // X 198 | aTextEnt.mRc.top = stoi( mr[5] ); // Y 199 | aTextEnt.mRc.right = stoi( mr[6] ); // Width 200 | aTextEnt.mRc.bottom = stoi( mr[7] ); // Height 201 | break; 202 | 203 | default: 204 | assert(!"unsupported type code!"); 205 | } // end switch 206 | 207 | aTextEnt.mDlgName = mDlgName; 208 | aTextEnt.mLineNr = mLineNr; 209 | aTextEnt.mCode = code; 210 | return *this; 211 | } 212 | 213 | //---------------------------------------------------------------------------- 214 | // Class definition - RcTextReader private methods. 215 | 216 | string RcTextReader::DotCodepage(const wstring & aFilename) 217 | { 218 | ifstream file(aFilename); 219 | if ( !file.is_open() ) 220 | return string(".1252"); 221 | 222 | string line; 223 | smatch mr; // match results 224 | regex exp("^#pragma code_page\\((\\d+)\\)$"); 225 | 226 | while ( !file.eof() ) 227 | { 228 | getline(file, line); 229 | 230 | // empty line 231 | if (line.size() <= 1) 232 | continue; 233 | 234 | // skip anything but macros 235 | if ('#' != line[0]) 236 | continue; 237 | 238 | if ( regex_match(line, mr, exp) ) 239 | break; 240 | } 241 | file.close(); 242 | 243 | // no #pragma code_page() 244 | if ( mr.empty() ) 245 | return string(".1252"); 246 | 247 | mCodepage = stoi( mr[1] ); 248 | return "." + mr[1].str(); 249 | } 250 | -------------------------------------------------------------------------------- /src/RcTextReader.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | struct TextEntity; 18 | 19 | /** 20 | * Reader for a resource script file. Ignores all non-text blocks. 21 | * 22 | * @author Teodor MICU 23 | */ 24 | class RcTextReader 25 | { 26 | public: 27 | /** 28 | * Class constructor. 29 | */ 30 | RcTextReader(const std::wstring & /*aFilename*/); 31 | 32 | /** 33 | * @return true if the file was found and is open for reading 34 | */ 35 | bool IsOpen() const; 36 | 37 | /** 38 | * @return the ANSI codepage found in the resource script file 39 | */ 40 | UINT GetCodepage() const; 41 | 42 | /** 43 | * Method that checks if a text block was (previously) read from file. 44 | * 45 | * @return true if last extraction was successful, false otherwise 46 | */ 47 | bool HasFoundText() const; 48 | 49 | /** 50 | * Read the next text block with all associated parameters. 51 | */ 52 | RcTextReader & operator>>(TextEntity & /*aTextEnt*/); 53 | 54 | private: 55 | /** 56 | * Get the string from pragma code_page() directive, dot prefixed. 57 | * (".1252" for ENGLISH_US, the default ANSI encoding) 58 | */ 59 | std::string DotCodepage(const std::wstring & /*aFilename*/); 60 | 61 | std::wifstream mIStream; // (file) input stream 62 | UINT mCodepage; 63 | 64 | // attributes read from the resource script file 65 | std::wstring mDlgName; // current dialog name 66 | int mLineNr; // current line# read from file 67 | bool mFound; // new text block read from file 68 | }; 69 | -------------------------------------------------------------------------------- /src/TextDlg.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "stdafx.h" 16 | #include "TextDlg.h" 17 | 18 | LRESULT TextDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 19 | { 20 | mDC = GetDC(); 21 | mDC.SelectFont( GetFont() ); 22 | 23 | // base units for non-system font (custom) 24 | // http://support.microsoft.com/kb/145994 25 | RECT dlgbu = { 0, 0, 4, 8 }; 26 | MapDialogRect(&dlgbu); 27 | mDlgBU.cx = dlgbu.right; 28 | mDlgBU.cy = dlgbu.bottom; 29 | 30 | // detect text height 31 | TEXTMETRIC tm; 32 | mDC.GetTextMetrics( &tm ); 33 | 34 | CSize szText; 35 | szText.cx = tm.tmAveCharWidth; 36 | szText.cy = tm.tmHeight; 37 | mDC.LPtoDP(&szText); 38 | mTxtHeight = szText.cy; 39 | 40 | return TRUE; 41 | } 42 | 43 | CSize TextDlg::GetDlgBaseUnits() const 44 | { 45 | return mDlgBU; 46 | } 47 | 48 | CSize TextDlg::GetTextSize(const std::wstring & aText) const 49 | { 50 | CSize szText; 51 | mDC.GetTextExtent(aText.c_str(), -1, &szText); 52 | mDC.LPtoDP(&szText); 53 | 54 | return szText; 55 | } 56 | 57 | LONG TextDlg::GetTextHeight() const 58 | { 59 | return mTxtHeight; 60 | } 61 | 62 | CSize TextDlg::DUtoPX(LONG aWidthDU, LONG aHeightDU) const 63 | { 64 | RECT rc = { 0, 0, aWidthDU, aHeightDU }; 65 | ::MapDialogRect(*this, &rc); 66 | 67 | return CSize(rc.right, rc.bottom); 68 | } 69 | 70 | CSize TextDlg::PXtoDU(LONG aWidthDU, LONG aHeightDU) const 71 | { 72 | LONG widthDU = ::MulDiv(aWidthDU, 4, mDlgBU.cx); 73 | LONG heightDU = ::MulDiv(aHeightDU, 8, mDlgBU.cy); 74 | 75 | return CSize(widthDU, heightDU); 76 | } 77 | -------------------------------------------------------------------------------- /src/TextDlg.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "resource.h" 18 | 19 | /** 20 | * Simple dialog used for computing the required size for some text. 21 | * 22 | * @author Teodor MICU 23 | */ 24 | class TextDlg : public CDialogImpl 25 | { 26 | public: 27 | enum { IDD = IDD_MEASURE_DIALOG }; 28 | 29 | BEGIN_MSG_MAP(TextDlg) 30 | MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) 31 | END_MSG_MAP() 32 | 33 | /** 34 | * Calculate dialog base units based on the current font. 35 | */ 36 | CSize GetDlgBaseUnits() const; 37 | 38 | /** 39 | * Calculate the size of text based on the current font. 40 | */ 41 | CSize GetTextSize(const std::wstring & /*aText*/) const; 42 | 43 | /** 44 | * Calculate the height of (one line) text based on the current font. 45 | */ 46 | LONG GetTextHeight() const; 47 | 48 | /** 49 | * Convert du->px based on the current font. 50 | */ 51 | CSize DUtoPX(LONG /*aWidthDU*/, LONG /*aHeightDU*/) const; 52 | 53 | /** 54 | * Convert px->du based on the current font. 55 | */ 56 | CSize PXtoDU(LONG /*aWidthDU*/, LONG /*aHeightDU*/) const; 57 | 58 | private: 59 | LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 60 | 61 | CDCHandle mDC; // handle for device context 62 | CSize mDlgBU; // dialog base units 63 | LONG mTxtHeight; 64 | }; 65 | -------------------------------------------------------------------------------- /src/TextEntity.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "stdafx.h" 16 | #include "TextEntity.h" 17 | #include "TextSize.h" 18 | 19 | using std::wstring; 20 | 21 | TextEntity::operator TextSize() const 22 | { 23 | TextSize szText; 24 | szText.mDlgName = this->mDlgName; 25 | szText.mLineNr = this->mLineNr; 26 | szText.mText = this->mText; 27 | szText.mType = this->mType; 28 | szText.mMultiLine = this->mMultiLine; 29 | szText.mRcWidthDU = this->mRc.right; 30 | szText.mRcHeightDU = this->mRc.bottom; 31 | 32 | return szText; 33 | } 34 | 35 | void TextEntity::ReplaceAll(const wstring & aToken, const wstring & aReplace) 36 | { 37 | if (mText.empty() || aToken.empty()) 38 | return; 39 | 40 | size_t pos = mText.find(aToken); 41 | while (pos != wstring::npos) 42 | { 43 | mText.replace(pos, aToken.length(), aReplace); 44 | pos = mText.find(aToken, pos + aReplace.length()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/TextEntity.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | struct TextSize; 18 | 19 | /** 20 | * A text block with all associated parameters. 21 | * (usually read from a Visual Studio resource script file) 22 | * - [LCR]TEXT 23 | * - [DEF]PUSHBUTTON 24 | * - CONTROL(check, 3state, radio) 25 | * - RADIOBUTTON 26 | * 27 | * @author Teodor MICU 28 | */ 29 | struct TextEntity 30 | { 31 | operator TextSize() const; 32 | void ReplaceAll(const std::wstring & aToken, const std::wstring & aReplace); 33 | 34 | enum TypeCode 35 | { 36 | TEXT = 0, // LTEXT, CTEXT, RTEXT 37 | PUSHBUTTON, // PUSHBUTTON, DEFPUSHBUTTON 38 | CONTROLBUTTON, // CONTROL: checkbox, 3state, radiobutton 39 | RADIOBUTTON, // RADIOBUTTON 40 | OTHER 41 | }; 42 | 43 | std::wstring mDlgName; // dialog on which this text block was found 44 | int mLineNr; // line# were this text block was found 45 | std::wstring mText; // text string literal 46 | std::wstring mType; // type string literal 47 | TypeCode mCode; // associated code for mType 48 | bool mMultiLine; // found or implicit multiline flag 49 | RECT mRc; // rectangle coordinates and size (du) 50 | }; 51 | -------------------------------------------------------------------------------- /src/TextMeasurer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "stdafx.h" 16 | #include "TextMeasurer.h" 17 | #include "TextEntity.h" 18 | #include "TextSize.h" 19 | 20 | using std::wstring; 21 | 22 | TextMeasurer::TextMeasurer() 23 | : mTextEnt(nullptr), mRcWidth(0), mRcHeight(0), mTxtWidth(0), mTxtHeight(0) 24 | { 25 | mDlg.Create(NULL); 26 | } 27 | 28 | TextMeasurer::~TextMeasurer() 29 | { 30 | mDlg.DestroyWindow(); 31 | } 32 | 33 | void TextMeasurer::ComputeSize(TextEntity & aTextEnt) 34 | { 35 | mTextEnt = &aTextEnt; 36 | 37 | // we assume text block was already read from file prior to this call 38 | assert(mTextEnt->mText.size() > 0); 39 | 40 | LONG & rcWidthDU = mTextEnt->mRc.right; 41 | LONG & rcHeightDU = mTextEnt->mRc.bottom; 42 | CSize sz; 43 | 44 | // adjust visible text area in rectangle (du) 45 | switch (mTextEnt->mCode) 46 | { 47 | case TextEntity::RADIOBUTTON: 48 | case TextEntity::CONTROLBUTTON: 49 | // compute rectangle width (px) 50 | sz = mDlg.DUtoPX(rcWidthDU, rcHeightDU); 51 | mRcWidth = sz.cx - ::GetSystemMetrics(SM_CXMENUCHECK); 52 | mRcHeight = sz.cy; 53 | break; 54 | 55 | case TextEntity::PUSHBUTTON: 56 | // compute rectangle width (px) 57 | sz = mDlg.DUtoPX(rcWidthDU - PUSHBUTTON_X, rcHeightDU); 58 | mRcWidth = sz.cx; 59 | mRcHeight = sz.cy; 60 | break; 61 | 62 | default: // TEXT 63 | // compute rectangle width (px) 64 | sz = mDlg.DUtoPX(rcWidthDU, rcHeightDU); 65 | mRcWidth = sz.cx; 66 | mRcHeight = sz.cy; 67 | } // end switch 68 | 69 | sz = mDlg.GetTextSize(mTextEnt->mText); 70 | mTxtWidth = sz.cx; 71 | mTxtHeight = sz.cy; 72 | 73 | if (!mTextEnt->mMultiLine) 74 | return; 75 | 76 | // simple case: no escape sequence for new line 77 | if ( wstring::npos == mTextEnt->mText.find(L"\\n") ) 78 | // rectangle height has space for just one line of text 79 | if ( (mTxtWidth <= mRcWidth) || (mRcHeight <= mTxtHeight) ) 80 | return; 81 | 82 | // detect text height for empty lines found in some escape seq "\n\n" 83 | LONG baseUnitY = mDlg.GetTextHeight(); 84 | 85 | mTxtWidth = mTxtHeight = 0; 86 | wstring wline; // substring wrapped on one line 87 | wstring::size_type offset = 0; 88 | wstring::size_type lastpos; // last known good position 89 | wstring::size_type nextpos = 0; // next position to try out 90 | wstring::size_type nextnl; // next new line sequence \n 91 | bool foundnl = false; 92 | 93 | // wrap text in multiple lines less or equal to mRcWidth 94 | do 95 | { 96 | lastpos = nextpos; // last word is included in current line 97 | nextpos = mTextEnt->mText.find(L" ", lastpos); 98 | if (wstring::npos == nextpos) // remaining text has no spaces 99 | nextpos = mTextEnt->mText.size(); 100 | else 101 | ++nextpos; // +1 to include the current white space 102 | 103 | // \n escape sequence forces END of line 104 | nextnl = mTextEnt->mText.find(L"\\n", lastpos); 105 | if (nextnl < nextpos) 106 | { 107 | foundnl = true; 108 | nextpos = nextnl; 109 | } 110 | 111 | // compute width of current line 112 | wline = mTextEnt->mText.substr(offset, nextpos-offset); 113 | sz = mDlg.GetTextSize(wline); 114 | 115 | if (sz.cx <= mRcWidth) // current substring is not full 116 | { 117 | if (!foundnl) 118 | continue; 119 | } 120 | // one word is NOT too big to fit on one line? 121 | else if (offset < lastpos) 122 | { 123 | if ( !foundnl && 124 | (mTextEnt->mText.size() != nextpos) ) // not end of text 125 | { 126 | assert( iswspace(wline[wline.size()-1]) ); 127 | 128 | // remove trailing white space from current line 129 | wline.pop_back(); 130 | sz = mDlg.GetTextSize(wline); 131 | } 132 | 133 | if (sz.cx > mRcWidth) // doesn't fit w/ last space 134 | { 135 | // current substring is too big, get back to last position 136 | nextpos = lastpos; 137 | foundnl = false; 138 | 139 | // recompute width of current line 140 | wline = mTextEnt->mText.substr(offset, nextpos-offset); 141 | sz = mDlg.GetTextSize(wline); 142 | } 143 | } 144 | 145 | if (mTxtWidth < sz.cx) // adjust maximum (line of) text width 146 | mTxtWidth = sz.cx; 147 | 148 | if (offset == nextpos) // adjust text height (px) 149 | mTxtHeight += baseUnitY; // empty line -> no text to measure 150 | else 151 | mTxtHeight += sz.cy; // non-empty text 152 | 153 | if (foundnl) 154 | { 155 | foundnl = false; 156 | nextpos += 2; // advance over "\n" 157 | } 158 | 159 | // start of a new line 160 | offset = nextpos; 161 | } while (nextpos < mTextEnt->mText.size()); 162 | 163 | if (mTextEnt->mText.size() == offset) // last word was processed 164 | return; 165 | 166 | // last word was NOT processed 167 | wline = mTextEnt->mText.substr(offset); 168 | sz = mDlg.GetTextSize(wline); 169 | 170 | if (mTxtWidth < sz.cx) // adjust maximum (line of) text width 171 | mTxtWidth = sz.cx; 172 | mTxtHeight += sz.cy; // adjust text height (px) 173 | assert(mTxtWidth <= mRcWidth); 174 | } 175 | 176 | bool TextMeasurer::IsResizeNeeded() const 177 | { 178 | return (mTxtWidth > mRcWidth) || (mTxtHeight > mRcHeight); 179 | } 180 | 181 | TextSize TextMeasurer::GetRealSize() const 182 | { 183 | assert(nullptr != mTextEnt); 184 | 185 | TextSize szText = *mTextEnt; 186 | szText.mRcWidthPX = mRcWidth; 187 | szText.mRcHeightPX = mRcHeight; 188 | szText.mTxtWidthPX = mTxtWidth; 189 | szText.mTxtHeightPX = mTxtHeight; 190 | 191 | // convert pixels to dialog units 192 | CSize sz = mDlg.PXtoDU(mTxtWidth, mTxtHeight); 193 | szText.mTxtWidthDU = sz.cx; 194 | szText.mTxtHeightDU = sz.cy; 195 | 196 | // adjust text width on round-off error 197 | sz = mDlg.DUtoPX(szText.mTxtWidthDU, szText.mTxtHeightDU); 198 | if (szText.mTxtWidthPX > sz.cx) // usually only 1px loss 199 | ++szText.mTxtWidthDU; 200 | #if _DEBUG 201 | sz = mDlg.DUtoPX(szText.mTxtWidthDU, szText.mTxtHeightDU); 202 | assert(szText.mTxtWidthPX <= sz.cx); 203 | #endif 204 | 205 | // adjust computed text area to rectangle area 206 | switch (mTextEnt->mCode) 207 | { 208 | case TextEntity::RADIOBUTTON: 209 | case TextEntity::CONTROLBUTTON: 210 | szText.mTxtWidthDU += CONTROLBUTTON_X; 211 | 212 | // recommended size, but not required 213 | if (szText.mTxtHeightDU + CONTROLBUTTON_Y <= szText.mRcHeightDU) 214 | szText.mTxtHeightDU += CONTROLBUTTON_Y; 215 | break; 216 | 217 | case TextEntity::PUSHBUTTON: 218 | szText.mTxtWidthDU += PUSHBUTTON_X; 219 | 220 | // recommended size, but not required 221 | if (szText.mTxtHeightDU + PUSHBUTTON_Y <= szText.mRcHeightDU) 222 | szText.mTxtHeightDU += PUSHBUTTON_Y; 223 | break; 224 | } // end switch 225 | 226 | return szText; 227 | } 228 | -------------------------------------------------------------------------------- /src/TextMeasurer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "TextDlg.h" 18 | 19 | // Layout Specifications: Win32 20 | // http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818.aspx 21 | #define CONTROLBUTTON_X 12 22 | #define CONTROLBUTTON_Y (10 - 8) 23 | #define PUSHBUTTON_X (12 - 8) 24 | #define PUSHBUTTON_Y (14 - 8) 25 | 26 | struct TextEntity; 27 | struct TextSize; 28 | 29 | /** 30 | * Measures the (minimum) required size of a TextEntity. 31 | * 32 | * @author Teodor MICU 33 | */ 34 | class TextMeasurer 35 | { 36 | public: 37 | /** 38 | * Class constructor. 39 | */ 40 | TextMeasurer(); 41 | 42 | /** 43 | * Class destructor. 44 | */ 45 | ~TextMeasurer(); 46 | 47 | /** 48 | * Detect the required rectangle width (X) and height (Y) so 49 | * that the given text string would fit after word wrap. 50 | * 51 | * If rectangle height (px) is equal to text height (px), the text is 52 | * measured for one line fit. 53 | * If the rectangle height is greater than the text height, the text 54 | * will be wrapped in lines less or equal to the rectangle width (px). 55 | */ 56 | void ComputeSize(TextEntity & /*aTextEnt*/); 57 | 58 | /** 59 | * Check if rectangle area is big enough to fit the text. 60 | * 61 | * @return true is text doesn't fit in rectangle area, false otherwise 62 | */ 63 | bool IsResizeNeeded() const; 64 | 65 | /** 66 | * @return current and computed size of a text in du&px 67 | */ 68 | TextSize GetRealSize() const; 69 | 70 | private: 71 | TextDlg mDlg; // dialog were the size is computed 72 | TextEntity * mTextEnt; // text block to measure 73 | LONG mRcWidth; // computed rectangle width (px) 74 | LONG mRcHeight; // computed rectangle height (px) 75 | LONG mTxtWidth; // computed text width (px) 76 | LONG mTxtHeight; // computed text height (px) 77 | }; 78 | -------------------------------------------------------------------------------- /src/TextReporter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "stdafx.h" 16 | #include "TextReporter.h" 17 | #include "TextSize.h" 18 | 19 | using std::endl; 20 | 21 | TextReporter::TextReporter(std::wostream & aOStream, UINT aCodepage) 22 | : mOStream(aOStream) 23 | { 24 | if (CODEPAGE_ENGLISH != aCodepage) // custom ANSI encoding 25 | { 26 | char cpstr[20]; 27 | cpstr[0] = '.'; // ".1252" 28 | sprintf_s(cpstr+1, 20-2, "%d", aCodepage); 29 | 30 | aOStream.imbue( std::locale(cpstr) ); 31 | ::SetConsoleOutputCP(aCodepage); 32 | } 33 | } 34 | 35 | TextReporter & TextReporter::operator<<(const TextSize & aSzText) 36 | { 37 | // we assume TextSize structure was already initialized 38 | assert(aSzText.mText.size() > 0); 39 | 40 | // write new header on dialog change 41 | if (mOldDlgName != aSzText.mDlgName) 42 | { 43 | mOStream << L"Dialog ID: " << aSzText.mDlgName << endl 44 | << L"-------------------------------" << endl; 45 | mOldDlgName = aSzText.mDlgName; 46 | } 47 | 48 | // write text and required size 49 | mOStream 50 | << aSzText.mLineNr << L": " << aSzText.mType 51 | << L" \"" << aSzText.mText << L'"' << endl 52 | << L"- detected text size: (" << aSzText.mTxtWidthPX << L"," 53 | << aSzText.mTxtHeightPX << L")px" << endl 54 | << L"- detected rect size: (" << aSzText.mRcWidthDU << L"," 55 | << aSzText.mRcHeightDU << L")du -> (" 56 | << aSzText.mRcWidthPX << L"," 57 | << aSzText.mRcHeightPX << L")px" << endl 58 | << L"+ minimum required rectangle size: (" 59 | << aSzText.mTxtWidthDU << L"," 60 | << aSzText.mTxtHeightDU << L")du"; 61 | 62 | if ( aSzText.mMultiLine && (aSzText.mTxtHeightDU > 8) ) 63 | mOStream << L" [MULTILINE]"; 64 | 65 | mOStream << endl << endl; 66 | return *this; 67 | } 68 | -------------------------------------------------------------------------------- /src/TextReporter.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | struct TextSize; 18 | 19 | /** 20 | * Print the current and required size of a text block. 21 | * 22 | * @author Teodor MICU 23 | */ 24 | class TextReporter 25 | { 26 | public: 27 | /** 28 | * Class constructor. 29 | */ 30 | TextReporter(std::wostream & /*aOStream*/, UINT aCodepage = CODEPAGE_ENGLISH); 31 | 32 | /** 33 | * Print the text block measurements. 34 | */ 35 | TextReporter & operator<<(const TextSize & /*aSzText*/); 36 | 37 | private: 38 | std::wostream & mOStream; // output stream 39 | std::wstring mOldDlgName; // parent of this text block 40 | }; 41 | -------------------------------------------------------------------------------- /src/TextSize.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Caphyon Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http ://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | /** 18 | * Current and computed size of a TextEntity. 19 | * 20 | * @author Teodor MICU 21 | */ 22 | struct TextSize 23 | { 24 | std::wstring mDlgName; // dialog on which this text block was found 25 | int mLineNr; // line# were this text block was found 26 | std::wstring mText; // text string literal 27 | std::wstring mType; // type string literal 28 | bool mMultiLine; // found or implicit multiline flag 29 | 30 | LONG mRcWidthDU; // rectangle width (du) -- read from resource 31 | LONG mRcWidthPX; // computed rectangle width (px) 32 | LONG mRcHeightDU; // rectangle height (du) -- read from resource 33 | LONG mRcHeightPX; // computed rectangle height (px) 34 | 35 | LONG mTxtWidthDU; // computed text width (du) 36 | LONG mTxtWidthPX; // computed text width (px) 37 | LONG mTxtHeightDU; // computed text height (du) 38 | LONG mTxtHeightPX; // computed text height (px) 39 | }; 40 | -------------------------------------------------------------------------------- /src/ckrctxt.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "afxres.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (United States) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 20 | #pragma code_page(1252) 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""afxres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Dialog 51 | // 52 | 53 | IDD_MEASURE_DIALOG DIALOGEX 0, 0, 316, 182 54 | STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU 55 | CAPTION "Dialog" 56 | FONT 8, "MS Shell Dlg", 400, 0, 0x1 57 | BEGIN 58 | DEFPUSHBUTTON "OK",IDOK,204,161,50,14 59 | PUSHBUTTON "Cancel",IDCANCEL,259,161,50,14 60 | LTEXT "Product Name:",IDC_STATIC,25,23,50,8 61 | LTEXT "Product Version:",IDC_STATIC,25,42,55,8 62 | LTEXT "Technical Support URL:",IDC_STATIC,25,62,78,8 63 | LTEXT "After translation you can add the created dictionary to the project's translation dictionaries list or import it into the application.",IDC_STATIC2,24,91,219,16 64 | PUSHBUTTON "&Add Folder...",IDC_BUTTON1,165,39,47,14,BS_MULTILINE 65 | CONTROL "|",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,167,66,19,10 66 | CONTROL "Automate package installation by invoking UI controls in order to walk-through the installation steps. Leave it unchecked if the installer requires special user input.\nBy using this option, you agree to the installer License terms.",IDC_CHECK1, 67 | "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,25,120,278,26 68 | RADIOBUTTON "Use file from disk",IDC_RADIO2,222,66,69,10 69 | END 70 | 71 | 72 | ///////////////////////////////////////////////////////////////////////////// 73 | // 74 | // DESIGNINFO 75 | // 76 | 77 | #ifdef APSTUDIO_INVOKED 78 | GUIDELINES DESIGNINFO 79 | BEGIN 80 | IDD_MEASURE_DIALOG, DIALOG 81 | BEGIN 82 | LEFTMARGIN, 7 83 | RIGHTMARGIN, 309 84 | TOPMARGIN, 7 85 | BOTTOMMARGIN, 175 86 | HORZGUIDE, 120 87 | END 88 | END 89 | #endif // APSTUDIO_INVOKED 90 | 91 | 92 | ///////////////////////////////////////////////////////////////////////////// 93 | // 94 | // Version 95 | // 96 | 97 | VS_VERSION_INFO VERSIONINFO 98 | FILEVERSION 1,0,0,0 99 | PRODUCTVERSION 1,0,0,0 100 | FILEFLAGSMASK 0x3fL 101 | #ifdef _DEBUG 102 | FILEFLAGS 0x1L 103 | #else 104 | FILEFLAGS 0x0L 105 | #endif 106 | FILEOS 0x40004L 107 | FILETYPE 0x0L 108 | FILESUBTYPE 0x0L 109 | BEGIN 110 | BLOCK "StringFileInfo" 111 | BEGIN 112 | BLOCK "040904b0" 113 | BEGIN 114 | VALUE "FileDescription", "Visual Studio RC Text Bounds Checker" 115 | VALUE "FileVersion", "1.0.0.0" 116 | VALUE "InternalName", "ckrctxt.rc" 117 | VALUE "LegalCopyright", "(c) 2016" 118 | VALUE "OriginalFilename", "ckrctxt.exe" 119 | VALUE "ProductName", "Check RC Text" 120 | VALUE "ProductVersion", "1.0.0.0" 121 | END 122 | END 123 | BLOCK "VarFileInfo" 124 | BEGIN 125 | VALUE "Translation", 0x409, 1200 126 | END 127 | END 128 | 129 | #endif // English (United States) resources 130 | ///////////////////////////////////////////////////////////////////////////// 131 | 132 | 133 | 134 | #ifndef APSTUDIO_INVOKED 135 | ///////////////////////////////////////////////////////////////////////////// 136 | // 137 | // Generated from the TEXTINCLUDE 3 resource. 138 | // 139 | 140 | 141 | ///////////////////////////////////////////////////////////////////////////// 142 | #endif // not APSTUDIO_INVOKED 143 | 144 | -------------------------------------------------------------------------------- /src/compatibility.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/dpi_aware.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by ckrctxt.rc 4 | // 5 | #define IDD_MEASURE_DIALOG 101 6 | #define IDC_STATIC2 200 7 | #define IDC_BUTTON1 1001 8 | #define IDC_COMMAND1 1002 9 | #define IDC_RADIO1 1003 10 | #define IDC_CHECK1 1004 11 | #define IDC_RADIO2 1005 12 | 13 | // Next default values for new objects 14 | // 15 | #ifdef APSTUDIO_INVOKED 16 | #ifndef APSTUDIO_READONLY_SYMBOLS 17 | #define _APS_NEXT_RESOURCE_VALUE 102 18 | #define _APS_NEXT_COMMAND_VALUE 40001 19 | #define _APS_NEXT_CONTROL_VALUE 1006 20 | #define _APS_NEXT_SYMED_VALUE 101 21 | #endif 22 | #endif 23 | -------------------------------------------------------------------------------- /src/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // ckrctxt.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /src/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #define CODEPAGE_ENGLISH 1252 9 | 10 | #include "targetver.h" 11 | 12 | #include 13 | #include 14 | 15 | // Windows Template Library (WTL) - extends ATL 16 | // http://sourceforge.net/projects/wtl/ 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #if defined _M_IX86 26 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") 27 | #elif defined _M_IA64 28 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") 29 | #elif defined _M_X64 30 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") 31 | #else 32 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 33 | #endif 34 | -------------------------------------------------------------------------------- /src/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | --------------------------------------------------------------------------------