FoxPro and .NET Interop
How to have ASP.NET load a VFP COM server from a given path
Gravatar is a globally recognized avatar based on your email address. How to have ASP.NET load a VFP COM server from a given path
  Markus Winhard
  All
  Apr 27, 2021 @ 02:38pm

Hi Rick,

I have an little asp.net web application that uses a vfp mtdll to access it's vfp tables. The vfp dll is registered in the windows registry. Worked fine so far. Because there was just one instance of the vfp dll.

Now I was asked to provide several independent copies of this asp.net web application on the same machine. Each running in it's own IIS application pool, it's own directory tree, with it's own vfp tables. It should be even possible to upgrade one by one. No problem with asp.net, folder security and files on disk.

But how can I tell each asp.net web application to load the vfp dll from a different path?

TIA,

Markus

Gravatar is a globally recognized avatar based on your email address. re: How to have ASP.NET load a VFP COM server from a given path
  Rick Strahl
  Markus Winhard
  Apr 27, 2021 @ 03:21pm

There's no easy way to do this. COM registers in a central machine location, which is the whole point of COM - single source object.

You can use local COM registration and have custom registrations, but it's really difficult to set this up.

I've played around with this in Web Connection years ago and it was a pain in the ass to get to working, but nobody actually used it because it's such a pain in the ass to setup.

Just to give you an idea what's involved (even with the custom ActivationContext in place):

Creating Registrationless COM Deployments

It ain't pretty - I have no idea if this even still works and wouldn't really recommend anybody actually uses this because it all so fragile especially if you keep updating the components frequently.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: How to have ASP.NET load a VFP COM server from a given path
  Markus Winhard
  Rick Strahl
  Apr 27, 2021 @ 04:42pm

Thank you very much, Rick. I'll give it a try.

As you don't like this technology any more, can you imagine a better approach?

Markus

Gravatar is a globally recognized avatar based on your email address. re: How to have ASP.NET load a VFP COM server from a given path
  Rick Strahl
  Markus Winhard
  Apr 27, 2021 @ 04:52pm

Nothing wrong with using ASP.NET with COM into Foxpro, but self-registration is a pain.

You can build separate DLLs (projects) for each implementation and register them separately. You can create one 'base' application that holds all the logic, then subclass from that for each of the other instances so other than creating the COM wrapper class all the code lives in one place. It would essentially just be an empty class subclassed from the actual worker class with an OLEPUBLIC clause - no other code.

IOW, one Foxpro project per implementation, each with a different COM ProgId and ClassId (ie. totally separate project).

To be clear though -you can use the same exact COM object in multiple ASP.NET ApplicationPools. So I'm assuming if you need separate copies you need to customize somehow and for that the sub-class approach may work.

Another option: Ditch FoxPro code and use .NET directly and use OleDb to access the database. Then the whole app becomes XCOPY deployable at that point. The VFP OleDb provider is sketchy though and in both scenarios you have to deal with maintenance issue for exclusive file access.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: How to have ASP.NET load a VFP COM server from a given path
  Markus Winhard
  Rick Strahl
  Apr 28, 2021 @ 04:41am

Let's assume I'll go for the multiple registered vfp dlls approach. Is it really necessary to have multiple vfp dll projects?

How about exporting the ProgId and ClSID registry hives of my dll to .reg files. Then replace ProgID value, CSLID value and InProcServer32 path. Then import them back into the registry.

Would this allow me to load different instances of my vfp dll by using different ProgIds in c# code?

TIA,

Markus

Gravatar is a globally recognized avatar based on your email address. re: How to have ASP.NET load a VFP COM server from a given path
  Rick Strahl
  Markus Winhard
  Apr 28, 2021 @ 02:46pm

Good luck with that.

COM registrations have many references in the registry - it's not just one key. ProgId, ClassId, TypeLib etc. and they all need to line up and they all need to be unique.

To be honest, I don't understand why you need separate dlls if you're wanting to point at the same binary in the first place. If you're using the same binary just point at the same COM object and each AppPool gets its own set of private instances.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: How to have ASP.NET load a VFP COM server from a given path
  Markus Winhard
  Rick Strahl
  Apr 29, 2021 @ 01:34am

At user login there's a check if web application version number matches vfp dll version number and matches database version number.

One requirement is that the web applications can be upgraded one by one. So I need separate copies of the vfp dll to fulfill this requirement.

I'll build a little console program to check if the registry hack mentioned in my previous message works.

