c++ - 打开 NFC - 错误 LNK2019 : unresolved external symbol __imp__ShellExecuteW@24

标签 c++ visual-studio visual-c++ nfc open-nfc

我遇到错误,但我不知道问题出在哪里。

我正在尝试为一个项目编译一个 Open NFC 示例。示例是 test_ndef_url。我不知道问题是否出在编码错误或Windows库上,shellapi.h。

Test_ndef_url 代码是:

    /*
 * Copyright (c) 2007-2012 Inside Secure, All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*******************************************************************************

  Implementation of the Example 1 for Open NFC.

*******************************************************************************/

/* Allow use of features specific to Windows XP or later. */
#ifndef _WIN32_WINNT
/* Change this to the appropriate value to target other versions of Windows. */
#define _WIN32_WINNT 0x0601
#endif

/* Suppress many files from the compilation */
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#include "shellapi.h"
#include <stdio.h>
#include <stdlib.h>

#include "open_nfc.h"

#include "win32_test_core.h"

/* Type definititions */
/* ------------------ */

/* Local prototypes */
/* ---------------- */

/* Global variables */
/* ---------------- */

struct __testContext
{
   char16_t*      pURL;
   bool_t        bVirtualTag;
   bool_t        bReadTest;
   W_HANDLE    hRegistry;
} ;

struct __testContext g_testCtx = { null, W_FALSE, W_FALSE, W_NULL_HANDLE };

/* Callback function of type tWBasicGenericHandleCallbackFunction */
static void ReadMessageOnAnyTagCompletedURL(void *pCallbackParameter, W_HANDLE hMessage, W_ERROR nError)
{
   if(nError == W_SUCCESS)
   {
      W_HANDLE hRecord = WNDEFGetRecord(hMessage, 0);
      WBasicCloseHandle(hMessage);

      if(WRTDIsURIRecord(hRecord))
      {
         char16_t aURIValue[256];

         if(WRTDURIGetValue(hRecord, (char16_t*)&aURIValue, 256) == W_SUCCESS)
         {
            printf("The URL read in the tag is \"%S\"\n", aURIValue);

            ShellExecute(NULL, L"open", (char16_t*)aURIValue, NULL, NULL, SW_SHOWNORMAL);
         }
      }
      else
      {
         printf("Error URL: Error detected in the tag message.\n");
      }

      WBasicCloseHandle(hRecord);
   }
   else if(nError == W_ERROR_ITEM_NOT_FOUND)
   {
      printf("Error URL: This tag does not contain a message of the right type.\n");
   }
   else if(nError == W_ERROR_TIMEOUT)
   {
      printf("Error URL: Lost the communication with the tag.\n");
   }
   else
   {
      printf("Error URL: Error 0x%08X returned during the tag detection.\n", nError);
   }

   printf("Present a new tag to be read or press Ctrl+C to stop the application\n");
}

/* Callback function of type tWBasicGenericCallbackFunction */
static void WriteMessageOnAnyTagCompleted(void *pCallbackParameter, W_ERROR nError)
{
   switch(nError)
   {
      case W_SUCCESS:
         printf("The message is written in the tag.\n");
         break;
      case W_ERROR_LOCKED_TAG:
         printf("The operation failed because the tag is locked.\n");
         break;
      case W_ERROR_TAG_FULL:
         printf("The message is too large for the remaining free space in the tag.\n");
         break;
      default:
         printf("An error occured during the writing operation (code 0x%x)\n", nError);
         break;
   }
   StopApplication();
}

/* Receive the event of the virtual tag */
static void VirtualTagEventHandler(void *pCallbackParameter, uint32_t nEventCode)
{
   switch(nEventCode)
   {
      case W_VIRTUAL_TAG_EVENT_SELECTION:
         printf("The tag is selected by the reader.\n");
         break;
      case W_VIRTUAL_TAG_EVENT_READER_LEFT:
         printf("The reader left the tag without reading the content.\n");
         break;
      case W_VIRTUAL_TAG_EVENT_READER_READ_ONLY :
         printf("The reader read the tag.\nPresent again a reader to read the virtual tag or press Ctrl+C to stop the application\n");
         break;
      case W_VIRTUAL_TAG_EVENT_READER_WRITE:
      default:
         printf("This event should not occur for a read-only virtual tag.\n");
         break;
   }
}

