Link to home
Start Free TrialLog in
Avatar of SITPL
SITPL

asked on

Failing to get unicode text from Active Directory in ATL dll project

Hi,
I am facing an issue regarding unicode text.
In a ATL dll project I am using LDAP to get data from Active Directory. Following is the sample code.  

IDirectorySearch *pDSSearch;
ADS_SEARCH_COLUMN col;
hr = pDSSearch->SetSearchPreference(rgSearchPrefs, ARRAYSIZE(rgSearchPrefs));
hr = pDSSearch->ExecuteSearch(strFilter, pszAttr ,dwAttrNameSize, &hSearch );

if(SUCCEEDED(hr))
	{						
		switch(col.dwADsType)
		{ 
			case  ADSTYPE_DN_STRING:
			case ADSTYPE_CASE_IGNORE_STRING:
				{			
					for(size_t x=0; x<col.dwNumValues;x++)
					{
						CString name = col.pADsValues[x].CaseIgnoreString; //fails for unicode text
					}
				}
		}
	}

Open in new window


The line CString name = col.pADsValues[x].CaseIgnoreString; works fine for English text, but returns '???' for other languages. For example if the Active directory contains any user's name in Chinese or Japanese text '邮箱' then CString name shows '???' instead of the actual unicode text.
The same code works properly in another MFC Application project but fails for this ATL dll project.

Project settings are :
Configuration Type : Dynamic Library(.dll)
Use of MFC :      Use MFC in a Static Library
Use of ATL :       Static Link to ATL
Character Set :  Use Unicode Character Set

Cannot trace what I have been missing out. Please help.
Avatar of sarabande
sarabande
Flag of Luxembourg image

int wchars_num = MultiByteToWideChar( CP_UTF8 , 0 , col.pADsValues[x].CaseIgnoreString , -1, NULL , 0 );
CString wstr;
MultiByteToWideChar( CP_UTF8 , 0 ,  col.pADsValues[x].CaseIgnoreString, -1, wstr.GetBuffer(wchars_num+1) , wchars_num );
wstr.ReleaseBuffer(-1);

this code would convert from UTF-8 to UTF-16. the latter is a 16-bit layer of UTF-32 called "UNICODE" by microsoft. UTF-8 is a multi-byte character set where a UNICODE character has 1 to 4 bytes and it is mightier than UTF-16 though both cover most common characters used in the word.

Sara
col.pADsValues[x].CaseIgnoreString

i assumed that this is a byte buffer. you may have to use an intermediate char buffer if the string you got in col.pADsValues[x].CaseIgnoreString already is converted to a wide character string buffer.

byte buffer[SOME_SIZE+1] = { 0 };
memcpy(buffer, your_byte_array, SOME_SIZE);
// this call checks how many characters are needed for the wide char string
int wchars_num = MultiByteToWideChar( CP_UTF8 , 0 , (const char *)buffer , -1, NULL , 0 );
// the next call retrieves the wide string
MultiByteToWideChar( CP_UTF8 , 0 ,  (const char *)buffer, -1, name.GetBuffer(wchars_num+1) , wchars_num);
name.ReleaseBuffer();

Open in new window


Sara
Avatar of SITPL
SITPL

ASKER

Sara, thanks for the suggestion. I tried with the byte buffer but it still shows junk. I am wondering why is this not working only in ATL project when it works fine in another MFC application.
Still stuck on this. Any help would be very much appreciated.
write the byte array you get to a file.

#include <fstream>
...
std::ofstream ofs("c:\\temp\\bytes,bin", std::ios::binary | std::ios::out);
ofs.write((const char *)bytes_arr, num_bytes);
ofs.close();

Open in new window


then open the file "with the binary editor" of visual studio.

make a picture of the contents and post it here.

additionally post the code you made to convert from utf-8 to utf-16. especially the part of the code where you determine the size of the byte array.

finally, show a picture of the error (or garbage) you got.

Sara
ASKER CERTIFIED SOLUTION
Avatar of SITPL
SITPL

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial