I have an application that seems on the surface to be straightforward, and is similar to scores of similar situations that have given me little or no trouble. After adapting a sample that I found on The Code Project, I set about to move the top level routine into a new console application, leaving the rest of the code to go into a conventional Win32 DLL. This is something that I've done dozens of times, and I know my way around __declspec(dllexport) and __declspec(dllimport) fairly well. I defined the usual pair of macros and preprocessor variables to tell the compiler to emit __declspec(dllimport) for the caller and __declspec(dllexport) for the callee. Every bit of this is "garden variety" Windows programming, yet the console program won't link.
Searching for answers, I used the /EP switch on the Microsoft Visual C++ compiler to obtain copies of the preprocessor output of both affected programs.
The main routine, ProcessTestCase_ELS, is defined in a separate source file, ProcessTestCase_ELS.cpp. As you can imagine, the listing is rather lengthy, even with WINDOWS_LEAN_AND_MEAN defined, but the relevant bit is only the following handful of lines.
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the EVENTLOGGINGFORALL_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// EVENTLOGGINGFORALL_API functions as being imported from a DLL, wheras this DLL sees symbols
// defined with this macro as being exported.
// ============================================================================
// Install an app as a source of events under the name pszName into the Windows
// Registry.
// ============================================================================
extern "C" __declspec(dllimport) DWORD AddEventSource
(
PCTSTR pszName , // Pointer to string containing event source ID
PCTSTR pszMessages , // Optional (default = NULL) pointer to string containing name of associated message file
PCTSTR pszLogName , // Optional (default = NULL) pointer to string containing name of event log
PCTSTR pszCategories , // Optional (default = NULL) pointer to string containing name of category message file
DWORD dwCategoryCount // Optional (default = 0) category count
) ;
The preprocessor output of the routine exported by the DLL is equally long, but the definition of the routine at issue is blessedly short. The entire routine follows.
// ============================================================================
// Install an app as a source of events under the name pszName into the Windows
// Registry.
// ============================================================================
extern "C" __declspec(dllexport) DWORD AddEventSource
(
PCTSTR pszName , // Pointer to string containing event source ID
PCTSTR pszMessages , // Optional (default = NULL) pointer to string containing name of associated message file
PCTSTR pszLogName , // Optional (default = NULL) pointer to string containing name of event log
PCTSTR pszCategories , // Optional (default = NULL) pointer to string containing name of category message file
DWORD dwCategoryCount // Optional (default = 0) category count
)
{
TCHAR szPath [ 260 ] ;
TCHAR * lpszPath = ( TCHAR * ) &szPath ;
HKEY hRegKey = 0 ;
DWORD dwError = 0L ;
sprintf ( szPath , // Output buffer
"%s\\%s\\%s" , // Format string
"SYSTEM\\CurrentControlSet\\Services\\EventLog" , // Substitute for token 1
pszLogName
? pszLogName
: "Application" , // Substitute for token 2
pszName ) ; // Substitute for token 3
// ------------------------------------------------------------------------
// Create the event source registry key.
// ------------------------------------------------------------------------
dwError = RegCreateKeyA ( (( HKEY ) (ULONG_PTR)((LONG)0x80000002) ) , // Hive Name
szPath , // Key Name
&hRegKey ) ; // Pointer to place to store handle to key
// ------------------------------------------------------------------------
// If pszMessages is NULL, assume that this module contains the messages,
// and get its absolute (fully qualfied) name.
// ------------------------------------------------------------------------
if ( !(pszMessages) )
{
if ( !(( HMODULE ) GetModuleFileNameA ( m_hinstDLL , szPath , 260 )) ) // Sze of buffer, in TCHARs.
{
return util::ReportErrorOnConsole ( ) ;
} // Unless ( ( HMODULE ) GetModuleFileName ( m_hinstDLL , szPath , MAX_PATH ) )
} // Unless ( pszMessages )
// ------------------------------------------------------------------------
// Register EventMessageFile.
// ------------------------------------------------------------------------
dwError = RegSetValueExA ( hRegKey , // Handle to key
"EventMessageFile" , // Value Name
0x00000000L , // Reserved - pass NULL
( 2 ) , // Value type
( PBYTE ) szPath , // Value data
( ( ( strlen ( ( LPCTSTR ) szPath ) + 1 ) * sizeof ( TCHAR ) ) ) ) ; // Size of value data - Macro TCharBufSizeP6C encapsulates all of this: ( _tcslen ( szPath ) + 1 ) * sizeof TCHAR )
// ------------------------------------------------------------------------
// Register supported event types.
// ------------------------------------------------------------------------
DWORD dwTypes = 0x0001
| 0x0002
| 0x0004 ;
dwError = RegSetValueExA ( hRegKey , // Handle to key
"TypesSupported" , // Value Name
0x00000000L , // Reserved - pass NULL
( 4 ) , // Value type
( LPBYTE ) &dwTypes , // Value data
sizeof dwTypes ) ; // Size of value data
if ( dwError )
{
return util::ReportErrorOnConsole ( dwError ) ;
} // if ( dwError )
// ------------------------------------------------------------------------
// If we want to support event categories, we have also to register the
// CategoryMessageFile, and set CategoryCount. Note that categories need to
// have the message ids 1 to CategoryCount!
// ------------------------------------------------------------------------
if ( dwCategoryCount > 0x00000000 )
{
if ( !(pszCategories && pszMessages) )
{
if ( !(( HMODULE ) GetModuleFileNameA ( m_hinstDLL , szPath , 260 )) )
{
return util::ReportErrorOnConsole ( ) ;
} // Unless ( ( HMODULE ) GetModuleFileName ( m_hinstDLL , szPath , MAX_PATH ) )
} // Unless ( pszCategories && pszMessages )
dwError = RegSetValueExA ( hRegKey , // Handle to key
"CategoryMessageFile" , // Value name
0x00000000L , // Reserved - pass NULL
( 2 ) , // Value type
MsgFileNameString ( pszMessages ,
pszCategories ,
lpszPath ) , // Value data
MsgFileNameLen ( pszMessages ,
pszCategories ,
lpszPath ) ) ; // Size of value data
if ( dwError )
{
return util::ReportErrorOnConsole ( dwError ) ;
} // if ( dwError )
dwError = RegSetValueExA ( hRegKey , // handle to key
"CategoryCount" , // value name
0x00000000L , // reserved
( 4 ) , // value type
( PBYTE ) &dwCategoryCount , // value data
sizeof dwCategoryCount ) ; // size of value data
if ( dwError )
{
return util::ReportErrorOnConsole ( dwError ) ;
} // if ( dwError )
} // if ( dwCategoryCount > 0 )
dwError = RegCloseKey ( hRegKey ) ;
if ( dwError )
{
return util::ReportErrorOnConsole ( dwError ) ;
} // if ( dwError )
else
{
return util::AnnounceChangeToAll ( ) ;
} // FALSE (UNexpected outcome) block, if ( lr )
} // DWORD •
The DLL project has a module definition file. Excluding the internal documentation, it is as follows.
LIBRARY EventLoggingForAll
VERSION 1, 0, 0, 1
EXPORTS
AddEventSource #2
RemoveEventSource #3
With respect to the DLL, dumpbin.exe gives the following reports on the DLL file and its import library.
Microsoft (R) COFF Binary File Dumper Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
Dump of file C:\Documents and Settings\DAG\My Documents\Programming\Visual Studio 6\DLL\EventLogging\Debug\EventLoggingForAll.lib
File Type: LIBRARY
Exports
ordinal name
2 _AddEventSource#20
3 _RemoveEventSource#8
Summary
A8 .debug$S
14 .idata$2
14 .idata$3
4 .idata$4
4 .idata$5
18 .idata$6
Microsoft (R) COFF Binary File Dumper Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
Dump of file C:\Documents and Settings\DAG\My Documents\Programming\Visual Studio 6\DLL\EventLogging\Debug\EventLoggingForAll.dll
File Type: DLL
Section contains the following exports for EventLoggingForAll.dll
0 characteristics
54BB1CE9 time date stamp Sat Jan 17 20:39:37 2015
0.00 version
2 ordinal base
2 number of functions
2 number of names
ordinal hint RVA name
2 0 00001014 AddEventSource
3 1 00001019 RemoveEventSource
Summary
1000 .data
1000 .idata
1000 .rdata
1000 .reloc
1000 .rsrc
12000 .text
Everything appears to be in order, yet the link step reports LNK2001: unresolved external symbol __imp__AddEventSource when I try to build the console program.
One final note; the error doesn't appear to be the result of the linker not seeing the import library, because it is the first library searched, and I can see it listed as such in the build log. I am also certain that there isn't an old version of the import library that could interfere, because I deleted every instance of it from the machine, verified that they were all gone, and started fresh.
LNK2001: unresolved external symbol __imp__AddEventSource
The linker error message says what you are doing wrong. It is looking for _AddEventSource but that's not the name of your exported function. It is _AddEventSource#20. Note the added "#20" name decoration. You obfuscated the problem by using a DEF file, but it is still visible from the dump of the .lib file.
This linker error is very much by design, it protects the client of your DLL from a exceedingly nasty problem. Your question contains no hints, but if the info is accurate, you changed a global compile option. Project + Properties, C/C++, Advanced, "Calling Convention" setting. The default is /Gd, you changed it to /Gz. But did not make the same change in the client project. This is so nasty because any call that the client code makes to an exported function will unbalance the stack. The runtime errors that this can cause are very hard to diagnose. The #20 postfix was designed to not let it come this far.
Change the setting back and make the calling convention explicit by adding the __stdcall attribute to the function declaration.
Other mistakes you are making:
Very important, not just for this problem, is to have only one .h file that declares the exported functions. Suitable to be #included into the client program's source code. That way there will never be a mismatch between the DLL and the client. This includes the need to put __stdcall in the declaration, now the DLL and client will always agree and a mismatch in the /G option can't hurt anybody.
The way you are using the TCHAR types (like PCTSTR in your declaration) is very, very nasty as well. You now critically depend on another global compile option. Project + Properties, General, "Character Set". You changed this one as well from the default so it is very, very easy to overlook that in the client project. This mistake is way nastier than the /Gz option since you do not get a linker error for that one when you use extern "C". The misbehavior you get a runtime is a bit easier to diagnose, you'll only lose an hour or two of your life when you discover that the strings only contain a single character. Stop using TCHAR completely, it stopped being relevant 10 years ago. Your code as written can only work with char*.
The VERSION statement in the DEF file is wrong, it can have only 2 digits that must be separated by a .. That produces a link error on later VS versions. You should omit it completely, it has been outdated for over 20 years, the version number should be set in a VERSION resource. Don't skip adding the resource to your .rc file, very easy to do in VS, versioning is import for DLLs.
Make sure you are building your project as 64-bit or 32-bit and that the library is found in the correct bin folder under x64 or x86.
From personal experience, I was trying to add an a new exported function to a dll I was maintaining and could not get the compiler to link against the new exported function. It turned out I had inadvertently changed the build target to x86 while trying to update the 64-bit version of the dll.
Related
I am using pHash and that library uses libpng. I am having issues running my program because libpng fails loading a PNG file.
Version of libpng: 1.4.19
Platform: Windows 10
Environment: Visual Studio 2015
Trivial
Just if you came up with the following questions...
Is the path to image correct? Yes
Is the image a valid PNG file? Yes
Code details
Library pHash uses CImg, the version of CImg they are using is a bit old I think:
#define cimg_version 148 // In CImg.h
I have debugged the library and the problems occurs in CImg.h (contained in the pHash VC++ project):
CImg<T>& _load_png(std::FILE *const file, const char *const filename) {
if (!file && !filename)
throw CImgArgumentException(_cimg_instance
"load_png() : Specified filename is (null).",
cimg_instance);
// Open file and check for PNG validity
if (Buffer) strcat(Buffer, "Checking PNG availability\r\n");
const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb");
unsigned char pngCheck[8] = { 0 };
cimg::fread(pngCheck,8,(std::FILE*)nfile);
if (png_sig_cmp(pngCheck,0,8)) {
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_png() : Invalid PNG file '%s'.",
cimg_instance,
nfilename?nfilename:"(FILE*)");
}
// Setup PNG structures for read
png_voidp user_error_ptr = 0;
png_error_ptr user_error_fn = 0, user_warning_fn = 0;
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn);
if (!png_ptr) { // <-- PROBLEM HERE
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_png() : Failed to initialize 'png_ptr' structure for file '%s'.",
cimg_instance,
nfilename?nfilename:"(FILE*)");
...
}
The snippet shows the first part of CImg<T>& _load_png(std::FILE *const file, const char *const filename) which is called by the CImg library used by pHash.
Runtime issue
The code compiles fine but I get this error at runtime which I can see in the debugger:
CImgIOException: Failed to initialize 'png_ptr'...
In the point indicated in the code. I don't know why, it fails loading the image. The failure occurs when calling png_create_read_struct in CImg.h. That code is a bit obscure as defined through preprocessor directives. It is not clear why it is failing.
Any ideas?
Either if you are including libpng yourself or if another library is including and using libpng there are a few things to be aware of.
Which ever version of Visual Studio you are using, the libpng (dll or lib) files must be built from the same version of Visual Studio that your solution is linking against.
The platform you are using 32bit or 64bit is of concern.
Project settings when building the png library must match the build types of your current project. (Code Generation -> Runtime Library) must match. Your character set should match as well.
It is a little to difficult to tell what exactly is causing the problem but these are a few things to have a look at.
One thing I would suggest is to go to the website that provides the newest version of libpng and download it. Set a folder on your computer and create "system environment variable through windows" to point to your library. Open the solution to this library in the current version of VS you are using, build it out for both a static lib and dynamic lib (two different solutions) and build them both out for 32 bit and 64 bit saving the generated files into separated folders. Then go into the other library that depends on this and try to switch the dlls or libs and link against the new ones if possible. Also the other 3rd party library you should try to open its solution in the same version of VS and try to do a clean build from there. Then make sure you link everything properly. You may have to also modify the props file.
EDIT
I am not familiar with pHash or CImg, but I am familiar with libpng.
Here is a function in one of my projects to load in a png into a texture structure. Now this is a part of a class object that relies on many other classes, but you should be able to see from this snippet that I am successfully using libpng.
// ----------------------------------------------------------------------------
// loadPng()
bool TextureFileReader::loadPng( Texture* pTexture ) {
struct PngFile {
FILE* fp;
png_struct* pStruct;
png_info* pInfo;
// --------------------------------------------------------------------
PngFile() :
fp( NULL ),
pStruct( NULL ),
pInfo( NULL )
{} // PngFile
// --------------------------------------------------------------------
~PngFile() {
if ( NULL != fp ) {
fclose( fp );
}
if ( NULL != pStruct ) {
if ( NULL != pInfo ) {
png_destroy_read_struct( &pStruct, &pInfo, NULL );
} else {
png_destroy_read_struct( &pStruct, NULL, NULL );
}
}
} // ~PngFile
} png;
// Error Message Handling
std::ostringstream strStream;
strStream << __FUNCTION__ << " ";
if ( fopen_s( &png.fp, m_strFilenameWithPath.c_str(), "rb" ) != 0 ) {
strStream << "can not open file for reading";
throwError( strStream );
}
// Test If File Is Actually A PNG Image
const int NUM_HEADER_BYTES = 8;
png_byte headerBytes[NUM_HEADER_BYTES];
// Read The File Header
if ( fread( headerBytes, 1, NUM_HEADER_BYTES, png.fp ) != NUM_HEADER_BYTES ) {
strStream << "error reading header";
return false;
}
// Test Header
if ( png_sig_cmp( headerBytes, 0, NUM_HEADER_BYTES ) != 0 ) {
return false; // Not A PNG FILE
}
// Init PNG Read Structure - Test PNG Version Compatibility
png.pStruct = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
if ( NULL == png.pStruct ) {
strStream << "can not create struct for PNG file";
throwError( strStream );
}
// Init PNG Info Structure - Allocate Memory For Image Info
png.pInfo = png_create_info_struct( png.pStruct );
if ( NULL == png.pInfo ) {
strStream << "can not create info for PNG file";
throwError( strStream );
}
// Prepare For Error Handling
if ( setjmp( png_jmpbuf( png.pStruct ) ) ) {
strStream << "can not init error handling for PNG file";
throwError( strStream );
}
// Tell libPng Where The File Data Is
png_init_io( png.pStruct, png.fp );
// Tell libPng That You Have Already Read The Header Bytes
png_set_sig_bytes( png.pStruct, NUM_HEADER_BYTES );
// Read Image Data From The File
png_read_png( png.pStruct, png.pInfo, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_GRAY_TO_RGB, NULL );
// Show Image Attributes
png_byte colorType = png_get_color_type( png.pStruct, png.pInfo );
switch( colorType ) {
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGBA: {
break;
}
default: {
strStream << "PNG is saved in an unsupported color type (" << colorType << ")";
throwError( strStream );
}
}
unsigned uHeight = png_get_image_height( png.pStruct, png.pInfo );
unsigned uBytesPerRow = png_get_rowbytes( png.pStruct, png.pInfo );
if ( 0 == uHeight || 0 == uBytesPerRow ) {
strStream << "invalid image size. Height(" << uHeight << "), Bytes per row(" << uBytesPerRow << ")";
throwError( strStream );
}
// Make Room For All Pixel Data
unsigned uTotalNumBytes = uHeight * uBytesPerRow;
pTexture->vPixelData.resize( uTotalNumBytes );
// Get All Pixel Data From PNG Image
png_bytepp ppPixelRow = png_get_rows( png.pStruct, png.pInfo );
for ( unsigned int r = 0; r < uHeight; ++r ) {
memcpy( &pTexture->vPixelData[ uBytesPerRow * ( uHeight - 1 - r ) ], ppPixelRow[r], uBytesPerRow );
}
// Store Other Values In Texture
pTexture->uWidth = png_get_image_width( png.pStruct, png.pInfo );
pTexture->uHeight = uHeight;
pTexture->hasAlphaChannel = ( colorType == PNG_COLOR_TYPE_RGBA );
return true;
} // loadPng
Looking through the source code for png_create_read_struct_2(), there are only 2 failure modes: inability to allocate memory, which is unlikely to be the problem, and a library version conflict.
If you are using a precompiled build of the pHash library, you must ensure that the copy of the libpng DLL that gets linked dynamically at runtime is the same version of the library that pHash was compiled against. The latest Windows build on pHash.org ships with libpng12.dll in the "Release" subdirectory, which is probably incompatible the version that you mentioned in the question, namely 1.4.19.
If you are building pHash from source, make sure that the libpng include files that are being used in your build process match the version being loaded at runtime.
If you're unsure exactly which DLLs are being loaded at runtime, the surest way I know to determine it would be to use Process Monitor.
I'm trying to create a C++ DLL for use in a VBA program. I'm following this example and had success compiling the example code and using the resulting DLL. However, I needed to add some additional functionality to the DLL so I created a few more functions in the example code and recompiled it. I then made a test program to test my new functions. When I try to call some of the DLL functions from my test project I get linker errors similar to this:
error LNK2019: unresolved external symbol "int __stdcall PWCreateDocument(long,char *,char *)" (?PWCreateDocument##YGHJPAD0#Z) referenced in function _wmain
This error occurs when I call the functions to initialize ProjectWise, CVbaHelperApp::InitInstance(), and my custom function PWCreateDocument.
This error DOES NOT OCCUR when I call PWGetLastErrorMessage(). I am able to access this function from my test program, but not any other functions in the DLL.
I've ruled out any common linker errors such as, misspellings/incorrect types between function header and definition.
I find it strange that I can successfully call PWGetLastErrorMesssage but not any other functions.
Here is the code for my test program vbaHelperTest3.cpp:
#include "stdafx.h"
typedef long LONG;
typedef int BOOL;
int _tmain(int argc, _TCHAR* argv[])
{
char* filePath = "C:\\pwworking\\cemvn\\b2edsjga\\d0572507\\";
char* fileName = "BUMP Imagery 2009.xwms";
LONG projID = 572507;
char* errorMsg;
std::cout << "Hello World" << std::endl;
CVbaHelperApp myApp;
BOOL isInit = myApp.InitInstance();
std::cout << "Is Initialized? " << isInit << std::endl;
errorMsg = PWGetLastErrorMessage();
std::cout << "Error Message: " << errorMsg << std::endl;
BOOL results = PWCreateDocument(projID, filePath, fileName);
std::cout << "PWCreateDocument Result: " << results << std::endl;
return 0;
}
The header stdafx.h includes the header for my DLL, vbaHelper.h. This is the code for vbaHelper.h:
// vbaHelper.h : main header file for the VBAHELPER DLL
//
#include "stdafx.h"
#if !defined(AFX_VBAHELPER_H__3FBDA9E4_EE8B_4AA1_8FD0_21A0A8B6C590__INCLUDED_)
#define AFX_VBAHELPER_H__3FBDA9E4_EE8B_4AA1_8FD0_21A0A8B6C590__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////
// CVbaHelperApp
// See vbaHelper.cpp for the implementation of this class
//
class CVbaHelperApp : public CWinApp
{
public:
CVbaHelperApp();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CVbaHelperApp)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
//}}AFX_VIRTUAL
//{{AFX_MSG(CVbaHelperApp)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
//Function definitions added by me
typedef int BOOL;
typedef long LONG;
LONG __stdcall PWGetDocumentName( LONG , LONG , VOID **);
LONG __stdcall PWGetDocumentIDs( TCHAR **, LONG *, LONG *);
BOOL __stdcall PWCreateDocument( LONG, char*, char*);
char * __stdcall PWGetLastErrorMessage(void);
#endif // !defined(AFX_VBAHELPER_H__3FBDA9E4_EE8B_4AA1_8FD0_21A0A8B6C590__INCLUDED_)
Finaly, here is the code for vbaHelper.cpp, the DLL:
/****************************************************************************
*
* ProjectWise(TM) Software Development Kit
* Sample Application
* Copyright (C) 2003 Bentley Systems, Incorporated
* All Rights Reserved
*
****************************************************************************/
/****************************************************************************
*
* Project Name: VbaHelper
*
* Project Description: This example is used in conjunction with MicroStation's
* VBA to extract a Design file's attributes.
*
* File name: VbaHelper.cpp
*
* File description: Custom Module implementation
*
****************************************************************************/
/*---------------------------------------------------------------------------
Copyright (C) 2003 Bentley Systems, Incorporated
All Rights Reserved
THIS IS AN OPEN SOURCE CODE OF BENTLEY SYSTEMS, INCORPORATED
You have a royalty-free right to use, modify, reproduce and distribute
the Sample Applications (and/or any modified version) in any way you find
useful, provided that you agree that Bentley Systems, Incorporated has no
warranty obligations or liability for any Sample Application files which
are modified.
No guarantees of performance accompany Sample Application, nor is any
responsibility assumed on the part of the author(s). The software has
been tested extensively and every effort has been made to insure its
reliability.
---------------------------------------------------------------------------*/
/****************************************************************************
*
* Include Files
*
****************************************************************************/
#include "stdafx.h"
#include "vbaHelper.h"
#include "aaatypes.h"
#include "aadmsdef.h"
#include "aawddef.h"
#include "aawindef.h"
#include "aaodsdef.h"
#include "stdtypes.h"
#include "aadmsapi.fdf"
#include "aawinapi.fdf"
#include "aawindms.fdf"
#include "aaodsapi.fdf"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define DLLEXPORT __declspec( dllexport )
#define WINAPI __stdcall
//
// Note!
//
// If this DLL is dynamically linked against the MFC
// DLLs, any functions exported from this DLL which
// call into MFC must have the AFX_MANAGE_STATE macro
// added at the very beginning of the function.
//
// For example:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // normal function body here
// }
//
// It is very important that this macro appear in each
// function, prior to any calls into MFC. This means that
// it must appear as the first statement within the
// function, even before any object variable declarations
// as their constructors may generate calls into the MFC
// DLL.
//
// Please see MFC Technical Notes 33 and 58 for additional
// details.
//
/////////////////////////////////////////////////////////////////////////////
// CVbaHelperApp
BEGIN_MESSAGE_MAP(CVbaHelperApp, CWinApp)
//{{AFX_MSG_MAP(CVbaHelperApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CVbaHelperApp construction
CVbaHelperApp::CVbaHelperApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CVbaHelperApp object
CVbaHelperApp theApp;
/*----------------------------------------------------------------------+
|
| name mcmMain_GetDocumentIdByFilePath
|
| author BSI 04/2003
|
| Description This function finds document and project
| numbers of the document specified by its path.
|
+----------------------------------------------------------------------*/
extern "C" int mcmMain_GetDocumentIdByFilePath
(
LPWSTR pchFilePath, /* i full file path to search */
long *plProNo, /* o project id */
long *plDocNo /* o document id */
);
/*----------------------------------------------------------------------+
|
| name HooksInitialize
|
| author BSI 04/2003
|
| Description Dll entry function for ProjectWise.
|
+----------------------------------------------------------------------*/
extern "C" LONG HooksInitialize
(
ULONG ulMask, // i Application Mask
LPVOID lpReserved // i Reserved (must be NULL)
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return IDOK;
}
/*----------------------------------------------------------------------+
|
| name PWGetDocumentName
|
| author BSI 04/2003
|
| Description A function that will populate documentName for the given
| DOCUMENT_ID.
|
| Return SUCCESS - The path and file name of the specified document
| were built successfully.
|
| -1 - Failed to build the path and file name of the
| specified document.
|
+----------------------------------------------------------------------*/
LONG WINAPI PWGetDocumentName
(
LONG PROJECT_ID, /* i Project ID*/
LONG DOCUMENT_ID, /* i Document ID */
VOID **documentName /* o Document Name*/
)
{
BOOL status = FALSE;
TCHAR tempDocName[MAX_STRING];
// Extract the document's name
status = aaApi_GetDocumentFileName (PROJECT_ID, DOCUMENT_ID, tempDocName, MAX_STRING);
_tcscpy ((TCHAR*)(*documentName), tempDocName);
return (status == TRUE ? SUCCESS : -1);
}
/*----------------------------------------------------------------------+
|
| name PWGetDocumentIDs
|
| author BSI 04/2003
|
| Description A function that will return the document's
| Project and Document IDs.
|
| Return SUCCESS or error number
|
+----------------------------------------------------------------------*/
LONG WINAPI PWGetDocumentIDs
(
TCHAR **fileName, /* i Desgin File Name */
LONG *ProjectID, /* o Project ID */
LONG *DocumentID /* o Document ID */
)
{
return mcmMain_GetDocumentIdByFilePath (*fileName, ProjectID, DocumentID);
}
/*----------------------------------------------------------------------+
|
| name convertCharArrayToLPCWSTR
|
| author MY CUSTOM FUNCTION 10/2015
|
| Description Converts regular string to LPCWSTR, which
| is required by projectwise.
|
| Return The converted string.
|
+----------------------------------------------------------------------*/
wchar_t *convertCharArrayToLPCWSTR(const char* charArray)
{
wchar_t * wString=new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
return wString;
}
/*----------------------------------------------------------------------+
|
| name PWCreateDocument
|
| author MY CUSTOM FUNCTION 10/2015
|
| Description A function that will create a new document in the
| specified PW project.
|
| Return SUCCESS or error number
|
+----------------------------------------------------------------------*/
BOOL WINAPI PWCreateDocument
(
LONG PROJECT_ID, /* i Project ID*/
char* PATH_NAME, /* path of document */
char* FILE_NAME /* name of document */
)
{
LONG docID = 0L;
//LONG lngAppID = aaApi_GetFExtensionApplication(L"xwms");
LONG lngAppID = aaApi_GetFExtensionApplication(L"pdf");
LONG lngWorkSpaceID = aaApi_GetWorkspaceProfileId(PROJECT_ID, 0);
LPCWSTR _path_name = convertCharArrayToLPCWSTR(PATH_NAME);
LPCWSTR _file_name = convertCharArrayToLPCWSTR(FILE_NAME);
WCHAR strWorkingDir[_MAX_PATH]; // for checked out file locationmemset (strWorkingDir, '\0', _MAX_PATH);
BOOL status = aaApi_CreateDocument(
&docID, //new document's ID
PROJECT_ID, //Passed in project ID
0, //default
0, //default
0, //default
lngAppID, //Applicaiton ID
0, //no department
lngWorkSpaceID, //workspace profile
_path_name, //source file
_file_name, //Name of file in PW, must be the same as Document Name
_file_name, //Document Name
NULL, //Document description
NULL, //Document Version
FALSE, //Specifies that this document is checked out to the user after it is create in PW.
AADMSDOCCREF_DEFAULT, //Checks documentaiton for flags
//_path_name, //location of the file if checked out
strWorkingDir,
_MAX_PATH - 1, //make sure the buffer is large enough
0 //New attribute ID in environment if created
);
//???
//long errorID=aaApi_GetLastErrorID();
//LPCWSTR errorStr = aaApi_GetLastErrorDetail();
return status;
}
/*----------------------------------------------------------------------+
|
| name PWGetLastErrorMessage
|
| author BSI 04/2003
|
| Description A function that will return the last ProjectWise Error
| message.
|
| Return Last Error message.
|
+----------------------------------------------------------------------*/
char * WINAPI PWGetLastErrorMessage
(
void
)
{
char *errorMsg;
TCHAR TerrorMsg [MAX_STRING];
errorMsg = (char *)malloc (sizeof (char) *MAX_STRING);
_tcscpy (TerrorMsg, aaApi_GetLastErrorMessage());
aaApi_UnicodeToAnsiStr (TerrorMsg, errorMsg,MAX_STRING);
return errorMsg;
}
/*----------------------------------------------------------------------+
|
| name PWGetDocumentAttributes
|
| author BSI 04/2003
|
| Description A function that will return the documents attributes.
|
| Return SUCCESS or -1 if error.
|
+----------------------------------------------------------------------*/
LONG WINAPI PWGetDocumentAttributes
(
LONG ProjectID, /* i Project ID */
LONG DocumentID, /* i Document ID */
void **AttributeData /* o Document attributes */
)
{
CString message;
LONG status = SUCCESS;
LONG lEnvId = aaApi_GetEnvId (0);
LONG lTabNo = aaApi_GetEnvNumericProperty (ENV_PROP_TABLEID, 0);
LONG count = -1;
int rowCount = -1;
/* Select environment for given project */
status = aaApi_SelectEnvByProjectId (ProjectID);
if (status == -1 || status == 0)
{
return -1;
}
else
{
// Select the documents Attribute Data
rowCount = aaApi_SelectLinkDataByObject (
lTabNo, /* i Table identifier (required) */
AADMSLDT_DOCUMENT, /* i Reference Item type */
ProjectID, /* i First item identifier */
DocumentID, /* i Second item identifier */
NULL, /* i Where statement (optional) */
&count, /* io Column count in lplColumnIds */
NULL, /* i Columns to fetch (NULL - all) */
0 /* i Flags (AADMSLDSF_XXX) */
);
if (rowCount <= 0)
return -1;
for (int colIndex= 0; colIndex<count; colIndex++)
{
message += aaApi_GetLinkDataColumnStringProperty (LINKDATA_PROP_COLUMN_NAME, colIndex);
message += ": ";
message += aaApi_GetLinkDataColumnValue (0, colIndex);
message +="\n";
}// end for
_tcscpy ((TCHAR*)(*AttributeData), message);
}
return SUCCESS;
}
/*----------------------------------------------------------------------+
|
| name InitInstance
|
| author BSI 04/2003
|
| Description Initialize the PW API
|
| Return Nonzero if initialization is successful; otherwise 0.
|
+----------------------------------------------------------------------*/
BOOL CVbaHelperApp::InitInstance()
{
// Initialize PW
aaApi_Initialize (AAMODULE_ALL);
return CWinApp::InitInstance();
}
/*----------------------------------------------------------------------+
|
| name ExitInstance
|
| author BSI 04/2003
|
| Description Remove the hook function on exit.
|
| Return 0 for success or > 0 for error.
|
+----------------------------------------------------------------------*/
int CVbaHelperApp::ExitInstance()
{
return CWinApp::ExitInstance();
}
Edit Update
I realized that my header file does not need function definitioins. The project uses a vbaHelper.def file to define the functions. I removed the definitions from the header and now have different errors:
error C3861: 'PWGetLastErrorMessage': identifier not found
error C3861: 'PWCreateDocument': identifier not found
Edit Number 2
I do not believe this should qualify as a duplicate of other Unresolved external symbol questions as I have vetted all the common reasons for this error. Also, I have now resolved the linker error and I'm looking for reason why I would be receiving "identifier not found" errors.
You need to append your function definitions with extern "C" if you want to be able to call them from c. You already have such an example in the code that you've posted.
extern "C" LONG HooksInitialize
BOOL WINAPI PWCreateDocument
is should be
BOOL DLLEXPORT PWCreateDocument
I am struggling with Windows and FreeType2. I am following the tutorial and the following is shown as example code:
FT_Library library; /* handle to library */
FT_Face face; /* handle to face object */
error = FT_Init_FreeType( &library );
if ( error ) { ... }
error = FT_New_Face(library, "/usr/share/fonts/truetype/arial.ttf", 0, &face ); // <-- this does not exist...
if ( error == FT_Err_Unknown_File_Format )
{
... the font file could be opened and read, but it appears
... that its font format is unsupported
}
else if ( error )
{
... another error code means that the font file could not
... be opened or read, or simply that it is broken...
}
This /usr/share/fonts/truetype/arial.ttf just simply does not exist, how can I get the Arial font to work with this.
It varies from system to system. Check FOLDERID_Fonts.
I am trying to use the pcre library (from AIX) on IBM iseries.
It should be possible using PASE.
I installed the pcre library with the rpm provided by yips.
I tried to use it in c ile source, but i couldn't achieve it.
Exemples : yips, ibm, ibm redbook
I can't find the way to do it.
Here is what i have done so far.
#include <stdio.h>
#include <qp2shell2.h>
#include <qp2user.h>
#define JOB_CCSID 0
int main(int argc, char *argv[])
{
int rc;
QP2_ptr64_t id;
void *getpid_pase;
const QP2_arg_type_t signature[] = { QP2_ARG_END };
QP2_word_t result;
/*
* Call QP2SHELL2 to run the OS/400 PASE program
* /usr/lib/start32, which starts OS/400 PASE in
* 32-bit mode (and leaves it active on return)
*/
QP2SHELL2("/usr/lib/start32");
/*
* Qp2dlopen opens the global name space (rather than
* loading a new shared executable) when the first
* argument is a null pointer. Qp2dlsym locates the
* function descriptor for the OS/400 PASE getpid
* subroutine (exported by shared library libc.a)
*/
id = Qp2dlopen("/usr/lib/libpcre.a", QP2_RTLD_NOW, JOB_CCSID);
getpid_pase = Qp2dlsym(id, "pcrecpp::RE", JOB_CCSID, NULL);
//id = Qp2dlopen(NULL, QP2_RTLD_NOW, JOB_CCSID);
//getpid_pase = Qp2dlsym(id, "getpid", JOB_CCSID, NULL);
/*
* Call Qp2CallPase to run the OS/400 PASE getpid
* function, and print the result. Use Qp2errnop
* to find and print the OS/400 PASE errno if the
* function result was -1
*/
rc = Qp2CallPase(getpid_pase,
NULL, // no argument list
signature,
QP2_RESULT_WORD,
&result);
printf("OS/400 PASE getpid() = %i\n", result);
if (result == -1)
printf("OS/400 errno = %i\n", *Qp2errnop());
/*
* Close the Qp2dlopen instance, and then call
* Qp2EndPase to end OS/400 PASE in this job
*/
Qp2dlclose(id);
Qp2EndPase();
return 0;
}
Today I tried the same and I could compile pcre to ILE using CRTCMOD.
In the zip-file of pcre you can find a file named NON_AUTOTOOLS_BUILD (if I remember the name correctly) with with all information needed to compile it.
In fact you only need to:
edit config.h to match your environment (available functions like memmove, features like pthreads, EBCDIC support and NewLine=37 (x'25') )
compile dftables.c using CRTBNDC DEFINE(HAVE_CONFIG_H) ...
CALL DFTABLES to generate the character tables for EBCDIC (this step was a bit tricky, because it couldn't open the IFS-File for output. so I put the output in a source member and used CPYTOSTMF to get it in the IFS)
compile the all the .c files unsing CRTCMOD DEFINE(HAVE_CONFIG_H) ...
create a *SRVPGM from the modules
write the Prototypes for RPG
It works like a charm, except for a little problem with CCSIDs. I generated the chartables for CCSID 1141, but for some reason PCRE expects input to be CCSID 37.
Also note that, if you write the prototypes in RPG, pcre_free is special. This function is not implemented in PCRE (you could write your own and plug it in if you want) and defaults to free. Your prototype should look like
Dpcre_free PR EXTPROC('free')
D * value
*white spaces not accurate
Hope that helps
I would like to load image to my application, but I have an error:
http://img510.imageshack.us/img510/5814/blad07864.png
This is a code of this application:
#include <stdio.h>
#include <stdlib.h>
#undef _UNICODE
#include "il.h"
#pragma comment( lib, "DevIL.lib" )
// Wow. DevIL is amazing.
// From http://gpwiki.org/index.php/DevIL:Tutorials:Basics
// The library consists of three sub-libraries:
// * IL - main DevIL library. It allows you to load and save images to files. Every function in this library have 'il' prefixed to their name.
// * ILU - this library contains functions for altering images. Every function in this library have 'ilu' prefixed to their name.
// * ILUT - this library connects DevIL with OpenGL. Every function in this library have 'ilut' prefixed to their name.
int main()
{
ilInit();
printf("DevIL has been initialized\n");
// Loading an image
ILboolean result = ilLoadImage( "tex1.png" ) ;
if( result == true )
{
printf("the image loaded successfully\n");
}
else
{
printf("The image failed to load\n" ) ;
ILenum err = ilGetError() ;
printf( "the error %d\n", err );
printf( "string is %s\n", ilGetString( err ) );
}
int size = ilGetInteger( IL_IMAGE_SIZE_OF_DATA ) ;
printf("Data size: %d\n", size );
ILubyte * bytes = ilGetData() ;
for( int i = 0 ; i < size; i++ )
{
// see we should see the byte data of the image now.
printf( "%d\n", bytes[ i ] );
}
}
I found code from this site: http://bobobobo.wordpress.com/2009/03/02/how-to-load-a-png-image-in-c/
Can you help me?
According to this post, 1290 means the image path wasn't found. Try using an absolute file path and see if it can load then.