I'm relatively new to PHP development. I hope this is the appropriate area for this question since I was thinking maybe I could use the opportunity to get involved with the internals by making a patch regarding how DLLs are loaded.

Specifically, the extension_dir="path" directive which only allows a single path for finding dlls.

I'm nearly done with a new Windows-based PHP extension (php_wildcat.dll) and one of the issues was DLL dependencies.

The PHP extension offers direct SDK/API support for our application server and all our DLLs are in a specific server folder.

The installation of the Extension is preferred to be placed in our server folder so ideally, something like so would be ideal:

   extension_dir="./ext;c:/wildcat"

But of course, this isn't supported and it will not work, in fact, it fails the loading of other PHP extensions.

The official method of placing extensions in the PHP "./Ext" requires that we alter our long (12 years) recommended policy of a) not copying our DLLS to other folders (for auto update/version control reasons) or not requiring of adding the server folder in the Windows PATH.

I came up with an somewhat "kludgy" solution but I somewhat feel this has to be a common PHP extension issues with extension authors, thus maybe I must of a missed something where I don't have to do any of this.

The solution I came up with is to use DELAY LOADING where the extension is compiled and linked with delayed loading of implicit dlls.

For example: the extension is compiled/linked using pragma directives like so:

#define USE_DELAY_LOADING
...
#ifdef USE_DELAY_LOADING
#  pragma comment(lib, "delayimp.lib")
#  pragma comment(linker, "/delayload:wcsrv2.dll")
#  pragma comment(linker, "/delayload:door32.dll")
#endif

delayimp.lib is part of the VC6.0 C/C++ runtime library and it handles the delayed implicit loading of dlls. The DLLs above are part of our RPC server API interface.

Now, our RPC server folder is recorded in the registry so using the dll entry point DllMain(), the registry location is read and this is used to add to the process environment path. So I have this at the end of my PHP_WILDCAT.CPP code:

#ifdef USE_DELAY_LOADING

#define GETENV GetEnvironmentVariable
#define SETENV SetEnvironmentVariable

BOOL GetRegistry(const TCHAR *key,
                 const TCHAR *name,
                 DWORD type,
                 void *data,
                 DWORD datasize)
{
  BOOL ok = FALSE;
  HKEY k;
  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
            key, 0, KEY_READ, &k) == ERROR_SUCCESS) {
    DWORD t;
    if (RegQueryValueEx(k, (TCHAR *)name,  NULL,
            &t, (BYTE *)data, &datasize) == ERROR_SUCCESS) {
      ok = t == type;
    }
    RegCloseKey(k);
  }
  return ok;
}

BOOL GetRegistryString(const TCHAR *name,
                       TCHAR *data,
                       DWORD datasize,
                       const TCHAR *key = "SOFTWARE\\SSI\\Wildcat")
{
  return GetRegistry(key, name, REG_SZ, data, datasize);
}

BOOL PrepareWildcatPath()
{
   char srvPath[MAX_PATH]={0};
   if (GetRegistryString("ServerDirectory",srvPath,MAX_PATH-1)) {
      char ePath[1024*4] = {0};
      strcpy(ePath,srvPath);
      strcat(ePath,";");
      DWORD dw = strlen(ePath);
      return (GETENV("PATH",&ePath[dw],sizeof(ePath)-dw) &&
              SETENV("PATH",ePath));
   }
   return FALSE;
}

////////////////////////////////////////////////////////////////////
// DllMain
////////////////////////////////////////////////////////////////////

BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID)
{
  switch (dwReason) {
    case DLL_PROCESS_ATTACH:
      PrepareWildcatPath();
      break;
  }
  return TRUE;
}

#endif

This works really well. We can install PHP*.DLLs in the PHP "./EXT" folder and when the extension is loaded by PHP, all of its dependencies are now resolved during the temporary PHP runtime residence time.

I could of gone deeper (and more elegant without having to alter the process PATH) by using the delayimp.lib helper hooks available which will issue a callback for the delayed implicit dlls. But seems overly complexed and before I begin on that I wanted so see if a) there was already a method to address this and/or b) I could patch PHP to offer an multi-path extension_dir method.

Ideally we would love to keep our specific PHP*.DLL files in our server folder and have extension_dir defined to look at multiple paths.

Comments?

TIA

--
Hector Santos


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to