Gravatar is a globally recognized avatar based on your email address. re: How to have ASP.NET load a VFP COM server from a given path
  Markus Winhard
  Rick Strahl
  May 2, 2021 @ 04:12am

Unfortunately I found out that hacking the registry will not work. As soon as you change the CLSID either in the registry or in the vfp dll it's over. You get the same error in vfp an c#:

0x80004002 (E_NOINTERFACE), no such interface supported.

Gravatar is a globally recognized avatar based on your email address. re: How to have ASP.NET load a VFP COM server from a given path
  Markus Winhard
  Markus Winhard
  May 2, 2021 @ 07:11am

...and here comes the working solution. 😃 (at least it worked in my tests)

        private static bool _vfpDllConfigured = false;

        private void ConfigureVfpDll()
        {
            string vfpDllPath = ReadVfpDllPath();
            SetDllPathInHkcuRegistry(vfpDllPath);
            vfpdata.DataService ds = new vfpdata.DataService();
            Marshal.ReleaseComObject(ds);
            _vfpDllConfigured = true;
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!_vfpDllConfigured)
            {
                ConfigureVfpDll();
            }
        }

ReadVfpDllPath() reads the desired vfp dll path from a text file. SetDllPathInHkcuRegistry() writes the desired path to HKCU\Software\Classes\CLSID\{vfpDllClsId}\InProcServer32\(Default) and HKCU\Software\Classes\TypeLib\{vfpDllTypeLibClsId}\1.0\0\win32\(Default). new vfpdata.DataService() makes sure the desired vfp dll is cached by the .NET runtime.

I had to set the AppPool's LoadUserProfile=True to make writing to HKCU registry possible.

Every copy of my little ASP.NET web application uses it's own AppPool, which in turn uses it's own copy of the vpf dll, which in turn uses it's own vfp tables.

It worked in my tests. Can it go wrong in practice with several copies within the same IIS? Any ideas?

Gravatar is a globally recognized avatar based on your email address. re: How to have ASP.NET load a VFP COM server from a given path
  Rick Strahl
  Markus Winhard
  May 2, 2021 @ 10:31pm

Clever!

So you're just writing the ClassId with the path in HKCU, and leave the rest of the registration as is in HKR and HKLM? I wouldn't have thought, that that works...

I don't see any reason that this wouldn't work if it works in your local tests, but you'll end up with a user profile for each unique application/apppool for this to work. That probably chews up a bit of disk space and messy in the c:\Users folder.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: How to have ASP.NET load a VFP COM server from a given path
  Markus Winhard
  Rick Strahl
  May 3, 2021 @ 08:40am

HKCR is a virtual registry hive. It's constructed at runtime from HKLM\Software\Classes and HKCU\Software Classes. Global settings go into HKLM. But the current user can overwrite them in HKCU.

That's usual windows behavior. So nothing special here. However...

I have an IIS ApplicationPool named AppPool01 with Idenity=ApplicationPoolIdentity and LoadUserProfile=True. In the background Windows creates a user AppPool01. In my little web application Environment.UserName is AppPool01. So far that's what I expected.

But if I query Request.LogonUserIdentity, that's the output:

User: S-1-5-17  
Name: NT-AUTORITÄT\IUSR  
AuthenticationType:  
ImpersonationLevel: Impersonation  
IsAnonymous: False  
IsGuest: False  
IsSystem: False  
Owner: S-1-5-17  

Somehow user AppPool01 impersonates IUSR or inherits from IUSR. So I'm not sure if this is a real user profile or just a pointer to IUSR's HKCU.

If it's just a pointer, the problem happens as follows: AppPool01 writes to her HKCU registry. Then AppPool02 writes to her HKCU registry, effectively overwriting AppPool01's settings. Then AppPool01 instantiates vfpdata.dll from the wrong path.

Do you know if an AppPool's ApplicationPoolIdentity user get's just a pointer to IUSR's HKCU or a real own HKCU?

Gravatar is a globally recognized avatar based on your email address. re: How to have ASP.NET load a VFP COM server from a given path
  Markus Winhard
  Markus Winhard
  May 25, 2021 @ 07:15am

In the meanwhile we have tested enough with Server 2019 and Server 2016. An IIS ApplicationPool with Idenity=ApplicationPoolIdentity and LoadUserProfile=True has a real user profile. Whatever you write into HKCU registry cannot be seen from other IIS ApplicationPools.

So it works the same as a real user's HKCU registry. Nothing special here.

Hope this helps someone else some day.

© 1996-2024