Fix off-by-one error in placing trailing \0.
[wine] / dlls / oleaut32 / ole2disp.c
1 /*
2  *      OLE2DISP library
3  *
4  *      Copyright 1995  Martin von Loewis
5  */
6
7 #include "config.h"
8
9 #include <string.h>
10
11 #include "wine/windef16.h"
12 #include "ole2.h"
13 #include "oleauto.h"
14 #include "windef.h"
15 #include "winbase.h"
16 #include "winerror.h"
17 #include "wingdi.h"
18 #include "winuser.h"
19
20 #include "ole2disp.h"
21 #include "olectl.h"
22
23 #include "debugtools.h"
24
25 DEFAULT_DEBUG_CHANNEL(ole);
26
27 /* This implementation of the BSTR API is 16-bit only. It
28    represents BSTR as a 16:16 far pointer, and the strings
29    as ISO-8859 */
30
31 /******************************************************************************
32  *              BSTR_AllocBytes [Internal]
33  */
34 static BSTR16 BSTR_AllocBytes(int n)
35 {
36     void *ptr = HeapAlloc( GetProcessHeap(), 0, n );
37     return (BSTR16)MapLS(ptr);
38 }
39
40 /******************************************************************************
41  * BSTR_Free [INTERNAL]
42  */
43 static void BSTR_Free(BSTR16 in)
44 {
45     void *ptr = MapSL( (SEGPTR)in );
46     UnMapLS( (SEGPTR)in );
47     HeapFree( GetProcessHeap(), 0, ptr );
48 }
49
50 /******************************************************************************
51  * BSTR_GetAddr [INTERNAL]
52  */
53 static void* BSTR_GetAddr(BSTR16 in)
54 {
55     return in ? MapSL((SEGPTR)in) : 0;
56 }
57
58 /******************************************************************************
59  *              SysAllocString  [OLE2DISP.2]
60  */
61 BSTR16 WINAPI SysAllocString16(LPCOLESTR16 in)
62 {
63         BSTR16 out;
64     
65         if (!in) return 0;
66     
67         out = BSTR_AllocBytes(strlen(in)+1);
68         if (!out) return 0;
69         strcpy(BSTR_GetAddr(out),in);
70         return out;
71 }
72
73 /******************************************************************************
74  *              SysAllocString  [OLEAUT32.2]
75  *
76  * MSDN (October 2001) states that this returns a NULL value if the argument
77  * is a zero-length string.  This does not appear to be true; certainly it
78  * returns a value under Win98 (Oleaut32.dll Ver 2.40.4515.0)
79  */
80 BSTR WINAPI SysAllocString(LPCOLESTR in)
81 {
82     if (!in) return 0;
83     
84     /* Delegate this to the SysAllocStringLen32 method. */
85     return SysAllocStringLen(in, lstrlenW(in));
86 }
87
88 /******************************************************************************
89  *              SysReallocString        [OLE2DISP.3]
90  */
91 INT16 WINAPI SysReAllocString16(LPBSTR16 old,LPCOLESTR16 in)
92 {
93         BSTR16 new=SysAllocString16(in);
94         BSTR_Free(*old);
95         *old=new;
96         return 1;
97 }
98
99 /******************************************************************************
100  *              SysReAllocString        [OLEAUT32.3]
101  */
102 INT WINAPI SysReAllocString(LPBSTR old,LPCOLESTR in)
103 {
104     /*
105      * Sanity check
106      */
107     if (old==NULL) 
108       return 0;
109
110     /*
111      * Make sure we free the old string.
112      */
113     if (*old!=NULL)      
114       SysFreeString(*old);
115
116     /*
117      * Allocate the new string
118      */
119     *old = SysAllocString(in);
120
121      return 1;
122 }
123
124 /******************************************************************************
125  *              SysAllocStringLen       [OLE2DISP.4]
126  */
127 BSTR16 WINAPI SysAllocStringLen16(const char *in, int len)
128 {
129         BSTR16 out=BSTR_AllocBytes(len+1);
130
131         if (!out)
132                 return 0;
133
134     /*
135      * Copy the information in the buffer.
136      * Since it is valid to pass a NULL pointer here, we'll initialize the
137      * buffer to nul if it is the case.
138      */
139     if (in != 0)
140         strcpy(BSTR_GetAddr(out),in);
141     else
142       memset(BSTR_GetAddr(out), 0, len+1);
143
144         return out;
145 }
146
147 /******************************************************************************
148  *             SysAllocStringLen     [OLEAUT32.4]
149  *
150  * In "Inside OLE, second edition" by Kraig Brockshmidt. In the Automation
151  * section, he describes the DWORD value placed *before* the BSTR data type.
152  * he describes it as a "DWORD count of characters". By experimenting with
153  * a windows application, this count seems to be a DWORD count of bytes in
154  * the string. Meaning that the count is double the number of wide 
155  * characters in the string.
156  */
157 BSTR WINAPI SysAllocStringLen(const OLECHAR *in, unsigned int len)
158 {
159     DWORD  bufferSize;
160     DWORD* newBuffer;
161     WCHAR* stringBuffer;
162
163     /*
164      * Find the length of the buffer passed-in in bytes.
165      */
166     bufferSize = len * sizeof (WCHAR);
167
168     /*
169      * Allocate a new buffer to hold the string.
170      * dont't forget to keep an empty spot at the beginning of the
171      * buffer for the character count and an extra character at the
172      * end for the NULL.
173      */
174     newBuffer = (DWORD*)HeapAlloc(GetProcessHeap(),
175                                  0,
176                                  bufferSize + sizeof(WCHAR) + sizeof(DWORD));
177
178     /*
179      * If the memory allocation failed, return a null pointer.
180      */
181     if (newBuffer==0)
182       return 0;
183
184     /*
185      * Copy the length of the string in the placeholder.
186      */
187     *newBuffer = bufferSize;
188
189     /*
190      * Skip the byte count.
191      */
192     newBuffer++;
193
194     /*
195      * Copy the information in the buffer.
196      * Since it is valid to pass a NULL pointer here, we'll initialize the
197      * buffer to nul if it is the case.
198      */
199     if (in != 0)
200       memcpy(newBuffer, in, bufferSize);
201     else
202       memset(newBuffer, 0, bufferSize);
203
204     /*
205      * Make sure that there is a nul character at the end of the
206      * string.
207      */
208     stringBuffer = (WCHAR*)newBuffer;
209     stringBuffer[len] = L'\0';
210
211     return (LPWSTR)stringBuffer;
212 }
213
214 /******************************************************************************
215  *              SysReAllocStringLen     [OLE2DISP.5]
216  */
217 int WINAPI SysReAllocStringLen16(BSTR16 *old,const char *in,int len)
218 {
219         BSTR16 new=SysAllocStringLen16(in,len);
220         BSTR_Free(*old);
221         *old=new;
222         return 1;
223 }
224
225  
226 /******************************************************************************
227  *             SysReAllocStringLen   [OLEAUT32.5]
228  */
229 int WINAPI SysReAllocStringLen(BSTR* old, const OLECHAR* in, unsigned int len)
230 {
231     /*
232      * Sanity check
233      */
234     if (old==NULL) 
235       return 0;
236
237     /*
238      * Make sure we free the old string.
239      */
240     if (*old!=NULL)      
241       SysFreeString(*old);
242
243     /*
244      * Allocate the new string
245      */
246     *old = SysAllocStringLen(in, len);
247
248     return 1;
249 }
250
251 /******************************************************************************
252  *              SysFreeString   [OLE2DISP.6]
253  */
254 void WINAPI SysFreeString16(BSTR16 in)
255 {
256         BSTR_Free(in);
257 }
258
259 /******************************************************************************
260  *              SysFreeString   [OLEAUT32.6]
261  */
262 void WINAPI SysFreeString(BSTR in)
263 {
264     DWORD* bufferPointer;
265     
266     /* NULL is a valid parameter */
267     if(!in) return;
268
269     /*
270      * We have to be careful when we free a BSTR pointer, it points to
271      * the beginning of the string but it skips the byte count contained
272      * before the string.
273      */
274     bufferPointer = (DWORD*)in;
275
276     bufferPointer--;
277
278     /*
279      * Free the memory from its "real" origin.
280      */
281     HeapFree(GetProcessHeap(), 0, bufferPointer);
282 }
283
284 /******************************************************************************
285  *              SysStringLen    [OLE2DISP.7]
286  */
287 int WINAPI SysStringLen16(BSTR16 str)
288 {
289         return strlen(BSTR_GetAddr(str));
290 }
291
292 /******************************************************************************
293  *             SysStringLen  [OLEAUT32.7]
294  *
295  * The Windows documentation states that the length returned by this function
296  * is not necessarely the same as the length returned by the _lstrlenW method.
297  * It is the same number that was passed in as the "len" parameter if the
298  * string was allocated with a SysAllocStringLen method call.
299  */
300 int WINAPI SysStringLen(BSTR str)
301 {
302     DWORD* bufferPointer;
303
304      if (!str) return 0;
305     /*
306      * The length of the string (in bytes) is contained in a DWORD placed 
307      * just before the BSTR pointer
308      */
309     bufferPointer = (DWORD*)str;
310
311     bufferPointer--;
312
313     return (int)(*bufferPointer/sizeof(WCHAR));
314 }
315
316 /******************************************************************************
317  *             SysStringByteLen  [OLEAUT32.149]
318  *
319  * The Windows documentation states that the length returned by this function
320  * is not necessarely the same as the length returned by the _lstrlenW method.
321  * It is the same number that was passed in as the "len" parameter if the
322  * string was allocated with a SysAllocStringLen method call.
323  */
324 int WINAPI SysStringByteLen(BSTR str)
325 {
326     DWORD* bufferPointer;
327
328      if (!str) return 0;
329     /*
330      * The length of the string (in bytes) is contained in a DWORD placed 
331      * just before the BSTR pointer
332      */
333     bufferPointer = (DWORD*)str;
334
335     bufferPointer--;
336
337     return (int)(*bufferPointer);
338 }
339
340 /******************************************************************************
341  * CreateDispTypeInfo [OLE2DISP.31]
342  */
343 HRESULT WINAPI CreateDispTypeInfo16(
344         INTERFACEDATA *pidata,
345         LCID lcid,
346         ITypeInfo **pptinfo)
347 {
348         FIXME("(%p,%ld,%p),stub\n",pidata,lcid,pptinfo);
349         return 0;
350 }
351
352 /******************************************************************************
353  * CreateDispTypeInfo [OLEAUT32.31]
354  */
355 HRESULT WINAPI CreateDispTypeInfo(
356         INTERFACEDATA *pidata,
357         LCID lcid,
358         ITypeInfo **pptinfo)
359 {
360         FIXME("(%p,%ld,%p),stub\n",pidata,lcid,pptinfo);
361         return 0;
362 }
363
364 /******************************************************************************
365  * CreateStdDispatch [OLE2DISP.32]
366  */
367 HRESULT WINAPI CreateStdDispatch16(
368         IUnknown* punkOuter,
369         void* pvThis,
370         ITypeInfo* ptinfo,
371         IUnknown** ppunkStdDisp)
372 {
373         FIXME("(%p,%p,%p,%p),stub\n",punkOuter, pvThis, ptinfo,
374                ppunkStdDisp);
375         return 0;
376 }
377
378 /******************************************************************************
379  * CreateStdDispatch [OLEAUT32.32]
380  */
381 HRESULT WINAPI CreateStdDispatch(
382         IUnknown* punkOuter,
383         void* pvThis,
384         ITypeInfo* ptinfo,
385         IUnknown** ppunkStdDisp)
386 {
387         FIXME("(%p,%p,%p,%p),stub\n",punkOuter, pvThis, ptinfo,
388                ppunkStdDisp);
389         return 0;
390 }
391
392 /******************************************************************************
393  * RegisterActiveObject [OLE2DISP.35]
394  */
395 HRESULT WINAPI RegisterActiveObject16(
396         IUnknown *punk, REFCLSID rclsid, DWORD dwFlags, unsigned long *pdwRegister
397 ) {
398         FIXME("(%p,%s,0x%08lx,%p):stub\n",punk,debugstr_guid(rclsid),dwFlags,pdwRegister);
399         return 0;
400 }
401
402 /******************************************************************************
403  *              OleTranslateColor       [OLEAUT32.421]
404  *
405  * Converts an OLE_COLOR to a COLORREF.
406  * See the documentation for conversion rules.
407  * pColorRef can be NULL. In that case the user only wants to test the 
408  * conversion.
409  */
410 HRESULT WINAPI OleTranslateColor(
411   OLE_COLOR clr,
412   HPALETTE  hpal,
413   COLORREF* pColorRef)
414 {
415   COLORREF colorref;
416   BYTE b = HIBYTE(HIWORD(clr));
417
418   TRACE("(%08lx, %d, %p):stub\n", clr, hpal, pColorRef);
419
420   /*
421    * In case pColorRef is NULL, provide our own to simplify the code.
422    */
423   if (pColorRef == NULL)
424     pColorRef = &colorref;
425
426   switch (b)
427   {
428     case 0x00:
429     {
430       if (hpal != 0)
431         *pColorRef =  PALETTERGB(GetRValue(clr),
432                                  GetGValue(clr),
433                                  GetBValue(clr));
434       else
435         *pColorRef = clr;
436
437       break;
438     }
439
440     case 0x01:
441     {
442       if (hpal != 0)
443       {
444         PALETTEENTRY pe;
445         /*
446          * Validate the palette index.
447          */
448         if (GetPaletteEntries(hpal, LOWORD(clr), 1, &pe) == 0)
449           return E_INVALIDARG;
450       }
451
452       *pColorRef = clr;
453
454       break;
455     }
456
457     case 0x02:
458       *pColorRef = clr;
459       break;
460
461     case 0x80:
462     {
463       int index = LOBYTE(LOWORD(clr));
464
465       /*
466        * Validate GetSysColor index.
467        */
468       if ((index < COLOR_SCROLLBAR) || (index > COLOR_GRADIENTINACTIVECAPTION))
469         return E_INVALIDARG;
470
471       *pColorRef =  GetSysColor(index);
472
473       break;
474     }
475
476     default:
477       return E_INVALIDARG;
478   }
479
480   return S_OK;
481 }
482
483 /******************************************************************************
484  *             SysAllocStringByteLen     [OLEAUT32.150]
485  *
486  */
487 BSTR WINAPI SysAllocStringByteLen(LPCSTR in, UINT len)
488 {
489     DWORD* newBuffer;
490     char* stringBuffer;
491
492     /*
493      * Allocate a new buffer to hold the string.
494      * dont't forget to keep an empty spot at the beginning of the
495      * buffer for the character count and an extra character at the
496      * end for the NULL.
497      */
498     newBuffer = (DWORD*)HeapAlloc(GetProcessHeap(),
499                                  0,
500                                  len + sizeof(WCHAR) + sizeof(DWORD));
501
502     /*
503      * If the memory allocation failed, return a null pointer.
504      */
505     if (newBuffer==0)
506       return 0;
507
508     /*
509      * Copy the length of the string in the placeholder.
510      */
511     *newBuffer = len;
512
513     /*
514      * Skip the byte count.
515      */
516     newBuffer++;
517
518     /*
519      * Copy the information in the buffer.
520      * Since it is valid to pass a NULL pointer here, we'll initialize the
521      * buffer to nul if it is the case.
522      */
523     if (in != 0)
524       memcpy(newBuffer, in, len);
525
526     /*
527      * Make sure that there is a nul character at the end of the
528      * string.
529      */
530     stringBuffer = (char *)newBuffer;
531     stringBuffer[len] = 0;
532     stringBuffer[len+1] = 0;
533
534     return (LPWSTR)stringBuffer;
535 }
536
537