I have an error and I don´t have idea what´s the problem.
I'm trying to compile one example of Open NFC for a project. The example is test_ndef_url. I do not know if the problem to a coding error or a library of windows is due, shellapi.h.
Test_ndef_url code is:
/*
* 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 );
}
The part of the code is defined shellapi.h where ShellExecute is:
#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
And that tells me the error Microsoft Visual Studio 2013 is:
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
Please, I need help with this.
You are missing the actual body (or a placeholder for a function body) of the
ShellExecute
function (OK,ShellExecuteW
, but that's a detail you don't need to worry about now.) What's in the header is the declaration, but you still need the definition. In this case, that's in a library.Do these:
#pragma comment (lib, "Shell32")
. (Note the lack of a semicolon.)and that's it. There are better (more scalable, flexible and portable) methods for larger projects, but you should be fine for this small sample.