Menu

Print template for TPrintDialog

2016-02-03
2016-02-09
  • Oskar Wåglund

    Oskar Wåglund - 2016-02-03

    Hi,

    In this code which I have inherited there is a custom printer dialog defined in the resource file.

    When something should be printed the ID (IDD_PRINT) of the dialog is passed to TPrintDialog like this:

    DPrintDialog::DPrintDialog(TWindow* parent, TData& data, bool *compressPtr, const char far* title, TModule* module)
    :TPrintDialog(parent, data, MAKEINTRESOURCE(compressPtr ? IDD_PRINT : 0), MAKEINTRESOURCE(0), title, module ? module : theRes)
    

    The problem is that I get an access violation everytime I try to do this. This is compiled with OWLNext 6.42, VS13. Compiled with OWL and B5.02 it works fine.

    Running it in debug mode I find that the LPCTSTR printTemplateName, which is the argument for IDD_PRINT, says "Error reading characters of string", and "Unable to read memory". The exception is then thrown when

    PrintTemplateName(ToString(printTemplateName)),

    is called (The ToString function). This is the constructor that is used

    TPrintDialog::TPrintDialog(TWindow* parent, TData& data, LPCTSTR printTemplateName, LPCTSTR setupTemplateName,
      LPCTSTR title, TModule* module)
    :
      TCommonDialog(parent, title, module),
      Data(data),
      PrintTemplateName(ToString(printTemplateName)),
      SetupTemplateName(ToString(setupTemplateName))
    {
      Init();
    }
    

    Any idea of what may be wrong? Is this still the correct way to do it in OWLNext?

    Many thanks
    Oskar

     
  • Vidar Hasfjord

    Vidar Hasfjord - 2016-02-06

    Hi Oskar, thanks for reporting this issue!

    This is compiled with OWLNext 6.42, VS13. Compiled with OWL and B5.02 it works fine.

    This is my fault. The problem is a regression in [r513], which "added string-aware overloads for TPrintDialog". In this revision, it was assumed that the original single constructor TPrintDialog (TWindow*, TData&, LPCTSTR, LPCTSTR, LPCTSTR, TModule*) only accepted pointers to true strings (or null). However, as you point out, it also accepted resource identifiers created by the MAKEINTRESOURCE macro, i.e. short integers masquerading as string pointers. This no longer works, since TPrintDialog now does internal buffering of the given strings (for safety, to guard against dangling pointers), hence the given pointers must point to real strings (if not null).

    One way to circumvent the problem is by changing your resource file to use a true string as your dialog template identifier, i.e. replace integer IDD_PRINT by, say, "IDD_PRINT".

    :::C++
    // Replace this:
    
    #define IDD_PRINT 123
    
    // by this:
    
    #define IDD_PRINT _T("IDD_PRINT")
    


    Alternatively, you can manually circumvent the problem in your constructor, like so:

    :::C++
    DPrintDialog::DPrintDialog(TWindow* parent, TData& data, bool *compressPtr, const char far* title, TModule* module)
      : TPrintDialog(parent, data, nullptr, nullptr, title, module ? module : theRes)
    {
      if (compressPtr)
      {
        Pd.lpPrintTemplateName = TResId{IDD_PRINT}.GetPointerRepresentation();
        Pd.Flags |= PD_ENABLEPRINTTEMPLATE;
    
        Pde.lpPrintTemplateName = Pd.lpPrintTemplateName;
        Pde.Flags |= PD_ENABLEPRINTTEMPLATE;
        Pde.hInstance = GetModule()->GetHandle();
      }
    }
    


    Hopefully that's helpful. I will investigate a better solution, replacing the use of LPCTSTR in the TPrintDialog constructor by TResId, which properly encapsulates the dual use of string pointers in the original version.

     

    Related

    Commit: [r513]


    Last edit: Vidar Hasfjord 2016-02-09
  • Vidar Hasfjord

    Vidar Hasfjord - 2016-02-06

    I have filed a bug report for this issue [bugs:#335], and I have comitted a fix to the trunk [r3350], in which the type of TPrintDialog constructor parameters printTemplateName and setupTemplateName has been changed to TResId. Please review and test. If feasible, I'll consider back-porting the fix to 6.43 and 6.35.

     

    Related

    Bugs: #335
    Commit: [r3350]

  • Oskar Wåglund

    Oskar Wåglund - 2016-02-08

    Hi Vidar,

    Thank you for your suggestions! I was able to get it working with a combination of your code and an addition from another thread ("TPrintDialog does not show"). It was Jogy that suggested to use Data.UseOldDialog. My code now looks like this:

    DPrintDialog::DPrintDialog(TWindow* parent, TData& data, bool *compressPtr, const char far* title, TModule* module)
    :TPrintDialog(parent, data, nullptr, nullptr, title, module ? module : theRes)
    {
        if (compressPtr){
            *compressPtr = PRINTCOMPRESSMODE; // Set default value
    
            Pd.lpPrintTemplateName = TResId{ IDD_PRINT };
            Pd.Flags |= PD_ENABLEPRINTTEMPLATE;
    
            Data.UseOldDialog = true;
        }
        this->compressPtr=compressPtr;
    }
    

    Wihout the UseOldDialog line I got a message saying that something went wrong during printing, although not crashing the program. This was however with the three Pde lines as well:

    Pde.lpPrintTemplateName = Pd.lpPrintTemplateName;
    Pde.Flags |= PD_ENABLEPRINTTEMPLATE;
    Pde.hInstance = GetModule()->GetHandle();
    

    //Oskar

     

    Last edit: Oskar Wåglund 2016-02-08
  • Vidar Hasfjord

    Vidar Hasfjord - 2016-02-09

    Good to hear you made it work!

    Wihout the UseOldDialog line I got a message saying that something went wrong during printing

    I guess customising the new-style Print Property Sheet (invoked by PrintDlgEx, rather than PrintDlg, within TPrintDialog::DoExecute) requires changes to your code, due to differences in the dialog template etc. See MSDN for details.

    http://msdn.microsoft.com/en-us/library/windows/desktop/ms646966.aspx#_win32_Customizing_the_Print_Property_Sheet

     

Anonymous
Anonymous

Add attachments
Cancel





MongoDB Logo MongoDB