Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion GroupsVB SyntaxEnterprise DevelopmentDatabase AccessControlsCOMWin APICrystal ReportDeploymentGeneralGeneral 2
Related Topics
VB.NET / ASP.NETMS SQL ServerMS AccessOther Database ProductsMore Topics ...

VB Forum / Database Access / November 2008



Tip: Looking for answers? Try searching our database.

Method '~' of object '~' failed

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
T. Valen - 19 Nov 2008 17:56 GMT
A VB6 program I wrote accesses the AD and fails with

Method '~' of object '~' failed

on a set of PCs of ONE particular customer. Other customers don't seem
to have problems with that.

The line that causes the error is
Set oRecordSet = oConnection.Execute(strQuery) '(see code sniplet below)

I googled and found that this might have to do with the MDAC version
differing between my development machine and the customers machine. So I
asked the customer to run the component checker, which I did, too.

I found we're both using the (apparently) correct version MDAC 2.8 SP1
ON WINDOWS XP SP2. The details of his XML-report showed that a few files
on the customers machine are in a slightly newer version (me:
2.81.1117.0, his: 2.81.1128.0 xpsp_sp2_gdr.061226-0034).

Question remains: I don't see how the MDAC version could have caused this.

Anyone got another idea what I could tell the user to try?

Thanks in advance!

Regards,
T.

------------------------

Set oRecordSet = CreateObject("ADODB.Recordset")
   Set oConnection = CreateObject("ADODB.Connection")

   Set oAD = GetObject(Provider) 'Determine the global catalog path
   For Each oGlobalCatalog In oAD
       strADsPath = oGlobalCatalog.ADsPath 'get last one
   Next
   oConnection.Provider = "ADsDSOObject" 'Initialize the ADO object
   oConnection.Open "ADs Provider" 'The ADSI OLE-DB provider

   'Create the search string

   strQuery = "<" & strADsPath & _
     ">;(&(objectclass=computer)(samaccountname=" & sUserName &
"$));samaccountname,cn,distinguishedName;subtree"

Set oRecordSet = oConnection.Execute(strQuery) 'Execute the query