/**
 * GetSpecificTestSyntax
 *
 * @return     String describing the command line syntax specific to this test
 **/
char16_t * GetSpecificTestSyntax( void )
{
   return L"[url <URL> | virtualurl <URL>\n"
          L" - If the parameter is not present, the application waits to read a tag with an URL.\n"
          L" - If \"url\" is present, the application waits for a Tag to write the URL.\n"
          L" - If \"virtualurl\" is present, the application simulates a tag containing the URL.\n\n"
          L"The following tags are supported: Type 2, Type 4-A, Type 4-B, Type 5-2K, Type 5-32K and Type 6.\n\n" ;
}

/**
 * VerifyTestConditions
 *
 * @param[in]  nArgc       number of arguments
 *
 * @param[in]  pArgv       arguments array
 *
 * @return     W_SUCCESS   Arguments syntax is correct
 *             W_ERROR_xxx is syntax error is detected
 **/

W_ERROR VerifyTestConditions( int32_t nArgc, char16_t* pArgv[] )
{
   if(nArgc == 3)
   {
      if(wcscmp(pArgv[1], L"url") == 0)
      {
         g_testCtx.pURL = pArgv[2];
      }
      else if(wcscmp(pArgv[1], L"virtualurl") == 0)
      {
         g_testCtx.bVirtualTag = W_TRUE;
         g_testCtx.pURL = pArgv[2];
      }
      else
      {
         nArgc = 0;
      }
   }

   if((nArgc != 1) && (nArgc != 3))
   {
      return W_ERROR_BAD_PARAMETER;
   }

   g_testCtx.bReadTest = (nArgc == 1) ? W_TRUE : W_FALSE ;

   return W_SUCCESS;
}

/**
 * LaunchTest
 *
 **/

W_ERROR LaunchTest( void )
{
   W_HANDLE hMessage = W_NULL_HANDLE;

   if(g_testCtx.bReadTest != W_FALSE)
   {
      WNDEFReadMessageOnAnyTag(ReadMessageOnAnyTagCompletedURL, null, W_PRIORITY_MAXIMUM,
         W_NDEF_TNF_WELL_KNOWN, L"U", &g_testCtx.hRegistry);

      printf("Present the tag to be read or press Ctrl+C to stop the application\n");
   }
   else
   {
      if(WNDEFCreateNewMessage(&hMessage) != W_SUCCESS)
      {
         printf("Error: Cannot create the new message.\n");
         goto return_function;
      }
      if(WRTDURIAddRecord(hMessage, g_testCtx.pURL) != W_SUCCESS)
      {
         printf("Error: Cannot add the URI record in the message.\n");
         goto return_function;
      }

      if(g_testCtx.bVirtualTag == W_FALSE)
      {
         printf("Ready to write the URL \"%S\"\n", g_testCtx.pURL);

         WNDEFWriteMessageOnAnyTag(WriteMessageOnAnyTagCompleted, null, W_PRIORITY_MAXIMUM, hMessage, W_NDEF_ACTION_BIT_ERASE | W_NDEF_ACTION_BIT_FORMAT_ALL, &g_testCtx.hRegistry);

         printf("Present the tag to be written or press Ctrl+C to stop the application\n");
      }
      else
      {
         W_ERROR nError;
         W_HANDLE hVirtualTag;
         static const uint8_t aPUPI[] = { 0x01, 0x02, 0x03, 0x04 };

         printf("Ready to simulate a tag with the URL \"%S\"\n", g_testCtx.pURL);

         /* Create the virtual tag, the maximum length is set to the size of the message */
         nError = WVirtualTagCreate(W_PROP_NFC_TAG_TYPE_4_B, aPUPI, sizeof(aPUPI),
            WNDEFGetMessageLength(hMessage), &hVirtualTag);
         if(nError != W_SUCCESS)
         {
            printf("Cannot create the virtual tag\n");
         }
         else
         {
            /* Write the message in the virtual tag */
            nError = WNDEFWriteMessageSync(hVirtualTag, hMessage, W_NDEF_ACTION_BIT_ERASE | W_NDEF_ACTION_BIT_LOCK | W_NDEF_ACTION_BIT_FORMAT_ALL);
            if(nError != W_SUCCESS)
            {
               printf("Cannot write the message in the virtual tag\n");
               WBasicCloseHandle(hVirtualTag);
            }
            else
            {
               /* Start the tag simulation */
               nError = WVirtualTagStartSync(hVirtualTag, VirtualTagEventHandler, null, W_TRUE);
               if(nError != W_SUCCESS)
               {
                  printf("Cannot activate the virtual tag\n");
                  WBasicCloseHandle(hVirtualTag);
               }
               else
               {
                  printf("Present a reader to read the virtual tag or press Ctrl+C to stop the application\n");
               }
            }
         }
      }
   }

return_function:

   WBasicCloseHandle(hMessage);

   /* Go pending on WaitForSingleObject (Card/Tag operation completed or Ctrl-C) */

   return W_SUCCESS;
}

