No announcement yet.

RTF File Editor

  • Filter
  • Time
  • Show
Clear All
new posts

  • RTF File Editor

    I want to output program-generated text to an RTF file, then let my users edit the RTF file. I can generate the RTF file but don't have a solution yet for the RTF file editor.

    As best I know there's no way to embed WordPad into a PBWin app, so if I want to use WordPad, then SHELLing is the only option.

    Using a RichEdit control to create an embeddable editor would be one approach, but that's a lot of effort and I'd much rather not go that approach.


  • #2
    Depends on the amount of features you want to include.Simple text editing and save is easy to implement using RichEdit. Complete format features and print preview, etc, means a lot of work so then ShellExecute to WordPad sounds like a good alternative.


    • #3
      Hey Gary, long time no see.....

      Also to add to what Borje said, there is more then one version of RTF file formats. So the version that you use will also matter and the target OS that has that version also will matter.

      Last official version from MS was back in 2007 / 8.

      EDIT : Just did a search for you in case you needed some history on it.


      • #4
        Howdy, John!

        Good to see you posting! Bummer, I didn't want the RTF to be complicated but from what you say I may be in for a rude awakening.

        And, Howdy, Borje!

        If I can satisfy my users WordPad, that is the way I will go. Writing a RichEdit-based editor is no small task.

        One thing I want in the saved RTF file is "\page" page-break markers. I've seen editors which put in the Chr$(12) when a user requests it, but I've not found anything specific to WordPad that enters a page break.

        So, I just simply enter "\page" into the visible text in WordPad, wherever I want a page break. Then when the RTF is saved the "\page" is there to use for parsing out the individual page content.

        Even thought I've read that "\page" is sort of official, it seems like I could put in any text I want as a page break since I'm going to parse on it.


        • #5
          From the specs that I found, you might need \sbkpage. However, again, it depends on the version of RTF you are trying to use. Look up the specs for your particular version.

          RTF 1.5 specs :


          • #6
            Howdy, John!

            Thanks for that link!

            In my application, users provide RTF files and I open them in a RichEdit control in order to have access to the text content. At some point, I also create an RTF file from the modified text.

            If there's a way to tell the RichEdit control which version of RTF formatting to use, I've never heard of it.


            • #7
              Glad I could help. Finding out which version you have, I am unsure of how to go about that. And even doing a websearch doesn't look promising, especially since the latest "known" version specification 1.9, that I am aware of, was literally taken down off the Mocrosoft website.
              I have a strong feeling this is one of the reasons MS dropped support for it back in 2008. I don't know anyone who is using it these days... until now.

              On a side note : Keep in mind, your copy could also be using a particular DLL file that others will not have. So your end-users could end up bugging you for help. Food for thought.

              There was a time I dove into RTF as well, but I eventually ended up having to write my own in C#. And that in of itself was a pain. I do not like C#. I just hadn't had the motivation to write it in C/C++... yet. In fact, if I write a small IDE / Editor, I might need to write my own after all.


              • #8
                As best I know there's no way to embed WordPad into a PBWin app, so if I want to use WordPad, then SHELLing is the only option
                Microsoft Word has an API. I know I have used it myself, but I don't recall posting a demo here. For sure it's worth a search here; I'd be surprised if you cannot find an example.

                Regardless, MSDN online will have it.

                DOES REQUIRE MS-Word be installed on the using machine. And yes you may "Save as <richtext> "

                Another option is to create a hidden rich text control, set if for rich [ not plain] text and add the text. Then you can stream it out (demos here).

                BUT..... what I do not understand......

                I want to output program-generated text to an RTF file, then let my users edit the RTF file.
                Are you going the long way?

                ... but don't have a solution yet for the RTF file editor
                I am positive Borje Hagsten has an RTF editor here. You may canniibalize that to embed it in your own program. Regardless, a rich text control, a couple of menus and a few keyboard accelerators and there you are.

                No, I'm not going to do your searches for you.

                I might be enticed out of retirement to do the editor were you to supplement my Social Security check.
                Michael Mattias
                Tal Systems Inc. (retired)
                Racine WI USA
                [email protected]


                • #9
                  For the detailed version, I wouldn't care much, simply use the latest "RichEdit50W" that is available since XP.

                  I got a fairly good editor doing more than WordPad. It will be free and hopefully well coded, so you win on both sides.
                  Send me an email.

                  For the WordPad embedding part, I did a little research, seems like mucho side effects from what I saw, more googeling to do.
                  I'm on another project but will try a few things if I can find a little time.


                  • #10
                    Originally posted by Gary Beene View Post
                    Howdy, John!

                    If there's a way to tell the RichEdit control which version of RTF formatting to use, I've never heard of it.
                    If memory serves me correctly the header on the file should provide that info.

                    Something like this...

                    Did you see this?


                    • #11
                      Originally posted by Jim Fritts View Post


                      Did you see this?
                      Hehe, that is the link I posted above.


                      • #12
                        Ah yes. Like minds.


                        • #13
                          Click image for larger version

