1/*
2 *  drvconn.c
3 *
4 *  $Id: drvconn.c,v 1.11 2006/07/10 13:46:56 source Exp $
5 *
6 *  The data_sources dialog for SQLDriverConnect
7 *
8 *  The iODBC driver manager.
9 *
10 *  Copyright (C) 1996-2006 by OpenLink Software <iodbc@openlinksw.com>
11 *  All Rights Reserved.
12 *
13 *  This software is released under the terms of either of the following
14 *  licenses:
15 *
16 *      - GNU Library General Public License (see LICENSE.LGPL)
17 *      - The BSD License (see LICENSE.BSD).
18 *
19 *  Note that the only valid version of the LGPL license as far as this
20 *  project is concerned is the original GNU Library General Public License
21 *  Version 2, dated June 1991.
22 *
23 *  While not mandated by the BSD license, any patches you make to the
24 *  iODBC source code may be contributed back into the iODBC project
25 *  at your discretion. Contributions will benefit the Open Source and
26 *  Data Access community as a whole. Submissions may be made at:
27 *
28 *      http://www.iodbc.org
29 *
30 *
31 *  GNU Library Generic Public License Version 2
32 *  ============================================
33 *  This library is free software; you can redistribute it and/or
34 *  modify it under the terms of the GNU Library General Public
35 *  License as published by the Free Software Foundation; only
36 *  Version 2 of the License dated June 1991.
37 *
38 *  This library is distributed in the hope that it will be useful,
39 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
40 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41 *  Library General Public License for more details.
42 *
43 *  You should have received a copy of the GNU Library General Public
44 *  License along with this library; if not, write to the Free
45 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
46 *
47 *
48 *  The BSD License
49 *  ===============
50 *  Redistribution and use in source and binary forms, with or without
51 *  modification, are permitted provided that the following conditions
52 *  are met:
53 *
54 *  1. Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 *  2. Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in
58 *     the documentation and/or other materials provided with the
59 *     distribution.
60 *  3. Neither the name of OpenLink Software Inc. nor the names of its
61 *     contributors may be used to endorse or promote products derived
62 *     from this software without specific prior written permission.
63 *
64 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
65 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
66 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
67 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
68 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
69 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
70 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
71 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
72 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
73 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
74 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
75 */
76
77
78#include "gui.h"
79
80#include <herr.h>
81#include <unicode.h>
82#include <dlproc.h>
83
84#ifndef WIN32
85#include <unistd.h>
86
87typedef SQLRETURN SQL_API (*pDriverConnFunc) (HWND hwnd, LPSTR szInOutConnStr,
88    DWORD cbInOutConnStr, int FAR * sqlStat, SQLUSMALLINT fDriverCompletion, UWORD *config);
89typedef SQLRETURN SQL_API (*pDriverConnWFunc) (HWND hwnd, LPWSTR szInOutConnStr,
90    DWORD cbInOutConnStr, int FAR * sqlStat, SQLUSMALLINT fDriverCompletion, UWORD *config);
91
92#define CALL_DRVCONN_DIALBOXW(path, a) \
93  { \
94    char *_path_u8 = (a == 'A') ? NULL : dm_SQL_W2A ((wchar_t*)path, SQL_NTS); \
95    if ((handle = DLL_OPEN((a == 'A') ? (char*)path : _path_u8)) != NULL) \
96      { \
97        if ((pDrvConnW = (pDriverConnWFunc)DLL_PROC(handle, "_iodbcdm_drvconn_dialboxw")) != NULL) \
98          { \
99            SQLSetConfigMode (*config); \
100            if (pDrvConnW (hwnd, szInOutConnStr, cbInOutConnStr, sqlStat, fDriverCompletion, config) == SQL_SUCCESS) \
101              { \
102                MEM_FREE (_path_u8); \
103                DLL_CLOSE(handle); \
104                retcode = SQL_SUCCESS; \
105                goto quit; \
106              } \
107            else \
108              { \
109                MEM_FREE (_path_u8); \
110                DLL_CLOSE(handle); \
111                retcode = SQL_NO_DATA_FOUND; \
112                goto quit; \
113              } \
114          } \
115        else \
116          { \
117            if ((pDrvConn = (pDriverConnFunc)DLL_PROC(handle, "_iodbcdm_drvconn_dialbox")) != NULL) \
118              { \
119                char *_szinoutconstr_u8 = malloc (cbInOutConnStr + 1); \
120                wchar_t *_prvw; char *_prvu8; \
121                for (_prvw = szInOutConnStr, _prvu8 = _szinoutconstr_u8 ; \
122                  *_prvw != L'\0' ; _prvw += WCSLEN (_prvw) + 1, \
123                  _prvu8 += STRLEN (_prvu8) + 1) \
124                  dm_StrCopyOut2_W2A (_prvw, _prvu8, cbInOutConnStr, NULL); \
125                *_prvu8 = '\0'; \
126                SQLSetConfigMode (*config); \
127                if (pDrvConn (hwnd, _szinoutconstr_u8, cbInOutConnStr, sqlStat, fDriverCompletion, config) == SQL_SUCCESS) \
128                  { \
129                    dm_StrCopyOut2_A2W (_szinoutconstr_u8, szInOutConnStr, cbInOutConnStr, NULL); \
130                    MEM_FREE (_path_u8); \
131                    MEM_FREE (_szinoutconstr_u8); \
132                    DLL_CLOSE(handle); \
133                    retcode = SQL_SUCCESS; \
134                    goto quit; \
135                  } \
136                else \
137                  { \
138                    MEM_FREE (_path_u8); \
139                    MEM_FREE (_szinoutconstr_u8); \
140                    DLL_CLOSE(handle); \
141                    retcode = SQL_NO_DATA_FOUND; \
142                    goto quit; \
143                  } \
144              } \
145          } \
146        DLL_CLOSE(handle); \
147      } \
148    MEM_FREE (_path_u8); \
149  }
150#endif
151
152SQLRETURN SQL_API
153iodbcdm_drvconn_dialbox (
154    HWND hwnd,
155    LPSTR szInOutConnStr,
156    DWORD cbInOutConnStr,
157    int * sqlStat,
158    SQLUSMALLINT fDriverCompletion,
159    UWORD *config)
160{
161  RETCODE retcode = SQL_ERROR;
162  wchar_t *_string_w = NULL;
163
164  if (cbInOutConnStr > 0)
165    {
166      if ((_string_w = malloc (cbInOutConnStr * sizeof(wchar_t) + 1)) == NULL)
167          goto done;
168    }
169
170  dm_StrCopyOut2_A2W (szInOutConnStr, _string_w,
171    cbInOutConnStr * sizeof(wchar_t), NULL);
172
173  retcode = iodbcdm_drvconn_dialboxw (hwnd, _string_w,
174    cbInOutConnStr, sqlStat, fDriverCompletion, config);
175
176  if (retcode == SQL_SUCCESS)
177    {
178      dm_StrCopyOut2_W2A (_string_w, szInOutConnStr, cbInOutConnStr - 1, NULL);
179    }
180
181done:
182  MEM_FREE (_string_w);
183
184  return retcode;
185}
186
187
188SQLRETURN SQL_API
189iodbcdm_drvconn_dialboxw (
190    HWND hwnd,
191    LPWSTR szInOutConnStr,
192    DWORD cbInOutConnStr,
193    int * sqlStat,
194    SQLUSMALLINT fDriverCompletion,
195	 UWORD *config)
196{
197  RETCODE retcode = SQL_ERROR;
198  TDSNCHOOSER choose_t;
199  wchar_t *string = NULL, *prov, *prov1, *szDSN = NULL, *szDriver = NULL;
200  wchar_t *szFILEDSN = NULL, *szSAVEFILE = NULL;
201  wchar_t tokenstr[4096];
202  wchar_t drvbuf[4096] = { L'\0'};
203  char *_szdriver_u8 = NULL;
204  wchar_t *_szdriver_w = NULL;
205  HDLL handle;
206  pDriverConnFunc pDrvConn;
207  pDriverConnWFunc pDrvConnW;
208  int i, skip;
209#if defined (__APPLE__) && !(defined (NO_FRAMEWORKS) || defined (_LP64))
210  CFStringRef libname = NULL;
211  CFBundleRef bundle = NULL;
212  CFURLRef liburl = NULL;
213  char name[1024] = { '\0' };
214#endif
215
216  /* Check input parameters */
217  if (!szInOutConnStr || cbInOutConnStr < 1)
218    goto quit;
219
220  /* Transform the string connection to list of key pairs */
221  string = (wchar_t*) malloc((cbInOutConnStr + 1) * sizeof(wchar_t));
222  if (string == NULL)
223    {
224      if (sqlStat)
225#if (ODBCVER>=0x3000)
226        *sqlStat = en_HY092;
227#else
228        *sqlStat = en_S1000;
229#endif
230      retcode = SQL_ERROR;
231      goto quit;
232    }
233
234  /* Conversion to the list of key pairs */
235  wcsncpy (string, szInOutConnStr, cbInOutConnStr);
236  string[WCSLEN (string) + 1] = L'\0';
237  skip = 0;
238  for (i = WCSLEN (string) - 1 ; i >= 0 ; i--)
239  {
240    if (string[i] == L'}')
241      skip = 1;
242    else if (string[i] == L'{')
243      skip = 0;
244    else if (skip == 0 && string[i] == L';') string[i] = L'\0';
245  }
246
247  /* Look for the DSN and DRIVER keyword */
248  for (prov = string ; *prov != L'\0' ; prov += WCSLEN (prov) + 1)
249    {
250      if (!wcsncasecmp (prov, L"DSN=", WCSLEN (L"DSN=")))
251        {
252          szDSN = prov + WCSLEN (L"DSN=");
253          continue;
254        }
255      if (!wcsncasecmp (prov, L"DRIVER=", WCSLEN (L"DRIVER=")))
256        {
257          szDriver = prov + WCSLEN (L"DRIVER=");
258          continue;
259        }
260      if (!wcsncasecmp (prov, L"FILEDSN=", WCSLEN (L"FILEDSN=")))
261        {
262          szFILEDSN = prov + WCSLEN (L"FILEDSN=");
263          continue;
264        }
265      if (!wcsncasecmp (prov, L"SAVEFILE=", WCSLEN (L"SAVEFILE=")))
266        {
267          szSAVEFILE = prov + WCSLEN (L"SAVEFILE=");
268          continue;
269        }
270    }
271
272  if (!szDSN && !szDriver)
273    {
274      /* Display the DSN chooser dialog box */
275      create_dsnchooser (hwnd, &choose_t);
276
277      /* Check output parameters */
278      if (choose_t.dsn || choose_t.fdsn)
279        {
280#if (ODBCVER>=0x3000)
281          int errSqlStat = en_HY092;
282#else
283          int errSqlStat = en_HY092;
284#endif
285          /* Change the config mode */
286          switch (choose_t.type_dsn)
287            {
288              case USER_DSN:
289                *config = ODBC_USER_DSN;
290                break;
291              case SYSTEM_DSN:
292                *config = ODBC_SYSTEM_DSN;
293                break;
294            };
295
296          if (choose_t.dsn && (choose_t.type_dsn == USER_DSN || choose_t.type_dsn == SYSTEM_DSN))
297            {
298              /* Try to copy the DSN */
299              if (cbInOutConnStr > WCSLEN (choose_t.dsn) + WCSLEN (L"DSN=") + 2)
300                {
301                  WCSCPY (string, L"DSN=");
302                  WCSCAT (string, choose_t.dsn);
303                  string[WCSLEN (string) + 1] = L'\0';
304                  szDSN = string + WCSLEN (L"DSN=");
305                  retcode = SQL_SUCCESS;
306                }
307              else
308                {
309                  if (sqlStat)
310                    *sqlStat = errSqlStat;
311                }
312            }
313          else if (choose_t.fdsn && choose_t.type_dsn == FILE_DSN)
314            {
315              DWORD sz, sz_entry;
316              wchar_t entries[4096];
317              WORD read_len;
318              wchar_t *p, *p_next;
319
320              sz = WCSLEN(choose_t.fdsn) + WCSLEN(L"FILEDSN=") + 2;
321              if (cbInOutConnStr > sz)
322                {
323                  WCSCPY (string, L"FILEDSN=");
324                  WCSCAT (string, choose_t.fdsn);
325                  WCSCAT (string, L";");
326                  retcode = SQL_SUCCESS;
327                }
328
329              /* Get list of entries in .dsn file */
330              if (retcode == SQL_SUCCESS
331                  && SQLReadFileDSNW (choose_t.fdsn, L"ODBC", NULL,
332		       entries, sizeof (entries)/sizeof(wchar_t), &read_len))
333                {
334                  /* add params from the .dsn file */
335                  for (p = entries; *p != '\0'; p = p_next)
336                    {
337                      wchar_t value[1024];
338
339                      /* get next entry */
340                      p_next = wcschr (p, L';');
341                      if (p_next)
342                        *p_next++ = L'\0';
343
344                      if (!SQLReadFileDSNW (choose_t.fdsn, L"ODBC", p, value,
345                              sizeof(value)/sizeof(wchar_t), &read_len))
346                        {
347                          retcode = SQL_ERROR;
348                          break;
349                        }
350
351                      if (!wcsncasecmp (p, L"DRIVER", WCSLEN(L"DRIVER")))
352                        {
353                          szDriver = _szdriver_w = (wchar_t*) malloc((WCSLEN(value) + 1) * sizeof(wchar_t));
354                          if (szDriver)
355                            WCSCPY(szDriver, value);
356                        }
357
358                      sz_entry = WCSLEN(p) + 1 + WCSLEN(value) + 2;
359                      if (cbInOutConnStr > sz + sz_entry)
360                        {
361                          WCSCAT (string, p);
362                          WCSCAT (string, L"=");
363                          WCSCAT (string, value);
364                          WCSCAT (string, L";");
365                          sz += sz_entry;
366                        }
367                      else
368                        {
369                          retcode = SQL_ERROR;
370                        }
371                    }
372                }
373              if (retcode == SQL_SUCCESS)
374                {
375                  string[WCSLEN (string) + 1] = L'\0';
376                  for (i = WCSLEN (string) - 1 ; i >= 0 ; i--)
377                    if (string[i] == L';') string[i] = L'\0';
378                }
379              else if (sqlStat)
380                *sqlStat = errSqlStat;
381            }
382          else
383            {
384              if (sqlStat)
385                *sqlStat = errSqlStat;
386            }
387        }
388      else
389        retcode = SQL_NO_DATA_FOUND;
390
391      if (choose_t.dsn)
392	free (choose_t.dsn);
393      if (choose_t.fdsn)
394	free (choose_t.fdsn);
395
396      if (retcode != SQL_SUCCESS)
397	goto quit;
398    }
399
400
401  /* Constitute the string connection */
402  for (prov = szInOutConnStr, prov1 = string, i = 0 ; *prov1 != L'\0' ;
403    prov1 += WCSLEN (prov) + 1, i += WCSLEN (prov) + 1, prov += WCSLEN (prov) + 1)
404    WCSCPY (prov, prov1);
405  *prov = L'\0';
406
407  /* Check if the driver is provided */
408  if (szDriver == NULL)
409    {
410      SQLSetConfigMode (ODBC_BOTH_DSN);
411      SQLGetPrivateProfileStringW (L"ODBC Data Sources",
412        szDSN && szDSN[0] != L'\0' ? szDSN : L"default",
413        L"", tokenstr, sizeof (tokenstr)/sizeof(wchar_t), NULL);
414      szDriver = tokenstr;
415    }
416
417  /* Call the iodbcdm_drvconn_dialbox */
418  _szdriver_u8 = dm_SQL_W2A (szDriver, SQL_NTS);
419
420  SQLSetConfigMode (ODBC_USER_DSN);
421  if (!access (_szdriver_u8, X_OK))
422    { CALL_DRVCONN_DIALBOXW (_szdriver_u8, 'A'); }
423  if (SQLGetPrivateProfileStringW (szDriver, L"Driver", L"", drvbuf,
424    sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
425    { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
426  if (SQLGetPrivateProfileStringW (szDriver, L"Setup", L"", drvbuf,
427    sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
428    { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
429  if (SQLGetPrivateProfileStringW (L"Default", L"Driver", L"", drvbuf,
430    sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
431    { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
432  if (SQLGetPrivateProfileStringW (L"Default", L"Setup", L"", drvbuf,
433    sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
434    { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
435
436  SQLSetConfigMode (ODBC_SYSTEM_DSN);
437  if (!access (_szdriver_u8, X_OK))
438    { CALL_DRVCONN_DIALBOXW (_szdriver_u8, 'A'); }
439  if (SQLGetPrivateProfileStringW (szDriver, L"Driver", L"", drvbuf,
440    sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
441    { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
442  if (SQLGetPrivateProfileStringW (szDriver, L"Setup", L"", drvbuf,
443    sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
444    { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
445  if (SQLGetPrivateProfileStringW (L"Default", L"Driver", L"", drvbuf,
446    sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
447    { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
448  if (SQLGetPrivateProfileStringW (L"Default", L"Setup", L"", drvbuf,
449    sizeof (drvbuf) / sizeof(wchar_t), L"odbcinst.ini"))
450    { CALL_DRVCONN_DIALBOXW (drvbuf, 'W'); }
451
452  /* The last ressort, a proxy driver */
453#if defined (__APPLE__) && !(defined (NO_FRAMEWORKS) || defined (_LP64))
454  bundle = CFBundleGetBundleWithIdentifier (CFSTR ("org.iodbc.core"));
455  if (!bundle)
456    bundle = CFBundleGetBundleWithIdentifier (CFSTR ("org.iodbc.inst"));
457  if (bundle)
458    {
459      /* Search for the drvproxy library */
460      liburl =
461	  CFBundleCopyResourceURL (bundle, CFSTR ("iODBCdrvproxy.bundle"),
462	  NULL, NULL);
463      if (liburl && (libname =
464       CFURLCopyFileSystemPath (liburl, kCFURLPOSIXPathStyle)))
465	{
466          CFStringGetCString (libname, name, sizeof (name),
467            kCFStringEncodingASCII);
468          STRCAT (name, "/Contents/MacOS/iODBCdrvproxy");
469          CALL_DRVCONN_DIALBOXW (name, 'A');
470	}
471    }
472#else
473  CALL_DRVCONN_DIALBOXW ("libdrvproxy.so", 'A');
474#endif /* __APPLE__ */
475
476  if (sqlStat)
477    *sqlStat = en_IM003;
478
479quit:
480#if defined (__APPLE__) && !(defined (NO_FRAMEWORKS) || defined (_LP64))
481  if (liburl) CFRelease (liburl);
482  if (libname) CFRelease (libname);
483#endif
484
485  MEM_FREE (string);
486  MEM_FREE (_szdriver_u8);
487  MEM_FREE (_szdriver_w);
488
489  return retcode;
490}
491
492
493SQLRETURN SQL_API
494_iodbcdm_drvchoose_dialbox (
495    HWND hwnd,
496    LPSTR szInOutConnStr,
497    DWORD cbInOutConnStr,
498    int * sqlStat)
499{
500  RETCODE retcode = SQL_ERROR;
501  wchar_t *_string_w = NULL;
502  WORD len;
503
504  if (cbInOutConnStr > 0)
505    {
506      if ((_string_w = malloc (cbInOutConnStr * sizeof(wchar_t) + 1)) == NULL)
507          goto done;
508    }
509
510  retcode = _iodbcdm_drvchoose_dialboxw (hwnd, _string_w,
511    cbInOutConnStr * sizeof(wchar_t), sqlStat);
512
513  if (retcode == SQL_SUCCESS)
514    {
515      dm_StrCopyOut2_W2A (_string_w, szInOutConnStr, cbInOutConnStr - 1, &len);
516    }
517
518done:
519  MEM_FREE (_string_w);
520
521  return retcode;
522}
523
524
525SQLRETURN SQL_API
526_iodbcdm_drvchoose_dialboxw (HWND hwnd,
527    LPWSTR szInOutConnStr,
528    DWORD cbInOutConnStr,
529    int FAR * sqlStat)
530{
531  RETCODE retcode = SQL_ERROR;
532  TDRIVERCHOOSER choose_t;
533
534  /* Check input parameters */
535  if (!hwnd || !szInOutConnStr || cbInOutConnStr < 1)
536    goto quit;
537
538  create_driverchooser (hwnd, &choose_t);
539
540  /* Check output parameters */
541  if (choose_t.driver)
542    {
543      if (cbInOutConnStr > WCSLEN (choose_t.driver) + WCSLEN (L"DRIVER="))
544	{
545          WCSCPY (szInOutConnStr, L"DRIVER=");
546          WCSCAT (szInOutConnStr, choose_t.driver);
547	  retcode = SQL_SUCCESS;
548	}
549      else
550	{
551	  if (sqlStat)
552#if (ODBCVER>=0x3000)
553	    *sqlStat = en_HY092;
554#else
555	    *sqlStat = en_S1000;
556#endif
557	  retcode = SQL_ERROR;
558	}
559    }
560  else
561    retcode = SQL_NO_DATA;
562
563  if (choose_t.driver)
564    free (choose_t.driver);
565
566quit:
567  return retcode;
568}
569
570
571SQLRETURN SQL_API
572_iodbcdm_admin_dialbox (HWND hwnd)
573{
574  RETCODE retcode = SQL_ERROR;
575
576  /* Check input parameters */
577  if (!hwnd)
578    goto quit;
579
580  create_administrator (hwnd);
581  retcode = SQL_SUCCESS;
582
583quit:
584  return retcode;
585}
586
587
588SQLRETURN SQL_API
589_iodbcdm_trschoose_dialbox (
590    HWND hwnd,
591    LPSTR szInOutConnStr,
592    DWORD cbInOutConnStr,
593    int FAR * sqlStat)
594{
595  RETCODE retcode = SQL_ERROR;
596  wchar_t *_string_w = NULL;
597  WORD len;
598
599  if (cbInOutConnStr > 0)
600    {
601      if ((_string_w = malloc (cbInOutConnStr * sizeof(wchar_t) + 1)) == NULL)
602          goto done;
603    }
604
605  retcode = _iodbcdm_trschoose_dialboxw (hwnd, _string_w,
606    cbInOutConnStr * sizeof(wchar_t), sqlStat);
607
608  if (retcode == SQL_SUCCESS)
609    {
610      dm_StrCopyOut2_W2A (_string_w, szInOutConnStr, cbInOutConnStr - 1, &len);
611    }
612
613done:
614  MEM_FREE (_string_w);
615
616  return retcode;
617}
618
619
620SQLRETURN SQL_API
621_iodbcdm_trschoose_dialboxw (
622    HWND hwnd,
623    LPWSTR szInOutConnStr,
624    DWORD cbInOutConnStr,
625    int * sqlStat)
626{
627  RETCODE retcode = SQL_ERROR;
628  TTRANSLATORCHOOSER choose_t;
629
630  /* Check input parameters */
631  if (!hwnd || !szInOutConnStr || cbInOutConnStr < 1)
632    goto quit;
633
634  create_translatorchooser (hwnd, &choose_t);
635
636  /* Check output parameters */
637  if (choose_t.translator)
638    {
639      if (cbInOutConnStr >
640          WCSLEN (choose_t.translator) + WCSLEN (L"TranslationName="))
641	{
642          WCSCPY (szInOutConnStr, L"TranslationName");
643          WCSCAT (szInOutConnStr, choose_t.translator);
644	  retcode = SQL_SUCCESS;
645	}
646      else
647	{
648	  if (sqlStat)
649#if (ODBCVER>=0x3000)
650	    *sqlStat = en_HY092;
651#else
652	    *sqlStat = en_S1000;
653#endif
654	  retcode = SQL_ERROR;
655	}
656    }
657  else
658    retcode = SQL_NO_DATA;
659
660  if (choose_t.translator)
661    free (choose_t.translator);
662
663quit:
664  return retcode;
665}
666
667
668