/**
 * CloseTest
 *
 **/
void CloseTest( void )
{
   WBasicCloseHandle( g_testCtx.hRegistry );
}

这部分代码定义在shellapi.h中,其中ShellExecute是:

    #include <winapifamily.h>

/*****************************************************************************\
*                                                                             *
* shellapi.h -  SHELL.DLL functions, types, and definitions                   *
*                                                                             *
* Copyright (c) Microsoft Corporation. All rights reserved.                   *
*                                                                             *
\*****************************************************************************/

#ifndef _INC_SHELLAPI
#define _INC_SHELLAPI

#include <SpecStrings.h>

//
// Define API decoration for direct importing of DLL references.
//
#ifndef WINSHELLAPI
#if !defined(_SHELL32_)
#define WINSHELLAPI       DECLSPEC_IMPORT
#else
#define WINSHELLAPI
#endif
#endif // WINSHELLAPI

#ifndef SHSTDAPI
#if !defined(_SHELL32_)
#define SHSTDAPI          EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
#define SHSTDAPI_(type)   EXTERN_C DECLSPEC_IMPORT type STDAPICALLTYPE
#else
#define SHSTDAPI          STDAPI
#define SHSTDAPI_(type)   STDAPI_(type)
#endif
#endif // SHSTDAPI

#ifndef SHDOCAPI
#if !defined(_SHDOCVW_)
#define SHDOCAPI          EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
#define SHDOCAPI_(type)   EXTERN_C DECLSPEC_IMPORT type STDAPICALLTYPE
#else
#define SHDOCAPI          STDAPI
#define SHDOCAPI_(type)   STDAPI_(type)
#endif
#endif // SHDOCAPI


#if !defined(_WIN64)
#include <pshpack1.h>
#endif

#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif  /* __cplusplus */


#pragma region Desktop Family
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)



DECLARE_HANDLE(HDROP);

_Success_(return != 0)
SHSTDAPI_(UINT) DragQueryFileA(_In_ HDROP hDrop, _In_ UINT iFile, _Out_writes_opt_(cch) LPSTR lpszFile, _In_ UINT cch);
_Success_(return != 0)
SHSTDAPI_(UINT) DragQueryFileW(_In_ HDROP hDrop, _In_ UINT iFile, _Out_writes_opt_(cch) LPWSTR lpszFile, _In_ UINT cch);
#ifdef UNICODE
#define DragQueryFile  DragQueryFileW
#else
#define DragQueryFile  DragQueryFileA
#endif // !UNICODE
SHSTDAPI_(BOOL) DragQueryPoint(_In_ HDROP hDrop, _Out_ POINT *ppt);
SHSTDAPI_(void) DragFinish(_In_ HDROP hDrop);
SHSTDAPI_(void) DragAcceptFiles(_In_ HWND hWnd, _In_ BOOL fAccept);

