cscript: Correct forming cmd for forwarding to wscript.
[wine] / dlls / wmiutils / path.c
1 /*
2  * Copyright 2012 Hans Leidekker for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #define COBJMACROS
20
21 #include "config.h"
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "ole2.h"
27 #include "wbemcli.h"
28 #include "wmiutils.h"
29
30 #include "wine/debug.h"
31 #include "wmiutils_private.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(wmiutils);
34
35 struct path
36 {
37     IWbemPath        IWbemPath_iface;
38     LONG             refs;
39     CRITICAL_SECTION cs;
40     WCHAR           *text;
41     int              len_text;
42     WCHAR           *server;
43     int              len_server;
44     WCHAR          **namespaces;
45     int             *len_namespaces;
46     int              num_namespaces;
47     WCHAR           *class;
48     int              len_class;
49     ULONGLONG        flags;
50 };
51
52 static void init_path( struct path *path )
53 {
54     path->text           = NULL;
55     path->len_text       = 0;
56     path->server         = NULL;
57     path->len_server     = 0;
58     path->namespaces     = NULL;
59     path->len_namespaces = NULL;
60     path->num_namespaces = 0;
61     path->class          = NULL;
62     path->len_class      = 0;
63     path->flags          = 0;
64 }
65
66 static void clear_path( struct path *path )
67 {
68     heap_free( path->text );
69     heap_free( path->server );
70     heap_free( path->namespaces );
71     heap_free( path->len_namespaces );
72     heap_free( path->class );
73     init_path( path );
74 }
75
76 static inline struct path *impl_from_IWbemPath( IWbemPath *iface )
77 {
78     return CONTAINING_RECORD(iface, struct path, IWbemPath_iface);
79 }
80
81 static ULONG WINAPI path_AddRef(
82     IWbemPath *iface )
83 {
84     struct path *path = impl_from_IWbemPath( iface );
85     return InterlockedIncrement( &path->refs );
86 }
87
88 static ULONG WINAPI path_Release(
89     IWbemPath *iface )
90 {
91     struct path *path = impl_from_IWbemPath( iface );
92     LONG refs = InterlockedDecrement( &path->refs );
93     if (!refs)
94     {
95         TRACE("destroying %p\n", path);
96         clear_path( path );
97         path->cs.DebugInfo->Spare[0] = 0;
98         DeleteCriticalSection( &path->cs );
99         heap_free( path );
100     }
101     return refs;
102 }
103
104 static HRESULT WINAPI path_QueryInterface(
105     IWbemPath *iface,
106     REFIID riid,
107     void **ppvObject )
108 {
109     struct path *path = impl_from_IWbemPath( iface );
110
111     TRACE("%p, %s, %p\n", path, debugstr_guid( riid ), ppvObject );
112
113     if ( IsEqualGUID( riid, &IID_IWbemPath ) ||
114          IsEqualGUID( riid, &IID_IUnknown ) )
115     {
116         *ppvObject = iface;
117     }
118     else
119     {
120         FIXME("interface %s not implemented\n", debugstr_guid(riid));
121         return E_NOINTERFACE;
122     }
123     IWbemPath_AddRef( iface );
124     return S_OK;
125 }
126
127 static HRESULT parse_text( struct path *path, ULONG mode, const WCHAR *text )
128 {
129     HRESULT hr = E_OUTOFMEMORY;
130     const WCHAR *p, *q;
131     unsigned int i, len;
132
133     p = q = text;
134     if ((p[0] == '\\' && p[1] == '\\') || (p[0] == '/' && p[1] == '/'))
135     {
136         p += 2;
137         q = p;
138         while (*q && *q != '\\' && *q != '/') q++;
139         len = q - p;
140         if (!(path->server = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
141         memcpy( path->server, p, len * sizeof(WCHAR) );
142         path->server[len] = 0;
143         path->len_server = len;
144         path->flags |= WBEMPATH_INFO_PATH_HAD_SERVER;
145     }
146     p = q;
147     while (*q && *q != ':')
148     {
149         if (*q == '\\' || *q == '/') path->num_namespaces++;
150         q++;
151     }
152     if (path->num_namespaces)
153     {
154         if (!(path->namespaces = heap_alloc( path->num_namespaces * sizeof(WCHAR *) ))) goto done;
155         if (!(path->len_namespaces = heap_alloc( path->num_namespaces * sizeof(int) ))) goto done;
156
157         i = 0;
158         q = p;
159         while (*q && *q != ':')
160         {
161             if (*q == '\\' || *q == '/')
162             {
163                 p = q + 1;
164                 while (*p && *p != '\\' && *p != '/' && *p != ':') p++;
165                 len = p - q - 1;
166                 if (!(path->namespaces[i] = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
167                 memcpy( path->namespaces[i], q + 1, len * sizeof(WCHAR) );
168                 path->namespaces[i][len] = 0;
169                 path->len_namespaces[i] = len;
170                 i++;
171             }
172             q++;
173         }
174     }
175     if (*q == ':') q++;
176     p = q;
177     while (*q && *q != '.') q++;
178     len = q - p;
179     if (!(path->class = heap_alloc( (len + 1) * sizeof(WCHAR) ))) goto done;
180     memcpy( path->class, p, len * sizeof(WCHAR) );
181     path->class[len] = 0;
182     path->len_class = len;
183
184     if (*q == '.') FIXME("handle key list\n");
185     hr = S_OK;
186
187 done:
188     if (hr != S_OK) clear_path( path );
189     else path->flags |= WBEMPATH_INFO_CIM_COMPLIANT | WBEMPATH_INFO_V2_COMPLIANT;
190     return hr;
191 }
192
193 static HRESULT WINAPI path_SetText(
194     IWbemPath *iface,
195     ULONG uMode,
196     LPCWSTR pszPath)
197 {
198     struct path *path = impl_from_IWbemPath( iface );
199     HRESULT hr = S_OK;
200     int len;
201
202     TRACE("%p, %u, %s\n", iface, uMode, debugstr_w(pszPath));
203
204     if (!uMode || !pszPath) return WBEM_E_INVALID_PARAMETER;
205
206     EnterCriticalSection( &path->cs );
207
208     clear_path( path );
209     if (!pszPath[0]) goto done;
210     if ((hr = parse_text( path, uMode, pszPath )) != S_OK) goto done;
211
212     len = strlenW( pszPath );
213     if (!(path->text = heap_alloc( (len + 1) * sizeof(WCHAR) )))
214     {
215         clear_path( path );
216         hr = E_OUTOFMEMORY;
217         goto done;
218     }
219     strcpyW( path->text, pszPath );
220     path->len_text = len;
221
222 done:
223     LeaveCriticalSection( &path->cs );
224     return hr;
225 }
226
227 static WCHAR *build_namespace( struct path *path, int *len, BOOL leading_slash )
228 {
229     WCHAR *ret, *p;
230     int i;
231
232     *len = 0;
233     for (i = 0; i < path->num_namespaces; i++)
234     {
235         if (i > 0 || leading_slash) *len += 1;
236         *len += path->len_namespaces[i];
237     }
238     if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) ))) return NULL;
239     for (i = 0; i < path->num_namespaces; i++)
240     {
241         if (i > 0 || leading_slash) *p++ = '\\';
242         memcpy( p, path->namespaces[i], path->len_namespaces[i] * sizeof(WCHAR) );
243         p += path->len_namespaces[i];
244     }
245     *p = 0;
246     return ret;
247 }
248
249 static WCHAR *build_server( struct path *path, int *len )
250 {
251     WCHAR *ret, *p;
252
253     *len = 0;
254     if (path->len_server) *len += 2 + path->len_server;
255     else *len += 3;
256     if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) ))) return NULL;
257     if (path->len_server)
258     {
259         p[0] = p[1] = '\\';
260         strcpyW( p + 2, path->server );
261     }
262     else
263     {
264         p[0] = p[1] = '\\';
265         p[2] = '.';
266     }
267     return ret;
268 }
269
270 static WCHAR *build_path( struct path *path, LONG flags, int *len )
271 {
272     switch (flags)
273     {
274     case 0:
275     {
276         int len_namespace;
277         WCHAR *ret, *namespace = build_namespace( path, &len_namespace, FALSE );
278
279         if (!namespace) return NULL;
280
281         *len = len_namespace;
282         if (path->len_class) *len += 1 + path->len_class;
283         if (!(ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
284         {
285             heap_free( namespace );
286             return NULL;
287         }
288         strcpyW( ret, namespace );
289         if (path->len_class)
290         {
291             ret[len_namespace] = ':';
292             strcpyW( ret + len_namespace + 1, path->class );
293         }
294         heap_free( namespace );
295         return ret;
296
297     }
298     case WBEMPATH_GET_RELATIVE_ONLY:
299         if (!path->len_class)
300         {
301             *len = 0;
302             return NULL;
303         }
304         *len = path->len_class;
305         return strdupW( path->class );
306
307     case WBEMPATH_GET_SERVER_TOO:
308     {
309         int len_namespace, len_server;
310         WCHAR *p, *ret, *namespace = build_namespace( path, &len_namespace, TRUE );
311         WCHAR *server = build_server( path, &len_server );
312
313         if (!namespace || !server)
314         {
315             heap_free( namespace );
316             heap_free( server );
317             return NULL;
318         }
319         *len = len_namespace + len_server;
320         if (path->len_class) *len += 1 + path->len_class;
321         if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
322         {
323             heap_free( namespace );
324             heap_free( server );
325             return NULL;
326         }
327         strcpyW( p, server );
328         p += len_server;
329         strcpyW( p, namespace );
330         p += len_namespace;
331         if (path->len_class)
332         {
333             *p = ':';
334             strcpyW( p + 1, path->class );
335         }
336         heap_free( namespace );
337         heap_free( server );
338         return ret;
339     }
340     case WBEMPATH_GET_SERVER_AND_NAMESPACE_ONLY:
341     {
342         int len_namespace, len_server;
343         WCHAR *p, *ret, *namespace = build_namespace( path, &len_namespace, TRUE );
344         WCHAR *server = build_server( path, &len_server );
345
346         if (!namespace || !server)
347         {
348             heap_free( namespace );
349             heap_free( server );
350             return NULL;
351         }
352         *len = len_namespace + len_server;
353         if (!(p = ret = heap_alloc( (*len + 1) * sizeof(WCHAR) )))
354         {
355             heap_free( namespace );
356             heap_free( server );
357             return NULL;
358         }
359         strcpyW( p, server );
360         p += len_server;
361         strcpyW( p, namespace );
362         heap_free( namespace );
363         heap_free( server );
364         return ret;
365     }
366     case WBEMPATH_GET_NAMESPACE_ONLY:
367         return build_namespace( path, len, FALSE );
368
369     case WBEMPATH_GET_ORIGINAL:
370         if (!path->len_text)
371         {
372             *len = 0;
373             return NULL;
374         }
375         *len = path->len_text;
376         return strdupW( path->text );
377
378     default:
379         ERR("unhandled flags 0x%x\n", flags);
380         return NULL;
381     }
382 }
383
384 static HRESULT WINAPI path_GetText(
385     IWbemPath *iface,
386     LONG lFlags,
387     ULONG *puBufferLength,
388     LPWSTR pszText)
389 {
390     struct path *path = impl_from_IWbemPath( iface );
391     HRESULT hr = S_OK;
392     WCHAR *str;
393     int len;
394
395     TRACE("%p, 0x%x, %p, %p\n", iface, lFlags, puBufferLength, pszText);
396
397     if (!puBufferLength) return WBEM_E_INVALID_PARAMETER;
398
399     EnterCriticalSection( &path->cs );
400
401     str = build_path( path, lFlags, &len );
402     if (*puBufferLength < len + 1)
403     {
404         *puBufferLength = len + 1;
405         goto done;
406     }
407     if (!pszText)
408     {
409         hr = WBEM_E_INVALID_PARAMETER;
410         goto done;
411     }
412     if (str) strcpyW( pszText, str );
413     else pszText[0] = 0;
414     *puBufferLength = len + 1;
415
416     TRACE("returning %s\n", debugstr_w(pszText));
417
418 done:
419     heap_free( str );
420     LeaveCriticalSection( &path->cs );
421     return hr;
422 }
423
424 static HRESULT WINAPI path_GetInfo(
425     IWbemPath *iface,
426     ULONG info,
427     ULONGLONG *response)
428 {
429     struct path *path = impl_from_IWbemPath( iface );
430
431     TRACE("%p, %u, %p\n", iface, info, response);
432
433     if (info || !response) return WBEM_E_INVALID_PARAMETER;
434
435     FIXME("some flags are not implemented\n");
436
437     EnterCriticalSection( &path->cs );
438
439     *response = path->flags;
440     if (!path->server || (path->len_server == 1 && path->server[0] == '.'))
441         *response |= WBEMPATH_INFO_ANON_LOCAL_MACHINE;
442     else
443         *response |= WBEMPATH_INFO_HAS_MACHINE_NAME;
444
445     if (!path->class)
446         *response |= WBEMPATH_INFO_SERVER_NAMESPACE_ONLY;
447     else
448     {
449         *response |= WBEMPATH_INFO_HAS_SUBSCOPES;
450         if (path->text && strchrW( path->text, '=' )) /* FIXME */
451             *response |= WBEMPATH_INFO_IS_INST_REF;
452         else
453             *response |= WBEMPATH_INFO_IS_CLASS_REF;
454     }
455
456     LeaveCriticalSection( &path->cs );
457     return S_OK;
458 }
459
460 static HRESULT WINAPI path_SetServer(
461     IWbemPath *iface,
462     LPCWSTR name)
463 {
464     struct path *path = impl_from_IWbemPath( iface );
465     static const ULONGLONG flags =
466         WBEMPATH_INFO_PATH_HAD_SERVER | WBEMPATH_INFO_V1_COMPLIANT |
467         WBEMPATH_INFO_V2_COMPLIANT | WBEMPATH_INFO_CIM_COMPLIANT;
468     WCHAR *server;
469
470     TRACE("%p, %s\n", iface, debugstr_w(name));
471
472     EnterCriticalSection( &path->cs );
473
474     if (name)
475     {
476         if (!(server = strdupW( name )))
477         {
478             LeaveCriticalSection( &path->cs );
479             return WBEM_E_OUT_OF_MEMORY;
480         }
481         heap_free( path->server );
482         path->server = server;
483         path->len_server = strlenW( path->server );
484         path->flags |= flags;
485     }
486     else
487     {
488         heap_free( path->server );
489         path->server = NULL;
490         path->len_server = 0;
491         path->flags &= ~flags;
492     }
493
494     LeaveCriticalSection( &path->cs );
495     return S_OK;
496 }
497
498 static HRESULT WINAPI path_GetServer(
499     IWbemPath *iface,
500     ULONG *len,
501     LPWSTR name)
502 {
503     struct path *path = impl_from_IWbemPath( iface );
504
505     TRACE("%p, %p, %p\n", iface, len, name);
506
507     if (!len || (*len && !name)) return WBEM_E_INVALID_PARAMETER;
508
509     EnterCriticalSection( &path->cs );
510
511     if (!path->server)
512     {
513         LeaveCriticalSection( &path->cs );
514         return WBEM_E_NOT_AVAILABLE;
515     }
516     if (*len > path->len_server) strcpyW( name, path->server );
517     *len = path->len_server + 1;
518
519     LeaveCriticalSection( &path->cs );
520     return S_OK;
521 }
522
523 static HRESULT WINAPI path_GetNamespaceCount(
524     IWbemPath *iface,
525     ULONG *puCount)
526 {
527     struct path *path = impl_from_IWbemPath( iface );
528
529     TRACE("%p, %p\n", iface, puCount);
530
531     if (!puCount) return WBEM_E_INVALID_PARAMETER;
532
533     EnterCriticalSection( &path->cs );
534     *puCount = path->num_namespaces;
535     LeaveCriticalSection( &path->cs );
536     return S_OK;
537 }
538
539 static HRESULT WINAPI path_SetNamespaceAt(
540     IWbemPath *iface,
541     ULONG idx,
542     LPCWSTR name)
543 {
544     struct path *path = impl_from_IWbemPath( iface );
545     static const ULONGLONG flags =
546         WBEMPATH_INFO_V1_COMPLIANT | WBEMPATH_INFO_V2_COMPLIANT |
547         WBEMPATH_INFO_CIM_COMPLIANT;
548     int i, *tmp_len;
549     WCHAR **tmp, *new;
550     DWORD size;
551
552     TRACE("%p, %u, %s\n", iface, idx, debugstr_w(name));
553
554     EnterCriticalSection( &path->cs );
555
556     if (idx > path->num_namespaces || !name)
557     {
558         LeaveCriticalSection( &path->cs );
559         return WBEM_E_INVALID_PARAMETER;
560     }
561     if (!(new = strdupW( name )))
562     {
563         LeaveCriticalSection( &path->cs );
564         return WBEM_E_OUT_OF_MEMORY;
565     }
566     size = (path->num_namespaces + 1) * sizeof(WCHAR *);
567     if (path->namespaces) tmp = heap_realloc( path->namespaces, size );
568     else tmp = heap_alloc( size );
569     if (!tmp)
570     {
571         heap_free( new );
572         LeaveCriticalSection( &path->cs );
573         return WBEM_E_OUT_OF_MEMORY;
574     }
575     path->namespaces = tmp;
576     size = (path->num_namespaces + 1) * sizeof(int);
577     if (path->len_namespaces) tmp_len = heap_realloc( path->len_namespaces, size );
578     else tmp_len = heap_alloc( size );
579     if (!tmp_len)
580     {
581         heap_free( new );
582         LeaveCriticalSection( &path->cs );
583         return WBEM_E_OUT_OF_MEMORY;
584     }
585     path->len_namespaces = tmp_len;
586     for (i = idx; i < path->num_namespaces; i++)
587     {
588         path->namespaces[i + 1] = path->namespaces[i];
589         path->len_namespaces[i + 1] = path->len_namespaces[i];
590     }
591     path->namespaces[idx] = new;
592     path->len_namespaces[idx] = strlenW( new );
593     path->num_namespaces++;
594     path->flags |= flags;
595
596     LeaveCriticalSection( &path->cs );
597     return S_OK;
598 }
599
600 static HRESULT WINAPI path_GetNamespaceAt(
601     IWbemPath *iface,
602     ULONG idx,
603     ULONG *len,
604     LPWSTR name)
605 {
606     struct path *path = impl_from_IWbemPath( iface );
607
608     TRACE("%p, %u, %p, %p\n", iface, idx, len, name);
609
610     EnterCriticalSection( &path->cs );
611
612     if (!len || (*len && !name) || idx >= path->num_namespaces)
613     {
614         LeaveCriticalSection( &path->cs );
615         return WBEM_E_INVALID_PARAMETER;
616     }
617     if (*len > path->len_namespaces[idx]) strcpyW( name, path->namespaces[idx] );
618     *len = path->len_namespaces[idx] + 1;
619
620     LeaveCriticalSection( &path->cs );
621     return S_OK;
622 }
623
624 static HRESULT WINAPI path_RemoveNamespaceAt(
625     IWbemPath *iface,
626     ULONG idx)
627 {
628     struct path *path = impl_from_IWbemPath( iface );
629
630     TRACE("%p, %u\n", iface, idx);
631
632     EnterCriticalSection( &path->cs );
633
634     if (idx >= path->num_namespaces)
635     {
636         LeaveCriticalSection( &path->cs );
637         return WBEM_E_INVALID_PARAMETER;
638     }
639     heap_free( path->namespaces[idx] );
640     while (idx < path->num_namespaces - 1)
641     {
642         path->namespaces[idx] = path->namespaces[idx + 1];
643         path->len_namespaces[idx] = path->len_namespaces[idx + 1];
644         idx++;
645     }
646     path->num_namespaces--;
647
648     LeaveCriticalSection( &path->cs );
649     return S_OK;
650 }
651
652 static HRESULT WINAPI path_RemoveAllNamespaces(
653     IWbemPath *iface)
654 {
655     struct path *path = impl_from_IWbemPath( iface );
656     int i;
657
658     TRACE("%p\n", iface);
659
660     EnterCriticalSection( &path->cs );
661
662     for (i = 0; i < path->num_namespaces; i++) heap_free( path->namespaces[i] );
663     path->num_namespaces = 0;
664     heap_free( path->namespaces );
665     path->namespaces = NULL;
666     heap_free( path->len_namespaces );
667     path->len_namespaces = NULL;
668
669     LeaveCriticalSection( &path->cs );
670     return S_OK;
671 }
672
673 static HRESULT WINAPI path_GetScopeCount(
674     IWbemPath *iface,
675     ULONG *puCount)
676 {
677     FIXME("%p, %p\n", iface, puCount);
678     return E_NOTIMPL;
679 }
680
681 static HRESULT WINAPI path_SetScope(
682     IWbemPath *iface,
683     ULONG uIndex,
684     LPWSTR pszClass)
685 {
686     FIXME("%p, %u, %s\n", iface, uIndex, debugstr_w(pszClass));
687     return E_NOTIMPL;
688 }
689
690 static HRESULT WINAPI path_SetScopeFromText(
691     IWbemPath *iface,
692     ULONG uIndex,
693     LPWSTR pszText)
694 {
695     FIXME("%p, %u, %s\n", iface, uIndex, debugstr_w(pszText));
696     return E_NOTIMPL;
697 }
698
699 static HRESULT WINAPI path_GetScope(
700     IWbemPath *iface,
701     ULONG uIndex,
702     ULONG *puClassNameBufSize,
703     LPWSTR pszClass,
704     IWbemPathKeyList **pKeyList)
705 {
706     FIXME("%p, %u, %p, %p, %p\n", iface, uIndex, puClassNameBufSize, pszClass, pKeyList);
707     return E_NOTIMPL;
708 }
709
710 static HRESULT WINAPI path_GetScopeAsText(
711     IWbemPath *iface,
712     ULONG uIndex,
713     ULONG *puTextBufSize,
714     LPWSTR pszText)
715 {
716     FIXME("%p, %u, %p, %p\n", iface, uIndex, puTextBufSize, pszText);
717     return E_NOTIMPL;
718 }
719
720 static HRESULT WINAPI path_RemoveScope(
721     IWbemPath *iface,
722     ULONG uIndex)
723 {
724     FIXME("%p, %u\n", iface, uIndex);
725     return E_NOTIMPL;
726 }
727
728 static HRESULT WINAPI path_RemoveAllScopes(
729     IWbemPath *iface)
730 {
731     FIXME("%p\n", iface);
732     return E_NOTIMPL;
733 }
734
735 static HRESULT WINAPI path_SetClassName(
736     IWbemPath *iface,
737     LPCWSTR name)
738 {
739     struct path *path = impl_from_IWbemPath( iface );
740     WCHAR *class;
741
742     TRACE("%p, %s\n", iface, debugstr_w(name));
743
744     if (!name) return WBEM_E_INVALID_PARAMETER;
745     if (!(class = strdupW( name ))) return WBEM_E_OUT_OF_MEMORY;
746
747     EnterCriticalSection( &path->cs );
748
749     heap_free( path->class );
750     path->class = class;
751     path->len_class = strlenW( path->class );
752     path->flags |= WBEMPATH_INFO_V2_COMPLIANT | WBEMPATH_INFO_CIM_COMPLIANT;
753
754     LeaveCriticalSection( &path->cs );
755     return S_OK;
756 }
757
758 static HRESULT WINAPI path_GetClassName(
759     IWbemPath *iface,
760     ULONG *len,
761     LPWSTR name)
762 {
763     struct path *path = impl_from_IWbemPath( iface );
764
765     TRACE("%p, %p, %p\n", iface, len, name);
766
767     if (!len || (*len && !name)) return WBEM_E_INVALID_PARAMETER;
768
769     EnterCriticalSection( &path->cs );
770
771     if (!path->class)
772     {
773         LeaveCriticalSection( &path->cs );
774         return WBEM_E_INVALID_OBJECT_PATH;
775     }
776     if (*len > path->len_class) strcpyW( name, path->class );
777     *len = path->len_class + 1;
778
779     LeaveCriticalSection( &path->cs );
780     return S_OK;
781 }
782
783 static HRESULT WINAPI path_GetKeyList(
784     IWbemPath *iface,
785     IWbemPathKeyList **pOut)
786 {
787     FIXME("%p, %p\n", iface, pOut);
788     return E_NOTIMPL;
789 }
790
791 static HRESULT WINAPI path_CreateClassPart(
792     IWbemPath *iface,
793     LONG lFlags,
794     LPCWSTR Name)
795 {
796     FIXME("%p, 0x%x, %s\n", iface, lFlags, debugstr_w(Name));
797     return E_NOTIMPL;
798 }
799
800 static HRESULT WINAPI path_DeleteClassPart(
801     IWbemPath *iface,
802     LONG lFlags)
803 {
804     FIXME("%p, 0x%x\n", iface, lFlags);
805     return E_NOTIMPL;
806 }
807
808 static BOOL WINAPI path_IsRelative(
809     IWbemPath *iface,
810     LPWSTR wszMachine,
811     LPWSTR wszNamespace)
812 {
813     FIXME("%p, %s, %s\n", iface, debugstr_w(wszMachine), debugstr_w(wszNamespace));
814     return E_NOTIMPL;
815 }
816
817 static BOOL WINAPI path_IsRelativeOrChild(
818     IWbemPath *iface,
819     LPWSTR wszMachine,
820     LPWSTR wszNamespace,
821     LONG lFlags)
822 {
823     FIXME("%p, %s, %s, 0x%x\n", iface, debugstr_w(wszMachine), debugstr_w(wszNamespace), lFlags);
824     return E_NOTIMPL;
825 }
826
827 static BOOL WINAPI path_IsLocal(
828     IWbemPath *iface,
829     LPCWSTR wszMachine)
830 {
831     FIXME("%p, %s\n", iface, debugstr_w(wszMachine));
832     return E_NOTIMPL;
833 }
834
835 static BOOL WINAPI path_IsSameClassName(
836     IWbemPath *iface,
837     LPCWSTR wszClass)
838 {
839     FIXME("%p, %s\n", iface, debugstr_w(wszClass));
840     return E_NOTIMPL;
841 }
842
843 static const struct IWbemPathVtbl path_vtbl =
844 {
845     path_QueryInterface,
846     path_AddRef,
847     path_Release,
848     path_SetText,
849     path_GetText,
850     path_GetInfo,
851     path_SetServer,
852     path_GetServer,
853     path_GetNamespaceCount,
854     path_SetNamespaceAt,
855     path_GetNamespaceAt,
856     path_RemoveNamespaceAt,
857     path_RemoveAllNamespaces,
858     path_GetScopeCount,
859     path_SetScope,
860     path_SetScopeFromText,
861     path_GetScope,
862     path_GetScopeAsText,
863     path_RemoveScope,
864     path_RemoveAllScopes,
865     path_SetClassName,
866     path_GetClassName,
867     path_GetKeyList,
868     path_CreateClassPart,
869     path_DeleteClassPart,
870     path_IsRelative,
871     path_IsRelativeOrChild,
872     path_IsLocal,
873     path_IsSameClassName
874 };
875
876 HRESULT WbemPath_create( IUnknown *pUnkOuter, LPVOID *ppObj )
877 {
878     struct path *path;
879
880     TRACE("%p, %p\n", pUnkOuter, ppObj);
881
882     if (!(path = heap_alloc( sizeof(*path) ))) return E_OUTOFMEMORY;
883
884     path->IWbemPath_iface.lpVtbl = &path_vtbl;
885     path->refs = 1;
886     InitializeCriticalSection( &path->cs );
887     path->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wmiutils_path.cs");
888     init_path( path );
889
890     *ppObj = &path->IWbemPath_iface;
891
892     TRACE("returning iface %p\n", *ppObj);
893     return S_OK;
894 }