xref: /trunk/main/basic/source/runtime/dllmgr.cxx (revision 14a9b8c1d9d8a83e7aea66b019fb3c6483f0b402)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "precompiled_basic.hxx"
25 #include "sal/config.h"
26 
27 #include <algorithm>
28 #include <cstddef>
29 #include <list>
30 #include <map>
31 #include <vector>
32 
33 #include "basic/sbx.hxx"
34 #include "basic/sbxvar.hxx"
35 #include "runtime.hxx"
36 #include "osl/thread.h"
37 #include "rtl/ref.hxx"
38 #include "rtl/string.hxx"
39 #include "rtl/ustring.hxx"
40 #include "salhelper/simplereferenceobject.hxx"
41 #include "tools/svwin.h"
42 
43 #undef max
44 
45 #include "dllmgr.hxx"
46 
47 /* Open issues:
48 
49    Only 32-bit Windows for now.
50 
51    Missing support for functions returning structs (see TODO in call()).
52 
53    Missing support for additional data types (64 bit integers, Any, ...; would
54    trigger OSL_ASSERT(false) in various switches).
55 
56    It is assumed that the variables passed into SbiDllMgr::Call to represent
57    the arguments and return value have types that exactly match the Declare
58    statement; it would be better if this code had access to the function
59    signature from the Declare statement, so that it could convert the passed
60    variables accordingly.
61 */
62 
63 #if defined(WNT) && defined(INTEL)   // only 32-bit Windows: the DllMgr_call32/callFp
64                                      // trampolines (wnt.asm) are x86 stdcall only.
65                                      // x64 falls through to the not-implemented stub
66                                      // below (Basic Declare'd DLL calls unsupported on
67                                      // x64 until an x64 trampoline is written).
68 
69 extern "C" {
70 
71 int __stdcall DllMgr_call32(FARPROC, void const * stack, std::size_t size);
72 double __stdcall DllMgr_callFp(FARPROC, void const * stack, std::size_t size);
73 
74 }
75 
76 namespace {
77 
address(std::vector<char> & blob)78 char * address(std::vector< char > & blob) {
79     return blob.empty() ? 0 : &blob[0];
80 }
81 
convert(rtl::OUString const & source,rtl::OString * target)82 SbError convert(rtl::OUString const & source, rtl::OString * target) {
83     return
84         source.convertToString(
85             target, osl_getThreadTextEncoding(),
86             (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
87              RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
88         ? ERRCODE_NONE : ERRCODE_BASIC_BAD_ARGUMENT;
89         //TODO: more specific errcode?
90 }
91 
convert(char const * source,sal_Int32 length,rtl::OUString * target)92 SbError convert(char const * source, sal_Int32 length, rtl::OUString * target) {
93     return
94         rtl_convertStringToUString(
95             &target->pData, source, length, osl_getThreadTextEncoding(),
96             (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
97              RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
98              RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))
99         ? ERRCODE_NONE : ERRCODE_BASIC_BAD_ARGUMENT;
100         //TODO: more specific errcode?
101 }
102 
103 struct UnmarshalData {
UnmarshalData__anonb4aed0bd0111::UnmarshalData104     UnmarshalData(SbxVariable * theVariable, void * theBuffer):
105         variable(theVariable), buffer(theBuffer) {}
106 
107     SbxVariable * variable;
108     void * buffer;
109 };
110 
111 struct StringData: public UnmarshalData {
StringData__anonb4aed0bd0111::StringData112     StringData(SbxVariable * theVariable, void * theBuffer, bool theSpecial):
113         UnmarshalData(theVariable, theBuffer), special(theSpecial) {}
114 
115     bool special;
116 };
117 
118 class MarshalData: private boost::noncopyable {
119 public:
newBlob()120     std::vector< char > * newBlob() {
121         blobs_.push_front(std::vector< char >());
122         return &blobs_.front();
123     }
124 
125     std::vector< UnmarshalData > unmarshal;
126 
127     std::vector< StringData > unmarshalStrings;
128 
129 private:
130     std::list< std::vector< char > > blobs_;
131 };
132 
align(std::size_t address,std::size_t alignment)133 std::size_t align(std::size_t address, std::size_t alignment) {
134     // alignment = 2^k for some k >= 0
135     return (address + (alignment - 1)) & ~(alignment - 1);
136 }
137 
align(std::vector<char> & blob,std::size_t alignment,std::size_t offset,std::size_t add)138 char * align(
139     std::vector< char > & blob, std::size_t alignment, std::size_t offset,
140     std::size_t add)
141 {
142     std::vector< char >::size_type n = blob.size();
143     n = align(n - offset, alignment) + offset; //TODO: overflow in align()
144     blob.resize(n + add); //TODO: overflow
145     return address(blob) + n;
146 }
147 
add(std::vector<char> & blob,T const & data,std::size_t alignment,std::size_t offset)148 template< typename T > void add(
149     std::vector< char > & blob, T const & data, std::size_t alignment,
150     std::size_t offset)
151 {
152     *reinterpret_cast< T * >(align(blob, alignment, offset, sizeof (T))) = data;
153 }
154 
alignment(SbxVariable * variable)155 std::size_t alignment(SbxVariable * variable) {
156     OSL_ASSERT(variable != 0);
157     if ((variable->GetType() & SbxARRAY) == 0) {
158         switch (variable->GetType()) {
159         case SbxINTEGER:
160             return 2;
161         case SbxLONG:
162         case SbxSINGLE:
163         case SbxSTRING:
164             return 4;
165         case SbxDOUBLE:
166             return 8;
167         case SbxOBJECT:
168             {
169                 std::size_t n = 1;
170                 SbxArray * props = PTR_CAST(SbxObject, variable->GetObject())->
171                     GetProperties();
172                 for (sal_uInt16 i = 0; i < props->Count(); ++i) {
173                     n = std::max(n, alignment(props->Get(i)));
174                 }
175                 return n;
176             }
177         case SbxBOOL:
178         case SbxBYTE:
179             return 1;
180         default:
181             OSL_ASSERT(false);
182             return 1;
183         }
184     } else {
185         SbxDimArray * arr = PTR_CAST(SbxDimArray, variable->GetObject());
186         int dims = arr->GetDims();
187         std::vector< sal_Int32 > low(dims);
188         for (int i = 0; i < dims; ++i) {
189             sal_Int32 up;
190             arr->GetDim32(i + 1, low[i], up);
191         }
192         return alignment(arr->Get32(&low[0]));
193     }
194 }
195 
196 SbError marshal(
197     bool outer, SbxVariable * variable, bool special,
198     std::vector< char > & blob, std::size_t offset, MarshalData & data);
199 
marshalString(SbxVariable * variable,bool special,MarshalData & data,void ** buffer)200 SbError marshalString(
201     SbxVariable * variable, bool special, MarshalData & data, void ** buffer)
202 {
203     OSL_ASSERT(variable != 0 && buffer != 0);
204     rtl::OString str;
205     SbError e = convert(variable->GetString(), &str);
206     if (e != ERRCODE_NONE) {
207         return e;
208     }
209     std::vector< char > * blob = data.newBlob();
210     blob->insert(
211         blob->begin(), str.getStr(), str.getStr() + str.getLength() + 1);
212     *buffer = address(*blob);
213     data.unmarshalStrings.push_back(StringData(variable, *buffer, special));
214     return ERRCODE_NONE;
215 }
216 
marshalStruct(SbxVariable * variable,std::vector<char> & blob,std::size_t offset,MarshalData & data)217 SbError marshalStruct(
218     SbxVariable * variable, std::vector< char > & blob, std::size_t offset,
219     MarshalData & data)
220 {
221     OSL_ASSERT(variable != 0);
222     SbxArray * props = PTR_CAST(SbxObject, variable->GetObject())->
223         GetProperties();
224     for (sal_uInt16 i = 0; i < props->Count(); ++i) {
225         SbError e = marshal(false, props->Get(i), false, blob, offset, data);
226         if (e != ERRCODE_NONE) {
227             return e;
228         }
229     }
230     return ERRCODE_NONE;
231 }
232 
marshalArray(SbxVariable * variable,std::vector<char> & blob,std::size_t offset,MarshalData & data)233 SbError marshalArray(
234     SbxVariable * variable, std::vector< char > & blob, std::size_t offset,
235     MarshalData & data)
236 {
237     OSL_ASSERT(variable != 0);
238     SbxDimArray * arr = PTR_CAST(SbxDimArray, variable->GetObject());
239     int dims = arr->GetDims();
240     std::vector< sal_Int32 > low(dims);
241     std::vector< sal_Int32 > up(dims);
242     for (int i = 0; i < dims; ++i) {
243         arr->GetDim32(i + 1, low[i], up[i]);
244     }
245     for (std::vector< sal_Int32 > idx = low;;) {
246         SbError e = marshal(
247             false, arr->Get32(&idx[0]), false, blob, offset, data);
248         if (e != ERRCODE_NONE) {
249             return e;
250         }
251         int i = dims - 1;
252         while (idx[i] == up[i]) {
253             idx[i] = low[i];
254             if (i == 0) {
255                 return ERRCODE_NONE;
256             }
257             --i;
258         }
259         ++idx[i];
260     }
261 }
262 
263 // 8-aligned structs are only 4-aligned on stack, so alignment of members in
264 // such structs must take that into account via "offset"
marshal(bool outer,SbxVariable * variable,bool special,std::vector<char> & blob,std::size_t offset,MarshalData & data)265 SbError marshal(
266     bool outer, SbxVariable * variable, bool special,
267     std::vector< char > & blob, std::size_t offset, MarshalData & data)
268 {
269     OSL_ASSERT(variable != 0);
270 
271     SbxDataType eVarType = variable->GetType();
272     bool bByVal = (variable->GetFlags() & SBX_REFERENCE) == 0;
273     if( !bByVal && !SbiRuntime::isVBAEnabled() && eVarType == SbxSTRING )
274         bByVal = true;
275 
276     if (bByVal) {
277         if ((eVarType & SbxARRAY) == 0) {
278             switch (eVarType) {
279             case SbxINTEGER:
280                 add(blob, variable->GetInteger(), outer ? 4 : 2, offset);
281                 break;
282             case SbxLONG:
283                 add(blob, variable->GetLong(), 4, offset);
284                 break;
285             case SbxSINGLE:
286                 add(blob, variable->GetSingle(), 4, offset);
287                 break;
288             case SbxDOUBLE:
289                 add(blob, variable->GetDouble(), outer ? 4 : 8, offset);
290                 break;
291             case SbxSTRING:
292                 {
293                     void * p;
294                     SbError e = marshalString(variable, special, data, &p);
295                     if (e != ERRCODE_NONE) {
296                         return e;
297                     }
298                     add(blob, p, 4, offset);
299                     break;
300                 }
301             case SbxOBJECT:
302                 {
303                     align(blob, outer ? 4 : alignment(variable), offset, 0);
304                     SbError e = marshalStruct(variable, blob, offset, data);
305                     if (e != ERRCODE_NONE) {
306                         return e;
307                     }
308                     break;
309                 }
310             case SbxBOOL:
311                 add(blob, variable->GetBool(), outer ? 4 : 1, offset);
312                 break;
313             case SbxBYTE:
314                 add(blob, variable->GetByte(), outer ? 4 : 1, offset);
315                 break;
316             default:
317                 OSL_ASSERT(false);
318                 break;
319             }
320         } else {
321             SbError e = marshalArray(variable, blob, offset, data);
322             if (e != ERRCODE_NONE) {
323                 return e;
324             }
325         }
326     } else {
327         if ((eVarType & SbxARRAY) == 0) {
328             switch (eVarType) {
329             case SbxINTEGER:
330             case SbxLONG:
331             case SbxSINGLE:
332             case SbxDOUBLE:
333             case SbxBOOL:
334             case SbxBYTE:
335                 add(blob, variable->data(), 4, offset);
336                 break;
337             case SbxSTRING:
338                 {
339                     std::vector< char > * blob2 = data.newBlob();
340                     void * p;
341                     SbError e = marshalString(variable, special, data, &p);
342                     if (e != ERRCODE_NONE) {
343                         return e;
344                     }
345                     add(*blob2, p, 4, 0);
346                     add(blob, address(*blob2), 4, offset);
347                     break;
348                 }
349             case SbxOBJECT:
350                 {
351                     std::vector< char > * blob2 = data.newBlob();
352                     SbError e = marshalStruct(variable, *blob2, 0, data);
353                     if (e != ERRCODE_NONE) {
354                         return e;
355                     }
356                     void * p = address(*blob2);
357                     if (outer) {
358                         data.unmarshal.push_back(UnmarshalData(variable, p));
359                     }
360                     add(blob, p, 4, offset);
361                     break;
362                 }
363             default:
364                 OSL_ASSERT(false);
365                 break;
366             }
367         } else {
368             std::vector< char > * blob2 = data.newBlob();
369             SbError e = marshalArray(variable, *blob2, 0, data);
370             if (e != ERRCODE_NONE) {
371                 return e;
372             }
373             void * p = address(*blob2);
374             if (outer) {
375                 data.unmarshal.push_back(UnmarshalData(variable, p));
376             }
377             add(blob, p, 4, offset);
378         }
379     }
380     return ERRCODE_NONE;
381 }
382 
read(void const ** pointer)383 template< typename T > T read(void const ** pointer) {
384     T const * p = static_cast< T const * >(*pointer);
385     *pointer = static_cast< void const * >(p + 1);
386     return *p;
387 }
388 
unmarshal(SbxVariable * variable,void const * data)389 void const * unmarshal(SbxVariable * variable, void const * data) {
390     OSL_ASSERT(variable != 0);
391     if ((variable->GetType() & SbxARRAY) == 0) {
392         switch (variable->GetType()) {
393         case SbxINTEGER:
394             variable->PutInteger(read< sal_Int16 >(&data));
395             break;
396         case SbxLONG:
397             variable->PutLong(read< sal_Int32 >(&data));
398             break;
399         case SbxSINGLE:
400             variable->PutSingle(read< float >(&data));
401             break;
402         case SbxDOUBLE:
403             variable->PutDouble(read< double >(&data));
404             break;
405         case SbxSTRING:
406             read< char * >(&data); // handled by unmarshalString
407             break;
408         case SbxOBJECT:
409             {
410                 data = reinterpret_cast< void const * >(
411                     align(
412                         reinterpret_cast< sal_uIntPtr >(data),
413                         alignment(variable)));
414                 SbxArray * props = PTR_CAST(SbxObject, variable->GetObject())->
415                     GetProperties();
416                 for (sal_uInt16 i = 0; i < props->Count(); ++i) {
417                     data = unmarshal(props->Get(i), data);
418                 }
419                 break;
420             }
421         case SbxBOOL:
422             variable->PutBool(read< sal_Bool >(&data));
423             break;
424         case SbxBYTE:
425             variable->PutByte(read< sal_uInt8 >(&data));
426             break;
427         default:
428             OSL_ASSERT(false);
429             break;
430         }
431     } else {
432         SbxDimArray * arr = PTR_CAST(SbxDimArray, variable->GetObject());
433         int dims = arr->GetDims();
434         std::vector< sal_Int32 > low(dims);
435         std::vector< sal_Int32 > up(dims);
436         for (int i = 0; i < dims; ++i) {
437             arr->GetDim32(i + 1, low[i], up[i]);
438         }
439         for (std::vector< sal_Int32 > idx = low;;) {
440             data = unmarshal(arr->Get32(&idx[0]), data);
441             int i = dims - 1;
442             while (idx[i] == up[i]) {
443                 idx[i] = low[i];
444                 if (i == 0) {
445                     goto done;
446                 }
447                 --i;
448             }
449             ++idx[i];
450         }
451     done:;
452     }
453     return data;
454 }
455 
unmarshalString(StringData const & data,SbxVariable & result)456 SbError unmarshalString(StringData const & data, SbxVariable & result) {
457     rtl::OUString str;
458     if (data.buffer != 0) {
459         char const * p = static_cast< char const * >(data.buffer);
460         sal_Int32 len;
461         if (data.special) {
462             len = static_cast< sal_Int32 >(result.GetULong());
463             if (len < 0) { // i.e., DWORD result >= 2^31
464                 return ERRCODE_BASIC_BAD_ARGUMENT;
465                     //TODO: more specific errcode?
466             }
467         } else {
468             len = rtl_str_getLength(p);
469         }
470         SbError e = convert(p, len, &str);
471         if (e != ERRCODE_NONE) {
472             return e;
473         }
474     }
475     data.variable->PutString(String(str));
476     return ERRCODE_NONE;
477 }
478 
479 struct ProcData {
480     rtl::OString name;
481     FARPROC proc;
482 };
483 
call(rtl::OUString const & dll,ProcData const & proc,SbxArray * arguments,SbxVariable & result)484 SbError call(
485     rtl::OUString const & dll, ProcData const & proc, SbxArray * arguments,
486     SbxVariable & result)
487 {
488     std::vector< char > stack;
489     MarshalData data;
490     // For DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
491     // from kernel32, upon return, filled lpBuffer length is result DWORD, which
492     // requires special handling in unmarshalString; other functions might
493     // require similar treatment, too:
494     bool special =
495         dll.equalsIgnoreAsciiCaseAsciiL(
496             RTL_CONSTASCII_STRINGPARAM("KERNEL32.DLL")) &&
497         (proc.name ==
498          rtl::OString(RTL_CONSTASCII_STRINGPARAM("GetLogicalDriveStringsA")));
499     for (sal_uInt16 i = 1; i < (arguments == 0 ? 0 : arguments->Count()); ++i) {
500         SbError e = marshal(
501             true, arguments->Get(i), special && i == 2, stack, stack.size(),
502             data);
503         if (e != ERRCODE_NONE) {
504             return e;
505         }
506         align(stack, 4, 0, 0);
507     }
508     switch (result.GetType()) {
509     case SbxEMPTY:
510         DllMgr_call32(proc.proc, address(stack), stack.size());
511         break;
512     case SbxINTEGER:
513         result.PutInteger(
514             static_cast< sal_Int16 >(
515                 DllMgr_call32(proc.proc, address(stack), stack.size())));
516         break;
517     case SbxLONG:
518         result.PutLong(
519             static_cast< sal_Int32 >(
520                 DllMgr_call32(proc.proc, address(stack), stack.size())));
521         break;
522     case SbxSINGLE:
523         result.PutSingle(
524             static_cast< float >(
525                 DllMgr_callFp(proc.proc, address(stack), stack.size())));
526         break;
527     case SbxDOUBLE:
528         result.PutDouble(
529             DllMgr_callFp(proc.proc, address(stack), stack.size()));
530         break;
531     case SbxSTRING:
532         {
533             char const * s1 = reinterpret_cast< char const * >(
534                 DllMgr_call32(proc.proc, address(stack), stack.size()));
535             rtl::OUString s2;
536             SbError e = convert(s1, rtl_str_getLength(s1), &s2);
537             if (e != ERRCODE_NONE) {
538                 return e;
539             }
540             result.PutString(String(s2));
541             break;
542         }
543     case SbxOBJECT:
544         //TODO
545         DllMgr_call32(proc.proc, address(stack), stack.size());
546         break;
547     case SbxBOOL:
548         result.PutBool(
549             static_cast< sal_Bool >(
550                 DllMgr_call32(proc.proc, address(stack), stack.size())));
551         break;
552     case SbxBYTE:
553         result.PutByte(
554             static_cast< sal_uInt8 >(
555                 DllMgr_call32(proc.proc, address(stack), stack.size())));
556         break;
557     default:
558         OSL_ASSERT(false);
559         break;
560     }
561     for (sal_uInt16 i = 1; i < (arguments == 0 ? 0 : arguments->Count()); ++i) {
562         arguments->Get(i)->ResetFlag(SBX_REFERENCE);
563             //TODO: skipped for errors?!?
564     }
565     for (std::vector< UnmarshalData >::iterator i(data.unmarshal.begin());
566          i != data.unmarshal.end(); ++i)
567     {
568         unmarshal(i->variable, i->buffer);
569     }
570     for (std::vector< StringData >::iterator i(data.unmarshalStrings.begin());
571          i != data.unmarshalStrings.end(); ++i)
572     {
573         SbError e = unmarshalString(*i, result);
574         if (e != ERRCODE_NONE) {
575             return e;
576         }
577     }
578     return ERRCODE_NONE;
579 }
580 
getProcData(HMODULE handle,rtl::OUString const & name,ProcData * proc)581 SbError getProcData(HMODULE handle, rtl::OUString const & name, ProcData * proc)
582 {
583     OSL_ASSERT(proc != 0);
584     if ( !name.isEmpty() && name[0] == '@' ) { //TODO: "@" vs. "#"???
585         sal_Int32 n = name.copy(1).toInt32(); //TODO: handle bad input
586         if (n <= 0 || n > 0xFFFF) {
587             return ERRCODE_BASIC_BAD_ARGUMENT; //TODO: more specific errcode?
588         }
589         FARPROC p = GetProcAddress(handle, reinterpret_cast< LPCSTR >(n));
590         if (p != 0) {
591             proc->name = rtl::OString(RTL_CONSTASCII_STRINGPARAM("#")) +
592                 rtl::OString::valueOf(n);
593             proc->proc = p;
594             return ERRCODE_NONE;
595         }
596     } else {
597         rtl::OString name8;
598         SbError e = convert(name, &name8);
599         if (e != ERRCODE_NONE) {
600             return e;
601         }
602         FARPROC p = GetProcAddress(handle, name8.getStr());
603         if (p != 0) {
604             proc->name = name8;
605             proc->proc = p;
606             return ERRCODE_NONE;
607         }
608         sal_Int32 i = name8.indexOf('#');
609         if (i != -1) {
610             name8 = name8.copy(0, i);
611             p = GetProcAddress(handle, name8.getStr());
612             if (p != 0) {
613                 proc->name = name8;
614                 proc->proc = p;
615                 return ERRCODE_NONE;
616             }
617         }
618         rtl::OString real(
619             rtl::OString(RTL_CONSTASCII_STRINGPARAM("_")) + name8);
620         p = GetProcAddress(handle, real.getStr());
621         if (p != 0) {
622             proc->name = real;
623             proc->proc = p;
624             return ERRCODE_NONE;
625         }
626         real = name8 + rtl::OString(RTL_CONSTASCII_STRINGPARAM("A"));
627         p = GetProcAddress(handle, real.getStr());
628         if (p != 0) {
629             proc->name = real;
630             proc->proc = p;
631             return ERRCODE_NONE;
632         }
633     }
634     return ERRCODE_BASIC_PROC_UNDEFINED;
635 }
636 
637 struct Dll: public salhelper::SimpleReferenceObject {
638 private:
639     typedef std::map< rtl::OUString, ProcData > Procs;
640 
641     virtual ~Dll();
642 
643 public:
Dll__anonb4aed0bd0111::Dll644     Dll(): handle(0) {}
645 
646     SbError getProc(rtl::OUString const & name, ProcData * proc);
647 
648     HMODULE handle;
649     Procs procs;
650 };
651 
~Dll()652 Dll::~Dll() {
653     if (handle != 0 && !FreeLibrary(handle)) {
654         OSL_TRACE("FreeLibrary(%p) failed with %u", handle, GetLastError());
655     }
656 }
657 
getProc(rtl::OUString const & name,ProcData * proc)658 SbError Dll::getProc(rtl::OUString const & name, ProcData * proc) {
659     Procs::iterator i(procs.find(name));
660     if (i != procs.end()) {
661         *proc = i->second;
662         return ERRCODE_NONE;
663     }
664     SbError e = getProcData(handle, name, proc);
665     if (e == ERRCODE_NONE) {
666         procs.insert(Procs::value_type(name, *proc));
667     }
668     return e;
669 }
670 
fullDllName(rtl::OUString const & name)671 rtl::OUString fullDllName(rtl::OUString const & name) {
672     rtl::OUString full(name);
673     if (full.indexOf('.') == -1) {
674         full += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".DLL"));
675     }
676     return full;
677 }
678 
679 }
680 
681 struct SbiDllMgr::Impl: private boost::noncopyable {
682 private:
683     typedef std::map< rtl::OUString, rtl::Reference< Dll > > Dlls;
684 
685 public:
686     Dll * getDll(rtl::OUString const & name);
687 
688     Dlls dlls;
689 };
690 
getDll(rtl::OUString const & name)691 Dll * SbiDllMgr::Impl::getDll(rtl::OUString const & name) {
692     Dlls::iterator i(dlls.find(name));
693     if (i == dlls.end()) {
694         i = dlls.insert(Dlls::value_type(name, new Dll)).first;
695         HMODULE h = LoadLibraryW(reinterpret_cast<LPCWSTR>(name.getStr()));
696         if (h == 0) {
697             dlls.erase(i);
698             return 0;
699         }
700         i->second->handle = h;
701     }
702     return i->second.get();
703 }
704 
Call(rtl::OUString const & function,rtl::OUString const & library,SbxArray * arguments,SbxVariable & result,bool cdeclConvention)705 SbError SbiDllMgr::Call(
706     rtl::OUString const & function, rtl::OUString const & library,
707     SbxArray * arguments, SbxVariable & result, bool cdeclConvention)
708 {
709     if (cdeclConvention) {
710         return ERRCODE_BASIC_NOT_IMPLEMENTED;
711     }
712     rtl::OUString dllName(fullDllName(library));
713     Dll * dll = impl_->getDll(dllName);
714     if (dll == 0) {
715         return ERRCODE_BASIC_BAD_DLL_LOAD;
716     }
717     ProcData proc;
718     SbError e = dll->getProc(function, &proc);
719     if (e != ERRCODE_NONE) {
720         return e;
721     }
722     return call(dllName, proc, arguments, result);
723 }
724 
FreeDll(rtl::OUString const & library)725 void SbiDllMgr::FreeDll(rtl::OUString const & library) {
726     impl_->dlls.erase(library);
727 }
728 
729 #else
730 
731 struct SbiDllMgr::Impl {};
732 
Call(rtl::OUString const &,rtl::OUString const &,SbxArray *,SbxVariable &,bool)733 SbError SbiDllMgr::Call(
734     rtl::OUString const &, rtl::OUString const &, SbxArray *, SbxVariable &,
735     bool)
736 {
737     return ERRCODE_BASIC_NOT_IMPLEMENTED;
738 }
739 
FreeDll(rtl::OUString const &)740 void SbiDllMgr::FreeDll(rtl::OUString const &) {}
741 
742 #endif
743 
SbiDllMgr()744 SbiDllMgr::SbiDllMgr(): impl_(new Impl) {}
745 
~SbiDllMgr()746 SbiDllMgr::~SbiDllMgr() {}
747