Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Converting a function on Win64


This question is answered. Helpful answers available: 0. Correct answers available: 1.


Permlink Replies: 11 - Last Post: May 2, 2016 3:02 AM Last Post By: Yannick LANCHEC
Yannick LANCHEC

Posts: 43
Registered: 1/21/01
Converting a function on Win64  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 23, 2016 1:30 PM
Hi,

I have this function :

////////////////////////////////////////////////////////////////////////////////
// Enum objects
Function FindObjects(Server,
Base,
Attribute,
Filter:String;
Var List:TStrings):DWord;

Var
Search:IDirectorySearch;
Tst:PWideChar;
P:Array[0..0] Of PWideChar;
ptrResult:Pointer;
Col:ads_search_column;
Hr:HResult;
Opt:Array [0..0] Of ads_searchpref_info; // has to be an array
dwErr:DWord;
szErr:Array[0..255] Of WideCHar;
szName:Array[0..255] Of WideChar;
LDAPStr:String;
Res:dword;
Begin
If Server<>'' Then LDAPStr:=Format('LDAP://%s/%s',[Server,Base])
Else LDAPStr:=Format('LDAP://%s',[Base]);
Res:=ADsGetObject(StringToOleStr(LDAPStr),
IID_IDirectorySearch,
Pointer(Search));
If Res=0 Then
Try
Opt[0].dwSearchPref:=ADS_SEARCHPREF_SEARCH_SCOPE;
Opt[0].vValue.dwType:=ADSTYPE_INTEGER;
Opt[0].vValue.__MIDL____MIDL_itf_ads_0000_00000000.Integer:=ADS_SCOPE_SUBTREE;
Hr:=search.SetSearchPreference(opt[0],1);
If (Hr<>0) Then
Begin
Hr:=ADsGetLastError(dwErr,@szErr[0],254,@szName[0],254);
Exit;
End;
P[0]:=StringToOleStr(Attribute);
Hr:=Search.ExecuteSearch(StringToOleStr(Filter),
P[0],
1,
ptrResult);
Hr:=Search.GetNextRow(ptrResult);
While (Hr<>S_ADS_NOMORE_ROWS) Do
Begin
Application.ProcessMessages;
Hr:=Search.GetColumn(ptrResult,P[0],Col);
If Succeeded(Hr) Then
Begin
If Col.pADsValues<>Nil Then
Begin
If List=Nil Then List:=TStringList.Create;
List.Add(Col.pAdsvalues^.__MIDL____MIDL_itf_ads_0000_00000000.CaseIgnoreString);
End;
Search.FreeColumn(Col);
End;
Hr:=Search.GetNextRow(ptrResult);
End;
Search.CloseSearchHandle(ptrResult);
Finally
//
End;
Result:=Res;
End;
////////////////////////////////////////////////////////////////////////////////

It uses ActiveDS_TLB :

// *********************************************************************//
// Interface : IDirectorySearch
// Indicateurs : (0)
// GUID : {109BA8EC-92F0-11D0-A790-00C04FD8D5A8}
// *********************************************************************//
IDirectorySearch = interface(IUnknown)
['{109BA8EC-92F0-11D0-A790-00C04FD8D5A8}']
function SetSearchPreference(var pSearchPrefs: ads_searchpref_info; dwNumPrefs: LongWord): HResult; stdcall;
function ExecuteSearch(pszSearchFilter: PWideChar; var pAttributeNames: PWideChar;
dwNumberAttributes: LongWord; out phSearchResult: Pointer): HResult; stdcall;
function AbandonSearch(phSearchResult: Pointer): HResult; stdcall;
function GetFirstRow(hSearchResult: Pointer): HResult; stdcall;
function GetNextRow(hSearchResult: Pointer): HResult; stdcall;
function GetPreviousRow(hSearchResult: Pointer): HResult; stdcall;
function GetNextColumnName(hSearchHandle: Pointer; out ppszColumnName: PWideChar): HResult; stdcall;
function GetColumn(hSearchResult: Pointer; szColumnName: PWideChar;
out pSearchColumn: ads_search_column): HResult; stdcall;
function FreeColumn(var pSearchColumn: ads_search_column): HResult; stdcall;
function CloseSearchHandle(hSearchResult: Pointer): HResult; stdcall;
end;

