VFP and .NET Interop
wwDotNetBridge and iTextSharp
Gravatar is a globally recognized avatar based on your email address. wwDotNetBridge and iTextSharp
  Kathy
  All
  Feb 10, 2017 @ 07:53am

Hello, Despite of being too new to the whole subject, I'm trying to use iTextSharp.dll for autofilling .pdf files. I've been able to use my C# code in Foxpro but I'd like to see if I can use the .dll in Foxpro directly (in order to workaround passing my Foxpro dynamic Objects to C#).

I've already tried the following according to the example I found on the message board:

LOCAL loBridge  AS wwDotNetBridge, loPDF
DO wwDotNetBridge 
loBridge = CreateObject("wwDotNetBridge","V4")
? loBridge.LoadAssembly("iTextSharp.dll") 
? loBridge.cErrorMsg

loPDF = loBridge.CreateInstance("iTextSharp.text.pdf.PdfWriter")
? loBridge.cErrorMsg
And I followed Rick's suggestion looking into the documentation: iTextSharp.text.pdf Namespace But I have not been successful in any attempt. loPDF is always Null and I don't know how to make it work!

I've found another example: (http://entrail2.rssing.com/chan-2566305/all_p233.html)

DO wwDotNetBridge 
loBridge = CreateObject("wwDotNetBridge","V4")
loBridge.LoadAssembly("iTextSharp.dll") 
? loBridge.cErrorMsg
loFileMode = loBridge.CreateComValue()
loFileMode.SetValueFromStaticProperty("System.IO.FileMode", "Create")
loFileStream = loBridge.CreateInstance("System.IO.FileStream", "myform.pdf", loFileMode)

If !Empty(loBridge.cErrorMsg)
      MessageBox("Problem creating System.IO.FileStream: " + loBridge.cErrorMsg) 
      Return .f. 
EndIf

loStamper = loBridge.CreateInstance("iTextSharp.text.pdf.PdfStamper", loPdfReader, loFileStream, 0, .t.)

If !Empty(loBridge.cErrorMsg)
      MessageBox("Problem creating iTextSharp.text.pdf.PdfStamper: " + loBridge.cErrorMsg)
      Return .f.
EndIf
But it's not complete and I still need to know how to create an instance of the PdfReader.

Also I'm not sure if the .dll needs to be registered or not however I was not able to register it! From their support site: iTextSharp is not COM ready and never will. You can write a .NET COM wrapper that could call iTextSharp but that's quite a task for limited functionality.

Any help on this would be much appreciated.
Thanks,
Kathy

Gravatar is a globally recognized avatar based on your email address. re: wwDotNetBridge and iTextSharp
  Rick Strahl
  Kathy
  Feb 10, 2017 @ 12:39pm

I don't have time to look at this right now, but that should work. You shouldn't need any wrapper or to register anything. You can access those objects directly.

But, you have to make sure that all your signatures of the .NET objects match including calling the constructors. My guess would be that TextSharp has constructor overloads and you might have to pass a parameter it. I don't see a PdfWriter class in the documentation you point to so that might be one issue :-)

And what does the error message say?

All that said - I've played with TextSharp a while back and if I recall the API is pretty complex if you do all your text building. It might be much easier to create a wrapper .NET DLL that does all the hard work and call that from your FoxPro work. It'll be easier IMHO to deal with the API and get Intellisense and strong typing against the API to make life easier. It's probably doable in pure Fox code, but it's always more verbose at best and tricky at worst to match all the .NET interactions through FoxPro calls. If you're reasonably comfortable with C# (or VB.NET) it's easier to put more complex or lengthy code into .NET and call from FoxPro with wwDotnetBridge.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: wwDotNetBridge and iTextSharp
  Kathy
  Rick Strahl
  Feb 13, 2017 @ 11:54am

Thank you so much Rick.
Your advice was really helpful as usual and I really appreciate it.
The link for iTextSharp.text.pdf takes us to iTextSharp.text and we need to look for iTextSharp.text.pdf under the class tree.
Apparently I had not "closed" the old .pdf and I was trying to read it! My bad!
Any ways, I was able to do the autofill by the code below but according to your advice, I'm considering using the .Net wrapper as well.
I think I'll have to come back with more questions on creating & consuming dynamic objects with which I'm struggling now.
Thanks again,
Kathy

*** Calling wwDotNetBridge ****
DO wwDotNetBridge 
loBridge = CreateObject("wwDotNetBridge","V4")
loBridge.LoadAssembly("iTextSharp.dll") 

**** Creating loPdfReader Obj for reading the template file ****
loPdfReader = loBridge.CreateInstance("iTextSharp.text.pdf.PdfReader","myform.pdf")
? loBridge.setproperty(loPdfReader,"unethicalreading",.T.) 

