?
Solved

Converting unicode interface name to character string

Posted on 2003-02-26
13
Medium Priority
?
555 Views
Last Modified: 2013-12-04

I am writing some software that deals with internet interfaces. I have written a class that calls GetInterfaceInfo followed by GetIfEntry to get information on each of the interfaces:

std::list<Interface> sysList;
sysList = Interface::Discover();

The Interface class contains the name, index, broadcast address etc. of each interface. I have tested my class and it is correctly returning all the interfaces on the system. For compatibility with other classes it is necessary that I have a method in my interface class that returns the name of the interface as a string. However, in the microsoft documentation: (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rras/rras/mib_ifrow.asp) it says that the name of the interface is returned as an array of wide characters: WCHAR wszName[MAX_INTERFACE_NAME_LEN].

My questions:
Is there any way to print the interface name so that I can verify that it has been returned correctly? (I have tried printf, wprintf, wcout etc with a variety of options however they always either return nothing or a string of about 500 identical characters).

Having verified that the interface name is being returned correctly, is there any way to convert from wide characters to characters so that my method can return a string of charaters??
0
Comment
Question by:jeordsta
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 4
  • 3
  • +1
13 Comments
 

Expert Comment

by:GrahamRowe
ID: 8033409
The Microsoft macro W2A will convert a wide string to a single byte string. Bear in mind that you must provide the USES_CONVERSION macro in tandem with this one as it allocates a temporary variable used in the conversion.

Code Sample:

wchar_t* pwsName = L"Hello World.";

USES_CONVERSION;

char* pszName = W2A (pwsName);

printf ("%s\n", pszName);
0
 
LVL 86

Expert Comment

by:jkr
ID: 8033592
>>The Microsoft macro W2A will convert a wide string to a single byte string.

... if you are using ATL. It is actually easier to

#include <stdlib.h>

WCHAR wszName[MAX_INTERFACE_NAME_LEN];
char szName[MAX_INTERFACE_NAME_LEN];

wcstombs ( szName, wszName, sizeof ( szName));


0
 

Expert Comment

by:GrahamRowe
ID: 8036794
jkr - I think that you may have got things slightly wrong there.

A multibyte string is not the same as the single byte string asked for by jeordsta. Multibyte strings are (as I recall) a bit of a hack by MS from the early days before Unicode was standardised on. A multibyte string contains characters encoded into either one or two bytes and have a distinct API to allow you to traverse the strng.

G
0
Visualize your virtual and backup environments

Create well-organized and polished visualizations of your virtual and backup environments when planning VMware vSphere, Microsoft Hyper-V or Veeam deployments. It helps you to gain better visibility and valuable business insights.

 
LVL 86

Expert Comment

by:jkr
ID: 8036870
>>I think that you may have got things slightly wrong there

No :o)

Check atlconv.h where that 'W2A()' macro is declared and you will find out that they're using 'WideCharToMultiByte()' for the conversion ('wcstombs()' is just the CRT wrapper for that API). Not into a in-depth discussion of charsets now, though)
0
 

Expert Comment

by:GrahamRowe
ID: 8036974
Ta for that. Think I owe you points now ;-)

G.
0
 

Author Comment

by:jeordsta
ID: 8037821
Hey guys,

Thanks for the quick response however this still doesn't seem to be working. GrahamRowe: I tried your method first but the USESCONVERSION macro was undefined. What is ATL? I didn't know what I had to include to use the macro. jkr: I tried your method and it compiled without error. However it still isn't producing meaningful output. I have written a very simple program below which illustrates what I am trying to do:

int main(int argc,char* argv[]) {
  MIB_IFROW IfRow;
  char error_message[1024];

  IfRow.dwIndex=1;
  if (GetIfEntry(&IfRow)!=NO_ERROR) {
    strcpy(error_message, GetErrorMsg());
    printf ("Error in GetIfEntry: %s\n", error_message);
  }

  char szName[MAX_INTERFACE_NAME_LEN];

  wcstombs ( szName, IfRow.wszName, sizeof ( szName));    
  printf ("Interface name: %s\n", szName);
};

Here is the output:

Interface name: ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦

I have tried running this program on a variety of versions of windows (XP, 2000 and 98) but every version produces this same output. Is it possible to get meaningful output to thhe console??

TIA, jeordsta.
0
 

Author Comment

by:jeordsta
ID: 8037837
Oh, I forgot to mention that the above code will complain about GetErrorMsg() being undefined. It is just a little function that calls GetLastError() and then FormatMessage().
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8038173
>> jkr - I think that you may have got things slightly wrong there...

Hehehe ... I thought everybody knew that "Multibyte" really means "single byte"  Isn't it obvious?
=-=-=-=-=-=-=-=-=-=-=-