(with strQuery =
<GC://domain.de>;(&(objectclass=computer)(samaccountname=D1137$));samaccountname,cn,distinguishedName;subtree)
Richard Mueller [MVP] - 19 Nov 2008 23:05 GMT
>A VB6 program I wrote accesses the AD and fails with
>
[quoted text clipped - 46 lines]
> (with strQuery =
> <GC://domain.de>;(&(objectclass=computer)(samaccountname=D1137$));samaccountname,cn,distinguishedName;subtree)

I've used similar code for years. It should work with MDAC versions perhaps
as old as 2.0 (as I recall), and certainly 2.8 should be no problem. The
only question I have is the value of "Provider". I use the RootDSE object to
retrieve the DNS name of the domain programmatically. For example:
===========
Set objRootDSE = GetObject(LDAP://RootDSE)
strDNSDomain = objRootDSE.Get("defaultNamingContext")
strQuery = "<GC://" & strDNSDomain & ">;" _
   & "(&(objectClass=computer)(sAMAccountName=" & sUserName & "$));" _
   & "sAMAccountName,cn,distinguishedName;subtree"

strDNSDomain will be similar to:

   dc=MyDomain,dc=com

I've always used a base clause similar to:

   <GC://dc=MyDomain,dc=com>
or
   <LDAP://dc=MyDomain,dc=com>

I've never used your format (with dots separating the domain components).

Signature

Richard Mueller
MVP Directory Services
Hilltop Lab - http://www.rlmueller.net
--

Ralph - 19 Nov 2008 23:06 GMT
> A VB6 program I wrote accesses the AD and fails with
>
[quoted text clipped - 18 lines]
>
> Anyone got another idea what I could tell the user to try?

Let's see if I can explain this in simple terms ... <g>

It might not necessary be the "MDAC's" fault, but it is coming from ADO. It
is a COM error. In a chain of components the stub in one will catch an error
and communicate it back to the proxy, it is the proxy job to pass this on to
the client, and so on and so forth. In this case you should be getting "the
Method someMethod() of Object someObject failed". Unfortunately ADO is
notorous for not sending along all the information. So the error is
accurate, it is just missing important stuff - like who the heck is it that
failed. <g>

[The ADO/OLE DB components are not the only ones that will have this error
just the ones mostly commonly used and thus frequently experienced by the
average programmer.]

The most common reason for getting this COM error in the first place is
mismatched components. At least, that can be assumed because the most common
'fix' is to ensure all components for both the client and target are the
same MDAC (ADO/OLE DB) suite. But this is essentially a mismatch of
references or typelibs, so perhaps a Registry problem.

You didn't show the declaration for oRecordSet (or oAD), so this is just a
guess, but that might be part of the problem.
Say you did this ...
       ' A Reference to a specific component/typlib the program
       ' is compile against
       ' "ADODB.Recordset" is the GUID Identifier for a specific interface
  Dim oRecordSet As ADODB.Recordset ' A GUID
       ' When you call the following you are telling the COM library
       '  to use the ProgID to look up the component that supplies an
       ' coClass to use from the registry
  Set oRecordSet = CreateObject("ADODB.Recordset")
        ' They may not be the same component. Check the Registry

The same goes for oAD ~ what you Referenced in your program may not
necessarily be what you end up chewing on.

Change your declarations to
    Dim oRecordSet As Object
    Dim oAD As Object
and see what happends, or
     Dim oRecordSet As ADODB.Recordset
     Set oRecordSet = New ADODB.Recordset
[Note: the latter tells the COM library to find the component to use from
the
given GUID not a ProgID]

HTH
T. Valen - 20 Nov 2008 15:02 GMT
Ralph,

thank you for your reply.

> You didn't show the declaration for oRecordSet (or oAD), so this is just a
> guess, but that might be part of the problem.

Whatever I had as declaration before, I changed it like you proposed,
recompiled and asked the customer for debug logs.

> Change your declarations to
>      Dim oRecordSet As Object
>      Dim oAD As Object
> and see what happends,

Same as before (Method '~' of object '~' failed)

> or
>       Dim oRecordSet As ADODB.Recordset
>       Set oRecordSet = New ADODB.Recordset
> [Note: the latter tells the COM library to find the component to use from
> the
>  given GUID not a ProgID]

This resulted in the following:

13:29:11 ->FindHostPosition 430 Class does not support Automation or
does not support expected interface

I think this error was raised  either in the line
   Set oRecordSet = New ADODB.Recordset ' 2. Variante
or
   Set oConnection = CreateObject("ADODB.Connection") ' 2. Variante

Let me be honest: I don't know what to do.

I really appreciate your help, but it seems I have not completely
understood what you advised me to do.

Here's the complete code:

Private Function FindHostPosition(ByVal sUserName, ByVal RootDSA,
Optional Provider As String)
 Dim oAD As Object 'As IADs
 'Dim oRecordSet As Object ' 1. Variante
 Dim oRecordSet As ADODB.Recordset 'As Recordset '2. Variante
 Dim oGlobalCatalog 'As IADs
 Dim oConnection 'As New Connection
 Dim strADsPath 'As String
 Dim strQuery 'As String
 Dim strUPN 'As String

On Error GoTo Err

   If Provider = "" Then Provider = "GC:"

   WriteDebugLog "->FindHostPosition " & sUserName & " in " & RootDSA

   ' Set oRecordSet = CreateObject("ADODB.Recordset") '1. Variante
   Set oRecordSet = New ADODB.Recordset ' 2. Variante
   Set oConnection = CreateObject("ADODB.Connection") ' 2. Variante

   Set oAD = GetObject(Provider) 'Determine the (global catalog) path
   For Each oGlobalCatalog In oAD
       strADsPath = oGlobalCatalog.ADsPath 'go to last entry
   Next
   oConnection.Provider = "ADsDSOObject" 'Init ADO object
   oConnection.Open "ADs Provider" 'The ADSI OLE-DB provider

   strQuery = "<" & strADsPath & _
     ">;(&(objectclass=computer)(samaccountname=" & sUserName &
"$));samaccountname,cn,distinguishedName;subtree"
   WriteDebugLog "-> Preparing query " & strQuery
   Set oRecordSet = oConnection.Execute(strQuery) 'Execute the query

   If oRecordSet.EOF And oRecordSet.BOF Then
      'An empty recordset was returned
       WriteDebugLog "-> not found"
       FindHostPosition = "Not Found"
   Else    'Records were found; loop through them
       While Not oRecordSet.EOF
           FindHostPosition = oRecordSet.Fields("distinguishedName")
           WriteDebugLog "-> found " & FindHostPosition
           oRecordSet.MoveNext
       Wend
   End If
   WriteDebugLog "<-FindHostPosition"
   Exit Function
Err:
   WriteDebugLog "->FindHostPosition " & Err.Number & " " & Err.Description

End Function

Regards,
T.
Richard Mueller [MVP] - 20 Nov 2008 16:29 GMT
We need to know which line raises the error. Again, I don't see a problem in
the code. One possibility is that the value for "Provider" passed to the
function is invalid. However, I don't understand the purpose of this
variable. I also am not sure of the purpose of the function.

If the purpose is to determine the Distinguished Name of a computer given
the NetBIOS name, there are easier ways to do this. I would recommend using
the NameTranslate object. I also would use the RootDSE object to determine
the name of the current domain (as I pointed out earlier).

I assume the value of sUserName is the NetBIOS name of a computer because
you append a trailing "$" to the value and search for a computer object
whose sAMAccountName matches. The code to retrieve the DN of a computer from
the NetBIOS name could be as follows:
================
Private Function FindHostPosition(ByVal strComputer As String) As String
   ' Function to determine Distinguished Name of computer from NetBIOS
name.
   Dim objTrans As NameTranslate
   Dim objRootDSE As Object
   Dim strDNSDomain As String
   Dim strNetBIOSDomain As String

   ' Constants for the NameTranslate object.
   Const ADS_NAME_INITTYPE_GC = 3
   Const ADS_NAME_TYPE_NT4 = 3
   Const ADS_NAME_TYPE_1779 = 1

   ' Determine DNS name of domain from RootDSE.
   Set objRootDSE = GetObject("LDAP://RootDSE")
   strDNSDomain = objRootDSE.Get("defaultNamingContext")

   ' Use the NameTranslate object to find the NetBIOS domain name from the
   ' DNS domain name.
   Set objTrans = CreateObject("NameTranslate")
   ' Initialize NameTranslate by locating the Global Catalog.
   objTrans.Init ADS_NAME_INITTYPE_GC, ""
   objTrans.Set ADS_NAME_TYPE_1779, strDNSDomain
   strNetBIOSDomain = objTrans.Get(ADS_NAME_TYPE_NT4)
   ' Remove trailing backslash.
   strNetBIOSDomain = Left(strNetBIOSDomain, Len(strNetBIOSDomain) - 1)

   ' Use the Set method to specify the NT format of the object name.
   ' The sAMAccountName of computer objects is the NetBIOS name
   ' with a trailing "$" appended.
   ' Trap error if object does not exist.
   On Error Resume Next
   objTrans.Set ADS_NAME_TYPE_NT4, strNetBIOSDomain & "\" & strComputer &
"$"
   If (Err.Number = 0) Then
       On Error GoTo 0
       ' Use the Get method to retrieve the RPC 1779 Distinguished Name.
       FindHostPosition = objTrans.Get(ADS_NAME_TYPE_1779)
   Else
       On Error GoTo 0
       ' Object not found.
       FindHostPosition = "<Not found>"
   End If

End Function
==========
The NameTranslate object requires a reference to "Active DS Type Library"
(activeds.tlb). Using NameTranslate is more efficient than using ADO to
search for the object. However, I believe your code will work if the proper
values are passed to it.

Signature

Richard Mueller
MVP Directory Services
Hilltop Lab - http://www.rlmueller.net
--

> Ralph,
>
[quoted text clipped - 93 lines]
> Regards,
> T.
T. Valen - 20 Nov 2008 21:59 GMT
> We need to know which line raises the error.

I'll some more debug-lines and ask the customer to reproduce the issue.

> Again, I don't see a problem in  the code.

Nor do I. The code runs fine on hundreds of PCs, but this customer has
already four machines that run into this issue.

> One possibility is that the value for "Provider" passed to the
> function is invalid.

No. "Provider" can only be "GC:" or "LDAP:", I tried both with the same
error.

> However, I don't understand the purpose of this  variable.

The purpose of this variable was to be able to either use GC or LDAP
with the same function.

> I also am not sure of the purpose of the function.

I need to find the correct full LDAP path of the machine.

> If the purpose is to determine the Distinguished Name of a computer given
> the NetBIOS name, there are easier ways to do this.

To be honest: It's been a while since I last had my fingers in this area
of the code. A customer is complaining about issues and I found this in
the logs and tried to narrow it down a bit. What I want to say is: I
think you are right that I'm just trying to get the DN of a computer.
But I'm not sure if I haven't done it this way for a reason.

> I would recommend using the NameTranslate object.

I'll give that a try.

> I also would use the RootDSE object to determine
> the name of the current domain (as I pointed out earlier).

I read that but I can assure you that this was no issue yet. We
shouldn't forget that the code is working on a few hundred machines
without any trouble.

> The code to retrieve the DN of a computer from  the NetBIOS name
> could be as follows:
[...]

No matter what the reason for the issues in my code might be, I'm going
to give this a shot anyway.

> However, I believe your code will work if the proper
> values are passed to it.

I had the values printed out in the debug log and can assure you they
are correct. It must some form of incompatibility with something on the
customers machines. But maybe that's not much of importance anymore is
your code suggestion does the job. I'll try tomorrow.

Thanks a lot for your help!

Regards,
T.
T. Valen - 24 Nov 2008 11:42 GMT
Richard,

thank you so much!

I added the function that you proposed as fallback in case my function
does not work properly. It worked perfectly in the environment that had
caused the issues.

Best regards,
T.
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.