解決libcurl7.50.3在windows XP SP3 VC++ 6.0下編譯報錯 unresolved external symbol __imp__IdnToAscii@20 unresol

錯誤重現:

--------------------Configuration: curl - Win32 LIB Debug DLL Windows SSPI DLL WinIDN--------------------

xilink6: executing 'D:\vc6.0\VC98\Bin\link.exe'
libcurld.lib(idn_win32.obj) : error LNK2001: unresolved external symbol __imp__IdnToAscii@20
libcurld.lib(idn_win32.obj) : error LNK2001: unresolved external symbol __imp__IdnToUnicode@20
..\..\..\..\build\Win32\VC6\LIB Debug - DLL Windows SSPI - DLL WinIDN\curld.exe : fatal error LNK1120: 2 unresolved externals
Error executing xilink6.exe.

curld.exe - 3 error(s), 2 warning(s)


--------------------Configuration: curl - Win32 LIB Release DLL Windows SSPI DLL WinIDN--------------------
Linking...
xilink6: executing 'D:\vc6.0\VC98\Bin\link.exe'
libcurl.lib(idn_win32.obj) : error LNK2001: unresolved external symbol __imp__IdnToAscii@20
libcurl.lib(idn_win32.obj) : error LNK2001: unresolved external symbol __imp__IdnToUnicode@20
..\..\..\..\build\Win32\VC6\LIB Release - DLL Windows SSPI - DLL WinIDN/curl.exe : fatal error LNK1120: 2 unresolved externals

根據兩個API的名字google了一下windows

IdnToUnicode,IdnToAscii封裝在normaliz.dll中,查詢了本機的幾個SDK(Microsoft Platform SDK February 2003,Microsoft Windows SDK v6.0A,Microsoft Windows SDK v7.0A,
Microsoft Windows SDK v7.1),只有Microsoft Platform SDK February 2003沒有,心想這下壞了,很差編譯了,由於Microsoft Platform SDK February 2003是Windows XP最終版SDK,翻了一下%systemroot%\system32\又能夠找到normaliz.dll,查看了一下導出函數,又是有的,不懂什麼軟件帶過來的,仍是系統更新裝上的。

msdn對IdnToUnicode,IdnToAscii這兩個函數的使用要求以下:

Minimum supported clientapp

Windows Vista [desktop apps | Windows Store apps]less

Minimum supported servercurl

Windows Server 2008 [desktop apps | Windows Store apps]函數

Redistributableui

Microsoft Internationalized Domain Name (IDN) Mitigation APIs onWindows XP with SP2 and later,Windows Server 2003 with SP1google

Headerurl

Winnls.h (include Windows.h)

Libraryspa

Normaliz.lib

DLLdebug

Normaliz.dll
  從以上表格看出,這個庫一開始並非爲Windows XP準備的,只是後來在SP2之後纔有,用VC++6.0編譯的時候normaliz.lib指向的dll函數地址就是錯誤的,
因而想到用LoadLibrary和GetProcAddress函數配合,顯式調用者兩個函數,從這個程度上來講也能夠節省內存開銷,使用完當即釋放掉。

解決辦法:

問題的根源是idn,因而找到了CURL_FOLDER\lib\idn_win32.c進行開刀。
如下是7.50.3版本的idn_win32.c修改前的模樣:
#include "curl_setup.h"

#ifdef USE_WIN32_IDN

#include "curl_multibyte.h"
#include "curl_memory.h"
#include "warnless.h"

  /* The last #include file should be: */
#include "memdebug.h"

#ifdef WANT_IDN_PROTOTYPES
#  if defined(_SAL_VERSION)
WINNORMALIZEAPI int WINAPI
IdnToAscii(_In_                           DWORD    dwFlags,
           _In_reads_(cchUnicodeChar)     LPCWSTR  lpUnicodeCharStr,
           _In_                           int      cchUnicodeChar,
           _Out_writes_opt_(cchASCIIChar) LPWSTR   lpASCIICharStr,
           _In_                           int      cchASCIIChar);
WINNORMALIZEAPI int WINAPI
IdnToUnicode(_In_                             DWORD   dwFlags,
             _In_reads_(cchASCIIChar)         LPCWSTR lpASCIICharStr,
             _In_                             int     cchASCIIChar,
             _Out_writes_opt_(cchUnicodeChar) LPWSTR  lpUnicodeCharStr,
             _In_                             int     cchUnicodeChar);
#  else
WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags,
                                 const WCHAR *lpUnicodeCharStr,
                                 int cchUnicodeChar,
                                 WCHAR *lpASCIICharStr,
                                 int cchASCIIChar);
WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,
                                   const WCHAR *lpASCIICharStr,
                                   int cchASCIIChar,
                                   WCHAR *lpUnicodeCharStr,
                                   int cchUnicodeChar);
#  endif
#endif

#define IDN_MAX_LENGTH 255

bool curl_win32_idn_to_ascii(const char *in, char **out);
bool curl_win32_ascii_to_idn(const char *in, char **out);

bool curl_win32_idn_to_ascii(const char *in, char **out)
{
  bool success = FALSE;

  wchar_t *in_w = Curl_convert_UTF8_to_wchar(in);
  if(in_w) {
    wchar_t punycode[IDN_MAX_LENGTH];
    int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH);
    free(in_w);
    if(chars) {
      *out = Curl_convert_wchar_to_UTF8(punycode);
      if(*out)
        success = TRUE;
    }
  }

  return success;
}

bool curl_win32_ascii_to_idn(const char *in, char **out)
{
  bool success = FALSE;

  wchar_t *in_w = Curl_convert_UTF8_to_wchar(in);
  if(in_w) {
    size_t in_len = wcslen(in_w) + 1;
    wchar_t unicode[IDN_MAX_LENGTH];
    int chars = IdnToUnicode(0, in_w, curlx_uztosi(in_len),
                             unicode, IDN_MAX_LENGTH);
    free(in_w);
    if(chars) {
      *out = Curl_convert_wchar_to_UTF8(unicode);
      if(*out)
        success = TRUE;
    }
  }

  return success;
}

#endif /* USE_WIN32_IDN */
idn_win32.c修改後的模樣:
#include "curl_setup.h"

#ifdef USE_WIN32_IDN

#include "curl_multibyte.h"
#include "curl_memory.h"
#include "warnless.h"

  /* The last #include file should be: */
#include "memdebug.h"

#ifdef WANT_IDN_PROTOTYPES
//#  if defined(_SAL_VERSION)
typedef int (*fnIdnToAscii)(DWORD,const WCHAR *,int,WCHAR *,int);
typedef int (*fnIdnToUnicode)(DWORD,const WCHAR *,int,WCHAR *, int);
//#  endif
#endif

#define IDN_MAX_LENGTH 255

bool curl_win32_idn_to_ascii(const char *in, char **out);
bool curl_win32_ascii_to_idn(const char *in, char **out);

bool curl_win32_idn_to_ascii(const char *in, char **out)
{
  bool success = FALSE;

  wchar_t *in_w = Curl_convert_UTF8_to_wchar(in);
 
  if(in_w) {
    wchar_t punycode[IDN_MAX_LENGTH];
    int chars = -1;
    fnIdnToAscii IdnToAscii;
    HINSTANCE hNormalizDLL = LoadLibrary("normaliz.dll");
    if (!hNormalizDLL) {
        FreeLibrary(hNormalizDLL);
        assert(hNormalizDLL);
        return FALSE;
    }
    IdnToAscii = (fnIdnToAscii)GetProcAddress(hNormalizDLL, "IdnToAscii");
    if (!IdnToAscii) {
        assert(IdnToAscii);
        return TRUE;
    }
    chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH);
    
    free(IdnToAscii);
    FreeLibrary(hNormalizDLL);

    free(in_w);
    if(chars) {
      *out = Curl_convert_wchar_to_UTF8(punycode);
      if(*out)
        success = TRUE;
    }
  }

  return success;
}

bool curl_win32_ascii_to_idn(const char *in, char **out)
{
  bool success = FALSE;

  wchar_t *in_w = Curl_convert_UTF8_to_wchar(in);
  if(in_w) {
    size_t in_len = wcslen(in_w) + 1;
    wchar_t unicode[IDN_MAX_LENGTH];
    int chars = -1;
    fnIdnToUnicode IdnToUnicode;
    
    HINSTANCE hNormalizDLL = LoadLibrary("normaliz.dll");
    if (!hNormalizDLL) {
        FreeLibrary(hNormalizDLL);
        assert(hNormalizDLL);
        return FALSE;
    }
    IdnToUnicode = (fnIdnToUnicode)GetProcAddress(hNormalizDLL, "IdnToUnicode");
    if (!IdnToUnicode) {
        assert(IdnToUnicode);
        return FALSE;
    }
    chars = IdnToUnicode(0, in_w, curlx_uztosi(in_len),
                             unicode, IDN_MAX_LENGTH);
    
    free(IdnToUnicode);
    FreeLibrary(hNormalizDLL);
    free(in_w);
    if(chars) {
      *out = Curl_convert_wchar_to_UTF8(unicode);
      if(*out)
        success = TRUE;
    }
  }

  return success;
}

#endif /* USE_WIN32_IDN */
 通過以上修改就能夠編譯成功了。
相關文章
相關標籤/搜索