C
ChrisWoodruff
I have a C++ function in a COM object that I am trying to implement in
VB.NET (the functionality, NOT the COM object, I want to remove the
requirement for the COM DLL)
I am an experienced VB programmer, but this is my first .NET app...
Original Code (what I have been doing and works)
VB6 (extra stuff removed for clarity)
Set objWbem = CreateObject("WbemScripting.SWbemLocator")
Set objSvc = objWbem.ConnectServer(ComputerName, "root")
Set objSysSec = objSvc.Get("__SystemSecurity=@")
lngReturn = objSysSec.GetSD(SD_Array)
If lngReturn = 0 Then
Dim Dacl As AccessControlList
Dim Ace As AccessControlEntry
Dim SD As SecurityDescriptor
Dim SDConverter As Object
Dim lngErr As Long
On Error Resume Next
Set SDConverter = New ADS_SD_WRAPPERLib.SD_Converter
' ----- COM CALL
Set SD = SDConverter.GetADsSecurityDescriptor(SD_Array)
Set Dacl = SD.DiscretionaryAcl
Set Ace = CreateObject("AccessControlEntry")
Ace.AccessMask = WBEM_REMOTE_ACCESS _
+ WBEM_ENABLE _
+ READ_CONTROL _
+ WBEM_METHOD_EXECUTE
Ace.AceType = ADS_ACETYPE_ACCESS_ALLOWED
Ace.AceFlags = ADS_ACEFLAG_INHERIT_ACE
Ace.TRUSTEE = TRUSTEE ' String Value 'DOMAIN\USER'
Dacl.AddAce Ace
SD.DiscretionaryAcl = Dacl
' ----- COM CALL
SD_Array = SDConverter.GetBinarySecurityDescriptor(SD)
lngReturn = objSysSec.SetSD(SD_Array)
If lngReturn = 0 Then 'Successful setting permission
' Worked!
End If
End If
' ----- END VB6 CODE
The two calls being made in the C++ COM object are converting the byte
array received from SetSD into a Security Descriptor (so I can manipulate
it) then back again (so I can apply it)
The C++ code (bottom of this message) is manipulating the array via calls
to GetSafeArray (which are "arrays" in VB6 - I "assume" that won't be a
problem in .NET.) The problem I have is with the call to
"CoCreateInstance".
I don't think I'm supposed to use that call in .NET, but I don't know the
VB.NET equivelent. When I try to perform this same functionality, the
return code I get (from ym CoCreateInstance call in VB .NET) is -2147221164
(0x80040154) - according the error code lookup tool it means "Class not
registered". I'm assuming that they are talking about the reference to
CLSID_PropertyValue ("7b9e38b0-a97c-11d0-8534-00c04fd8d503" - which from
looking in the registry doesn't appear to have a "Class name", just a
reference to ActiveDS.dll)
Anyway, can someone tell me how I can do this in .NET? I've been reading
up on this stuff but I can't seem to find the "one piece" that I'm
missing...
Thanks
Chris
STDMETHODIMP CSD_Converter::GetADsSecurityDescriptor(VARIANT array_variant,
IUnknown **ADsSecurityDescriptor)
{
// TODO: Add your implementation code here
/* */
/* Create and fill SafeArray */
/* SafeArrayCreation code removed */
HRESULT hr;
long lbound = 0;
long ubound = 0;
VariantClear(&vt);
vt.vt = VT_ARRAY|VT_UI1;
vt.parray = psa;
// bind to directory object
IADsPropertyValue2 *pVal2 = NULL;
hr = CoCreateInstance
(CLSID_PropertyValue,NULL,CLSCTX_INPROC_SERVER,IID_IADsPropertyValue2,
(void**)&pVal2);
if (SUCCEEDED(hr))
{
hr = pVal2->PutObjectProperty(ADSTYPE_OCTET_STRING,vt);
VariantClear(&vt);
if (SUCCEEDED(hr))
{
long type = ADSTYPE_NT_SECURITY_DESCRIPTOR;
hr = pVal2->GetObjectProperty(&type,&vt);
if (SUCCEEDED(hr))
{
*ADsSecurityDescriptor = vt.punkVal;
}
}
pVal2->Release();
}
else
SafeArrayDestroy(psa);
CoUninitialize();
return hr;
}
STDMETHODIMP CSD_Converter::GetBinarySecurityDescriptor(IUnknown
*ADsSecurityDescriptor, VARIANT* p_array_variant)
{
// TODO: Add your implementation code here
HRESULT hr;
VARIANT vt,vtbyte;
vt.vt = VT_DISPATCH;
hr = ADsSecurityDescriptor->QueryInterface(IID_IDispatch,(void**)&
(vt.pdispVal));
IADsPropertyValue2 *pVal2 = NULL;
hr = CoCreateInstance
(CLSID_PropertyValue,NULL,CLSCTX_INPROC_SERVER,IID_IADsPropertyValue2,
(void**)&pVal2);
if (SUCCEEDED(hr))
{
hr = pVal2->PutObjectProperty(ADSTYPE_NT_SECURITY_DESCRIPTOR,vt);
VariantClear(&vt);
if (SUCCEEDED(hr))
{
long type = ADSTYPE_OCTET_STRING;
hr = pVal2->GetObjectProperty(&type,&vt);
if (SUCCEEDED(hr) && (vt.vt == (VT_ARRAY|VT_UI1)))
{
/* */
/* Create and fill SafeArray */
/* */
long lbound = 0;
long ubound = 0;
if (FAILED(SafeArrayGetLBound(vt.parray,1,&lbound)))
return E_FAIL;
if (FAILED(SafeArrayGetUBound(vt.parray,1,&ubound)))
return E_FAIL;
SAFEARRAY *psa = NULL;
SAFEARRAYBOUND saBounds;
saBounds.cElements = ubound-lbound+1;
saBounds.lLbound = 0;
psa = SafeArrayCreate(VT_VARIANT, 1, &saBounds);
unsigned char bVal;
VariantClear(&vtbyte);
vtbyte.vt = VT_UI1;
long j = 0;
long index = 1;
for (long i=lbound; i<=ubound; i++)
{
if (SUCCEEDED(hr=SafeArrayGetElement(vt.parray,&i,(void*)&bVal)))
{
vtbyte.bVal = bVal;
hr=SafeArrayPutElement(psa,&j,(void*)&vtbyte);
j++;
}
else
{
SafeArrayDestroy(psa);
return hr;
}
}
VariantClear(p_array_variant);
p_array_variant->vt = VT_ARRAY|VT_VARIANT;
p_array_variant->parray = psa;
VariantClear(&vt);
}
}
pVal2->Release();
}
else
VariantClear(&vt);
return hr;
}
VB.NET (the functionality, NOT the COM object, I want to remove the
requirement for the COM DLL)
I am an experienced VB programmer, but this is my first .NET app...
Original Code (what I have been doing and works)
VB6 (extra stuff removed for clarity)
Set objWbem = CreateObject("WbemScripting.SWbemLocator")
Set objSvc = objWbem.ConnectServer(ComputerName, "root")
Set objSysSec = objSvc.Get("__SystemSecurity=@")
lngReturn = objSysSec.GetSD(SD_Array)
If lngReturn = 0 Then
Dim Dacl As AccessControlList
Dim Ace As AccessControlEntry
Dim SD As SecurityDescriptor
Dim SDConverter As Object
Dim lngErr As Long
On Error Resume Next
Set SDConverter = New ADS_SD_WRAPPERLib.SD_Converter
' ----- COM CALL
Set SD = SDConverter.GetADsSecurityDescriptor(SD_Array)
Set Dacl = SD.DiscretionaryAcl
Set Ace = CreateObject("AccessControlEntry")
Ace.AccessMask = WBEM_REMOTE_ACCESS _
+ WBEM_ENABLE _
+ READ_CONTROL _
+ WBEM_METHOD_EXECUTE
Ace.AceType = ADS_ACETYPE_ACCESS_ALLOWED
Ace.AceFlags = ADS_ACEFLAG_INHERIT_ACE
Ace.TRUSTEE = TRUSTEE ' String Value 'DOMAIN\USER'
Dacl.AddAce Ace
SD.DiscretionaryAcl = Dacl
' ----- COM CALL
SD_Array = SDConverter.GetBinarySecurityDescriptor(SD)
lngReturn = objSysSec.SetSD(SD_Array)
If lngReturn = 0 Then 'Successful setting permission
' Worked!
End If
End If
' ----- END VB6 CODE
The two calls being made in the C++ COM object are converting the byte
array received from SetSD into a Security Descriptor (so I can manipulate
it) then back again (so I can apply it)
The C++ code (bottom of this message) is manipulating the array via calls
to GetSafeArray (which are "arrays" in VB6 - I "assume" that won't be a
problem in .NET.) The problem I have is with the call to
"CoCreateInstance".
I don't think I'm supposed to use that call in .NET, but I don't know the
VB.NET equivelent. When I try to perform this same functionality, the
return code I get (from ym CoCreateInstance call in VB .NET) is -2147221164
(0x80040154) - according the error code lookup tool it means "Class not
registered". I'm assuming that they are talking about the reference to
CLSID_PropertyValue ("7b9e38b0-a97c-11d0-8534-00c04fd8d503" - which from
looking in the registry doesn't appear to have a "Class name", just a
reference to ActiveDS.dll)
Anyway, can someone tell me how I can do this in .NET? I've been reading
up on this stuff but I can't seem to find the "one piece" that I'm
missing...
Thanks
Chris
STDMETHODIMP CSD_Converter::GetADsSecurityDescriptor(VARIANT array_variant,
IUnknown **ADsSecurityDescriptor)
{
// TODO: Add your implementation code here
/* */
/* Create and fill SafeArray */
/* SafeArrayCreation code removed */
HRESULT hr;
long lbound = 0;
long ubound = 0;
VariantClear(&vt);
vt.vt = VT_ARRAY|VT_UI1;
vt.parray = psa;
// bind to directory object
IADsPropertyValue2 *pVal2 = NULL;
hr = CoCreateInstance
(CLSID_PropertyValue,NULL,CLSCTX_INPROC_SERVER,IID_IADsPropertyValue2,
(void**)&pVal2);
if (SUCCEEDED(hr))
{
hr = pVal2->PutObjectProperty(ADSTYPE_OCTET_STRING,vt);
VariantClear(&vt);
if (SUCCEEDED(hr))
{
long type = ADSTYPE_NT_SECURITY_DESCRIPTOR;
hr = pVal2->GetObjectProperty(&type,&vt);
if (SUCCEEDED(hr))
{
*ADsSecurityDescriptor = vt.punkVal;
}
}
pVal2->Release();
}
else
SafeArrayDestroy(psa);
CoUninitialize();
return hr;
}
STDMETHODIMP CSD_Converter::GetBinarySecurityDescriptor(IUnknown
*ADsSecurityDescriptor, VARIANT* p_array_variant)
{
// TODO: Add your implementation code here
HRESULT hr;
VARIANT vt,vtbyte;
vt.vt = VT_DISPATCH;
hr = ADsSecurityDescriptor->QueryInterface(IID_IDispatch,(void**)&
(vt.pdispVal));
IADsPropertyValue2 *pVal2 = NULL;
hr = CoCreateInstance
(CLSID_PropertyValue,NULL,CLSCTX_INPROC_SERVER,IID_IADsPropertyValue2,
(void**)&pVal2);
if (SUCCEEDED(hr))
{
hr = pVal2->PutObjectProperty(ADSTYPE_NT_SECURITY_DESCRIPTOR,vt);
VariantClear(&vt);
if (SUCCEEDED(hr))
{
long type = ADSTYPE_OCTET_STRING;
hr = pVal2->GetObjectProperty(&type,&vt);
if (SUCCEEDED(hr) && (vt.vt == (VT_ARRAY|VT_UI1)))
{
/* */
/* Create and fill SafeArray */
/* */
long lbound = 0;
long ubound = 0;
if (FAILED(SafeArrayGetLBound(vt.parray,1,&lbound)))
return E_FAIL;
if (FAILED(SafeArrayGetUBound(vt.parray,1,&ubound)))
return E_FAIL;
SAFEARRAY *psa = NULL;
SAFEARRAYBOUND saBounds;
saBounds.cElements = ubound-lbound+1;
saBounds.lLbound = 0;
psa = SafeArrayCreate(VT_VARIANT, 1, &saBounds);
unsigned char bVal;
VariantClear(&vtbyte);
vtbyte.vt = VT_UI1;
long j = 0;
long index = 1;
for (long i=lbound; i<=ubound; i++)
{
if (SUCCEEDED(hr=SafeArrayGetElement(vt.parray,&i,(void*)&bVal)))
{
vtbyte.bVal = bVal;
hr=SafeArrayPutElement(psa,&j,(void*)&vtbyte);
j++;
}
else
{
SafeArrayDestroy(psa);
return hr;
}
}
VariantClear(p_array_variant);
p_array_variant->vt = VT_ARRAY|VT_VARIANT;
p_array_variant->parray = psa;
VariantClear(&vt);
}
}
pVal2->Release();
}
else
VariantClear(&vt);
return hr;
}