Jump to content
Mark Williams

Manipulating IIS with the Application Host Administration Interface - OLE issues

Recommended Posts

Posted (edited)

I cannot understand why the following code does not work:

 

function IsOleObjectActive(OleObject: OleVariant): Boolean;
begin
  Result := not VarIsClear(OleObject) and not VarIsEmpty(OleObject) and not VarIsNull(OleObject);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ServerManager: OleVariant;
  Site: OleVariant;
  AppPool: OleVariant;
  Security: OleVariant;
begin
  // Initialize COM library
  CoInitialize(nil);
  try
    // Create an instance of the ServerManager object
    ServerManager := CreateOleObject
      ('Microsoft.ApplicationHost.WritableAdminManager');

    ServerManager.CommitPath := 'MACHINE/WEBROOT/APPHOST';

    // Add a new site
    Site := ServerManager.GetAdminSection('system.applicationHost/sites',
      'MACHINE/WEBROOT/APPHOST');

-    if IsOleObjectActive(Site) then
      Showmessage('Active')
	 else
		exit;

    Site := Site.Collection.AddElement('site'); //FAILS HERE
    
	Site.Properties.Item('name').Value := trim(eSiteName.text);
    
    // Site.Properties.Item('id').Value := 2;
    Site.Properties.Item('physicalPath').Value := 'C:\inetpub\wwwroot\' + trim(ePhysicalPath.text);
    
    // Configure bindings
    Site.Bindings.Collection.AddElement('binding');
    Site.Bindings.Collection.Item(0).Properties.Item('protocol').Value
      := 'http';
    Site.Bindings.Collection.Item(0).Properties.Item('bindingInformation').Value
      := '*:80';

   
    Site.Bindings.Collection.AddElement('binding');
    Site.Bindings.Collection.Item(1).Properties.Item('protocol').Value
      := 'https';
    Site.Bindings.Collection.Item(1).Properties.Item('bindingInformation').Value
      := '*:443';
    
    // Add an application pool
    AppPool := ServerManager.GetAdminSection
      ('system.applicationHost/applicationPools', 'MACHINE/WEBROOT/APPHOST');
    AppPool := AppPool.Collection.AddElement('add');
  	AppPool.Properties.Item('name').Value := trim(eSiteName.text);
    AppPool.Properties.Item('managedRuntimeVersion').Value :=
      trim(eNetFramework.text);

    // Assign the application pool to the site
    Site.Applications.Collection.Item(0).Properties.Item('applicationPool')
      .Value := trim(eSiteName.text);
    
    // Commit the changes
    ServerManager.CommitChanges;
  finally
    // Uninitialize COM library
    CoUninitialize;
  end;

When I try to add the new site I get "Variant does not reference an automation object." 

 

I've tried adding the application pool first, but same problem.

 

As far as I can see the section names are correct as per the applicationHost.config file and all functions, properties are correct as per the nativerd.dll.

 

I've also tried running the app in elevated mode. Makes no difference.

Edited by Mark Williams

Share this post


Link to post

Try

Result := not (VarIsClear(OleObject) or VarIsEmpty(OleObject) or VarIsNull(OleObject)) and (VarType(OleObject) = VT_DISPATCH);

 

Share this post


Link to post

There is a type library you can import - would save a lot of casting C:\Windows\System32\inetsrv\nativerd.dll

 

It's a pretty awful api to work with, it's been a while since I looked at it - Microsoft created a pretty extensive dotnet wrapper for it - https://www.nuget.org/packages/Microsoft.Web.Administration you could download the nuget package and use Ilspy to have a look at it - might help

  • Thanks 1

Share this post


Link to post
On 1/6/2025 at 12:06 PM, PeterBelow said:

Try


Result := not (VarIsClear(OleObject) or VarIsEmpty(OleObject) or VarIsNull(OleObject)) and (VarType(OleObject) = VT_DISPATCH);

 

Same result. It reports true for Server Manager, but then fails with the variant does not reference... error on the call to ServerManager.GetAdminSection.

Share this post


Link to post
14 hours ago, Vincent Parrett said:

There is a type library you can import - would save a lot of casting C:\Windows\System32\inetsrv\nativerd.dll

 

It's a pretty awful api to work with, it's been a while since I looked at it - Microsoft created a pretty extensive dotnet wrapper for it - https://www.nuget.org/packages/Microsoft.Web.Administration you could download the nuget package and use Ilspy to have a look at it - might help

I had started to go down this route. I'm using the 64 bit type library, which is even more of a pain to use. It does seem to work however. Thanks for the reference to the dotnet wrapper.

Share this post


Link to post
11 hours ago, Mark Williams said:

Same result. It reports true for Server Manager, but then fails with the variant does not reference... error on the call to ServerManager.GetAdminSection.

Looks like the GetAdminSection function does not return an automation-compatible interface. Can you check what VarType the returned OleVariant has?

Share this post


Link to post
7 hours ago, PeterBelow said:

Looks like the GetAdminSection function does not return an automation-compatible interface. Can you check what VarType the returned OleVariant has?

The code I am using was an example I got off the web. Can't even remember where now! Can't fund the MS documentation for it although I can find the documentation for the Application Host Administration Interface.

If I change the call as follows:

 

Site := ServerManager.GetAdminSection('sites', 'system.applicationHost/');

I then get an error advising that the first parameter is not a valid section path in the config file. So I think the return value of an OLEVariant is okay. I think the problem lies with the parameters passed to the function. I think the first param is correct 'system.applicationHost/sites'. I think it is the second param that is causing the problem:'MACHINE/WEBROOT/APPHOST'.

 

The second param is already declared in  the call to:

 ServerManager.CommitPath := 'MACHINE/WEBROOT/APPHOST';

That is that is the path to the config file.

 

The MS documentation for the Application Host Administration Interface states it relates to IIS7 and IIS8 and I am using IIS10, but can't find later documentation and I have tested it a little with IIS10 and seems to work. The documentation declares the GetAdminSection function as

 

HRESULT GetAdminSection(  
   [in,  
   string] BSTR bstrSectionName,  
   [in,  
   string] BSTR bstrPath,  
   [out,  
   retval] IAppHostElement** ppAdminSection  
);  

Calling the function as:

GetAdminSection('system.applicationHost/', 'MACHINE/WEBROOT/APPHOST', SitesSection);

Results in a run time error that there are too many parameters. This works using thee imported type library, but not as an OLE call. That would suggest that the second parameter in the OLE call is also correct. 

 

As you can probably see I am floundering! I guess I will have to work with the rather yuk interface! Thanks for your help.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×