How to catch print, load and save dialogs?

  • First off, I'm using TextDynamic in Visual FoxPro (and it works great).

    I have a requirement to prevent export of texts outside the app - which is mainly the reason why we bought TextDynamic, to have text editing within. There's a lot of copyrighted text in the app, so I'm cleaning the clipboard when it loses focus (this also works).

    The next holes I need to plug: I need to catch the save, save As and print dialogs. Before Save, the text needs to be encrypted, which I'll do, just need to know how can I plug my code between the click on the icon and the actual save.

    Slightly different for printing - I need to allow printing, but not if it's a PDF printer driver saving into file. So I need to remove such drivers from the list of available printers, even if it takes writing my own printer selector form. Is there a good way to get my code to handle the event, and then which event is that?

    TX

    • Offizieller Beitrag

    Hi,

    >> First off, I'm using TextDynamic in Visual FoxPro (and it works great).

    Thats good news. I assume you use the ActiveX? If yes please get V1.25 since it will bring some improvements with DLL loading and unloading.

    >>I have a requirement to prevent export of texts outside the app - which is mainly the reason why we bought TextDynamic, to have text editing within. There's a lot of copyrighted text in the app, so I'm cleaning the clipboard when it loses focus (this also works). <<Thats>> The next holes I need to plug: I need to catch the save, save As and print dialogs. Before Save, the text needs to be encrypted, which I'll do, just need to know how can I plug my code between the click on the icon and the actual save. <<You>> Slightly different for printing - I need to allow printing, but not if it's a PDF printer driver saving into file. So I need to remove such drivers from the list of available printers, even if it takes writing my own printer selector form. Is there a good way to get my code to handle the event, and then which event is that? <<

    If you disable the printer dialog and the printer setup you can use your own code to select a printer using the method SelectPrinter. It is not possible to clear the list, the dialogs we are using are the standard custom dialogs.

    Kind Regards,

    Julian Ziersch

  • Zitat von wpsupport

    Hi,

    >> First off, I'm using TextDynamic in Visual FoxPro (and it works great).

    Thats good news. I assume you use the ActiveX? If yes please get V1.25 since it will bring some improvements with DLL loading and unloading.

    Actually, bought it yesterday - so 1.25 it is. Lucky coincidence :).

    And yes, I use it as OCX. As for the ease of use in VFP, it's actually doing much better than many other OCXes I used over the years - almost all of its interface is accessible. Though, when I create a reference to .memo, it doesn't register in my IntelliSense (which usually does a pretty good job of most COM objects), but it works fine for this.memo - which should be the same, but somehow isn't. This would be a problem if I had to pass a reference to this.memo (in VFP, this is equal to me in VB)

    Zitat von wpsupport

    If you disable the printer dialog and the printer setup you can use your own code to select a printer using the method SelectPrinter. It is not possible to clear the list, the dialogs we are using are the standard custom dialogs.

    So I figured - and that'd be the load, save, printer setup and print dialogs, where I (correct me if I'm wrong) need to remove the wpa parameter from the pcc file and handle these in my own OnButtonClick code.

    The trouble here is that I'm receiving only two parameters in OnButtonClick - editor and def. Editor=1 (or 2 if I enable the second editor), and def looks like an object... except I can't see any of its properties. Whatever I try, it returns error "Not implemented". What's the interface of this object?

    Thanks - this product has already saved me immesurable work.

    • Offizieller Beitrag

    Hi,

    Zitat

    ... when I create a reference to .memo, it doesn't register in my IntelliSense (which usually does a pretty good job of most COM objects), but it works fine for this.memo

    Is it the same for other interfaces as well, such as IWPTextCursor? In MS Access (GetText event) a global reference variable helped which is locally assigned.

    Zitat

    The trouble here is that I'm receiving only two parameters in OnButtonClick - editor and def. Editor=1 (or 2 if I enable the second editor), and def looks like an object... except I can't see any of its properties. Whatever I try, it returns error "Not implemented". What's the interface of this object?

    Thats a reference to IWPDllButton:
    https://www.wpcubed.com/manuals/tdref/…WPDllButton.htm

    So you can use the property "Name" - you need to set in in the PCC file of course.

    If you cannot work with the interface please try to assign it to a local or global reference variable of the type IWPDllButton.

    I hope this helps,

    Julian Ziersch

  • Zitat

    So you can use the property "Name" - you need to set in in the PCC file of course.

    If you cannot work with the interface please try to assign it to a local or global reference variable of the type IWPDllButton.

    Still no good - I tried with any of the properties listed, for each one I get the "Not implemented" error.

    And I tried to let Fox know its interface by

    Code
    LPARAMETERS editor, def as "{8F6368D4-20D7-47C0-BF15-BE84DC7A19B2}"

    but still no dice. It just seems that the interface for this is not published in the OCX - I can see it in object browser, but it's not bolded, i.e. not exposed. The object browser is a separate app, which reads the information from somewhere (probably ocx itself), but this doesn't help me to retrieve the info from this parameter.

    Setting the type of a variable does nothing in VFP - its variables can change type at will. And its COM uses late binding. Just need the interface exposed somehow.

    Is there a setting somewhere, to change the way this parameter is passed?

    • Offizieller Beitrag

    Hi,

    Zitat

    And I tried to let Fox know its interface by

    LPARAMETERS editor, def as "{8F6368D4-20D7-47C0-BF15-BE84DC7A19B2}"

    but still no dice. It just seems that the interface for this is not published in the OCX - I can see it in object browser, but it's not bolded, i.e. not exposed. The object browser is a separate app, which reads the information from somewhere (probably ocx itself), but this doesn't help me to retrieve the info from this parameter. :-x

    The interface is defined in the OCX (in its TLB) but it is not a type of any of the properties. In VB or Access you can create a variable and assign it:

    Code
    Private Sub WPDLLInt0_OnButtonClick(ByVal Editor As Long, ByVal Def As Object)
       Dim theButtons As WPTDynInt.IWPDllButton
       Set theButtons = Def
       If theButtons.NAME = "Print" Then
       ' ....
       End If
    End Sub

    Can you translate this example to FoxPro?

    -
    About the copyright protection: I plan to introudce a set of properties to protect the text, including disabling of the internal save and print dialogs and also by encrypting the clipboard contents with a password which is randomly created for the editor instance. Clearing the clipboard when focus changes can frustrate the people I think - if they just switch to a different program, look something up or so and than come back and cannot paste.

    Regards,

    Julian ZIersch

  • Zitat

    Can you translate this example to FoxPro?

    I can, but it wouldn't work - the equivalent of the "Dim ... as" serves only for Intellisense to read the TLB so its properties show up in the editor. However

    Zitat

    theButtons = Def

    would only create a new reference to the object, tried that already.

    There's another approach I'm considering, the eventhandler interface - and I almost got it to work, except that for some reason form's .init (equivalent of onLoad, fires after all the form's objects are instantiated) didn't quite fire (which is a first) and eventhandler() call was the last line there. I'll try to move the code elsewhere and see what happens. I assume that I either have to move the call to before this.oWpt.SetLayout(), or to move it into .owpt.init() or something like that - into some place that I know that code executes. It could be that the control itself initalizes somehow in a manner that steals the focus from VFP's code, or whatever. That's something to do today.

    Zitat


    About the copyright protection: I plan to introudce a set of properties to protect the text, including disabling of the internal save and print dialogs and also by encrypting the clipboard contents with a password which is randomly created for the editor instance. Clearing the clipboard when focus changes can frustrate the people I think - if they just switch to a different program, look something up or so and than come back and cannot paste.

    No, I plan to do this other way around - they will be able to paste into, they just won't be able to copy out of the app. That's customer's requirement and the users will be notified. I'd also like to see a drag'n'drop into the control (text, not just images), but that'd be the icing on the cake.

    As for the saving and printing - like I said, printing is fine as long as it's not to a PDF printer, and for saving and loading I'd use one of the encryption schemes that are already in use in other areas of the app.

    Say, if I manage to intercept printing, does the wpa="print" call the print dialog by itself, or does it go to the currently selected printer? I figure I'd find that by myself, but since you're already here... :)

    • Offizieller Beitrag

    Hi,

    >> ... would only create a new reference to the object, tried that already.

    Ok, yes, the "not supported" message is a runtime message and shows that you already have a COM interface.

    Can you show me the full code of this event handler - I have no idea how this looks in FoxPro.

    I would not recommend to redevelop the event interface - I would rather add a method to the control to read the current button.

    Zitat

    No, I plan to do this other way around - they will be able to paste into, they just won't be able to copy out of the app. That's customer's requirement and the users will be notified. I'd also like to see a drag'n'drop into the control (text, not just images), but that'd be the icing on the cake.

    With clipboard encryption I can make it so that they can paste INTO and copy and paste WITHIN the application. Drag&Drop from other applications into the editor does currently not work.

    And, yes, "print" for print only, "PrintDialog" and "DiaPrint" show the print dialog. The ImagePack program shows a searchable table with "wap" commands.

    BTW - I have no idea how one can detect a PDF printer - and also all printers can save to file and if this a post script printer you can convert the PS file to a PDF if you like.

    Regards,

    Julian

  • The EventHandler code is a VFP class which implements the interface of the COM object which it should track. The interface code is generated by object browser (which reads the tlb), and looks like this:

    Code
    DEFINE CLASS WpEvents AS session	IMPLEMENTS IWPDLLIntEvents IN "F:\PROGRAM FILES\TEXTDYNAMIC\REDIS\WPTDYNINT.OCX"	PROCEDURE IWPDLLIntEvents_OnKeyPress(Editor AS Number, Key AS NUMBER @) AS VOID	debugout program()	ENDPROC	PROCEDURE IWPDLLIntEvents_OnLoadText(Editor AS Number, filename AS STRING) AS VOID	* add user code here	ENDPROC*-- etc etc, one method for each published method or property set/getEndDefine


    and it's bound to the instance like this:

    Code
    this.NEWOBJECT("oWpt", "textdyn","libs\textdynwrap.vcx")this.owpt.visible=.t.thisform.AddProperty("oHandler", NEWOBJECT("WpEvents","tmp.prg"))EVENTHANDLER(this.owpt.object, thisform.oHandler)

    So far so good, but none of these ever fire. I got some other eventhandler code which detects Windows messages - this is how it knows when the user alt-tabs into or out of the app - and that works.

    Anyway, I got this to work by attacking it from the opposite direction: if I can't get the parameters out in a decent fashion, I can push them in. I'll add my own buttons for the functions I need to override, and have some code like this in them:

    Code
    thisform.owpt.wpaProcess("DiaSaveAs","dox\trtemrte.rtf")


    Tried this while suspended (in the debugger), and it worked like a charm. Now I just need to remove a few buttons from the .pcc file and draw my own somewhere by the top of the form, and I'm as happy as the little monkey when the big monkey is out :).

    • Offizieller Beitrag

    Hi,

    thanks for your clarification.

    I wonder why some events would not fire - the OCX control would attach an new event handler (and disconnect the previous)

    Maybe check when you attach the interface - if it before or after the DLL is loaded. (assign to property DLLName to load the DLL from a specific directory. You need to add such code anyways to make it possible to deploy the application)

    Using a custom toolbar is of course a possibility - but would really like to see that it works as supposed. Maybe the OnButtonClick event is not so important, but other events, such as the OnFieldGetText are - and they probably also have a problem since the key parameter is an interface reference.

    Kind Regards,

    Julian Ziersch

  • I wouldn't know why neither works - the event handler doesn't catch any events, and the event code in the control itself doesn't pass any usable parameters. I'm just happy I have a solution for my immediate problem.

    Maybe there need to be some additional settings in the TLB, I don't know, never went that deep. I know that there were several producers of OCXes who had to do a few more things to make their controls work with VFP. You may contact DbiTech, they've made sure all their OCXes work with VFP.

    Zitat

    Maybe check when you attach the interface - if it before or after the DLL is loaded. (assign to property DLLName to load the DLL from a specific directory. You need to add such code anyways to make it possible to deploy the application)

    I did it after - I'm actually using VFP's OleControl, which is a generic host for OCXes, and I've put all the settings (dll, password, layout) inside its .init, which happens before it's added to the form.

    You think it may be different if I hooked into it before loading the dll?

    • Offizieller Beitrag

    Hi,

    >> I did it after - I'm actually using VFP's OleControl, which is a generic host for OCXes, and I've put all the settings (dll, password, layout) inside its .init, which happens before it's added to the form.

    You think it may be different if I hooked into it before loading the dll?<<

    I think it would be better before - than it is assured that the correct interface pointer is passed to the engine. (The interface is called directly from the DLL, not from the OCX - except for the property change event)

    I think it would be even possible to create a replacement of the OCX in FoxPro - similar to the .NET assembly. I am not so sure about using this control in a container (if this is what OleControl is). I would rather expect to use it directly with CreateObject.

    Regards,

    Julian Ziersch

  • Zitat von wpsupport

    Maybe check when you attach the interface - if it before or after the DLL is loaded. (assign to property DLLName to load the DLL from a specific directory. You need to add such code anyways to make it possible to deploy the application)

    I tried instantiating the control first, then attaching the event handler, then setting the dll, options, password etc - still the event handler doesn't react at all. I've added a little "debugout program()" into each method, which is the most lightweight debugging device - a pretty much console output of the name of the current routine's name into a window of the debugger - and still nothing shows there.

    Well, never mind - since everything else seems to work, and I've found a way to override what I needed, problem solved.

    If you get anyone else using TextDynamic in Fox, you have my email address.

  • Zitat von wpsupport


    I think it would be better before - than it is assured that the correct interface pointer is passed to the engine. (The interface is called directly from the DLL, not from the OCX - except for the property change event)

    I think it would be even possible to create a replacement of the OCX in FoxPro - similar to the .NET assembly. I am not so sure about using this control in a container (if this is what OleControl is). I would rather expect to use it directly with CreateObject.

    Tried it all - and nope, OleControl is the only way to go. It's a host to OCXes, and doesn't have any visual presence of its own, it's just a wrapper object, which probably handles the communication to the OCX.

    I can createobject() it, but it stays invisible - as does any other createobject()ed thing in VFP, so you can set any of its stuff before showing it. When you're done, you either set oObj.visible=.t. (true), or do oObj.Show() if it has such a method. Haven't found any way to force oWPT to be visible - and I need it in a form anyway. The end user should be able to launch a dozen of these if he wants, and the form is the ideal wrapper for this - it has the caption I can set etc.

    However, I can't add such an object to a form, it reports "Object class is invalid for this container" - which is a Fox error telling me that it just won't accept that as a member of the form. It does, with the oleControl wrapper.

  • Zitat von wpsupport


    And, yes, "print" for print only, "PrintDialog" and "DiaPrint" show the print dialog. The ImagePack program shows a searchable table with "wap" commands.

    Solved the rest - now only for the printing. I have two conflicting requirements: to exclude certain printer drivers (like the Document Image Writer and any PDF writer) and yet to have some dialog to enable printing a page range.

    I can't have the standard dialog with those printers removed. I can hide them, but the code to do that is unreliable, slow and ugly. The other way around would be to have my own dialog with a filtered selection of printers (and yes, .SelectPrinter() method works fine), but I need a way to have a way to pass a page range.

    What's missing here is a wpaPrintPages wpa command. I can't use the .memo property, because it behaves just the same as the def parameter in the OnButton event, i.e. whichever of its properties I try to access, it errors with "not implemented", although my IntelliSense sees them all. Also tried to hook an event handler on it, doesn't fire. So I have no way to print a page range.

    I see two ways out of this - adding the wpa command (simpler, IMO, and more sure to work) or exposing the IWPMemo interface just the way the IWPDLLInt and IWPDLLIntEvents are exposed in the TLB. For some reason, those two are bolded in my object browser, and they list the PEMs (properties-events-methods, as called in Foxspeak) that I can use.

  • Great!

    I was able to insert my own print dialog (with just a filtered printers list and the Print Pages optiongroup) and it now prints what and where I want.

    I had to remove the PrintPreview for obvious reasons - I can't intercept anything there, and it allows saving into plain .rtf file, which is a no-no in the app I'm making, but it's no big deal. The editor is already quite WYSIWYG, so print preview won't be missed.

    Now the only remaining thing is the registration of the dictionaries (from the other thread) and we'll be ready to deploy.

    Thanks!