Name:	WordPad.png
Views:	75
Size:	47.9 KB
ID:	795054

                          #COMPILE EXE '#Win#
                          #DIM ALL
                          #TOOLS OFF
                          #REGISTER NONE
                          #INCLUDE ""
                          #RESOURCE MANIFEST, 1, "XPTheme.xml"
                          GLOBAL hDlg AS DWORD
                          %CaptionSizeY = 32 
                          $AppName = "WordPad as a child"
                          FUNCTION WordpadPathGet()AS STRING
                           LOCAL zWordPadPath         AS ASCIIZ * %MAX_PATH
                           LOCAL zWordPadPathExpanded AS ASCIIZ * %MAX_PATH
                           LOCAL hKey                 AS DWORD
                           IF RegOpenKeyEx(%HKEY_LOCAL_MACHINE, _ 'Registry entry for Wordpad...
                                           "SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\WORDPAD.EXE", _
                                           BYVAL %NULL, %KEY_READ, hKey) = %ERROR_SUCCESS THEN
                             RegQueryValueEx(hKey, "", BYVAL %NULL, BYVAL %NULL, BYVAL VARPTR(zWordPadPath), %MAX_PATH)
                             ExpandEnvironmentStrings(zWordPadPath, zWordPadPathExpanded, %MAX_PATH)
                           END IF
                           FUNCTION = zWordPadPathExpanded
                          END FUNCTION
                          FUNCTION GetHandleFromPid(BYVAL Pid AS DWORD)AS DWORD 'Get process id or thread id
                           LOCAL hTry     AS DWORD
                           LOCAL pidTry   AS DWORD
                           LOCAL idThread AS DWORD
                           hTry = GetForegroundWindow()
                           WHILE hTry
                             idThread = GetWindowThreadProcessId(hTry,  pidTry)
                             IF pidTry = Pid THEN  'Via ProcessId
                               FUNCTION = hTry
                               EXIT DO
                             END IF
                             hTry = GetWindow(hTry, %GW_HWNDNEXT)
                          END FUNCTION
                          FUNCTION ProcessCreate(zCommandLine AS ASCIIZ) AS DWORD
                           LOCAL ProcessInfo AS PROCESS_INFORMATION
                           LOCAL StartInfo   AS STARTUPINFO
                           StartInfo.cb          = SIZEOF(STARTUPINFO)
                           StartInfo.dwFlags     = %STARTF_USESHOWWINDOW
                           StartInfo.wShowWindow = %SW_SHOW
                           IF CreateProcess("", zCommandLine, BYVAL 0, BYVAL 0, 0, %NORMAL_PRIORITY_CLASS, BYVAL 0, BYVAL 0, StartInfo, ProcessInfo) THEN
                             WaitForInputIdle(ProcessInfo.hProcess, %INFINITE)
                             FUNCTION = GetHandleFromPid(ProcessInfo.dwProcessId)
                           END IF
                          END FUNCTION
                          CALLBACK FUNCTION DlgProc
                           STATIC CtrlClass AS ASCIIZ * 50
                           STATIC hWordPad AS DWORD
                           SELECT CASE CBMSG
                             CASE %WM_INITDIALOG
                               PostMessage(hDlg, %WM_APP, 0, 0)
                               FUNCTION = %TRUE
                             CASE %WM_APP
                               hWordPad = ProcessCreate(WordpadPathGet)
                               IF hWordPad THEN
                                 SetParent(hWordPad, hDlg)
                                 SetWindowLong(hWordPad, %GWL_STYLE, GetWindowLong(hWordPad, %GWL_STYLE) XOR (%WS_CAPTION OR %WS_THICKFRAME))
                                 SetWindowLong(hWordPad, %GWL_EXSTYLE, %WS_EX_ACCEPTFILES OR %WS_EX_STATICEDGE)
                                 LOCAL Rec AS RECT
                                 GetClientRect(hDlg, Rec)
                                 MoveWindow(hWordPad, 10, 10 - %CaptionSizeY, Rec.nRight - 20, Rec.nBottom - 20 + %CaptionSizeY, %TRUE)
                                 InvalidateRect(hWordPad, BYVAL %NULL, %TRUE) : UpdateWindow(hWordPad)
                               END IF
                             CASE %WM_SIZE
                               LOCAL ClientSizeX AS LONG
                               LOCAL ClientSizeY AS LONG
                               IF CBWPARAM <> %SIZE_MINIMIZED THEN
                                 ClientSizeX = LO(WORD, CBLPARAM)
                                 ClientSizeY = HI(WORD, CBLPARAM)
                                 MoveWindow(hWordPad, 10, 10 - %CaptionSizeY, ClientSizeX - 20, ClientSizeY - 20 + %CaptionSizeY, %TRUE)
                                 InvalidateRect(hWordPad, BYVAL %NULL, %TRUE) : UpdateWindow(hWordPad)
                               END IF
                            END SELECT
                          END FUNCTION
                          FUNCTION PBMAIN()
                           LOCAL hIcon AS DWORD
                           DIALOG FONT "Segoe UI", 9
                           DIALOG NEW %HWND_DESKTOP, $AppName, , , 500, 300, _
                           hIcon = ExtractIcon(GETMODULEHANDLE(""), "Shell32.dll", 294) 'o
                           SetClassLong(hDlg, %GCL_HICON, hIcon)
                           SetClassLong(hDlg, %GCL_HICONSM, hIcon)
                           DIALOG SHOW MODAL hDlg CALL DlgProc
                          END FUNCTION
                          Last edited by Pierre Bellisle; 8 Jun 2020, 12:26 AM.


                          • #14
                            Pierre, very good and elegant solution.


                            • #15
                              Very cool Pierre, and once we have a handle, we can change style, etc, like removing %WS_CAPTION so it cannot be moved (can cause som redraw problems), etc. A lot to experiment and have fun with there Me like - thanks!
                                   IF hWordPad THEN
                                     LOCAL dwStyle AS DWORD
                                     dwStyle = GetWindowLong(hWordPad, %GWL_STYLE)
                                     SetWindowLong(hWordPad, %GWL_STYLE, dwStyle XOR %WS_CAPTION)  ' or whatever...
                                    ' ....


                              • #16
                                Brilliant Pierre and Borje, what an excellent app


                                • #17
                                  I also removed WS_THICKFRAME.
                                  One also can cheat by moving WordPad's top in a negative vertical position...

                                  Anne and Jordi, glad that you liked. :-)
                                  Last edited by Pierre Bellisle; 8 Jun 2020, 12:36 PM.