I am attempting to use the WinAPI function GUIDFromString() but it requires some finagling to include it in my project.
According to the msdn documentation:
This function is not declared in a header or exported by name from a
.dll file. It must be loaded from Shell32.dll as ordinal 703 for
GUIDFromStringA and ordinal 704 for GUIDFromStringW.
It can also be accessed from Shlwapi.dll as ordinal 269 for
GUIDFromStringA and ordinal 270 for GUIDFromStringW.
I have never loaded a DLL before so I am not sure what I should do and I am unsure if loading the DLL is enough, do I also have to include an 'ordinal' with the number 703? Would anyone be able to provide any advice on what I need to do to use this function and even an example?
My attempt below does not work(I am using VC++ 2010 Express):
#pragma comment(lib, "shell32.lib") // if I am including the dll do I need to include the lib aswell?
// I've heard that the dll location differs across versions of windows
// Does anyone know of a Cross-Windows-Version way to include Shell32.dll no matter where it is? Maybe use a keyword like "%SYSTEM%/Shell32.dll"
HINSTANCE shell32DLL = LoadLibary("C:/System/Shell32.dll");
// Now do I include 'Ordinal 703' as described in msdn? And how do I do that?
If you read the documentation for GUIDFromString(), it says:
GUIDFromString is available through Windows XP with Service Pack 2 (SP2) or Windows Vista. It might be altered or unavailable in subsequent versions. Applications should use CLSIDFromString or IIDFromString in place of this function.
CLSIDFromString() and IIDFromString() are both exported by name from Ole32.dll, so you can use them like you would any other DLL function.
With that said, if you still want to use GUIDFromString() then use LoadLibrary() to load shell32.dll and then use GetProcAddress() to access the function. MSDN documentation demonstrates how to do that. To load a function by ordinal, you can use the MAKEINTRESOURCE() macro when calling GetProcAddress().
So, for example:
// MAKEINTRESOURCE() returns an LPTSTR, but GetProcAddress()
// expects LPSTR even in UNICODE, so using MAKEINTRESOURCEA()...
#ifdef UNICODE
#define MAKEINTRESOURCEA_T(a, u) MAKEINTRESOURCEA(u)
#else
#define MAKEINTRESOURCEA_T(a, u) MAKEINTRESOURCEA(a)
#endif
BOOL myGUIDFromString(LPCTSTR psz, LPGUID pguid)
{
BOOL bRet = FALSE;
typedef BOOL (WINAPI *LPFN_GUIDFromString)(LPCTSTR, LPGUID);
LPFN_GUIDFromString pGUIDFromString = NULL;
HINSTANCE hInst = LoadLibrary(TEXT("shell32.dll"));
if (hInst)
{
pGUIDFromString = (LPFN_GUIDFromString) GetProcAddress(hInst, MAKEINTRESOURCEA_T(703, 704));
if (pGUIDFromString)
bRet = pGUIDFromString(psz, pguid);
FreeLibrary(hInst);
}
if (!pGUIDFromString)
{
hInst = LoadLibrary(TEXT("Shlwapi.dll"));
if (hInst)
{
pGUIDFromString = (LPFN_GUIDFromString) GetProcAddress(hInst, MAKEINTRESOURCEA_T(269, 270));
if (pGUIDFromString)
bRet = pGUIDFromString(psz, pguid);
FreeLibrary(hInst);
}
}
return bRet;
}
Save the following lines as SHLWAPIX.DEF:
LIBRARY SHLWAPI
VERSION 6.0
EXPORTS
GUIDFromStringA #269
GUIDFromStringW #270
Save the following lines as SHLWAPIX.C:
// https://msdn.microsoft.com/en-us/library/bb776431.aspx
__declspec(dllexport)
int __stdcall GUIDFromStringA(void *_1, void *_2)
{ return 0; }
__declspec(dllexport)
int __stdcall GUIDFromStringW(void *_1, void *_2)
{ return 0; }
Run
CL.EXE /LD /Zl SHLWAPIX.C /link /DEF:SHLWAPIX.DEF /NOENTRY
to create the import library SHLWAPIX.LIB, then delete SHLWAPIX.OBJ, SHLWAPIX.EXP and SHLWAPIX.DLL
Save the following lines as SHLWAPIX.H:
#pragma once
#pragma comment(linker, "/DEFAULTLIB:SHLWAPIX.LIB")
__declspec(dllimport)
BOOL WINAPI GUIDFromStringA(LPCSTR psz, LPGUID pguid);
__declspec(dllimport)
BOOL WINAPI GUIDFromStringW(LPCWSTR psz, LPGUID pguid);
Finally save the following lines as SHLWAPIX.C:
#pragma comment(lib, "SHLWAPIX.LIB")
#pragma comment(lib, "USER32.LIB")
#pragma comment(linker, "/ENTRY:wWinMainCRTStartup")
#pragma comment(linker, "/SUBSYSTEM:WINDOWS,5.0")
#pragma comment(linker, "/VERSION:1.0")
#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "shlwapix.h"
VOID wWinMainCRTStartup()
{
GUID guid = {0};
WCHAR szBuffer[1025] = L"";
if (GUIDFromStringA("{00112233-4455-6677-8899-AABBCCDDEEFF}", &guid))
if (wsprintf(szBuffer, L"GUID = {%08lX-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",`
guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]) > 0)
MessageBox((HWND) NULL, szBuffer, L"GUIDFromStringA()", MB_OK);
if (GUIDFromStringW(L"{FFEEDDCC-BBAA-9988-7766-554433221100}", &guid))
if (wsprintf(szBuffer, L"GUID = {%08lX-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]) > 0)
MessageBox((HWND) NULL, szBuffer, L"GUIDFromStringW()", MB_OK);
}
Finally run CL.EXE /GS- SHLWAPIX.C to create SHLWAPIX.EXE, then run the latter.
This gives your an error "syntax error '('":
typedef BOOL WINAPI (*LPFN_GUIDFromString)(LPCTSTR, LPGUID);
The proper version is:
typedef BOOL (WINAPI *LPFN_GUIDFromString)(LPCTSTR, LPGUID);
Related
Below is the main code, the problems encountered, and how they were resolved
***.h
std::list<DISPLAY_DEVICE> m_vDisplayDevice_list;
std::list<DEVMODE> m_vDevmode_list;
int m_nDisplayScreen;
***.cpp
std::list<DISPLAY_DEVICE> devices;
std::list<DEVMODE> modes;
int devId = 0;
BOOL ret = false; // bool ret = false;
bool isPrimary = false;
//list all DisplayDevices (Monitors)
do
{
DISPLAY_DEVICE displayDevice;
ZeroMemory(&displayDevice, sizeof(DISPLAY_DEVICE));
displayDevice.cb = sizeof(displayDevice);
ret = EnumDisplayDevices(NULL, devId, &displayDevice, 0);
if (ret != 0) // reinterpret_cast
{
// 有‘DISPLAY_DEVICE_ATTACHED_TO_DESKTOP’标志的显示设备
if ((displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) == DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
{
devices.push_back(displayDevice);
isPrimary = ((displayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) == DISPLAY_DEVICE_PRIMARY_DEVICE);
}
}
devId++;
} while (ret);
m_vDisplayDevice_list = devices;
std::list<DISPLAY_DEVICE>::iterator it;
for (it = m_vDisplayDevice_list.begin(); it != m_vDisplayDevice_list.end(); it++)
{
DEVMODE deviceMode;
deviceMode.dmSize = sizeof(DEVMODE);
deviceMode.dmFields = DM_PELSWIDTH | // dmPelsWidth
DM_PELSHEIGHT | //dmPelsHeight
DM_BITSPERPEL |
DM_POSITION |
DM_DISPLAYFREQUENCY |
DM_DISPLAYFLAGS; // | DM_DISPLAYORIENTATION;
EnumDisplaySettings((const char*)(it->DeviceName), (int)ENUM_REGISTRY_SETTINGS, &deviceMode);
modes.push_back(deviceMode);
}
m_vDevmode_list = modes;
I used this function to open the Windows desktop shortcut:
ShellExecute(NULL,
NULL,
_T("C:\\Users\\Administrator\\Desktop\\BasePointV - ***.lnk"),
NULL,
NULL,
SW_SHOWNORMAL);
I have a problem:
--------Configuration: Display - Win32 Release--------
Linking...
***.obj : error LNK2001: unresolved external symbol __imp__EnumDisplayDevicesA#16
Debug/***.exe : fatal error LNK1120: 1 unresolved externals
***.exe - 1 error(s), 0 warning(s)
The project I built is MFC AppWinzard(exe);
Environment is:Windows10 VC 6.0
Online solutions include:
Define WINVER 0x0500
Add user32.DLL
There are many good solutions, but the linking problem is not solved yet!
Your linkage error concerning _EnumDisplayDevices says it all.
My psychic powers suggests that since Visual Studio 6.0 (released in 1998) predates the availability of EnumDisplayDevices (Windows 2000), you are trying to pre-declare the API yourself. You probably predeclared EnumDisplayDevices manually yourself. Something like this:
BOOL EnumDisplayDevices(
LPCSTR lpDevice,
DWORD iDevNum,
PDISPLAY_DEVICEA lpDisplayDevice,
DWORD dwFlags
);
There's two problems with this approach.
First, there's no API called EnumDisplayDevices. There is however, two APIs called EnumDisplayDevicesA and EnumDisplayDevicesW for both Unicode and ANSI builds. The Windows SDK will use a macro to map either one to the thing you can to invoke:
#ifdef UNICODE
#define EnumDisplayDevices EnumDisplayDevicesW
#else
#define EnumDisplayDevices EnumDisplayDevicesA
#endif // !UNICODE
Second, the actual declaration of EnumDisplayDevicesA and EnumDisplayDevicesW will are declared as stdcall calling type, like most Win32 APIs. Your declaration is likely missing this detail.
Hence, you want to declare this:
BOOL __stdcall EnumDisplayDevicesW(
LPCWSTR lpDevice,
DWORD iDevNum,
PDISPLAY_DEVICEW lpDisplayDevice,
DWORD dwFlags);
And this:
BOOL __stdcall EnumDisplayDevicesA(
LPCSTR lpDevice,
DWORD iDevNum,
PDISPLAY_DEVICEA lpDisplayDevice,
DWORD dwFlags);
If you manually declared DISPLAY_DEVICE and PDISPLAY_DEVICE yourself, you may also need to fixup your declaration as well. That's addressed in the sample code below.
Finally, even after you fix this, you still won't have a lib to link with since your version of user32.lib doesn't know anything about this API that came later.
You could find a newer version of the Windows SDK that still works with VC 6.0. But a simpler approach might to LoadLibrary the API directly at runtime. So putting it all together, here's a complete solution in which we'll dynamically load the EnumDisplayDevicesW and EnumDisplayDevicesA functions at runtime. Sample invocation as well:
#include <windows.h>
// BORROWED THIS FROM THE WINDOWS SDK - uncomment it if you need it
#if 0
typedef struct _DISPLAY_DEVICEA {
DWORD cb;
CHAR DeviceName[32];
CHAR DeviceString[128];
DWORD StateFlags;
CHAR DeviceID[128];
CHAR DeviceKey[128];
} DISPLAY_DEVICEA, *PDISPLAY_DEVICEA, *LPDISPLAY_DEVICEA;
typedef struct _DISPLAY_DEVICEW {
DWORD cb;
WCHAR DeviceName[32];
WCHAR DeviceString[128];
DWORD StateFlags;
WCHAR DeviceID[128];
WCHAR DeviceKey[128];
} DISPLAY_DEVICEW, *PDISPLAY_DEVICEW, *LPDISPLAY_DEVICEW;
#ifdef UNICODE
typedef DISPLAY_DEVICEW DISPLAY_DEVICE;
typedef PDISPLAY_DEVICEW PDISPLAY_DEVICE;
typedef LPDISPLAY_DEVICEW LPDISPLAY_DEVICE;
#else
typedef DISPLAY_DEVICEA DISPLAY_DEVICE;
typedef PDISPLAY_DEVICEA PDISPLAY_DEVICE;
typedef LPDISPLAY_DEVICEA LPDISPLAY_DEVICE;
#endif // UNICODE
#endif // if 0
// Declare the function types for EnumDisplayDevices
typedef BOOL(__stdcall* FN_EDD_W)(LPCWSTR, DWORD, PDISPLAY_DEVICEW, DWORD);
typedef BOOL(__stdcall* FN_EDD_A)(LPCSTR, DWORD, PDISPLAY_DEVICEA, DWORD);
int main()
{
FN_EDD_W fnEnumDisplayDevicesW;
FN_EDD_A fnEnumDisplayDevicesA;
// Dynamically load EnumDisplayDevices
HMODULE hMod = LoadLibraryW(L"user32.dll");
fnEnumDisplayDevicesW = (FN_EDD_W)GetProcAddress(hMod, "EnumDisplayDevicesW");
fnEnumDisplayDevicesA = (FN_EDD_A)GetProcAddress(hMod, "EnumDisplayDevicesA");
// now invoke the loaded API function
DISPLAY_DEVICEW device = {};
device.cb = sizeof(device);
fnEnumDisplayDevicesW(NULL, 0, &device, 0); // equivalent to EnumDisplayDevicesW
}
I'm working with Visual Studio 2012 & 2017 with C++ 11 and Pelles C 9.0 with C++ 11...
When I build a empty program and DLL but they contain lots of unused imports in pe file!
VC++ has 26 imports of KERNEL32 and Pelles has 70 imports of KERNEL32
My project is totally empty!
I need to remove them from linker and compiled file.
I have an DLL is compiled with Pelles C and it only has 4 import that it really use :
KERNEL32.dll
VirtualProtect ord:0 rva2iat: 000012A0
GetModuleHandleA ord:0 rva2iat: 000012A8
Sleep ord:0 rva2iat: 000012B0
CreateThread ord:0 rva2iat: 000012B8
I want to do the same , I don't need any of those 70 imports and functions , How Can I do it ?
Thanks to TimoVJL | Here's the solution :
#include <windows.h>
#ifdef _WIN64
#pragma comment(linker, "/ENTRY:DllMainCRTStartup")
#else
#pragma comment(linker, "/ENTRY:_DllMainCRTStartup#12")
#endif
BOOL WINAPI DllMainCRTStartup(HANDLE hDLL, DWORD dwReason, LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH) g_hmod = hDLL;
return TRUE;
}
I have the following file structure
C:\Application\application.exe
C:\Application\plugins\myplugin\myplugin.dll
C:\Application\plugins\myplugin\libs\utils.dll
Here application.exe loads myplugin.dll dynamically via LoadLibrary. Note that I have no control over application.exe as I am developing the plugin only.
What I want is to make myplugin.dll load libs\utils.dll via a relative path (ideally using static linking). That is, I don't want to be dependent on the location of application.exe. I currently add C:\Application\plugins\myplugin\libs to the PATH environment variable when installing myplugin, but environment variables are not an ideal solution and I want to avoid doing that.
I was hoping I could use assemblies and config files to specify the relative path libs\utils.dll in myplugin.dll. And I tried this, but to no avail. I then saw someone mentioning here on StackOverflow that config files only work for applications (i.e. executables). But as I said above, I have no control over application.exe. Is there a solution to this seemingly simple problem which I believe on Unix systems can be solved via rpaths?
You cannot statically link to a DLL path at all, relative or absolute. The PE imports table only contains filenames. That is why a DLL search path exists to locate DLLs.
If you want to control where utils.dll is loaded from, you have to load it dynamically. myplugin.dll can retrieve its own path using GetModuleFileName(), using the module handle that is passed in to its DllMain() entry point. It can then remove the filename from the path, append the relative path to the path, and then load the DLL when needed (not inside of DllMain() itself, or else a deadlock/crash may occur).
There are two ways you can handle this:
load everything dynamically yourself:
#include <windows.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
HINSTANCE hThisDLL = NULL;
HMODULE hUtils = NULL;
typedef ReturnType __CallingConv (*DllFuncType)(Params);
DllFuncType DllFunc = NULL;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
hThisDLL = hinstDLL;
...
}
return TRUE;
}
...
ReturnType CallDllFunc(Params)
{
if (!hUtils)
{
TCHAR szUtilsFileName[MAX_PATH] = {0};
GetModuleFileName(hThisDLL, szUtilsFileName, MAX_PATH);
if (!PathRemoveFileSpec(szUtilsFileName))
{
// do something...
return ...;
}
if (!PathAppend(szUtilsFileName, TEXT("libs\\utils.dll")))
{
// do something...
return ...;
}
hUtils = LoadLibrary(szUtilsFileName);
if (!hUtils)
{
// do something...
return ...;
}
}
if (!DllFunc)
{
DllFunc = (DllFuncType) GetProcAddress(hUtils, "DllFuncName");
if (!DllFunc)
{
// do something...
return ...;
}
}
return DllFunc(Params);
}
static link to everything like you normally would, but then utilize your compiler's delay load feature (if supported) so you can specify the DLL's filename dynamically at runtime, but still statically link to the DLL function itself (the delay-load mechanism will call GetProcAddress() for you).
#include <windows.h>
#include <shlwapi.h>
#include <delayimp.h>
#pragma comment(lib, "Delayimp.lib")
#pragma comment(lib, "shlwapi.lib")
HINSTANCE hThisDLL = NULL;
FARPROC WINAPI DelayLoadHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
if ((dliNotify == dliNotePreLoadLibrary) &&
(strcmpi(pdli->szDll, "utils.dll") == 0))
{
TCHAR szUtilsFileName[MAX_PATH] = {0};
GetModuleFileName(hThisDLL, szUtilsFileName, MAX_PATH);
if (!PathRemoveFileSpec(szUtilsFileName))
{
// do something...
return NULL;
}
if (!PathAppend(szUtilsFileName, TEXT("libs\\utils.dll")))
{
// do something...
return NULL;
}
HMODULE hUtils = LoadLibrary(szUtilsFileName);
return reinterpret_cast<FARPROC>(hUtils);
}
return NULL;
}
PfnDliHook __pfnDliNotifyHook2 = DelayLoadHook;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
hThisDLL = hinstDLL;
...
}
return TRUE;
}
...
ReturnType CallDllFunc(Params)
{
return DllFuncName(Params);
}
i need to create small dll to intercept simple mapi calls and send files via:
file->Send to as attachment (in excel, word, acrobat reader...)
or via explorer->rightclickmenu->Send to->Mail recipient
to attach to gmail.
after reading this:
Mapi32.dll Stub Registry Settings (Windows)
Mapi32 Stub Library (Windows)
and searching here on stackoverflow and other webs i have created one very small dll using code::blocks that shows me information for investigating the process.
I have installed it on registry correctly like indicated in previous links on HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail\SimpMapi.
I have selected on my win xp pro in control panel->Internet options my SimpMapi client.
when i open excel write some cells and go to File->Send like attachment dll shows me that first calls MapiLogon, second calls MapiSendMail and third when i close excel it calls MapiLogoff, but then it throws an error and closes excel.exe.
If i try it from explorer window right clicking one file and SendTo->Mail recipient it calls directly MapiSendMail and when i click on ok in MsgBox it throws an error and closes explorer.exe
Could you help me to find out what is wrong.
This is the mail.h file:
#ifndef __MAIN_H__
#define __MAIN_H__
#include <windows.h>
// Todo lo necesario a incluir por mapi.h
#define SUCCESS_SUCCESS 0
#define MAPI_E_USER_ABORT 1
#define MAPI_E_LOGIN_FAILURE 3
typedef unsigned long FLAGS;
typedef unsigned long LHANDLE;
typedef unsigned long FAR *LPLHANDLE, FAR *LPULONG;
typedef struct {
ULONG ulReserved;
ULONG ulRecipClass;
LPSTR lpszName;
LPSTR lpszAddress;
ULONG ulEIDSize;
LPVOID lpEntryID;
} MapiRecipDesc, *lpMapiRecipDesc;
typedef struct {
ULONG ulReserved;
ULONG flFlags;
ULONG nPosition;
LPSTR lpszPathName;
LPSTR lpszFileName;
LPVOID lpFileType;
} MapiFileDesc, *lpMapiFileDesc;
typedef struct {
ULONG ulReserved;
LPSTR lpszSubject;
LPSTR lpszNoteText;
LPSTR lpszMessageType;
LPSTR lpszDateReceived;
LPSTR lpszConversationID;
FLAGS flFlags;
lpMapiRecipDesc lpOriginator;
ULONG nRecipCount;
lpMapiRecipDesc lpRecips;
ULONG nFileCount;
lpMapiFileDesc lpFiles;
} MapiMessage, *lpMapiMessage;
/* To use this exported function of dll, include this header
* in your project.
*/
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
extern "C" void DLL_EXPORT SomeFunction(const LPCSTR sometext);
extern "C" ULONG DLL_EXPORT MAPILogon(ULONG_PTR ulUIParam,LPSTR lpszProfileName,LPSTR lpszPassword,FLAGS flFlags,ULONG ulReserved,LPLHANDLE lplhSession);
extern "C" ULONG DLL_EXPORT MAPILogoff(LHANDLE lhSession,ULONG_PTR ulUIParam,FLAGS flFlags,ULONG ulReserved);
extern "C" ULONG DLL_EXPORT MAPISendDocuments(ULONG_PTR ulUIParam,LPSTR lpszDelimChar,LPSTR lpszFilePaths,LPSTR lpszFileNames,ULONG ulReserved);
extern "C" ULONG DLL_EXPORT MAPISendMail(LHANDLE lhSession,ULONG_PTR ulUIParam,lpMapiMessage lpMessage,FLAGS flFlags,ULONG ulReserved);
#endif
This is the main.cpp file:
#include "main.h"
// a sample exported function
void DLL_EXPORT SomeFunction(const LPCSTR sometext)
{
MessageBoxA(0, sometext, "DLL Message", MB_OK | MB_ICONINFORMATION);
}
ULONG DLL_EXPORT MAPILogon(ULONG_PTR ulUIParam,LPSTR lpszProfileName,LPSTR lpszPassword,FLAGS flFlags,ULONG ulReserved,LPLHANDLE lplhSession)
{
MessageBoxA(0, "MAPILogon", "MAPILogon", MB_OK | MB_ICONINFORMATION);
return SUCCESS_SUCCESS;
}
ULONG DLL_EXPORT MAPILogoff(LHANDLE lhSession,ULONG_PTR ulUIParam,FLAGS flFlags,ULONG ulReserved)
{
MessageBoxA(0, "MAPILogoff", "MAPILogoff", MB_OK | MB_ICONINFORMATION);
return SUCCESS_SUCCESS;
}
ULONG DLL_EXPORT MAPISendDocuments(ULONG_PTR ulUIParam,LPSTR lpszDelimChar,LPSTR lpszFilePaths,LPSTR lpszFileNames,ULONG ulReserved)
{
MessageBoxA(0, "MAPISendDocuments", "MAPISendDocuments", MB_OK | MB_ICONINFORMATION);
return SUCCESS_SUCCESS;
}
ULONG DLL_EXPORT MAPISendMail(LHANDLE lhSession,ULONG_PTR ulUIParam,lpMapiMessage lpMessage,FLAGS flFlags,ULONG ulReserved)
{
MessageBoxA(0, "MAPISendMail", "MAPISendMail", MB_OK | MB_ICONINFORMATION);
return SUCCESS_SUCCESS;
}
extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
// attach to process
// return FALSE to fail DLL load
break;
case DLL_PROCESS_DETACH:
// detach from process
break;
case DLL_THREAD_ATTACH:
// attach to thread
break;
case DLL_THREAD_DETACH:
// detach from thread
break;
}
return TRUE; // succesful
}
Thanks in advance.
Jorge
In link: Creating Custom Simple Mapi DLL, throws error when executing
Andy helped me to solve the problem that was incorrect calling convention.
Adding WINAPI to all my Simple MAPI function declarations and definitions it worked, example:
extern "C" ULONG DLL_EXPORT WINAPI MAPILogon( // etc
Then the problem was that my exported functions were exported with declarations.
To correct this in code::blocks you have to add in:
Main menu: Project -> Build options -> GNU GCC Compiler -> Linker settings -> Other linker options: -Wl,--kill-at
Thanks!
I've basically been trying to get this working for the last couple of days, but all of my attempts and all the examples/suggestions found online have failed. I'm trying to use Microsoft's "setupapi.dll" methods in implementing my own .dll to access a peripheral device I have created.
Right now I'm simply trying to use the method "SetupDiGetClassDevs" found in "setupapi.dll" to retrieve a list of attached HID devices on my computer. I've tried everything from "AfxLoadLibrary" to "__declspec(dllimport)" and pretty much everything else I've found online to no avail.
I've found working examples in C# but have not found anything that even compiles in C++. I am running Microsoft visual C++ 2010 express on Windows 7 64-bit if that makes a difference (ideally I'd want it to be OS independent - at least across more recent versions of windows). Any code samples that can successfully import/use this method would be greatly appreciated. (Also don't forget to mention any configuration settings/resource files/etc as I need to figure out a holistic process to make this work.)
UPDATE!!!:
so i finally got my code to compile using a combination of suggestions from the responses given here + some more googling. my current code is as follows (and fyi the main issue here was that an "L" had to be prefixed to the .dll in quotes):
GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30};
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
PSP_DEVICE_INTERFACE_DATA InterfaceDataStructure = new SP_DEVICE_INTERFACE_DATA;
SP_DEVINFO_DATA DevInfoData;
DWORD InterfaceIndex = 0;
DWORD StatusLastError = 0;
DWORD dwRegType;
DWORD dwRegSize;
DWORD StructureSize = 0;
PBYTE PropertyValueBuffer;
bool MatchFound = false;
DWORD ErrorStatus;
BOOL BoolStatus = FALSE;
DWORD LoopCounter = 0;
HINSTANCE dllHandle = LoadLibrary(L"setupapi.dll");
if(dllHandle)
{
typedef HDEVINFO (WINAPI *pFUNC)(LPGUID, PCTSTR, HWND, DWORD);
pFUNC SetupDiGetClassDevs = (pFUNC) GetProcAddress(dllHandle,
#ifdef UNICODE
"SetupDiGetClassDevsW"
#else
"SetupDiGetClassDevsA"
#endif
);
if(SetupDiGetClassDevs)
hDevInfo = SetupDiGetClassDevsW(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
FreeLibrary(dllHandle);
unfortunately i wasn't able to get this working using the "safeloadlibrary" function remy mentioned. and my impression from other forums is that the standard "loadlibrary" function is non-ideal. so i'd like to know what is needed to implement it (header files, etc) or if there is another better way to do this. apparently there are also some issues that may arise using "loadlibrary" in a DLL (particularly in DLLMain entry point) but given my lack of experience using .dll's i'm not really sure what they are.
Your code fails because you are passing the wrong function name to GetProcAddress(). Like most API functions that have string parameters, SetupDiGetClassDevs() has separate Ansi and Unicode flavors available (SetupDiGetClassDevsA() and SetupDiGetClassDevsW(), respectively), and the API header files transparently hide this detail from you. So you need to adjust your string value according to which flavor you actually want to use, eg:
HINSTANCE dllHandle = SafeLoadLibrary("setupapi.dll");
if (dllHandle)
{
typedef HDEVINFO WINAPI (*pFUNC)(LPGUID, PCTSTR, HWND, DWORD);
pFUNC SetupDiGetClassDevs = (pFUNC) GetProcAddress(dllHandle,
#ifdef UNICODE
"SetupDiGetClassDevsW"
#else
"SetupDiGetClassDevsA"
#endif
);
if (SetupDiGetClassDevs)
hDevInfo = SetupDiGetClassDevs(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
FreeLibrary(dllHandle);
}
Here is a simply trick to make the mapping easier to work with if you have multiple functions to load dynamically:
#if defined(UNICODE)
#define _MAP_WINNAME_STR(n) n "W"
#else
#define _MAP_WINNAME_STR(n) n "A"
#endif
pFUNC SetupDiGetClassDevs = (pFUNC) GetProcAddress(dllHandle, _MAP_WINNAME_STR("SetupDiGetClassDevs"));