Are the other fields in the MIB_IFROW populated with valid data?  Possibly some types of these puppies don't have any kind of hyman-readable name associated.

You should prefill the structure with 0s before calling GetIfEntry.

-- Dan
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8038208
Also, the GetInterfaceInfo function provides a means to get the name. -- Dan
0
 

Author Comment

by:jeordsta
ID: 8038424
Dan,

I tried setting the memory to zero which produced:
Interface Name:
So it seems reasonable to assume that GetIfEntry() isn't returning anything for wszName.

I tried GetInterfaceInfo() but my first call, to work out how much memory is needed for IP_INTERFACE_INFO resulted in an error. When I used FormatMessage to retrieve the system error it complained that "this function is only available in Win32 mode." What on earth is Win32 mode??! And how do I get into that mode??
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8038695
It worked right away for me:

#include <windows.h>
#include <Iphlpapi.h>
#include <stdio.h>
#pragma comment(lib, "D:\\VisualStudio.NET\\Vc7\\PlatformSDK\\lib\\Iphlpapi.lib" )

void ShowErr( DWORD nErr )
{
     LPVOID lpMsgBuf;
     FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
          NULL, nErr,
          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
          (LPTSTR) &lpMsgBuf, 0, NULL
     );
     printf( "GetLastError (0x0%x) %s\r\n", nErr, (LPCSTR)lpMsgBuf );
     LocalFree( lpMsgBuf );
}
void ShowLastErr()  { ShowErr( GetLastError() ); }

int main()
{
     IP_INTERFACE_INFO rIPII;
     DWORD nSize= sizeof(rIPII);

     byte buf[5000];
     IP_INTERFACE_INFO* parIPII= (IP_INTERFACE_INFO*)buf;

     DWORD nRet= GetInterfaceInfo( &rIPII, &nSize ); // error code is 0x0007a
     ShowErr( nRet );

     nRet= GetInterfaceInfo( parIPII, &nSize ); // nSize is 0x0c30
     ShowLastErr();

     WCHAR* pwsName= parIPII->Adapter[0].Name;
     char   szName[MAX_ADAPTER_NAME];
     wcstombs ( szName, pwsName, sizeof ( szName));

     printf( "%s\r\n", szName );
     return(0);
}

output from this program is:

GetLastError (0x07a) The data area passed to a system call is too small.

GetLastError (0x00) The operation completed successfully.

\DEVICE\TCPIP_{1552B244-28CA-4492-980E-182BA89DCC06}

0
 
LVL 49

Accepted Solution

by:
DanRollins earned 150 total points
ID: 8038802
I added this code...

     MIB_IFROW rMIRow;
     DWORD nEntryCnt;

     nRet= GetNumberOfInterfaces( &nEntryCnt );

     for (DWORD j=1; j< nEntryCnt+1; j++ ) {
          memset( &rMIRow, 0 , sizeof(rMIRow));
          rMIRow.dwIndex=j;

          nRet= GetIfEntry( &rMIRow );
          if (nRet !=NO_ERROR ) {
               ShowErr( nRet );
               break;
          }
          printf("entry# %d: Name= '%S', description= '%s'\r\n", j,rMIRow.wszName, rMIRow.bDescr );
     }

and got this additional output....

entry# 1: Name= '', description= 'MS TCP Loopback interface'
entry# 2: Name= '', description= 'VIA PCI 10/100Mb Fast Ethernet Adapter'

-- Dan
0
 

Author Comment

by:jeordsta
ID: 8039240
Dear Dan,

Here is the output from your fist program:

GetLastError (0x07a) The data area passed to a system call is too
small.

GetLastError (0x00) The operation completed successfully.

¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦l_e
Press any key to continue

And your second program:

GetLastError (0x07a) The data area passed to a system call is too
small.

GetLastError (0x00) The operation completed successfully.

¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦l_e
entry# 1: Name= '', description= 'MS TCP Loopback interface'
GetLastError (0x0d) The data is invalid.

entry# 16777218: Name= '', description= 'Intel(R) PRO Adapter'
Press any key to continue

Note that I had to add a bit that manually told GetIfEntry to look for an index of 16777218 because it abandons the for loop before it finds it. Although this still doesn't allow me to see the name of the interface (ie display wszName) it does allow a description of the interface which I was after anyway! Thanks, Geordie.
0

Featured Post

New benefit for Premium Members - Upgrade now!

Ready to get started with anonymous questions today? It's easy! Learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Michael from AdRem Software explains how to view the most utilized and worst performing nodes in your network, by accessing the Top Charts view in NetCrunch network monitor (https://www.adremsoft.com/). Top Charts is a view in which you can set seve…

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question