SHSTDAPI_(HINSTANCE) ShellExecuteA(_In_opt_ HWND hwnd, _In_opt_ LPCSTR lpOperation, _In_ LPCSTR lpFile, _In_opt_ LPCSTR lpParameters,
    _In_opt_ LPCSTR lpDirectory, _In_ INT nShowCmd);
SHSTDAPI_(HINSTANCE) ShellExecuteW(_In_opt_ HWND hwnd, _In_opt_ LPCWSTR lpOperation, _In_ LPCWSTR lpFile, _In_opt_ LPCWSTR lpParameters,
    _In_opt_ LPCWSTR lpDirectory, _In_ INT nShowCmd);
#ifdef UNICODE
#define ShellExecute  ShellExecuteW
#else
#define ShellExecute  ShellExecuteA
#endif // !UNICODE
_Success_(return > 32) // SE_ERR_DLLNOTFOUND
SHSTDAPI_(HINSTANCE) FindExecutableA(_In_ LPCSTR lpFile, _In_opt_ LPCSTR lpDirectory, _Out_writes_(MAX_PATH) LPSTR lpResult);
_Success_(return > 32) // SE_ERR_DLLNOTFOUND
SHSTDAPI_(HINSTANCE) FindExecutableW(_In_ LPCWSTR lpFile, _In_opt_ LPCWSTR lpDirectory, _Out_writes_(MAX_PATH) LPWSTR lpResult);
#ifdef UNICODE
#define FindExecutable  FindExecutableW
#else
#define FindExecutable  FindExecutableA

这告诉我 Microsoft Visual Studio 2013 的错误是:

Warning 1   warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification    File:win32_test_core.obj    Project:test_ndef_url

Error   2   error LNK2019: unresolved external symbol __imp__ShellExecuteW@24 referenced in function _ReadMessageOnAnyTagCompletedURL   File:win32_test_ndef_url.obj    Project:test_ndef_url

Error   3   error LNK1120: 1 unresolved externals   File:test_ndef_url.exe  Project:test_ndef_url

拜托,我需要这方面的帮助。

最佳答案

您缺少 ShellExecute 的实际主体(或函数主体的占位符)函数(好的, ShellExecuteW ,但这是您现在不需要担心的细节。) header 中的内容是声明,但您仍然需要定义>。在本例中,它位于中。

执行这些操作:

  1. Google 搜索“MSDN ShellExecute”。 MSDN 是 Microsoft 开发人员网络,也是获取 Windows API 文档的地方。
  2. 第一个链接是 https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153%28v=vs.85%29.aspx (目前;微软网站在保持链接稳定以供将来引用方面表现不佳。)
  3. 这是该函数的文档。向下滚动到页面底部。有一个表格列出了此功能的“要求”。其中之一是“库”,在本例中为“Shell32.lib”。
  4. 您需要链接到该库。在 Visual C++(您正在使用的)和标准 Windows 库(这是)中,最简单的方法是将以下行添加到您的源文件之一(可能在最顶部): #pragma comment (lib, "Shell32") 。 (注意缺少分号。)

就是这样。对于较大的项目,有更好的(更具可扩展性、灵活和可移植性)方法,但对于这个小样本来说,您应该没问题。

关于c++ - 打开 NFC - 错误 LNK2019 : unresolved external symbol __imp__ShellExecuteW@24,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32040790/

相关文章:

c++ - 我可以使用定义来调用运算符 <<

c# - 配置文件 'C:\my\App.Config' 用于配置所有可执行文件

visual-studio - Visual Studio 2005 中的代码分析

javascript - 从动态表格中读取值

c++ - Isspace 字符函数

c++ - C++ 中的引用调用是如何工作的?

c++ - XMMATRIX 对 2D 转换是否有效,或者我应该制作自定义 3x3 矩阵套件?

c# - 将自定义系统光标重置为正常

c++ - 声明 const 全局变量时是否需要静态?

c++ - 将非常大且旧的 C++Builder 代码移植/重新编码到 Qt 或 CLI/Mono