Re: How to add a new MimeType to a Virtual Directory with VC++?
You're right. It's a pain. The following code has worked for me in the past.
#include <windows.h> #include <stdio.h> #include <oleauto.h> #include <ActiveDS.h>
#import "inetsrv/adsiis.dll"
_COM_SMARTPTR_TYPEDEF(IADs, __uuidof(IADs));
#define RETURN_ON_FAILURE(hr) if (FAILED(hr)) return (hr);
// Trivial wrapper to ensure that array gets cleaned up by destructor // if function terminates early class VariantArray { public: VARIANT* pa;
VariantArray( size_t n ) : pa(new VARIANT [n]) { if (NULL == pa) _com_issue_error(E_OUTOFMEMORY); for (size_t i = 0; i < n; ++i) VariantInit(&pa[i]); }
~VariantArray() { delete [] pa; } };
class SafeArray { public: SAFEARRAY* psa;
SafeArray( VARTYPE vt, unsigned int cDims, SAFEARRAYBOUND* rgsabound ) : psa(SafeArrayCreate(vt, cDims, rgsabound)) { if (NULL == psa) _com_issue_error(E_OUTOFMEMORY); }
~SafeArray() { if (NULL != psa) SafeArrayDestroy(psa); } };
// Updates the MimeMap for pwszMimeMapPath. // If pwszExtn != NULL and there is an extension matching pwszExtn, // it is removed if pwszMimeType == NULL, or updated with pwszMimeMapPath // otherwise. // In other words // MimeMap(L"IIS://localhost/MimeMap", NULL, NULL) // just reads the mime map and prints it out // MimeMap(L"IIS://localhost/MimeMap", L".foo", NULL) // removes the mapping for ".foo", if it was present // MimeMap(L"IIS://localhost/MimeMap", L".foo", L"bar/quux") // sets the mapping for ".foo" to "bar/quux" HRESULT MimeMap( LPCWSTR pwszMimeMapPath, LPCWSTR pwszExtn, LPCWSTR pwszMimeType) { HRESULT hr = S_OK; IADsPtr pADs; _variant_t var; _bstr_t bstrNewExtn(pwszExtn); _bstr_t bstrNewMimeType(pwszMimeType); _bstr_t bstrPropname(L"MimeMap");
hr = ADsGetObject(pwszMimeMapPath, IID_IADs, (void**) &pADs); RETURN_ON_FAILURE(hr);
hr = pADs->GetEx(bstrPropname, &var); RETURN_ON_FAILURE(hr);
// We should now have an array of variants, each of which is a dispobject // that implements the IISMimeType interface
if ((VT_VARIANT | VT_ARRAY) != V_VT(&var)) return E_ADS_CANT_CONVERT_DATATYPE;
LONG i, j, lSLBound, lSUBound, cVariants = 0;
hr = SafeArrayGetLBound(V_ARRAY(&var), 1, &lSLBound ); RETURN_ON_FAILURE(hr);
hr = SafeArrayGetUBound(V_ARRAY(&var), 1, &lSUBound ); RETURN_ON_FAILURE(hr);
cVariants = lSUBound - lSLBound + 1;
// Allocate an array to make a local copy of the mime maps that // can be updated VariantArray va(cVariants + 1);
// Copy the mime maps into the local array for (i = lSLBound, j = 0; i <= lSUBound; ++i) { IISOle::IISMimeTypePtr pmt; VARIANT varTemp;
VariantInit(&varTemp);
hr = SafeArrayGetElement(V_ARRAY(&var), &i, &varTemp); RETURN_ON_FAILURE(hr);
if (VT_DISPATCH != V_VT(&varTemp)) return E_ADS_CANT_CONVERT_DATATYPE;
hr = V_DISPATCH(&varTemp)->QueryInterface( __uuidof(IISOle::IISMimeType), (void**) &pmt); RETURN_ON_FAILURE(hr);
_bstr_t bstrExtn(pmt->GetExtension()); _bstr_t bstrMimeType(pmt->GetMimeType());
printf("%ls -> %ls/n", (LPCWSTR) bstrExtn, (LPCWSTR) bstrMimeType);
if (bstrExtn == bstrNewExtn) { --cVariants; } else { va.pa[j++] = varTemp; } }
// Remove or update the mapping for pwszExtn? if (NULL != pwszExtn) { IISOle::IISMimeTypePtr pmt;
// Update the mapping if (NULL != pwszMimeType) { // Create a new MimeMap object hr = pmt.CreateInstance(L"MimeMap"); RETURN_ON_FAILURE(hr);
pmt->PutExtension(bstrNewExtn); pmt->PutMimeType(bstrNewMimeType);
// Append pmt to the array V_VT(&va.pa[cVariants]) = VT_DISPATCH; V_DISPATCH(&va.pa[cVariants]) = pmt;
++cVariants; }
// Create a safearray to hold the full set of mappings SAFEARRAYBOUND saBound = {cVariants, 0}; SafeArray sa(VT_VARIANT, 1, &saBound);
VARIANT varArray; VariantInit(&varArray);
V_VT(&varArray) = (VT_VARIANT | VT_ARRAY); V_ARRAY(&varArray) = sa.psa;
for (i = 0; i < cVariants; ++i) { hr = SafeArrayPutElement(sa.psa, &i, &va.pa[i]); RETURN_ON_FAILURE(hr); }
// Finally, write the map back. If the map is empty, // delete the property.
ADS_PROPERTY_OPERATION_ENUM apo = (cVariants != 0) ? ADS_PROPERTY_UPDATE : ADS_PROPERTY_CLEAR;
hr = pADs->PutEx(apo, bstrPropname, varArray); RETURN_ON_FAILURE(hr);
hr = pADs->SetInfo(); RETURN_ON_FAILURE(hr); }
return hr; }
int __cdecl main( int argc, char **argv) { UNREFERENCED_PARAMETER(argc); UNREFERENCED_PARAMETER(argv); HRESULT hr;
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
// hr = MimeMap(L"IIS://localhost/MimeMap", NULL, NULL); // hr = MimeMap(L"IIS://localhost/MimeMap", L".foo", L"bar/quux");
hr = MimeMap(L"IIS://localhost/w3svc/1/Root", L".foo", L"bar/quux");
CoUninitialize();
return 0; } // main()
--
-- I've turned my Laserjet into a death ray! (Get Witty Auto-Generated Signatures from http://SmartBee.org) George V. Reilly
"C K" < > wrote in message news: om... > Hi, > > I can't seem to figure out how to add a new MimeType to a virtual > directory's MimeMap. The problem is how do I create an IISMimeType > object to add to the MimeMap's SAFEARRAY? > > With VB, all you have to do is (Microsoft example): > Const ADS_PROPERTY_UPDATE = 2 > 'Get the mimemap object. > Set MimeMapObj = GetObject("IIS://LocalHost/MimeMap") > 'Get the mappings from the MimeMap property. > aMimeMap = MimeMapObj.GetEx("MimeMap") > i = UBound(aMimeMap) + 1 > Redim Preserve aMimeMap(i) > Set aMimeMap(i) = CreateObject("MimeMap") > aMimeMap(i).Extension = ".jnq" > aMimeMap(i).MimeType = "junque/my-junque" > MimeMapObj.PutEx ADS_PROPERTY_UPDATE, "MimeMap", aMimeMap > MimeMapObj.SetInfo > > With C++, the problem is that aMimeMap(i) is actually of type > IISMimeType. But since IISMimeType is an abstract base class, how do > I create the new MimeType? > It's not possible to do : > > CComPtr<IISMimeType> pMimeType; > HRESULT hr = pNewMimeType.CoCreateInstance(_uuidof(IISMimeType) ); > > hr will return with a "Class not Registered" error. > > Ideally I want to do something similar to (some code omitted): > > CComPtr<IISMimeType> pMimeType; > // error > HRESULT hr = pNewMimeType.CoCreateInstance(_uuidof(IISMimeType) ); > > > pMimeType->put_Extension(_bstr_t(szExtension)); > pMimeType->put_MimeType(_bstr_t(szMimeType)); > CComVariant vNewMime = pMimeType; > hr = ::SafeArrayPutElement(pArrMimeMap, &NewElemIdx, &vNewMime); > hr = pADs->PutEx(ADS_PROPERTY_UPDATE, _bstr_t(_T("MimeMap")), > vMimeMap); > hr = pADs->SetInfo(); > > So how do I do what the VB code did with VC++? > > Thanks for the help
|
Re: How to add a new MimeType to a Virtual Directory with VC++?
Hi George,
Thank you very much for the code!
I still don't understand why I wasn't able to createinstance an IISMimeType object. The only thing maybe is I didn't include the right headers. These are the ones I included:
#include <iiis.h> #include <iiisext.h> #include <iiscnfg.h>
I also linked with: ActiveDS.lib Adsiid.lib
The only difference is that you did it the #import way. Is there something that's not exposed in the headers? Because I did try something similar to what was in your code (without the #import):
CComPtr<IISMimeType> pMimeType; pMimeType.CoCreateInstance(__uuidof(IISMimeType));
which returned that class not registered failure.
Would you happen to know why this is?
Thanks.
"George V. Reilly" < > wrote in message news:<# >... > You're right. It's a pain. The following code has worked for me in the past. > > #include <windows.h> > #include <stdio.h> > #include <oleauto.h> > #include <ActiveDS.h> > > #import "inetsrv/adsiis.dll" > > _COM_SMARTPTR_TYPEDEF(IADs, __uuidof(IADs)); > > > #define RETURN_ON_FAILURE(hr) if (FAILED(hr)) return (hr); > > > > // Trivial wrapper to ensure that array gets cleaned up by destructor > // if function terminates early > class VariantArray > { > public: > VARIANT* pa; > > VariantArray( > size_t n > ) > : pa(new VARIANT [n]) > { > if (NULL == pa) > _com_issue_error(E_OUTOFMEMORY); > for (size_t i = 0; i < n; ++i) > VariantInit(&pa[i]); > } > > ~VariantArray() > { > delete [] pa; > } > }; > > class SafeArray > { > public: > SAFEARRAY* psa; > > SafeArray( > VARTYPE vt, > unsigned int cDims, > SAFEARRAYBOUND* rgsabound > ) > : psa(SafeArrayCreate(vt, cDims, rgsabound)) > { > if (NULL == psa) > _com_issue_error(E_OUTOFMEMORY); > } > > ~SafeArray() > { > if (NULL != psa) > SafeArrayDestroy(psa); > } > }; > > > // Updates the MimeMap for pwszMimeMapPath. > // If pwszExtn != NULL and there is an extension matching pwszExtn, > // it is removed if pwszMimeType == NULL, or updated with pwszMimeMapPath > // otherwise. > // In other words > // MimeMap(L"IIS://localhost/MimeMap", NULL, NULL) > // just reads the mime map and prints it out > // MimeMap(L"IIS://localhost/MimeMap", L".foo", NULL) > // removes the mapping for ".foo", if it was present > // MimeMap(L"IIS://localhost/MimeMap", L".foo", L"bar/quux") > // sets the mapping for ".foo" to "bar/quux" > HRESULT > MimeMap( > LPCWSTR pwszMimeMapPath, > LPCWSTR pwszExtn, > LPCWSTR pwszMimeType) > { > HRESULT hr = S_OK; > IADsPtr pADs; > _variant_t var; > _bstr_t bstrNewExtn(pwszExtn); > _bstr_t bstrNewMimeType(pwszMimeType); > _bstr_t bstrPropname(L"MimeMap"); > > hr = ADsGetObject(pwszMimeMapPath, IID_IADs, (void**) &pADs); > RETURN_ON_FAILURE(hr); > > hr = pADs->GetEx(bstrPropname, &var); > RETURN_ON_FAILURE(hr); > > // We should now have an array of variants, each of which is a > dispobject > // that implements the IISMimeType interface > > if ((VT_VARIANT | VT_ARRAY) != V_VT(&var)) > return E_ADS_CANT_CONVERT_DATATYPE; > > LONG i, j, lSLBound, lSUBound, cVariants = 0; > > hr = SafeArrayGetLBound(V_ARRAY(&var), 1, &lSLBound ); > RETURN_ON_FAILURE(hr); > > hr = SafeArrayGetUBound(V_ARRAY(&var), 1, &lSUBound ); > RETURN_ON_FAILURE(hr); > > cVariants = lSUBound - lSLBound + 1; > > // Allocate an array to make a local copy of the mime maps that > // can be updated > VariantArray va(cVariants + 1); > > // Copy the mime maps into the local array > for (i = lSLBound, j = 0; i <= lSUBound; ++i) > { > IISOle::IISMimeTypePtr pmt; > VARIANT varTemp; > > VariantInit(&varTemp); > > hr = SafeArrayGetElement(V_ARRAY(&var), &i, &varTemp); > RETURN_ON_FAILURE(hr); > > if (VT_DISPATCH != V_VT(&varTemp)) > return E_ADS_CANT_CONVERT_DATATYPE; > > hr = V_DISPATCH(&varTemp)->QueryInterface( > __uuidof(IISOle::IISMimeType), > (void**) &pmt); > RETURN_ON_FAILURE(hr); > > _bstr_t bstrExtn(pmt->GetExtension()); > _bstr_t bstrMimeType(pmt->GetMimeType()); > > printf("%ls -> %ls/n", (LPCWSTR) bstrExtn, (LPCWSTR) bstrMimeType); > > if (bstrExtn == bstrNewExtn) > { > --cVariants; > } > else > { > va.pa[j++] = varTemp; > } > } > > // Remove or update the mapping for pwszExtn? > if (NULL != pwszExtn) > { > IISOle::IISMimeTypePtr pmt; > > // Update the mapping > if (NULL != pwszMimeType) > { > // Create a new MimeMap object > hr = pmt.CreateInstance(L"MimeMap"); > RETURN_ON_FAILURE(hr); > > pmt->PutExtension(bstrNewExtn); > pmt->PutMimeType(bstrNewMimeType); > > // Append pmt to the array > V_VT(&va.pa[cVariants]) = VT_DISPATCH; > V_DISPATCH(&va.pa[cVariants]) = pmt; > > ++cVariants; > } > > // Create a safearray to hold the full set of mappings > SAFEARRAYBOUND saBound = {cVariants, 0}; > SafeArray sa(VT_VARIANT, 1, &saBound); > > VARIANT varArray; > VariantInit(&varArray); > > V_VT(&varArray) = (VT_VARIANT | VT_ARRAY); > V_ARRAY(&varArray) = sa.psa; > > for (i = 0; i < cVariants; ++i) > { > hr = SafeArrayPutElement(sa.psa, &i, &va.pa[i]); > RETURN_ON_FAILURE(hr); > } > > // Finally, write the map back. If the map is empty, > // delete the property. > > ADS_PROPERTY_OPERATION_ENUM apo > = (cVariants != 0) ? ADS_PROPERTY_UPDATE : ADS_PROPERTY_CLEAR; > > hr = pADs->PutEx(apo, bstrPropname, varArray); > RETURN_ON_FAILURE(hr); > > hr = pADs->SetInfo(); > RETURN_ON_FAILURE(hr); > } > > return hr; > } > > > int > __cdecl > main( > int argc, > char **argv) > { > UNREFERENCED_PARAMETER(argc); > UNREFERENCED_PARAMETER(argv); > HRESULT hr; > > CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); > > // hr = MimeMap(L"IIS://localhost/MimeMap", NULL, NULL); > // hr = MimeMap(L"IIS://localhost/MimeMap", L".foo", L"bar/quux"); > > hr = MimeMap(L"IIS://localhost/w3svc/1/Root", L".foo", L"bar/quux"); > > CoUninitialize(); > > return 0; > } // main() > > -- > > -- > I've turned my Laserjet into a death ray! > (Get Witty Auto-Generated Signatures from http://SmartBee.org) > George V. Reilly > > > > "C K" < > wrote in message > news: om... > > Hi, > > > > I can't seem to figure out how to add a new MimeType to a virtual > > directory's MimeMap. The problem is how do I create an IISMimeType > > object to add to the MimeMap's SAFEARRAY? > > > > With VB, all you have to do is (Microsoft example): > > Const ADS_PROPERTY_UPDATE = 2 > > 'Get the mimemap object. > > Set MimeMapObj = GetObject("IIS://LocalHost/MimeMap") > > 'Get the mappings from the MimeMap property. > > aMimeMap = MimeMapObj.GetEx("MimeMap") > > i = UBound(aMimeMap) + 1 > > Redim Preserve aMimeMap(i) > > Set aMimeMap(i) = CreateObject("MimeMap") > > aMimeMap(i).Extension = ".jnq" > > aMimeMap(i).MimeType = "junque/my-junque" > > MimeMapObj.PutEx ADS_PROPERTY_UPDATE, "MimeMap", aMimeMap > > MimeMapObj.SetInfo > > > > With C++, the problem is that aMimeMap(i) is actually of type > > IISMimeType. But since IISMimeType is an abstract base class, how do > > I create the new MimeType? > > It's not possible to do : > > > > CComPtr<IISMimeType> pMimeType; > > HRESULT hr = pNewMimeType.CoCreateInstance(_uuidof(IISMimeType) ); > > > > hr will return with a "Class not Registered" error. > > > > Ideally I want to do something similar to (some code omitted): > > > > CComPtr<IISMimeType> pMimeType; > > // error > > HRESULT hr = pNewMimeType.CoCreateInstance(_uuidof(IISMimeType) ); > > > > > > pMimeType->put_Extension(_bstr_t(szExtension)); > > pMimeType->put_MimeType(_bstr_t(szMimeType)); > > CComVariant vNewMime = pMimeType; > > hr = ::SafeArrayPutElement(pArrMimeMap, &NewElemIdx, &vNewMime); > > hr = pADs->PutEx(ADS_PROPERTY_UPDATE, _bstr_t(_T("MimeMap")), > > vMimeMap); > > hr = pADs->SetInfo(); > > > > So how do I do what the VB code did with VC++? > > > > Thanks for the help
|