- AddRef type info stored in StdDispatch.
[wine] / dlls / kernel / computername.c
1 /*
2  * Win32 kernel functions
3  *
4  * Copyright 1995 Martin von Loewis and Cameron Heide
5  * Copyright 1999 Peter Ganten
6  * Copyright 2002 Martin Wilck
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <stdlib.h>
30 #include <errno.h>
31 #ifdef HAVE_NETDB_H
32 #include <netdb.h>
33 #endif
34
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winnls.h"
38 #include "winternl.h"
39 #include "wine/unicode.h"
40 #include "wine/exception.h"
41 #include "excpt.h"
42 #include "wine/debug.h"
43 #include "file.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(computername);
46
47 /* Wine config options */ 
48 static const WCHAR NetworkW[] = {'N','e','t','w','o','r','k',0};
49 static const WCHAR UseDNSW[] = {'U','s','e','D','n','s','C','o','m','p','u','t','e','r','N','a','m','e',0};
50
51 /* Registry key and value names */
52 static const WCHAR ComputerW[] = {'M','a','c','h','i','n','e','\\',
53                                   'S','y','s','t','e','m','\\',
54                                   'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
55                                   'C','o','n','t','r','o','l','\\',
56                                   'C','o','m','p','u','t','e','r','N','a','m','e',0};
57 static const WCHAR ActiveComputerNameW[] =   {'A','c','t','i','v','e','C','o','m','p','u','t','e','r','N','a','m','e',0};
58 static const WCHAR ComputerNameW[] = {'C','o','m','p','u','t','e','r','N','a','m','e',0};
59
60 static const char default_ComputerName[] = "WINE";
61
62 /* filter for page-fault exceptions */
63 static WINE_EXCEPTION_FILTER(page_fault)
64 {
65     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
66         return EXCEPTION_EXECUTE_HANDLER;
67     return EXCEPTION_CONTINUE_SEARCH;
68 }
69
70 /*********************************************************************** 
71  *                    dns_gethostbyname (INTERNAL)
72  *
73  *  From hostname(1):
74  *  "The FQDN is the name gethostbyname(2) returns for the host name returned by gethostname(2)."
75  *
76  *  Wine can use this technique only if the thread-safe gethostbyname_r is available.
77  */
78 #ifdef  HAVE_LINUX_GETHOSTBYNAME_R_6
79 static BOOL dns_gethostbyname ( char *name, int *size )
80 {
81     struct hostent* host = NULL;
82     char *extrabuf;
83     int ebufsize = 1024;
84     struct hostent hostentry;
85     int locerr = ENOBUFS, res = ENOMEM;
86
87     extrabuf = HeapAlloc( GetProcessHeap(), 0, ebufsize ) ;
88
89     while( extrabuf ) 
90     {
91         res = gethostbyname_r ( name, &hostentry, extrabuf, ebufsize, &host, &locerr );
92         if( res != ERANGE ) break;
93         ebufsize *= 2;
94         extrabuf = HeapReAlloc( GetProcessHeap(), 0, extrabuf, ebufsize ) ;
95     }
96     
97     if ( res )
98         WARN ("Error in gethostbyname_r %d (%d)\n", res, locerr);
99     else
100     {
101         size_t len = strlen ( host->h_name );
102         if ( len < *size )
103         {
104             strcpy ( name, host->h_name );
105             *size = len;
106         }
107         else
108         {
109             memcpy ( name, host->h_name, *size );
110             name[*size] = 0;
111             SetLastError ( ERROR_MORE_DATA );
112             res = 1;
113         }
114     }
115
116     HeapFree( GetProcessHeap(), 0, extrabuf );
117     return !res;
118 }
119 #else
120 #  define dns_gethostbyname(name,size) 0
121 #endif
122
123 /*********************************************************************** 
124  *                     dns_fqdn (INTERNAL)
125  */
126 static BOOL dns_fqdn ( char *name, int *size )
127 {
128     if ( gethostname ( name, *size + 1 ) ) 
129     {
130         switch( errno )
131         {
132         case ENAMETOOLONG:
133             SetLastError ( ERROR_MORE_DATA );
134         default:
135             SetLastError ( ERROR_INVALID_PARAMETER );
136         }
137         return FALSE;
138     }
139
140     if ( !dns_gethostbyname ( name, size ) )
141         *size = strlen ( name );
142
143     return TRUE;
144 }
145
146 /*********************************************************************** 
147  *                     dns_hostname (INTERNAL)
148  */
149 static BOOL dns_hostname ( char *name, int *size )
150 {
151     char *c;
152     if ( ! dns_fqdn ( name, size ) ) return FALSE;
153     c = strchr ( name, '.' );
154     if (c)
155     {
156         *c = 0;
157         *size = (c - name);
158     }
159     return TRUE;
160 }
161
162 /*********************************************************************** 
163  *                     dns_domainname (INTERNAL)
164  */
165 static BOOL dns_domainname ( char *name, int *size )
166 {
167     char *c;
168     if ( ! dns_fqdn ( name, size ) ) return FALSE;
169     c = strchr ( name, '.' );
170     if (c)
171     {
172         c += 1;
173         *size -= (c - name);
174         memmove ( name, c, *size + 1 );
175     }
176     return TRUE;
177 }
178
179 /*********************************************************************** 
180  *                      _init_attr    (INTERNAL)
181  */
182 inline static void _init_attr ( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *name )
183 {
184     attr->Length = sizeof (OBJECT_ATTRIBUTES);
185     attr->RootDirectory = 0;
186     attr->ObjectName = name;
187     attr->Attributes = 0;
188     attr->SecurityDescriptor = NULL;
189     attr->SecurityQualityOfService = NULL;
190 }
191
192 /*********************************************************************** 
193  *                      COMPUTERNAME_Init    (INTERNAL)
194  */
195 void COMPUTERNAME_Init (void)
196 {
197     HKEY hkey = INVALID_HANDLE_VALUE, hsubkey = INVALID_HANDLE_VALUE;
198     OBJECT_ATTRIBUTES attr;
199     UNICODE_STRING nameW;
200     char buf[offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ) + (MAX_COMPUTERNAME_LENGTH + 1) * sizeof( WCHAR )];
201     DWORD len = sizeof( buf );
202     LPWSTR computer_name = (LPWSTR) (buf + offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ));
203     NTSTATUS st = STATUS_INTERNAL_ERROR;
204
205     TRACE("(void)\n");
206     _init_attr ( &attr, &nameW );
207     
208     RtlInitUnicodeString( &nameW, ComputerW );
209     if ( ( st = NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) ) != STATUS_SUCCESS )
210         goto out;
211     
212     attr.RootDirectory = hkey;
213     RtlInitUnicodeString( &nameW, ComputerNameW );
214     if ( (st = NtCreateKey( &hsubkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) ) != STATUS_SUCCESS )
215         goto out;
216     
217     st = NtQueryValueKey( hsubkey, &nameW, KeyValuePartialInformation, buf, len, &len );
218
219     if ( st == STATUS_OBJECT_NAME_NOT_FOUND || 
220          ( st == STATUS_SUCCESS && PROFILE_GetWineIniBool( NetworkW, UseDNSW, 1 ) ) )
221     {
222         char hbuf[256];
223         int hlen = sizeof (hbuf);
224         char *dot;
225         TRACE( "retrieving Unix host name\n" );
226         if ( gethostname ( hbuf, hlen ) )
227         {
228             strcpy ( hbuf, default_ComputerName );
229             WARN( "gethostname() error: %d, using host name %s\n", errno, hbuf );
230         }
231         hbuf[MAX_COMPUTERNAME_LENGTH] = 0;
232         dot = strchr ( hbuf, '.' );
233         if ( dot ) *dot = 0;
234         hlen = strlen ( hbuf );
235         len = MultiByteToWideChar( CP_ACP, 0, hbuf, hlen + 1, computer_name, MAX_COMPUTERNAME_LENGTH + 1 )
236             * sizeof( WCHAR );
237         if ( NtSetValueKey( hsubkey, &nameW, 0, REG_SZ, computer_name, len ) != STATUS_SUCCESS )
238             WARN ( "failed to set ComputerName" );
239     }
240     else if ( st == STATUS_SUCCESS)
241     {
242         len = (len - offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ));
243         TRACE( "found in registry\n" );
244     }
245     else goto out;
246     
247     NtClose( hsubkey );
248     TRACE(" ComputerName: %s (%lu)\n", debugstr_w ( computer_name ), len / sizeof(WCHAR));
249
250     RtlInitUnicodeString( &nameW, ActiveComputerNameW );
251     if ( ( st = NtCreateKey( &hsubkey, KEY_ALL_ACCESS, &attr, 0, NULL, REG_OPTION_VOLATILE, NULL ) )
252          != STATUS_SUCCESS )
253         goto out;
254     
255     RtlInitUnicodeString( &nameW, ComputerNameW );
256     st = NtSetValueKey( hsubkey, &nameW, 0, REG_SZ, computer_name, len );
257
258 out:
259     NtClose( hsubkey );
260     NtClose( hkey );
261
262     if ( st == STATUS_SUCCESS )
263         TRACE( "success\n" );
264     else
265     {
266         WARN( "status trying to set ComputerName: %lx\n", st );
267         SetLastError ( RtlNtStatusToDosError ( st ) );
268     }
269 }
270
271
272 /***********************************************************************
273  *              GetComputerNameW         (KERNEL32.@)
274  */
275 BOOL WINAPI GetComputerNameW(LPWSTR name,LPDWORD size)
276 {
277     UNICODE_STRING nameW;
278     OBJECT_ATTRIBUTES attr;
279     HKEY hkey = INVALID_HANDLE_VALUE, hsubkey = INVALID_HANDLE_VALUE;
280     char buf[offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ) + (MAX_COMPUTERNAME_LENGTH + 1) * sizeof( WCHAR )];
281     DWORD len = sizeof( buf );
282     LPWSTR theName = (LPWSTR) (buf + offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ));
283     NTSTATUS st = STATUS_INVALID_PARAMETER;
284     
285     TRACE ("%p %p\n", name, size);
286
287     _init_attr ( &attr, &nameW );
288     RtlInitUnicodeString( &nameW, ComputerW );
289     if ( ( st = NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) ) != STATUS_SUCCESS )
290         goto out;
291          
292     attr.RootDirectory = hkey;
293     RtlInitUnicodeString( &nameW, ActiveComputerNameW );
294     if ( ( st = NtOpenKey( &hsubkey, KEY_ALL_ACCESS, &attr ) ) != STATUS_SUCCESS )
295         goto out;
296     
297     RtlInitUnicodeString( &nameW, ComputerNameW );
298     if ( ( st = NtQueryValueKey( hsubkey, &nameW, KeyValuePartialInformation, buf, len, &len ) )
299          != STATUS_SUCCESS )
300         goto out;
301
302     len = (len -offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data )) / sizeof (WCHAR) - 1;
303     TRACE ("ComputerName is %s (length %lu)\n", debugstr_w ( theName ), len);
304
305     __TRY
306     {
307         if ( *size < len )
308         {
309             memcpy ( name, theName, *size * sizeof (WCHAR) );
310             name[*size] = 0;
311             *size = len;
312             st = STATUS_MORE_ENTRIES;
313         }
314         else
315         {
316             memcpy ( name, theName, len * sizeof (WCHAR) );
317             name[len] = 0;
318             *size = len;
319             st = STATUS_SUCCESS;
320         }
321     }
322     __EXCEPT(page_fault)
323     {
324         st = STATUS_INVALID_PARAMETER;
325     }
326     __ENDTRY
327
328 out:
329     NtClose ( hsubkey );
330     NtClose ( hkey );
331
332     if ( st == STATUS_SUCCESS )
333         return TRUE;
334     else
335     {
336         SetLastError ( RtlNtStatusToDosError ( st ) );
337         WARN ( "Status %lu reading computer name from registry\n", st );
338         return FALSE;
339     }
340 }
341
342 /***********************************************************************
343  *              GetComputerNameA         (KERNEL32.@)
344  */
345 BOOL WINAPI GetComputerNameA(LPSTR name, LPDWORD size)
346 {
347     WCHAR nameW[ MAX_COMPUTERNAME_LENGTH + 1 ];
348     DWORD sizeW = MAX_COMPUTERNAME_LENGTH;
349     int len;
350     BOOL ret;
351
352     if ( !GetComputerNameW (nameW, &sizeW) ) return FALSE;
353
354     len = WideCharToMultiByte ( CP_ACP, 0, nameW, sizeW, NULL, 0, NULL, 0 );
355     __TRY
356     {
357         if ( *size < len )
358         {
359             WideCharToMultiByte ( CP_ACP, 0, nameW, sizeW, name, *size, NULL, 0 );
360             name[*size] = 0;
361             *size = len;
362             SetLastError( ERROR_MORE_DATA );
363             ret = FALSE;
364         }
365         else 
366         {
367             WideCharToMultiByte ( CP_ACP, 0, nameW, sizeW, name, len, NULL, 0 );
368             name[len] = 0;
369             *size = len;
370             ret = TRUE;
371         }
372     }
373     __EXCEPT(page_fault)
374     {
375         SetLastError( ERROR_INVALID_PARAMETER );
376         ret = FALSE;
377     }
378     __ENDTRY
379
380     return ret;
381 }
382
383 /***********************************************************************
384  *              GetComputerNameExA         (KERNEL32.@)
385  */
386 BOOL WINAPI GetComputerNameExA(COMPUTER_NAME_FORMAT type, LPSTR name, LPDWORD size)
387 {
388     char buf[256];
389     int len = sizeof (buf), ret;
390     TRACE("%d, %p, %p\n", type, name, size);
391     switch( type )
392     {
393     case ComputerNameNetBIOS:
394     case ComputerNamePhysicalNetBIOS:
395         return GetComputerNameA (name, size);
396     case ComputerNameDnsHostname:
397     case ComputerNamePhysicalDnsHostname:
398         ret = dns_hostname (buf, &len);
399         break;
400     case ComputerNameDnsDomain:
401     case ComputerNamePhysicalDnsDomain:
402         ret = dns_domainname (buf, &len);
403         break;
404     case ComputerNameDnsFullyQualified:
405     case ComputerNamePhysicalDnsFullyQualified:
406         ret = dns_fqdn (buf, &len);
407         break;
408     default:
409         SetLastError (ERROR_INVALID_PARAMETER);
410         return FALSE;
411     }
412
413     if ( ret )
414     {
415         TRACE ("-> %s (%d)\n", debugstr_a (buf), len);
416         __TRY
417         {
418             if ( *size < len )
419             {
420                 memcpy( name, buf, *size );
421                 name[*size] = 0;
422                 *size = len;
423                 SetLastError( ERROR_MORE_DATA );
424                 ret = FALSE;
425             }
426             else
427             {
428                 memcpy( name, buf, len );
429                 name[len] = 0;
430                 *size = len;
431                 ret = TRUE;
432             }
433         }
434         __EXCEPT(page_fault)
435         {
436             SetLastError( ERROR_INVALID_PARAMETER );
437             return FALSE;
438         }
439         __ENDTRY
440     }
441
442     return ret;
443 }
444
445
446 /***********************************************************************
447  *              GetComputerNameExW         (KERNEL32.@)
448  */
449 BOOL WINAPI GetComputerNameExW( COMPUTER_NAME_FORMAT type, LPWSTR name, LPDWORD size )
450 {
451     char buf[256];
452     int len = sizeof (buf), ret;
453
454     TRACE("%d, %p, %p\n", type, name, size);
455     switch( type )
456     {
457     case ComputerNameNetBIOS:
458     case ComputerNamePhysicalNetBIOS:
459         return GetComputerNameW (name, size);
460     case ComputerNameDnsHostname:
461     case ComputerNamePhysicalDnsHostname:
462         ret = dns_hostname (buf, &len);
463         break;
464     case ComputerNameDnsDomain:
465     case ComputerNamePhysicalDnsDomain:
466         ret = dns_domainname (buf, &len);
467         break;
468     case ComputerNameDnsFullyQualified:
469     case ComputerNamePhysicalDnsFullyQualified:
470         ret = dns_fqdn (buf, &len);
471         break;
472     default:
473         SetLastError (ERROR_INVALID_PARAMETER);
474         return FALSE;
475     }
476
477     if ( ret )
478     {
479         TRACE ("-> %s (%d)\n", debugstr_a (buf), len);
480         __TRY
481         {
482             int lenW = MultiByteToWideChar( CP_ACP, 0, buf, len, NULL, 0 );
483             if ( *size < lenW )
484             {
485                 MultiByteToWideChar( CP_ACP, 0, buf, len, name, *size );
486                 name[*size] = 0;
487                 *size = lenW;
488                 SetLastError( ERROR_MORE_DATA );
489                 ret = FALSE;
490             }
491             else
492             {
493                 MultiByteToWideChar( CP_ACP, 0, buf, len, name, lenW );
494                 name[lenW] = 0;
495                 *size = lenW;
496                 ret = TRUE;
497             }
498         }
499         __EXCEPT(page_fault)
500         {
501             SetLastError( ERROR_INVALID_PARAMETER );
502             return FALSE;
503         }
504         __ENDTRY
505     }
506
507     return ret;
508 }
509
510 /******************************************************************************
511  * netbios_char (INTERNAL)
512  */
513 static WCHAR netbios_char ( WCHAR wc )
514 {
515     static const WCHAR special[] = {'!','@','#','$','%','^','&','\'',')','(','-','_','{','}','~'};
516     static const WCHAR deflt = '_';
517     int i;
518     
519     if ( isalnumW ( wc ) ) return wc;
520     for ( i = 0; i < sizeof (special) / sizeof (WCHAR); i++ )
521         if ( wc == special[i] ) return wc;
522     return deflt;
523 }
524
525 /******************************************************************************
526  * SetComputerNameW [KERNEL32.@]
527  *
528  * PARAMS
529  *    lpComputerName [I] Address of new computer name
530  *
531  * RETURNS STD
532  */
533 BOOL WINAPI SetComputerNameW( LPCWSTR lpComputerName )
534 {
535     UNICODE_STRING nameW;
536     OBJECT_ATTRIBUTES attr;
537     HKEY hkey = INVALID_HANDLE_VALUE, hsubkey = INVALID_HANDLE_VALUE;
538     int plen = strlenW ( lpComputerName );
539     int i;
540     NTSTATUS st = STATUS_INTERNAL_ERROR;
541
542     if ( PROFILE_GetWineIniBool ( NetworkW, UseDNSW, 1 ) )
543     {
544         /* This check isn't necessary, but may help debugging problems. */
545         WARN( "Disabled by Wine Configuration.\n" );
546         WARN( "Set \"UseDnsComputerName\" = \"N\" in category [Network] to enable.\n" );
547         SetLastError ( ERROR_ACCESS_DENIED );
548         return FALSE;
549     }
550
551     TRACE( "%s\n", debugstr_w (lpComputerName) );
552
553     /* Check parameter */
554     if ( plen > MAX_COMPUTERNAME_LENGTH ) 
555         goto out;
556
557     /* This is NT behaviour. Win 95/98 would coerce characters. */
558     for ( i = 0; i < plen; i++ )
559     {
560         WCHAR wc = lpComputerName[i];
561         if ( wc != netbios_char( wc ) )
562             goto out;
563     }
564     
565     _init_attr ( &attr, &nameW );
566     
567     RtlInitUnicodeString (&nameW, ComputerW);
568     if ( ( st = NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) ) != STATUS_SUCCESS )
569         goto out;
570     attr.RootDirectory = hkey;
571     RtlInitUnicodeString( &nameW, ComputerNameW );
572     if ( ( st = NtOpenKey( &hsubkey, KEY_ALL_ACCESS, &attr ) ) != STATUS_SUCCESS )
573         goto out;
574     if ( ( st = NtSetValueKey( hsubkey, &nameW, 0, REG_SZ, lpComputerName, ( plen + 1) * sizeof(WCHAR) ) )
575          != STATUS_SUCCESS )
576         goto out;
577
578 out:
579     NtClose( hsubkey );
580     NtClose( hkey );
581     
582     if ( st == STATUS_SUCCESS )
583     {
584         TRACE( "ComputerName changed\n" );
585         return TRUE;
586     }
587
588     else
589     {
590         SetLastError ( RtlNtStatusToDosError ( st ) );
591         WARN ( "status %lu\n", st );
592         return FALSE;
593     }
594 }
595
596 /******************************************************************************
597  * SetComputerNameA [KERNEL32.@]
598  */
599 BOOL WINAPI SetComputerNameA( LPCSTR lpComputerName )
600 {
601     BOOL ret;
602     DWORD len = MultiByteToWideChar( CP_ACP, 0, lpComputerName, -1, NULL, 0 );
603     LPWSTR nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
604
605     MultiByteToWideChar( CP_ACP, 0, lpComputerName, -1, nameW, len );
606     ret = SetComputerNameW( nameW );
607     HeapFree( GetProcessHeap(), 0, nameW );
608     return ret;
609 }
610
611 /******************************************************************************
612  * SetComputerNameExW [KERNEL32.@]
613  *
614  */
615 BOOL WINAPI SetComputerNameExW( COMPUTER_NAME_FORMAT type, LPCWSTR lpComputerName )
616 {
617     TRACE("%d, %s\n", type, debugstr_w (lpComputerName));
618     switch( type )
619     {
620     case ComputerNameNetBIOS:
621     case ComputerNamePhysicalNetBIOS:
622         return SetComputerNameW( lpComputerName );
623     default:
624         SetLastError( ERROR_ACCESS_DENIED );
625         return FALSE;
626     }
627 }
628
629 /******************************************************************************
630  * SetComputerNameExA [KERNEL32.@]
631  *
632  */
633 BOOL WINAPI SetComputerNameExA( COMPUTER_NAME_FORMAT type, LPCSTR lpComputerName )
634 {
635     TRACE( "%d, %s\n", type, debugstr_a (lpComputerName) );
636     switch( type )
637     {
638     case ComputerNameNetBIOS:
639     case ComputerNamePhysicalNetBIOS:
640         return SetComputerNameA( lpComputerName );
641     default:
642         SetLastError( ERROR_ACCESS_DENIED );
643         return FALSE;
644     }
645 }
646
647 /***********************************************************************
648  *              DnsHostnameToComputerNameA         (KERNEL32.@)
649  */
650 BOOL WINAPI DnsHostnameToComputerNameA(LPCSTR Hostname, LPSTR ComputerName,
651                               LPDWORD nSize)
652 {
653     FIXME("(%s, %s, %08lx): stub\n", debugstr_a(Hostname),
654           debugstr_a(ComputerName), *nSize);
655     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
656     return FALSE;
657 }
658
659 /***********************************************************************
660  *              DnsHostnameToComputerNameW         (KERNEL32.@)
661  */
662 BOOL WINAPI DnsHostnameToComputerNameW(LPCWSTR Hostname, LPWSTR ComputerName,
663                               LPDWORD nSize)
664 {
665     FIXME("(%s, %s, %08lx): stub\n", debugstr_w(Hostname),
666           debugstr_w(ComputerName), *nSize);
667     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
668     return FALSE;
669 }