* Added internal support for expiring links replication.
* Added support for RPC session key change.
This commit is contained in:
parent
175cd2f2bc
commit
3b8beb1557
|
@ -73,6 +73,7 @@ namespace DSInternals
|
|||
DRS_EXTENSIONS_INT serverInfo = DRS_EXTENSIONS_INT(genericServerInfo);
|
||||
this->_serverSiteObjectGuid = RpcTypeConverter::ToGuid(serverInfo.siteObjGuid);
|
||||
this->_serverReplEpoch = serverInfo.dwReplEpoch;
|
||||
this->_serverCapabilities = serverInfo.dwFlags;
|
||||
}
|
||||
|
||||
array<byte>^ DrsConnection::SessionKey::get()
|
||||
|
@ -89,7 +90,7 @@ namespace DSInternals
|
|||
{
|
||||
auto clientInfo = make_midl_ptr<DRS_EXTENSIONS_INT>();
|
||||
clientInfo->dwFlags = DRS_EXT::ALL_EXT;
|
||||
clientInfo->dwFlagsExt = DRS_EXT2::DRS_EXT_LH_BETA2;
|
||||
clientInfo->dwFlagsExt = DRS_EXT2::DRS_EXT_LH_BETA2 | DRS_EXT2::DRS_EXT_RECYCLE_BIN | DRS_EXT2::DRS_EXT_PAM;
|
||||
clientInfo->dwExtCaps = DRS_EXT2::DRS_EXT_LH_BETA2 | DRS_EXT2::DRS_EXT_RECYCLE_BIN | DRS_EXT2::DRS_EXT_PAM;
|
||||
clientInfo->dwReplEpoch = this->_serverReplEpoch;
|
||||
return clientInfo;
|
||||
|
@ -134,10 +135,10 @@ namespace DSInternals
|
|||
return managedCursors;
|
||||
}
|
||||
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V8> DrsConnection::CreateGenericReplicateRequest(midl_ptr<DSNAME> &&dsName, array<ATTRTYP>^ partialAttributeSet, ULONG maxBytes, ULONG maxObjects)
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V10> DrsConnection::CreateGenericReplicateRequest(midl_ptr<DSNAME> &&dsName, array<ATTRTYP>^ partialAttributeSet, ULONG maxBytes, ULONG maxObjects)
|
||||
{
|
||||
// TODO: Add support for Windows Server 2003
|
||||
auto request = make_midl_ptr<DRS_MSG_GETCHGREQ_V8>();
|
||||
auto request = make_midl_ptr<DRS_MSG_GETCHGREQ_V10>();
|
||||
// Inset client ID:
|
||||
request->uuidDsaObjDest = RpcTypeConverter::ToUUID(this->_clientDsa);
|
||||
// Insert DSNAME
|
||||
|
@ -164,7 +165,7 @@ namespace DSInternals
|
|||
return request;
|
||||
}
|
||||
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V8> DrsConnection::CreateReplicateAllRequest(ReplicationCookie^ cookie, array<ATTRTYP>^ partialAttributeSet, ULONG maxBytes, ULONG maxObjects)
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V10> DrsConnection::CreateReplicateAllRequest(ReplicationCookie^ cookie, array<ATTRTYP>^ partialAttributeSet, ULONG maxBytes, ULONG maxObjects)
|
||||
{
|
||||
auto ncToReplicate = RpcTypeConverter::ToDsName(cookie->NamingContext);
|
||||
auto request = CreateGenericReplicateRequest(move(ncToReplicate), partialAttributeSet, maxBytes, maxObjects);
|
||||
|
@ -177,7 +178,7 @@ namespace DSInternals
|
|||
return request;
|
||||
}
|
||||
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V8> DrsConnection::CreateReplicateSingleRequest(Guid objectGuid, array<ATTRTYP>^ partialAttributeSet)
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V10> DrsConnection::CreateReplicateSingleRequest(Guid objectGuid, array<ATTRTYP>^ partialAttributeSet)
|
||||
{
|
||||
auto objectToReplicate = RpcTypeConverter::ToDsName(objectGuid);
|
||||
auto request = CreateGenericReplicateRequest(move(objectToReplicate), partialAttributeSet, defaultMaxBytes, defaultMaxObjects);
|
||||
|
@ -187,7 +188,7 @@ namespace DSInternals
|
|||
return request;
|
||||
}
|
||||
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V8> DrsConnection::CreateReplicateSingleRequest(String^ distinguishedName, array<ATTRTYP>^ partialAttributeSet)
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V10> DrsConnection::CreateReplicateSingleRequest(String^ distinguishedName, array<ATTRTYP>^ partialAttributeSet)
|
||||
{
|
||||
auto objectToReplicate = RpcTypeConverter::ToDsName(distinguishedName);
|
||||
auto request = CreateGenericReplicateRequest(move(objectToReplicate), partialAttributeSet, defaultMaxBytes, defaultMaxObjects);
|
||||
|
@ -282,7 +283,7 @@ namespace DSInternals
|
|||
}
|
||||
}
|
||||
|
||||
midl_ptr<DRS_MSG_GETCHGREPLY_V6> DrsConnection::GetNCChanges(midl_ptr<DRS_MSG_GETCHGREQ_V8> &&request)
|
||||
midl_ptr<DRS_MSG_GETCHGREPLY_V9> DrsConnection::GetNCChanges(midl_ptr<DRS_MSG_GETCHGREQ_V10> &&request)
|
||||
{
|
||||
// Validate connection
|
||||
if (this->IsInvalid)
|
||||
|
@ -291,17 +292,36 @@ namespace DSInternals
|
|||
throw gcnew Exception("Not connected");
|
||||
}
|
||||
DRS_HANDLE handle = this->handle.ToPointer();
|
||||
const DWORD inVersion = 8;
|
||||
const DWORD inVersion = this->MaxSupportedReplicationRequestVersion;
|
||||
DWORD outVersion = 0;
|
||||
auto reply = make_midl_ptr<DRS_MSG_GETCHGREPLY_V6>();
|
||||
auto reply = make_midl_ptr<DRS_MSG_GETCHGREPLY_V9>();
|
||||
// Send message:
|
||||
auto result = (Win32ErrorCode) IDL_DRSGetNCChanges_NoSEH(handle, inVersion, (DRS_MSG_GETCHGREQ*)request.get(), &outVersion, (DRS_MSG_GETCHGREPLY*)reply.get());
|
||||
|
||||
// Validate result
|
||||
// TODO: Check the returned version
|
||||
Validator::AssertSuccess(result);
|
||||
|
||||
// TODO: Test extended error code:
|
||||
DWORD extendedError = reply->dwDRSError;
|
||||
|
||||
// Check the returned structure version
|
||||
if (outVersion == 6 && reply->cNumValues > 0)
|
||||
{
|
||||
// We will now convert the REPLVALINF_V1 array into REPLVALINF_V3 array so that the caller does not have to differentiate between them.
|
||||
// This convenience comes at the price of a minor performance loss
|
||||
auto valuesV1 = ((DRS_MSG_GETCHGREPLY_V6*)reply.get())->rgValues;
|
||||
auto valuesV3 = make_midl_ptr<REPLVALINF_V3>(reply->cNumValues);
|
||||
|
||||
for (DWORD i = 0; i < reply->cNumValues; i++)
|
||||
{
|
||||
memcpy(&(valuesV3.get()[i]), &valuesV1[i], sizeof(REPLVALINF_V1));
|
||||
}
|
||||
|
||||
// Assign the new value and delete the old one. Only shallow free must be done.
|
||||
reply->rgValues = valuesV3.release();
|
||||
midl_user_free(valuesV1);
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
|
@ -485,7 +505,7 @@ namespace DSInternals
|
|||
return managedAttribute;
|
||||
}
|
||||
|
||||
ReplicaAttribute^ DrsConnection::ReadAttribute(const REPLVALINF_V1 &attribute)
|
||||
ReplicaAttribute^ DrsConnection::ReadAttribute(const REPLVALINF_V3 &attribute)
|
||||
{
|
||||
auto value = ReadValue(attribute.Aval);
|
||||
auto managedAttribute = gcnew ReplicaAttribute(attribute.attrTyp, value);
|
||||
|
@ -516,7 +536,7 @@ namespace DSInternals
|
|||
auto dn = ReadName(object.pName);
|
||||
return gcnew ReplicaObject(dn, guid, sid, attributes);
|
||||
}
|
||||
ReplicaObjectCollection^ DrsConnection::ReadObjects(const REPLENTINFLIST *objects, int objectCount, const REPLVALINF_V1 *linkedValues, int valueCount)
|
||||
ReplicaObjectCollection^ DrsConnection::ReadObjects(const REPLENTINFLIST *objects, int objectCount, const REPLVALINF_V3 *linkedValues, int valueCount)
|
||||
{
|
||||
// Read linked values first
|
||||
// TODO: Handle the case when linked attributes of an object are split between reveral responses.
|
||||
|
@ -574,25 +594,22 @@ namespace DSInternals
|
|||
return gcnew SecurityIdentifier(IntPtr((void*)&dsName->Sid));
|
||||
}
|
||||
|
||||
//! This method is called each time a RPC session key is negotiated.
|
||||
void DrsConnection::RetrieveSessionKey(void* rpcContext)
|
||||
{
|
||||
if (this->SessionKey != nullptr)
|
||||
{
|
||||
// This function sometimes gets called twice by Windows, so do not continue, if we already have the session key
|
||||
return;
|
||||
}
|
||||
// Retrieve RPC Security Context
|
||||
PSecHandle securityContext = nullptr;
|
||||
RPC_STATUS status1 = I_RpcBindingInqSecurityContext(rpcContext, (void**)&securityContext);
|
||||
if (status1 != 0)
|
||||
RPC_STATUS rpcStatus = I_RpcBindingInqSecurityContext(rpcContext, (void**)&securityContext);
|
||||
if (rpcStatus != RPC_S_OK)
|
||||
{
|
||||
// TODO: Error
|
||||
// We could not acquire the security context, so do not continue with session key retrieval
|
||||
return;
|
||||
}
|
||||
// Retrieve the Session Key information from Security Context
|
||||
SecPkgContext_SessionKey nativeKey = {};
|
||||
SECURITY_STATUS status2 = QueryContextAttributes(securityContext, SECPKG_ATTR_SESSION_KEY, &nativeKey);
|
||||
SECURITY_STATUS secStatus = QueryContextAttributes(securityContext, SECPKG_ATTR_SESSION_KEY, &nativeKey);
|
||||
// Extract the actual key if the authentication schema uses one
|
||||
if (nativeKey.SessionKey != nullptr)
|
||||
if (secStatus == SEC_E_OK && nativeKey.SessionKey != nullptr)
|
||||
{
|
||||
array<byte>^ managedKey = gcnew array<byte>(nativeKey.SessionKeyLength);
|
||||
// Pin it so the GC does not touch it
|
||||
|
@ -600,10 +617,27 @@ namespace DSInternals
|
|||
// Copy data from native to managed memory
|
||||
memcpy(pinnedManagedKey, nativeKey.SessionKey, nativeKey.SessionKeyLength);
|
||||
// Do not forget to free the unmanaged memory
|
||||
SECURITY_STATUS status3 = FreeContextBuffer(nativeKey.SessionKey);
|
||||
secStatus = FreeContextBuffer(nativeKey.SessionKey);
|
||||
this->_sessionKey = managedKey;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD DrsConnection::MaxSupportedReplicationRequestVersion::get()
|
||||
{
|
||||
DWORD version = 5;
|
||||
|
||||
if (this->_serverCapabilities & DRS_EXT::DRS_EXT_GETCHGREQ_V8)
|
||||
{
|
||||
version = 8;
|
||||
}
|
||||
|
||||
if (this->_serverCapabilities & DRS_EXT::DRS_EXT_GETCHGREQ_V10)
|
||||
{
|
||||
version = 10;
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ namespace DSInternals
|
|||
array<byte>^ _sessionKey;
|
||||
Guid _clientDsa;
|
||||
Guid _serverSiteObjectGuid;
|
||||
DRS_EXT _serverCapabilities;
|
||||
DWORD _serverReplEpoch;
|
||||
SecurityCallback^ _securityCallback;
|
||||
static const size_t defaultMaxObjects = 1000;
|
||||
|
@ -59,26 +60,30 @@ namespace DSInternals
|
|||
protected:
|
||||
virtual bool ReleaseHandle() override;
|
||||
private:
|
||||
property DWORD MaxSupportedReplicationRequestVersion
|
||||
{
|
||||
DWORD get();
|
||||
}
|
||||
DrsConnection();
|
||||
void Bind(IntPtr rpcHandle);
|
||||
midl_ptr<DRS_MSG_GETCHGREPLY_V6> GetNCChanges(midl_ptr<DRS_MSG_GETCHGREQ_V8> &&request);
|
||||
midl_ptr<DRS_MSG_GETCHGREPLY_V9> GetNCChanges(midl_ptr<DRS_MSG_GETCHGREQ_V10> &&request);
|
||||
midl_ptr<DRS_MSG_CRACKREPLY_V1> CrackNames(midl_ptr<DRS_MSG_CRACKREQ_V1> &&request);
|
||||
String^ TryResolveName(String^ name, DS_NAME_FORMAT formatOffered, DS_NAME_FORMAT formatDesired);
|
||||
midl_ptr<DRS_EXTENSIONS_INT> CreateClientInfo();
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V8> CreateReplicateAllRequest(ReplicationCookie^ cookie, array<ATTRTYP>^ partialAttributeSet, ULONG maxBytes, ULONG maxObjects);
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V8> CreateReplicateSingleRequest(String^ distinguishedName, array<ATTRTYP>^ partialAttributeSet);
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V8> CreateReplicateSingleRequest(Guid objectGuid, array<ATTRTYP>^ partialAttributeSet);
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V8> CreateGenericReplicateRequest(midl_ptr<DSNAME> &&dsName, array<ATTRTYP>^ partialAttributeSet, ULONG maxBytes, ULONG maxObjects);
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V10> CreateReplicateAllRequest(ReplicationCookie^ cookie, array<ATTRTYP>^ partialAttributeSet, ULONG maxBytes, ULONG maxObjects);
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V10> CreateReplicateSingleRequest(String^ distinguishedName, array<ATTRTYP>^ partialAttributeSet);
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V10> CreateReplicateSingleRequest(Guid objectGuid, array<ATTRTYP>^ partialAttributeSet);
|
||||
midl_ptr<DRS_MSG_GETCHGREQ_V10> CreateGenericReplicateRequest(midl_ptr<DSNAME> &&dsName, array<ATTRTYP>^ partialAttributeSet, ULONG maxBytes, ULONG maxObjects);
|
||||
void RetrieveSessionKey(void* rpcContext);
|
||||
static midl_ptr<DRS_MSG_GETREPLINFO_REQ_V1> CreateReplicationCursorsRequest(String^ namingContext);
|
||||
static midl_ptr<PARTIAL_ATTR_VECTOR_V1_EXT> CreateNativePas(array<ATTRTYP>^ partialAttributeSet);
|
||||
static array<byte>^ ReadValue(const ATTRVAL &value);
|
||||
static array<array<byte>^>^ ReadValues(const ATTRVALBLOCK &values);
|
||||
static ReplicaAttribute^ ReadAttribute(const ATTR &attribute);
|
||||
static ReplicaAttribute^ ReadAttribute(const REPLVALINF_V1 &attribute);
|
||||
static ReplicaAttribute^ ReadAttribute(const REPLVALINF_V3 &attribute);
|
||||
static ReplicaAttributeCollection^ ReadAttributes(const ATTRBLOCK &attributes);
|
||||
static ReplicaObject^ ReadObject(const ENTINF &object);
|
||||
static ReplicaObjectCollection^ ReadObjects(const REPLENTINFLIST *objects, int objectCount, const REPLVALINF_V1 *linkedValues, int valueCount);
|
||||
static ReplicaObjectCollection^ ReadObjects(const REPLENTINFLIST *objects, int objectCount, const REPLVALINF_V3 *linkedValues, int valueCount);
|
||||
static Guid ReadGuid(GUID const &guid);
|
||||
static String^ ReadName(const DSNAME* dsName);
|
||||
static SecurityIdentifier^ ReadSid(const DSNAME* dsName);
|
||||
|
|
|
@ -49,22 +49,44 @@ midl_ptr<DRS_MSG_CRACKREQ_V1> make_midl_ptr(ULONG numNames)
|
|||
return request;
|
||||
}
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETCHGREQ_V5>::operator()(DRS_MSG_GETCHGREQ_V5* request) const
|
||||
{
|
||||
if (request != nullptr)
|
||||
{
|
||||
// Perform deep free
|
||||
midl_user_free(request->pNC);
|
||||
midl_user_free(request->pUpToDateVecDestV1);
|
||||
|
||||
// Now free the encapsulating object:
|
||||
midl_user_free(request);
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETCHGREQ_V8>::operator()(DRS_MSG_GETCHGREQ_V8* request) const
|
||||
{
|
||||
if (request == nullptr)
|
||||
if (request != nullptr)
|
||||
{
|
||||
return;
|
||||
// Perform deep free
|
||||
midl_user_free(request->pPartialAttrSet);
|
||||
midl_user_free(request->pPartialAttrSetEx);
|
||||
// TODO: Free all PrefixTableDest items separately?
|
||||
midl_user_free(request->PrefixTableDest.pPrefixEntry);
|
||||
|
||||
// The DRS_MSG_GETCHGREQ_V8 message is a superset of DRS_MSG_GETCHGREQ_V5.
|
||||
auto requestV5 = midl_ptr<DRS_MSG_GETCHGREQ_V5>((DRS_MSG_GETCHGREQ_V5*)request);
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETCHGREQ_V10>::operator()(DRS_MSG_GETCHGREQ_V10* request) const
|
||||
{
|
||||
if (request != nullptr)
|
||||
{
|
||||
// The DRS_MSG_GETCHGREQ_V10 message is a superset of DRS_MSG_GETCHGREQ_V8.
|
||||
auto requestV8 = midl_ptr<DRS_MSG_GETCHGREQ_V8>((DRS_MSG_GETCHGREQ_V8*)request);
|
||||
}
|
||||
// Perform deep free
|
||||
midl_user_free(request->pNC);
|
||||
midl_user_free(request->pPartialAttrSet);
|
||||
midl_user_free(request->pPartialAttrSetEx);
|
||||
midl_user_free(request->pUpToDateVecDest);
|
||||
// TODO: Free all PrefixTableDest items separately?
|
||||
midl_user_free(request->PrefixTableDest.pPrefixEntry);
|
||||
// Finally, free the encapsulating object:
|
||||
midl_user_free(request);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -103,7 +125,7 @@ void midl_delete<DRS_MSG_CRACKREPLY_V1>::operator()(DRS_MSG_CRACKREPLY_V1* reply
|
|||
}
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETCHGREPLY_V6>::operator()(DRS_MSG_GETCHGREPLY_V6* reply) const
|
||||
void midl_delete<DRS_MSG_GETCHGREPLY_V1>::operator()(DRS_MSG_GETCHGREPLY_V1* reply) const
|
||||
{
|
||||
if (reply == nullptr)
|
||||
{
|
||||
|
@ -112,7 +134,7 @@ void midl_delete<DRS_MSG_GETCHGREPLY_V6>::operator()(DRS_MSG_GETCHGREPLY_V6* rep
|
|||
|
||||
// Perform deep free
|
||||
midl_user_free(reply->pNC);
|
||||
midl_user_free(reply->pUpToDateVecSrc);
|
||||
midl_user_free(reply->pUpToDateVecSrcV1);
|
||||
|
||||
// Free the prefix table:
|
||||
int numPrefixes = reply->PrefixTableSrc.PrefixCount;
|
||||
|
@ -154,20 +176,54 @@ void midl_delete<DRS_MSG_GETCHGREPLY_V6>::operator()(DRS_MSG_GETCHGREPLY_V6* rep
|
|||
currentObject = nextObject;
|
||||
}
|
||||
|
||||
// Free the linked values:
|
||||
DWORD numValues = reply->cNumValues;
|
||||
for (DWORD i = 0; i < numValues; i++)
|
||||
{
|
||||
auto currentValue = reply->rgValues[i];
|
||||
midl_user_free(currentValue.pObject);
|
||||
midl_user_free(currentValue.Aval.pVal);
|
||||
}
|
||||
midl_user_free(reply->rgValues);
|
||||
|
||||
// Finally, free the encapsulating object:
|
||||
midl_user_free(reply);
|
||||
}
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETCHGREPLY_V6>::operator()(DRS_MSG_GETCHGREPLY_V6* reply) const
|
||||
{
|
||||
if (reply != nullptr)
|
||||
{
|
||||
// Free the linked values (REPLVALINF_V1):
|
||||
for (DWORD i = 0; i < reply->cNumValues; i++)
|
||||
{
|
||||
auto currentValue = reply->rgValues[i];
|
||||
midl_user_free(currentValue.pObject);
|
||||
midl_user_free(currentValue.Aval.pVal);
|
||||
}
|
||||
|
||||
// Free the encapsulating array. It does not matter whether it is of type REPLVALINF_V1 or REPLVALINF_V3.
|
||||
midl_user_free(reply->rgValues);
|
||||
|
||||
// The DRS_MSG_GETCHGREPLY_V6 message is a superset of DRS_MSG_GETCHGREPLY_V1.
|
||||
auto replyV1 = midl_ptr<DRS_MSG_GETCHGREPLY_V1>((DRS_MSG_GETCHGREPLY_V1*)reply);
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETCHGREPLY_V9>::operator()(DRS_MSG_GETCHGREPLY_V9* reply) const
|
||||
{
|
||||
if (reply != nullptr)
|
||||
{
|
||||
// Free the linked values (REPLVALINF_V3):
|
||||
for (DWORD i = 0; i < reply->cNumValues; i++)
|
||||
{
|
||||
auto currentValue = reply->rgValues[i];
|
||||
midl_user_free(currentValue.pObject);
|
||||
midl_user_free(currentValue.Aval.pVal);
|
||||
}
|
||||
|
||||
/* The DRS_MSG_GETCHGREPLY_V6 deleter should not go through these values,
|
||||
because it would interpret them as REPLVALINF_V1 instead of REPLVALINF_V3.
|
||||
*/
|
||||
reply->cNumValues = 0;
|
||||
|
||||
// The DRS_MSG_GETCHGREPLY_V9 message is a superset of DRS_MSG_GETCHGREPLY_V6.
|
||||
auto replyV6 = midl_ptr<DRS_MSG_GETCHGREPLY_V6>((DRS_MSG_GETCHGREPLY_V6*)reply);
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETREPLINFO_REQ_V1>::operator()(DRS_MSG_GETREPLINFO_REQ_V1* request) const
|
||||
{
|
||||
|
|
|
@ -6,12 +6,24 @@
|
|||
|
||||
// Specialized allocators and deleters:
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETCHGREPLY_V1>::operator()(DRS_MSG_GETCHGREPLY_V1* reply) const;
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETCHGREPLY_V6>::operator()(DRS_MSG_GETCHGREPLY_V6* reply) const;
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETCHGREPLY_V9>::operator()(DRS_MSG_GETCHGREPLY_V9* reply) const;
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETCHGREQ_V5>::operator()(DRS_MSG_GETCHGREQ_V5* request) const;
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETCHGREQ_V8>::operator()(DRS_MSG_GETCHGREQ_V8* request) const;
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_GETCHGREQ_V10>::operator()(DRS_MSG_GETCHGREQ_V10* request) const;
|
||||
|
||||
template<>
|
||||
void midl_delete<DRS_MSG_CRACKREQ_V1>::operator()(DRS_MSG_CRACKREQ_V1* request) const;
|
||||
|
||||
|
|
Loading…
Reference in New Issue