**** Creating FileStream for output file ****
loFileMode = loBridge.CreateComValue()
loFileAccess = loBridge.CreateComValue()
loFileAccess.SetValueFromStaticProperty("System.IO.FileAccess", "ReadWrite")
loFileMode.SetValueFromStaticProperty("System.IO.FileMode", "CreateNew")
loFileStream = loBridge.CreateInstance("System.IO.FileStream", "myform_filled.pdf", loFileMode,loFileAccess)

**** Creating loStamper Obj. for filling the form fields ****
loStamper = loBridge.CreateInstance("iTextSharp.text.pdf.PdfStamper", loPdfReader, loFileStream)
? loBridge.setproperty(loStamper.AcroFields,"GenerateAppearances",.T.)

? loBridge.invokemethod(loStamper.AcroFields,"SetField","FirstName","John")
? loBridge.invokemethod(loStamper.AcroFields,"SetField","FamilyName","Smith")

? loBridge.setproperty(loStamper,"FormFlattening",.F.)
? loBridge.invokemethod(loStamper,"Close")

Gravatar is a globally recognized avatar based on your email address. re: wwDotNetBridge and iTextSharp
  Kathy
  Kathy
  Feb 21, 2017 @ 11:51am

Hello again,
In the progress of autofilling my .pdf files, I need to have a more generic code to autofill my different .pdf files by my Foxpro cursors.
I'm trying to use a .Net wrapper for this according to what was suggested above but I'm stuck in the middle and I'm not able to find the best solution.
I have a Dynamic object in C# which is created based on the field names in my .pdf files.
The values of its properties should be set by my Foxpro data which will be used to fill out the .pdf and could be different data types, string, numbers, logical, memo, etc.
Is it possible to get and set the dynamic object properties from Foxpro?
Or how should I pass the field names and values from Foxpro to .Net so the field names counterparts could be found and set by the values.
Thanks for your help in advance.
Kathy

         public class Dynamic 
         {
             public Dynamic Add<T>(string key, T value)
             {
                 AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("DynamicAssembly"), AssemblyBuilderAccess.Run);
                 ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Dynamic.dll");
                 TypeBuilder typeBuilder = moduleBuilder.DefineType(Guid.NewGuid().ToString());
                 typeBuilder.SetParent(this.GetType());
                 PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(key, System.Reflection.PropertyAttributes.None, typeof(T), Type.EmptyTypes);

                 MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_" + key, MethodAttributes.Public, CallingConventions.HasThis, typeof(T), Type.EmptyTypes);
                 ILGenerator getter = getMethodBuilder.GetILGenerator();
                 getter.Emit(OpCodes.Ldarg_0);
                 getter.Emit(OpCodes.Ldstr, key);
                 getter.Emit(OpCodes.Callvirt, typeof(Dynamic).GetMethod("Get", BindingFlags.Instance | BindingFlags.NonPublic).MakeGenericMethod(typeof(T)));
                 getter.Emit(OpCodes.Ret);
                 propertyBuilder.SetGetMethod(getMethodBuilder);

                 Type type = typeBuilder.CreateType();

                 Dynamic child = (Dynamic)Activator.CreateInstance(type);
                 child.dictionary = this.dictionary;
                 dictionary.Add(key, value);
                 return child;
             }

             protected T Get<T>(string key)
             {
                 return (T)dictionary[key];
             }

             private Dictionary<string, object> dictionary = new Dictionary<string, object>();
         }


         public Dynamic GetNewDynamicObj() 
         {
             return new Dynamic();
         }
Gravatar is a globally recognized avatar based on your email address. re: wwDotNetBridge and iTextSharp
  Rick Strahl
  Kathy
  Feb 21, 2017 @ 12:45pm

First I'd suggest you use a different name for your object. Dynamic is a reserved word in C# and there's a dynamic type so this can get confusing quickly.

Second if you're trying to interface code with FoxPro I'd stay away from Generics in the parameters and return values. By using generics you will be required to use the long hand syntax of indirect methods to access any of the methods (ie. InvokeMethod() calls instead of direct access). It's fine to use generics but it's more difficult for accessing through FoxPro because FoxPro doesn't understand the generics and it's often not easy for COM to resolve the generic resolution of types in the same way .NET code can (because it has access to all the necessary meta data).

As to dynamic as a type - yes you can pass that back to foxpro or accept it as input, but it will simply be of type object. The dynamic aspect is lost when going over COM as that's a language feature (C# or VB) that does runtime type resolution. Not that it matters FoxPro essentially treats any .NET object like a dynamic, except for types it doesn't understand in which case you need to use InvokeMethod,GetProperty,SetProperty.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: wwDotNetBridge and iTextSharp
  Kathy
  Rick Strahl
  Feb 27, 2017 @ 07:38am

I appreciate your help Rick.
Apparently I have to get back to this at a later time as I've got engaged in other projects.
I'm happy that I'll have your precious advice on this amazing message board.
Regards.

© 1996-2017