This function is call like :

FindObject('MyServer','dc=mydomain,dc=local','distinguishedName','(objectClass=computer)',MyList)

This function works in win32 (tested on XE7)

But it crashes in Win64 !

The GetColumn function does not return a good Col

Best regards

Yannick

Yannick LANCHEC

Posts: 43
Registered: 1/21/01
Re: Converting a function on Win64  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 24, 2016 2:14 AM   in response to: Yannick LANCHEC in response to: Yannick LANCHEC
Hi

The automatic ActiveDS_TLB export seems to have problems. (https://connect.microsoft.com/VisualStudio/feedback/details/618316/importing-the-activeds-tlb-type-library-gives-os-dependent-names-to-anonymous-union-types-and-variables)

I have replace it with the JWA version (and remove all the JWA include), and add {$A+} {$Z4}, so my library is standalone.

Then i have replace some structures, this works again in Win32 but in Win64 the "GetColumn" returns a Col.pADSValues empty..

No crashes this time but no return in Win64 !

////////////////////////////////////////////////////////////////////////////////
// Find AD objects
Function FindObjects(Server,
Base,
Attribute,
Filter:String;
Var List:TStrings):DWord;

Var
Search:IDirectorySearch;
P:Array[0..0] Of PWideChar;
ptrResult:ADS_SEARCH_HANDLE;
Col:ADS_SEARCH_COLUMN ;
Hr:HResult;
Opt:array [0..0] of ADS_SEARCHPREF_INFO; // has to be an array
dwErr:DWord;
szErr:array[0..255] of WideCHar;
szName:array[0..255] of WideChar;
LDAPStr:String;
Res:dword;
Begin
If Server<>'' Then LDAPStr:=Format('LDAP://%s/%s',[Server,Base])
Else LDAPStr:=Format('LDAP://%s',[Base]);
Res:=ADsGetObject(StringToOleStr(LDAPStr),
IID_IDirectorySearch,
Pointer(Search));
If Res=0 Then
Try
Opt[0].dwSearchPref:=ADS_SEARCHPREF_SEARCH_SCOPE;
Opt[0].vValue.dwType:=ADSTYPE_INTEGER;
Opt[0].vValue.Integer:=ADS_SCOPE_SUBTREE;
Hr:=search.SetSearchPreference(@opt[0],1);
If (hr<>0) Then
Begin
Hr:=ADsGetLastError(dwErr,@szErr[0],254,@szName[0],254);
Exit;
End;
P[0]:=StringToOleStr(Attribute);
hr:=Search.ExecuteSearch(StringToOleStr(Filter),
@P[0],
1,
ptrResult);
Hr:=Search.GetNextRow(ptrResult);
While (Hr<>S_ADS_NOMORE_ROWS) Do
Begin
Hr:=Search.GetColumn(ptrResult,P[0],Col);
If Succeeded(Hr) Then
Begin
If Col.pADsValues<>Nil Then
Begin
If List=Nil Then List:=TStringList.Create;
List.Add(Col.pAdsvalues^.CaseIgnoreString);
End;
Search.FreeColumn(@Col);
End;
Hr:=search.GetNextRow(ptrResult);
End;
Search.CloseSearchHandle(ptrResult);
Finally
//
End;
Result:=Res;
End;

Best Regards

Yannick

Edited by: Yannick LANCHEC on Jan 24, 2016 2:16 AM

Yannick LANCHEC

Posts: 43
Registered: 1/21/01
Re: Converting a function on Win64  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 2, 2016 10:21 PM   in response to: Yannick LANCHEC in response to: Yannick LANCHEC
Hi,

I see something strange, when i call ExecuteSearch, in w64, the pAttributeNames is return to nill, but it's not a var, so why ?

// *********************************************************************//
// Interface: IDirectorySearch
// Flags: (0)
// GUID: {109BA8EC-92F0-11D0-A790-00C04FD8D5A8}
// *********************************************************************//
IDirectorySearch = interface(IUnknown)
['{109BA8EC-92F0-11D0-A790-00C04FD8D5A8}']
function SetSearchPreference(pSearchPrefs: PADS_SEARCHPREF_INFO; dwNumPrefs: LongWord): HResult; stdcall;
function ExecuteSearch(pszSearchFilter: PWideChar; pAttributeNames: PWideChar;
dwNumberAttributes: LongWord; var phSearchResult: ADS_SEARCH_HANDLE): HResult; stdcall;
function AbandonSearch(phSearchResult: ADS_SEARCH_HANDLE): HResult; stdcall;
function GetFirstRow(hSearchResult: ADS_SEARCH_HANDLE): HResult; stdcall;
function GetNextRow(hSearchResult: ADS_SEARCH_HANDLE): HResult; stdcall;
function GetPreviousRow(hSearchResult: ADS_SEARCH_HANDLE): HResult; stdcall;
function GetNextColumnName(hSearchHandle: ADS_SEARCH_HANDLE; out ppszColumnName: PWideChar): HResult; stdcall;
function GetColumn(hSearchResult: ADS_SEARCH_HANDLE; szColumnName: PWideChar;
var pSearchColumn: ADS_SEARCH_COLUMN): HResult; stdcall;
function FreeColumn(pSearchColumn: PADS_SEARCH_COLUMN): HResult; stdcall;
function CloseSearchHandle(hSearchResult: ADS_SEARCH_HANDLE): HResult; stdcall;
end;

If i save pAttributeNames before this call, and re use it for the GetColumn, now it works on win64.

But why this value is modified but should not be ?

Best regards

Yannick
Peter Below

Posts: 1,227
Registered: 12/16/99
Re: Converting a function on Win64 [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 3, 2016 10:23 AM   in response to: Yannick LANCHEC in response to: Yannick LANCHEC
Yannick LANCHEC wrote:

Hi,

I see something strange, when i call ExecuteSearch, in w64, the
pAttributeNames is return to nill, but it's not a var, so why ?

//
*********************************************************************/
/ // Interface: IDirectorySearch // Flags: (0)
// GUID: {109BA8EC-92F0-11D0-A790-00C04FD8D5A8}
//
*********************************************************************/
/ IDirectorySearch = interface(IUnknown)
['{109BA8EC-92F0-11D0-A790-00C04FD8D5A8}']
function ExecuteSearch(pszSearchFilter: PWideChar;
pAttributeNames: PWideChar;
dwNumberAttributes: LongWord; var phSearchResult: ADS_SEARCH_HANDLE):
HResult; stdcall;

If I interpret the online docs
(https://msdn.microsoft.com/en-us/library/windows/desktop/aa746365%28v=v
s.85%29.aspx ) correctly pAttributeNames is actually not a PWideChar
but a pointer to the first PWidechar in an array of such items (it is
declared as LPWSTR *).

Please show the code that calls ExecuteSearch, including all variable
declarations for variables you pass to the function.


--
Peter Below
TeamB

Yannick LANCHEC

Posts: 43
Registered: 1/21/01
Re: Converting a function on Win64 [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 3, 2016 11:59 AM   in response to: Peter Below in response to: Peter Below
Hi Peter,

I know that it's an array of pointers, in my case one value ..

That's why the attribute is reach wirh @P[0]

This is the code :

////////////////////////////////////////////////////////////////////////////////
// Find AD objects
Function FindObjects(Server,
Base,
Attribute,
Filter:String;
Var List:TStrings):DWord;

Var
Search:IDirectorySearch;
P:Array[0..0] Of PWideChar;
ptrResult:ADS_SEARCH_HANDLE;
Col:ADS_SEARCH_COLUMN ;
Hr:HResult;
Opt:array [0..0] of ADS_SEARCHPREF_INFO; // has to be an array
dwErr:DWord;
szErr:array[0..255] of WideCHar;
szName:array[0..255] of WideChar;
LDAPStr:String;
Res:dword;
Begin
If Server<>'' Then LDAPStr:=Format('LDAP://%s/%s',[Server,Base])
Else LDAPStr:=Format('LDAP://%s',[Base]);
Res:=ADsGetObject(StringToOleStr(LDAPStr),
IID_IDirectorySearch,
Pointer(Search));
If Res=0 Then
Try
Opt[0].dwSearchPref:=ADS_SEARCHPREF_SEARCH_SCOPE;
Opt[0].vValue.dwType:=ADSTYPE_INTEGER;
Opt[0].vValue.Integer:=ADS_SCOPE_SUBTREE;
Hr:=search.SetSearchPreference(@opt[0],1);
If (hr<>0) Then
Begin
Hr:=ADsGetLastError(dwErr,@szErr[0],254,@szName[0],254);
Exit;
End;
P[0]:=StringToOleStr(Attribute);
Hr:=Search.ExecuteSearch(StringToOleStr(Filter),
@P[0],
SizeOf(P) Div SizeOf(PWideChar),
ptrResult);
P[0]:=StringToOleStr(Attribute); // in win64 this line is necessary because the pointer become nil after executesearch
Hr:=Search.GetFirstRow(ptrResult);
While (Hr<>S_ADS_NOMORE_ROWS) Do // in win 64, may be better with "Hr=0"
Begin
ProcessMessages;
Hr:=Search.GetColumn(ptrResult,
P[0],
Col);
If Succeeded(Hr) Then
Begin
If Col.pADsValues<>Nil Then
Begin
If List=Nil Then List:=TStringList.Create;
List.Add(Col.pAdsvalues^.CaseIgnoreString);
End;
Search.FreeColumn(@Col);
End;
Hr:=Search.GetNextRow(ptrResult);
End;
Search.CloseSearchHandle(ptrResult);
Finally
//
End;
Result:=Res;
End;
////////////////////////////////////////////////////////////////////////////////

i use the unit jwaAdsTlb.pas (http://sourceforge.net/p/jedi-apilib/mailman/message/24667723/) and i have remove jwa include and i have add alignement :

{*****************************************************************}
unit ActiveDS_TLB;

{$A+} {record alignment on 4 byte boundaries}
{$Z4} {enum size is 4 bytes}

interface

uses
Windows,
ActiveX;
...........

Thank you

Yannick
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Converting a function on Win64 [Edit] [Edit]
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 3, 2016 3:01 PM   in response to: Yannick LANCHEC in response to: Yannick LANCHEC
Yannick wrote:

This is the code

Your declaration of ExecuteSearch() is wrong.

Also, you are leaking memory every time you call StringToOleStr(). It returns
a newly allocated BSTR that must be freed using SysFreeString(), which you
are not calling. I would suggest using WideString variables instead of StringToOleStr().

Also, you are not handling S_ADS_NOMORE_ROWS correctly.

Try something more like this instead:

function ExecuteSearch(pszSearchFilter: PWideChar; pAttributeNames: PPWideChar;
  dwNumberAttributes: LongWord; var phSearchResult: ADS_SEARCH_HANDLE): HResult; 
stdcall;
 
...
 
Function FindObjects(const Server, Base, Attribute, Filter: String; Var List: 
TStrings): DWord;
Var
  Search: IDirectorySearch;
  P: PWideChar;
  ptrResult: ADS_SEARCH_HANDLE;
  Col: ADS_SEARCH_COLUMN ;
  Hr: HResult;
  Opt: ADS_SEARCHPREF_INFO;
  dwErr: Dword;
  szErr: array[0..255] of WideChar;
  szName: array[0..255] of WideChar;
  LDAPStr, LDAPAttr: WideString;
Begin
  Result := 0;
  If Server <> '' Then LDAPStr := Format('LDAP://%s/%s', [Server,Base])
  Else LDAPStr := Format('LDAP://%s',[Base]);
  Hr := ADsGetObject(PWideChar(LDAPStr), IID_IDirectorySearch, Pointer(Search));
  If (hr <> 0) Then
  Begin
    Hr := ADsGetLastError(dwErr, szErr, 254, szName, 254);
    Result := dwErr;
    Exit;
  End;
  Opt.dwSearchPref := ADS_SEARCHPREF_SEARCH_SCOPE;
  Opt.vValue.dwType := ADSTYPE_INTEGER;
  Opt.vValue.Integer := ADS_SCOPE_SUBTREE;
  Hr := search.SetSearchPreference(@opt, 1);
  If (hr <> 0) Then
  Begin
    Hr := ADsGetLastError(dwErr, szErr, Length(szErr), szName, Length(szName));
    Result := dwErr;
    Exit;
  End;
  LDAPAttr := Attribute;
  P := PWideChar(LDAPAttr);
  Hr := Search.ExecuteSearch(PWideChar(WideString(Filter)), @P, 1, ptrResult);
  If (hr <> 0) Then
  Begin
    Hr := ADsGetLastError(dwErr, szErr, Length(szErr), szName, Length(szName));
    Result := dwErr;
    Exit;
  End;
  Try
    Repeat
      ProcessMessages;
      Hr := Search.GetNextRow(ptrResult);
      if (hr = 0) Then
      Begin
        Hr := Search.GetColumn(ptrResult, P, Col);
        If Succeeded(Hr) Then
        Try
          If Col.pADsValues <> Nil Then
          Begin
            If List = Nil Then List := TStringList.Create;
            List.Add(Col.pAdsvalues^.CaseIgnoreString);
          End;
        Finally
          Search.FreeColumn(@Col);
        End;
      End
      Else If (hr = S_ADS_NOMORE_ROWS) Then
      Begin
        dwErr := 0;
        Hr := ADsGetLastError(dwErr, szErr, Length(szErr), szName, Length(szName));
        If (dwErr <> ERROR_MORE_DATA) Then Exit;
      End Else
      Begin
        Hr := ADsGetLastError(dwErr, szErr, Length(szErr), szName, Length(szName));
        Result := dwErr;
        Exit;
      End;
    Until False;
  Finally
    Search.CloseSearchHandle(ptrResult);
  End;
End;


--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Converting a function on Win64 [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 3, 2016 1:42 PM   in response to: Yannick LANCHEC in response to: Yannick LANCHEC
Yannick wrote:

I see something strange, when i call ExecuteSearch, in w64, the
pAttributeNames is return to nill, but it's not a var, so why ?

You have ExecuteSearch() declared wrong. The pAttributeNames parameter is
declared as LPWSTR* (a pointer to an array of LPWSTR pointers) in the Win32
API, so you need to declare it as either 'var LPWSTR' (var PWideChar) or
'PLPWSTR' (PPWideChar) in Delphi.

--
Remy Lebeau (TeamB)
Yannick LANCHEC

Posts: 43
Registered: 1/21/01
Re: Converting a function on Win64 [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 3, 2016 10:36 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hi Remy,

Thank you for your help, now it's almost good in win64.

I get results this times.

But, after, I get an ACCESS_VIOLATION with Search.FreeColumn(@Col) (only in win64).

Best regards

Yannick
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Converting a function on Win64 [Edit]
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 3, 2016 10:58 PM   in response to: Yannick LANCHEC in response to: Yannick LANCHEC
Yannick wrote:

But, after, I get an ACCESS_VIOLATION with Search.FreeColumn(@Col)
(only in win64).

Sorry, I do not know. Your declaration of FreeColumn() is fine, so it is
probably a bug in the 64bit IDirectorySearch implementation.

--
Remy Lebeau (TeamB)
Yannick LANCHEC

Posts: 43
Registered: 1/21/01
Re: Converting a function on Win64 [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 4, 2016 12:19 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hi Remi,

Yes, the declaration seems good, il have also look the file "iads.h" (visual stuidio) and it seems the same.

The automatic export TLB was already wrong.A guy already declare this problem, but it's not corrected for the moment.

I will continue some tests on this, or add a test on the type win64.

Thank you for your help.

Yannick
Yannick LANCHEC

Posts: 43
Registered: 1/21/01
Re: Converting a function on Win64 [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Feb 4, 2016 12:45 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hello,

if i don't want to free the structure on win 64
what is teh best method.

Yannick
Yannick LANCHEC

Posts: 43
Registered: 1/21/01
Re: Converting a function on Win64 [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 2, 2016 3:02 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy,

I have finally found the problem on x64.

In ActiveDS_TLB, we have :

type
ADS_SEARCH_HANDLE = HANDLE;
PADS_SEARCH_HANDLE = ^ADS_SEARCH_HANDLE;
......

This is good in Win32 but not in Win64 !

Because the size is not good.

So i take a THANDLE.

Best regards.

Yannick
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02