xref: /reactos/dll/win32/mswsock/mswhelper.c (revision 0f8439aa)
1 
2 #include "precomp.h"
3 
4 #include <winuser.h>
5 #include <winnls.h>
6 #include <wchar.h>
7 #include <sal.h>
8 
9 #include "mswhelper.h"
10 
11 #define MSW_BUFSIZE 512
12 #define MAX_ARRAY_SIZE 5
13 
14 void
mswBufferInit(_Inout_ PMSW_BUFFER mswBuf,_In_ BYTE * buffer,_In_ DWORD bufferSize)15 mswBufferInit(_Inout_ PMSW_BUFFER mswBuf,
16               _In_ BYTE* buffer,
17               _In_ DWORD bufferSize)
18 {
19     RtlZeroMemory(mswBuf, sizeof(*mswBuf));
20     RtlZeroMemory(buffer, bufferSize);
21     mswBuf->bytesMax = bufferSize;
22     mswBuf->buffer = buffer;
23     mswBuf->bufendptr = buffer;
24     mswBuf->bufok = TRUE;
25 }
26 
27 BOOL
mswBufferCheck(_Inout_ PMSW_BUFFER mswBuf,_In_ DWORD count)28 mswBufferCheck(_Inout_ PMSW_BUFFER mswBuf,
29                _In_ DWORD count)
30 {
31     if (mswBuf->bytesUsed + count <= mswBuf->bytesMax)
32         return TRUE;
33 
34     mswBuf->bufok = FALSE;
35     return FALSE;
36 }
37 
38 BOOL
mswBufferIncUsed(_Inout_ PMSW_BUFFER mswBuf,_In_ DWORD count)39 mswBufferIncUsed(_Inout_ PMSW_BUFFER mswBuf,
40                  _In_ DWORD count)
41 {
42     if (!mswBufferCheck(mswBuf, count))
43         return FALSE;
44 
45     mswBuf->bytesUsed += count;
46     mswBuf->bufendptr += count;
47     return TRUE;
48 }
49 
50 BYTE*
mswBufferEndPtr(_Inout_ PMSW_BUFFER mswBuf)51 mswBufferEndPtr(_Inout_ PMSW_BUFFER mswBuf)
52 {
53     return mswBuf->bufendptr;
54 }
55 
56 BOOL
mswBufferAppend(_Inout_ PMSW_BUFFER mswBuf,_In_ void * dataToAppend,_In_ DWORD dataSize)57 mswBufferAppend(_Inout_ PMSW_BUFFER mswBuf,
58                 _In_ void *dataToAppend,
59                 _In_ DWORD dataSize)
60 {
61     if (!mswBufferCheck(mswBuf, dataSize))
62         return FALSE;
63 
64     RtlCopyMemory(mswBuf->bufendptr, dataToAppend, dataSize);
65     mswBuf->bytesUsed += dataSize;
66     mswBuf->bufendptr += dataSize;
67 
68     return TRUE;
69 }
70 
mswBufferAppendStrA(_Inout_ PMSW_BUFFER mswBuf,_In_ char * str)71 BOOL mswBufferAppendStrA(_Inout_ PMSW_BUFFER mswBuf,
72                          _In_ char* str)
73 {
74     return mswBufferAppend(mswBuf, str, strlen(str) + sizeof(char));
75 }
76 
77 BOOL
mswBufferAppendStrW(_Inout_ PMSW_BUFFER mswBuf,_In_ WCHAR * str)78 mswBufferAppendStrW(_Inout_ PMSW_BUFFER mswBuf,
79                     _In_ WCHAR* str)
80 {
81     int bytelen = (wcslen(str) + 1) * sizeof(WCHAR);
82     return mswBufferAppend(mswBuf, str, bytelen);
83 }
84 
85 BOOL
mswBufferAppendPtr(_Inout_ PMSW_BUFFER mswBuf,_In_ void * ptr)86 mswBufferAppendPtr(_Inout_ PMSW_BUFFER mswBuf,
87                    _In_ void* ptr)
88 {
89     return mswBufferAppend(mswBuf, &ptr, sizeof(ptr));
90 }
91 
92 /* lst = pointer to pointer of items
93 
94    *lst[0] = 1st item
95    *lst[1] = 2nd item
96    ...
97    lst[n] = NULL = End of List
98 
99    itemLength = data in Bytes for each item.
100 
101    ptrofs = delta relative to mswBuf.buffer
102 */
103 BOOL
mswBufferAppendLst(_Inout_ PMSW_BUFFER mswBuf,_In_ void ** lst,_In_ DWORD itemByteLength,_In_opt_ int ptrofs)104 mswBufferAppendLst(_Inout_ PMSW_BUFFER mswBuf,
105                    _In_ void **lst,
106                    _In_ DWORD itemByteLength,
107                    _In_opt_ int ptrofs)
108 {
109     DWORD lstItemCount;
110     DWORD lstByteSize;
111     DWORD_PTR lstDataPos;
112     DWORD i1;
113     UINT_PTR *ptrSrcLstPos;
114 
115     /* calculate size of list */
116     ptrSrcLstPos = (UINT_PTR*)lst;
117     lstItemCount = 0;
118     while (*ptrSrcLstPos != (UINT_PTR)NULL)
119     {
120         lstItemCount++;
121         ptrSrcLstPos++;
122     }
123 
124     lstByteSize = ((lstItemCount + 1) * sizeof(UINT_PTR)) + /* item-pointer + null-ptr (for end) */
125                   (lstItemCount * itemByteLength); /* item-data */
126 
127     if (mswBuf->bytesUsed + lstByteSize > mswBuf->bytesMax)
128         return FALSE;
129 
130     /* calculate position for the data of the first item */
131     lstDataPos = ((lstItemCount + 1) * sizeof(UINT_PTR)) +
132                  (DWORD_PTR)mswBufferEndPtr(mswBuf);
133     /* add ptrofs */
134     lstDataPos += ptrofs;
135 
136     /* write array of Pointer to data */
137     for (i1 = 0; i1 < lstItemCount; i1++)
138     {
139         if (!mswBufferAppendPtr(mswBuf, (void*)lstDataPos))
140             return FALSE;
141 
142         lstDataPos += sizeof(UINT_PTR);
143     }
144 
145     /* end of list */
146     if (!mswBufferAppendPtr(mswBuf, NULL))
147         return FALSE;
148 
149     /* write data */
150     ptrSrcLstPos = (UINT_PTR*)lst;
151     for (i1 = 0; i1 < lstItemCount; i1++)
152     {
153         mswBufferAppend(mswBuf, *(BYTE**)ptrSrcLstPos, itemByteLength);
154         ptrSrcLstPos++;
155     }
156     return mswBuf->bufok;
157 }
158 
159 BOOL
mswBufferAppendStrLstA(_Inout_ PMSW_BUFFER mswBuf,_In_ void ** lst,_In_opt_ int ptrofs)160 mswBufferAppendStrLstA(_Inout_ PMSW_BUFFER mswBuf,
161                        _In_ void **lst,
162                        _In_opt_ int ptrofs)
163 {
164     DWORD lstItemLen[MAX_ARRAY_SIZE];
165     DWORD lstItemCount;
166     DWORD lstByteSize;
167     DWORD_PTR lstDataPos;
168     DWORD lstDataSize;
169     DWORD i1;
170     UINT_PTR *ptrSrcLstPos;
171 
172     /* calculate size of list */
173     ptrSrcLstPos = (UINT_PTR*)lst;
174     lstItemCount = 0;
175     lstDataSize = 0;
176 
177     while (*ptrSrcLstPos != (UINT_PTR)NULL)
178     {
179         if (lstItemCount >= MAX_ARRAY_SIZE)
180             return FALSE;
181 
182         i1 = strlen((char*)*ptrSrcLstPos) + sizeof(char);
183         lstItemLen[lstItemCount] = i1;
184         lstItemCount++;
185         lstDataSize += i1;
186         ptrSrcLstPos++;
187     }
188 
189     lstByteSize = ((lstItemCount + 1) * sizeof(UINT_PTR)) + /* item-pointer + null-ptr (for end) */
190                   lstDataSize; /* item-data */
191 
192     if (mswBuf->bytesUsed + lstByteSize > mswBuf->bytesMax)
193         return FALSE;
194 
195     /* calculate position for the data of the first item */
196     lstDataPos = ((lstItemCount + 1) * sizeof(UINT_PTR)) +
197                  (DWORD_PTR)mswBufferEndPtr(mswBuf);
198 
199     /* add ptrofs */
200     lstDataPos += ptrofs;
201 
202     for (i1 = 0; i1 < lstItemCount; i1++)
203     {
204         if (!mswBufferAppendPtr(mswBuf, (void*)lstDataPos))
205             return FALSE;
206 
207         lstDataPos += lstItemLen[i1];
208     }
209 
210     /* end of list */
211     if (!mswBufferAppendPtr(mswBuf, NULL))
212         return FALSE;
213 
214     /* write data */
215     ptrSrcLstPos = (UINT_PTR*)lst;
216     for (i1 = 0; i1 < lstItemCount; i1++)
217     {
218         if (!mswBufferAppendStrA(mswBuf, *(char**)ptrSrcLstPos))
219             return FALSE;
220 
221         ptrSrcLstPos++;
222     }
223     return mswBuf->bufok;
224 }
225 
226 BOOL
mswBufferAppendBlob_Hostent(_Inout_ PMSW_BUFFER mswBuf,_Inout_ LPWSAQUERYSETW lpRes,_In_ char ** hostAliasesA,_In_ char * hostnameA,_In_ DWORD ip4addr)227 mswBufferAppendBlob_Hostent(_Inout_ PMSW_BUFFER mswBuf,
228                             _Inout_ LPWSAQUERYSETW lpRes,
229                             _In_ char** hostAliasesA,
230                             _In_ char* hostnameA,
231                             _In_ DWORD ip4addr)
232 {
233     PHOSTENT phe;
234     void* lst[2];
235     BYTE* bytesOfs;
236 
237     /* blob */
238     lpRes->lpBlob = (LPBLOB)mswBufferEndPtr(mswBuf);
239 
240     if (!mswBufferIncUsed(mswBuf, sizeof(*lpRes->lpBlob)))
241         return FALSE;
242 
243     /* cbSize will be set later */
244     lpRes->lpBlob->cbSize = 0;
245     lpRes->lpBlob->pBlobData = mswBufferEndPtr(mswBuf);
246 
247     /* hostent */
248     phe = (PHOSTENT)lpRes->lpBlob->pBlobData;
249     bytesOfs = mswBufferEndPtr(mswBuf);
250 
251     if (!mswBufferIncUsed(mswBuf, sizeof(*phe)))
252         return FALSE;
253 
254     phe->h_addrtype = AF_INET;
255     phe->h_length = 4; /* 4 Byte (IPv4) */
256 
257     /* aliases */
258     phe->h_aliases = (char**)(mswBufferEndPtr(mswBuf) - bytesOfs);
259 
260     if (hostAliasesA)
261     {
262         if (!mswBufferAppendStrLstA(mswBuf,
263                                     (void**)hostAliasesA,
264                                     -(LONG_PTR)bytesOfs))
265             return FALSE;
266     }
267     else
268     {
269         if (!mswBufferAppendPtr(mswBuf, NULL))
270             return FALSE;
271     }
272 
273     /* addr_list */
274     RtlZeroMemory(lst, sizeof(lst));
275 
276     lst[0] = (void*)&ip4addr;
277 
278     phe->h_addr_list = (char**)(mswBufferEndPtr(mswBuf) - bytesOfs);
279 
280     if (!mswBufferAppendLst(mswBuf, lst, 4, -(LONG_PTR)bytesOfs))
281         return FALSE;
282 
283     /* name */
284     phe->h_name = (char*)(mswBufferEndPtr(mswBuf) - bytesOfs);
285 
286     if (!mswBufferAppendStrA(mswBuf, hostnameA))
287         return FALSE;
288 
289     lpRes->lpBlob->cbSize = (DWORD)(mswBufferEndPtr(mswBuf) - bytesOfs);
290     return mswBuf->bufok;
291 }
292 
293 BOOL
mswBufferAppendBlob_Servent(_Inout_ PMSW_BUFFER mswBuf,_Inout_ LPWSAQUERYSETW lpRes,_In_ char * serviceNameA,_In_ char ** serviceAliasesA,_In_ char * protocolNameA,_In_ WORD port)294 mswBufferAppendBlob_Servent(_Inout_ PMSW_BUFFER mswBuf,
295                             _Inout_ LPWSAQUERYSETW lpRes,
296                             _In_ char* serviceNameA,
297                             _In_ char** serviceAliasesA,
298                             _In_ char* protocolNameA,
299                             _In_ WORD port)
300 {
301     PSERVENT pse;
302     BYTE* bytesOfs;
303 
304     /* blob */
305     lpRes->lpBlob = (LPBLOB)mswBufferEndPtr(mswBuf);
306 
307     if (!mswBufferIncUsed(mswBuf, sizeof(*lpRes->lpBlob)))
308         return FALSE;
309 
310     lpRes->lpBlob->cbSize = 0;//later
311     lpRes->lpBlob->pBlobData = mswBufferEndPtr(mswBuf);
312 
313     /* servent */
314     pse = (LPSERVENT)lpRes->lpBlob->pBlobData;
315     bytesOfs = mswBufferEndPtr(mswBuf);
316 
317     if (!mswBufferIncUsed(mswBuf, sizeof(*pse)))
318         return FALSE;
319 
320     pse->s_aliases = (char**)(mswBufferEndPtr(mswBuf) - bytesOfs);
321 
322     if (serviceAliasesA)
323     {
324         if (!mswBufferAppendStrLstA(mswBuf,
325                                     (void**)serviceAliasesA,
326                                     -(LONG_PTR)bytesOfs))
327             return FALSE;
328     }
329     else
330     {
331         if (!mswBufferAppendPtr(mswBuf, NULL))
332             return FALSE;
333     }
334 
335     pse->s_name = (char*)(mswBufferEndPtr(mswBuf) - bytesOfs);
336 
337     if (!mswBufferAppendStrA(mswBuf, serviceNameA))
338         return FALSE;
339 
340     pse->s_port = htons(port);
341 
342     pse->s_proto = (char*)(mswBufferEndPtr(mswBuf) - bytesOfs);
343 
344     if (!mswBufferAppendStrA(mswBuf, protocolNameA))
345         return FALSE;
346 
347     lpRes->lpBlob->cbSize = (DWORD)(mswBufferEndPtr(mswBuf) - bytesOfs);
348     return mswBuf->bufok;
349 }
350 
351 BOOL
mswBufferAppendAddr_AddrInfoW(_Inout_ PMSW_BUFFER mswBuf,_Inout_ LPWSAQUERYSETW lpRes,_In_ DWORD ip4addr)352 mswBufferAppendAddr_AddrInfoW(_Inout_ PMSW_BUFFER mswBuf,
353                               _Inout_ LPWSAQUERYSETW lpRes,
354                               _In_ DWORD ip4addr)
355 {
356     LPCSADDR_INFO paddrinfo;
357     LPSOCKADDR_IN psa;
358 
359     lpRes->dwNumberOfCsAddrs = 1;
360     lpRes->lpcsaBuffer = (LPCSADDR_INFO)mswBufferEndPtr(mswBuf);
361 
362     paddrinfo = lpRes->lpcsaBuffer;
363 
364     if (!mswBufferIncUsed(mswBuf, sizeof(*paddrinfo)))
365         return FALSE;
366 
367     paddrinfo->LocalAddr.lpSockaddr = (LPSOCKADDR)mswBufferEndPtr(mswBuf);
368 
369     if (!mswBufferIncUsed(mswBuf, sizeof(*paddrinfo->LocalAddr.lpSockaddr)))
370         return FALSE;
371 
372     paddrinfo->RemoteAddr.lpSockaddr = (LPSOCKADDR)mswBufferEndPtr(mswBuf);
373 
374     if (!mswBufferIncUsed(mswBuf, sizeof(*paddrinfo->RemoteAddr.lpSockaddr)))
375         return FALSE;
376 
377     paddrinfo->iSocketType = SOCK_DGRAM;
378     paddrinfo->iProtocol = IPPROTO_UDP;
379 
380     psa = (LPSOCKADDR_IN)paddrinfo->LocalAddr.lpSockaddr;
381     paddrinfo->LocalAddr.iSockaddrLength = sizeof(*psa);
382     psa->sin_family = AF_INET;
383     psa->sin_port = 0;
384     psa->sin_addr.s_addr = 0;
385     RtlZeroMemory(psa->sin_zero, sizeof(psa->sin_zero));
386 
387     psa = (LPSOCKADDR_IN)paddrinfo->RemoteAddr.lpSockaddr;
388     paddrinfo->RemoteAddr.iSockaddrLength = sizeof(*psa);
389     psa->sin_family = AF_INET;
390     psa->sin_port = 0;
391     psa->sin_addr.s_addr = ip4addr;
392     RtlZeroMemory(psa->sin_zero, sizeof(psa->sin_zero));
393 
394     return TRUE;
395 }
396 
397 /* ansicode <-> unicode */
398 WCHAR*
StrA2WHeapAlloc(_In_opt_ HANDLE hHeap,_In_ char * aStr)399 StrA2WHeapAlloc(_In_opt_ HANDLE hHeap,
400                 _In_ char* aStr)
401 {
402     int aStrByteLen;
403     int wStrByteLen;
404     int charLen;
405     int ret;
406     WCHAR* wStr;
407 
408     if (aStr == NULL)
409         return NULL;
410 
411     charLen = strlen(aStr) + 1;
412 
413     aStrByteLen = (charLen * sizeof(char));
414     wStrByteLen = (charLen * sizeof(WCHAR));
415 
416     if (hHeap == 0)
417         hHeap = GetProcessHeap();
418 
419     wStr = HeapAlloc(hHeap, 0, wStrByteLen);
420     if (wStr == NULL)
421     {
422         HeapFree(hHeap, 0, wStr);
423         return NULL;
424     }
425 
426     ret = MultiByteToWideChar(CP_ACP,
427                               0,
428                               aStr,
429                               aStrByteLen,
430                               wStr,
431                               charLen);
432 
433     if (ret != charLen)
434     {
435         HeapFree(hHeap, 0, wStr);
436         return NULL;
437     }
438     return wStr;
439 }
440 
441 char*
StrW2AHeapAlloc(_In_opt_ HANDLE hHeap,_In_ WCHAR * wStr)442 StrW2AHeapAlloc(_In_opt_ HANDLE hHeap,
443                 _In_ WCHAR* wStr)
444 {
445     int charLen;
446     int aStrByteLen;
447     int ret;
448     char* aStr;
449 
450     if (wStr == NULL)
451         return NULL;
452 
453     charLen = wcslen(wStr) + 1;
454 
455     aStrByteLen = (charLen * sizeof(char));
456 
457     if (hHeap == 0)
458         hHeap = GetProcessHeap();
459 
460     aStr = HeapAlloc(hHeap, 0, aStrByteLen);
461     if (aStr == NULL)
462     {
463         HeapFree(hHeap, 0, aStr);
464         return NULL;
465     }
466 
467     ret = WideCharToMultiByte(CP_ACP,
468                               0,
469                               wStr,
470                               charLen,
471                               aStr,
472                               aStrByteLen,
473                               NULL,
474                               NULL);
475     if (ret != aStrByteLen)
476     {
477         HeapFree(hHeap, 0, aStr);
478         return NULL;
479     }
480     return aStr;
481 }
482 
483 WCHAR*
StrCpyHeapAllocW(_In_opt_ HANDLE hHeap,_In_ WCHAR * wStr)484 StrCpyHeapAllocW(_In_opt_ HANDLE hHeap,
485                  _In_ WCHAR* wStr)
486 {
487     size_t chLen;
488     size_t bLen;
489     WCHAR* resW;
490 
491     if (wStr == NULL)
492         return NULL;
493 
494     if (hHeap == 0)
495         hHeap = GetProcessHeap();
496 
497     chLen = wcslen(wStr);
498 
499     bLen = (chLen + 1) * sizeof(WCHAR);
500 
501     resW = HeapAlloc(hHeap, 0, bLen);
502     RtlCopyMemory(resW, wStr, bLen);
503     return resW;
504 }
505 
506 char*
StrCpyHeapAllocA(_In_opt_ HANDLE hHeap,_In_ char * aStr)507 StrCpyHeapAllocA(_In_opt_ HANDLE hHeap,
508                  _In_ char* aStr)
509 {
510     size_t chLen;
511     size_t bLen;
512     char* resA;
513 
514     if (aStr == NULL)
515         return NULL;
516 
517     if (hHeap == 0)
518         hHeap = GetProcessHeap();
519 
520     chLen = strlen(aStr);
521 
522     bLen = (chLen + 1) * sizeof(char);
523 
524     resA = HeapAlloc(hHeap, 0, bLen);
525     RtlCopyMemory(resA, aStr, bLen);
526     return resA;
527 }
528 
529 char**
StrAryCpyHeapAllocA(_In_opt_ HANDLE hHeap,_In_ char ** aStrAry)530 StrAryCpyHeapAllocA(_In_opt_ HANDLE hHeap,
531                     _In_ char** aStrAry)
532 {
533     char** aSrcPtr;
534     char** aDstPtr;
535     char* aDstNextStr;
536     DWORD aStrByteLen[MAX_ARRAY_SIZE];
537     size_t bLen;
538     size_t bItmLen;
539     int aCount;
540     int i1;
541     char** resA;
542 
543     if (hHeap == 0)
544         hHeap = GetProcessHeap();
545 
546     /* Calculating size of array ... */
547     aSrcPtr = aStrAry;
548     bLen = 0;
549     aCount = 0;
550 
551     while (*aSrcPtr != NULL)
552     {
553         if (aCount >= MAX_ARRAY_SIZE)
554             return NULL;
555 
556         bItmLen = strlen(*aSrcPtr) + 1;
557         aStrByteLen[aCount] = bItmLen;
558 
559         bLen += sizeof(*aSrcPtr) + bItmLen;
560 
561         aSrcPtr++;
562         aCount++;
563     }
564 
565     /* size for NULL-terminator */
566     bLen += sizeof(*aSrcPtr);
567 
568     /* get memory */
569     resA = HeapAlloc(hHeap, 0, bLen);
570 
571     /* copy data */
572     aSrcPtr = aStrAry;
573     aDstPtr = resA;
574 
575     /* pos for the first string */
576     aDstNextStr = (char*)(resA + aCount + 1);
577     for (i1 = 0; i1 < aCount; i1++)
578     {
579         bItmLen = aStrByteLen[i1];
580 
581         *aDstPtr = aDstNextStr;
582         RtlCopyMemory(*aDstPtr, *aSrcPtr, bItmLen);
583 
584         aDstNextStr = (char*)((DWORD_PTR)aDstNextStr + (DWORD)bItmLen);
585         aDstPtr++;
586         aSrcPtr++;
587     }
588 
589     /* terminate with NULL */
590     *aDstPtr = NULL;
591 
592     return resA;
593 }
594 
595 char**
StrAryCpyHeapAllocWToA(_In_opt_ HANDLE hHeap,_In_ WCHAR ** wStrAry)596 StrAryCpyHeapAllocWToA(_In_opt_ HANDLE hHeap,
597     _In_ WCHAR** wStrAry)
598 {
599     WCHAR** wSrcPtr;
600     char** aDstPtr;
601     char* aDstNextStr;
602     DWORD aStrByteLen[MAX_ARRAY_SIZE];
603     int bLen;
604     int bItmLen;
605     int aCount;
606     int i1;
607     char** resA;
608     int ret;
609     char* aStr;
610 
611     if (hHeap == 0)
612         hHeap = GetProcessHeap();
613 
614     /* Calculating size of array ... */
615     wSrcPtr = wStrAry;
616     bLen = 0;
617     aCount = 0;
618 
619     while (*wSrcPtr != NULL)
620     {
621         if (aCount >= MAX_ARRAY_SIZE)
622             return NULL;
623 
624         bItmLen = wcslen(*wSrcPtr) + 1;
625         aStrByteLen[aCount] = bItmLen;
626 
627         bLen += sizeof(*wSrcPtr) + bItmLen;
628 
629         wSrcPtr++;
630         aCount++;
631     }
632 
633     /* size for NULL-terminator */
634     bLen += sizeof(*wSrcPtr);
635 
636     /* get memory */
637     resA = HeapAlloc(hHeap, 0, bLen);
638 
639     /* copy data */
640     wSrcPtr = wStrAry;
641     aDstPtr = resA;
642 
643     /* pos for the first string */
644     aDstNextStr = (char*)(resA + aCount + 1);
645     for (i1 = 0; i1 < aCount; i1++)
646     {
647         bItmLen = aStrByteLen[i1];
648 
649         *aDstPtr = aDstNextStr;
650 
651         aStr = HeapAlloc(hHeap, 0, bItmLen);
652         if (aStr == NULL)
653         {
654             HeapFree(hHeap, 0, aStr);
655             return NULL;
656         }
657 
658         ret = WideCharToMultiByte(CP_ACP,
659                                   0,
660                                   *wSrcPtr,
661                                   bItmLen,
662                                   aStr,
663                                   bItmLen,
664                                   NULL,
665                                   NULL);
666         if (ret != bItmLen)
667         {
668             HeapFree(hHeap, 0, aStr);
669             return NULL;
670         }
671         RtlCopyMemory(*aDstPtr, aStr, bItmLen);
672         HeapFree(hHeap, 0, aStr);
673 
674         aDstNextStr = (char*)((DWORD_PTR)aDstNextStr + (DWORD)bItmLen);
675         aDstPtr++;
676         wSrcPtr++;
677     }
678 
679     /* terminate with NULL */
680     *aDstPtr = NULL;
681 
682     return resA;
683 }
684