I get this error when trying to use this function
void WSPAPI GetLspGuid( LPGUID lpGuid )
{
memcpy( lpGuid, &gProviderGuid, sizeof( GUID ) );
}
the error
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
the function is called by using
HMODULE hMod = NULL;
LPFN_GETLSPGUID fnGetLspGuid = NULL;
int retval = SOCKET_ERROR;
// Load teh library
hMod = LoadLibraryA( LspPath );
if ( NULL == hMod )
{
fprintf( stderr, "RetrieveLspGuid: LoadLibraryA failed: %d\n", GetLastError() );
goto cleanup;
}
// Get a pointer to the LSPs GetLspGuid function
fnGetLspGuid = (LPFN_GETLSPGUID) GetProcAddress( hMod, "GetLspGuid" );
if ( NULL == fnGetLspGuid )
{
fprintf( stderr, "RetrieveLspGuid: GetProcAddress failed: %d\n", GetLastError() );
goto cleanup;
}
// Retrieve the LSPs GUID
fnGetLspGuid( Guid );
This runtime check guards against a mismatch between the function declaration and the actual definition. Accidents that can happen when you compile code into a static library or a DLL. Common mismatches are the calling convention or the number or type of the arguments that are passed.
The shoe fits, you've got a macro named WSPAPI that declares the calling convention. It typically expands to either __cdecl or __stdcall, usually biased towards __stdcall. So very high odds that it this macro has the wrong value in your client code. Ask the library author for assistance if you can't figure out how to set this macro correctly.
After edit: with the additional failure mode that you are loading the wrong version of the DLL. And that your LPFN_GETLSPGUID function pointer declaration is wrong, missing the WSPAPI macro. I'll put my money on that one, especially since I can't see it.
After comment, the info is slowly trickling in:
it is defined as typedef void (*LPFN_GETLSPGUID) (GUID *lpGuid);
Which is wrong, it should be
typedef void (WSPAPI * LPFN_GETLSPGUID)(GUID *lpGuid);
If you don't have the macro available, unlikely, then substitute WSPAPI with __stdcall.
Related
I've got a simple piece of C++ code I'm exporting from a DLL.
DWORD WINAPI MessageBoxThread(LPVOID lpParam)
{
MessageBox(0, L"Test", L"Test", 0);
return 0;
}
Here's how I'm calling it
typedef DWORD(*MessageBoxThread)(LPVOID);
int StartMessageBoxThread() {
MessageBoxThread ShowMessageBox;
HMODULE testModule = LoadLibrary(L"C:\\Users\\david\\COMServer.dll");
ShowMessageBox = (MessageBoxThread)GetProcAddress(testModule, "MessageBoxThread");
ShowMessageBox(NULL);
FreeLibrary(testModule);
return 0;
}
I get an exception thrown in KernelBase.dll on the ShowMessageBox() line, involved an access violation when writing to a memory location.
I can't understand what I'm doing wrong. Both Visual Studio projects are set to Unicode, and I know using the L prefix denotes wide strings.
I can debug and step through into my DLL, I see the address of my function, so I can't see anything wrong with the code calling the function.
typedef DWORD(*MessageBoxThread)(LPVOID);
The prototype does not match the definition in dll. By default calling convention here is __cdecl whereas WINAPI is __stdcall
typedef DWORD(WINAPI *MessageBoxThread)(LPVOID);
Specifically, at the called end, since the convention is __stdcall(callee clears the stack), the function pops argument off the stack. At the caller end, it sees that the convention is __cdecl(caller clears the stack) and it also pops the argument from the stack, eventually corrupting the stack.
In your StartMessageBoxThread() code, MessageBoxThread is declared incorrectly. Specifically, it is missing a calling convention, so it uses the compiler's default convention, which is typically __cdecl rather than __stdcall (what WINAPI maps to). Calling convention mismatches are a common cause of crashes, call stack corruption, etc.
Also, the code has no error checking at all.
Try this instead:
typedef DWORD (WINAPI *MessageBoxThread)(LPVOID);
int StartMessageBoxThread()
{
HMODULE testModule = LoadLibrary(L"C:\\Users\\david\\COMServer.dll");
if (testModule)
{
MessageBoxThread ShowMessageBox = (MessageBoxThread) GetProcAddress(testModule, "MessageBoxThread");
if (ShowMessageBox)
ShowMessageBox(NULL);
FreeLibrary(testModule);
}
return 0;
}
Hi I'm having quite some issues with integrating a DLL inside my Delphi 2007 application.
i suspect that I'm doing something wrong with the parameters of the calls.
At this moment i have 2 issues, but i think they are related to eachother.
1)
First call with the DLL:
from the .h file:
extern "C" {
__declspec(dllexport) HRESULT Startup(char* version);
}
This call should initialize the DLL and give me the version back of the DLL. HRESULT should be 0, and the version pointer should contain the version.
My Delphi code:
function Startup(var version: Pchar): HRESULT; cdecl; stdcall; external 'myDLL.dll';
And the actual call:
var
res : HRESULT;
Name1 : PChar;
test : AnsiString;
buf2: array [0..20] of AnsiChar;
begin
FillChar(buf2,20,0);
Name1:= #buf2[0];
res := RdmStartup(Name1);
//Here res = 0, but the Name1 stays empty, and the buf2 still contains 0.
end;
But as the result is 0 the call was a success.
Then my second issue: i need to call a function in the DLL that will open a COM port.
The .h:
extern "C" {
__declspec(dllexport) HRESULT Open(HWND hWnd, int Port, DWORD BaudRate, DWORD Interval);
}
And my Delphi declare:
function Open(hWnd: HWND;Port : integer;BaudRate:LongInt;Interval:LongInt): HRESULT; cdecl; stdcall; external 'myDLL.dll';
and i call this by:
res:= Open(self.Handle,5,115200,500);
And here i'm getting a failure back from the DLL in the res variable.
i also have the source of the DLL, and the failure that i'm getting is from the part where the DLL is checking if the parameters are valid, if they are valid it will continue, else return the error i'm currently getting.
The things it is checking:
if(hWnd == NULL)
{
return false;
}
if(BaudRate != 2400 && BaudRate != 9600 && BaudRate != 38400 && BaudRate != 115200)
{
return false;
}
if(IntervalTimer < 300)
{
return false;
}
std::string strPortName = lexical_cast<std::string>( format("COM%d") % Port);
std::string strPortName(lpPortName.c_str());
std::string::size_type loci = strPortName.find("COM");
if( loci == std::string::npos )
{
return false;
}
return true;
And one of these above is returning false on my call, because if the result of this function is false, the DLL gives the error i'm currently getting in the results.
Does anyone have an idea of what i am doing wrong?
i've tried numerous of combinations for the types in the end i sticked to the conversion i found at: http://www.drbob42.com/delphi/headconv.htm
i've also tried different ways of reading the char pointer, but all of them failed.....
So at this stage i know i am succesfully communicating with the DLL as i'm getting different HRESULTs back for the 2 calls, but i suspect my parameters are not working like the should.
I'm using Delphi 2007 and the C++ DLL was build with VS2010.
The declaration of Startup is pretty suspicious:
__declspec(dllexport) HRESULT Startup(char* version);
This translates into:
function Startup(version: PAnsiChar): HResult; stdcall; external 'myDLL.dll';
So there should be no var there.
I got from your comments that the cdecl calling convention works for some of your code. In that case remove stdcall, since it overrules the preceding cdecl.
The declaration of Open() seems to be pretty OK (I would use DWORD as type, not Longint, especially since DWORD is Longword these days -- but in Win32 they are the same size, so that won't make any big difference for you). And you seem to be passing the right parameters too.
You did not write what the HRESULT value is that you get back. But I assume that the port COM5 simply cannot be opened with these settings.
What can you do?
You should remove the var from Startup().
So you can try:
to use cdecl instead of stdcall (the stdcall in your declaration overrules the cdecl)
to open different COM ports with different parameters
to decode the HRESULT that is returned.
A better diagnosis is not possible, from a distance, without the same hardware and software, sorry.
You could read my article on conversion. This has also a few paragraphs that explain how to debug the code to find out the proper calling convention. It can probably help you with more of your problems converting headers, too.
I'm trying to export a completely clean function name, this is because I need to use it within GetProcAddress (2nd parameter). I know this is possible as if you test dumpbin against Kernel32 it will display clean function names.
I have looked around found numerous "solutions", and I have gotten my mangled name from jibberish to:
1 0 00001810 SomeFunction = _SomeFunction
However I need it to look like:
1 0 00001810 SomeFunction
This would allow me to call it from the GetProcAddress function, as I can't get it to work with a "Mangled" name.
Here is how I'm defining it:
extern "C" __declspec(dllexport) void SomeFunction(void * SomeArguments)
{
//Function Content
}
With a module definition file, it's useless... I get a totally mangled name.
Using this way, I can get it nearly there however the '_' is preventing GetProcAddress resolving my function name to a address.
Module Definition output:
1 0 00001810 SomeFunction = ?SomeFunction##YAXPAX#Z (void __cdecl SomeFunction(void *))
EDIT: (If you mean the function aboves content... it's simply a message box MessageBoxA()... there can't be anything wrong there.)
GetProcAddressLine:
LPVOID SomeFunctionAddr = (LPVOID)GetProcAddress(GetModuleHandleA("Pies.dll"), "SomeFunction");
Full "GetProcAddress":
LPVOID SomeFunctionAddr = (LPVOID)GetProcAddress(GetModuleHandleA("Pies.dll"), "SomeFunction");
if (!SomeFunctionAddr)
{
std::cout << "Failed to obtain SomeFunction Address!\n";
return 0;
}
Allocate = VirtualAllocEx(Handle, NULL, strlen(Path), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
WriteProcessMemory(Handle, Allocate, Path, strlen(Path), NULL);
Thread = CreateRemoteThread(Handle, NULL, NULL, (LPTHREAD_START_ROUTINE)SomeFunctionAddr, Allocate, 0, NULL);
WaitForSingleObject(Thread, INFINITE);
VirtualFreeEx(Handle, Thread, strlen(Path), MEM_RELEASE);
I am a C++ (MSVC) writer, VB newbie trying to assist an expert VB.net writer who has just not done this task before.
We wish to develop both C/C++ and VB applications to use a DLL written in C++ with C extern-ed API functions. The C++ program is working just fine. It's VB where we are having difficulties.
The DLL provides an extern C function:
RegisterCallback( void* cbFuncPtr, void* dataPtr );
NOTE 1: See my note below for a design change and the reasons we made it.
NOTE 2: Additional update added as an answer below.
where the callback function havs this C typedef:
typedef (void)(* CALL_NACK)(void*);
The cbFuncPtr is expected to be a function pointer to some VB function that will get called as the CALL_BACK. The dataPtr is a pointer to a data structure that has this C definition:
typedef struct
{
int retCode;
void* a_C_ptr;
char message[500];
} cbResponse_t;
where a_C_ptr is an internal pointer in the DLL that the VB can cast tolong`. It uniquely identifies where in the DLL the callback was made and allows the VB function to recognize calls from same/different locations.
We are able to access and run the RegisterCallback() function from VB just fine. Logging shows we get there and that data is passed in. It is the actual data that seems to be the problem.
In reading about a million forum entries we have learned that VB doesn't know what pointers are and that a VB structure is more than just organized memory. We're pretty sure the "address" of a VB structure is not what C thinks an address is. We've seen repeated references to "marshaling" and "managed data", but lack enough understanding to know what that is telling us.
How should we code VB to give the DLL the execution address of its callback function and how do we code up a VB construct that the DLL can fill in just as it does for C++?
Might we need a DLL function where the calling app can say "C" or "VB" andhave the DLL handle the sturcture pointers differently? If so, how would one code up C to fill in the VB structure?
This is a bit too big and deep to just be an edit to the original posting...
From the link posted by #DaveNewman, I extracted this gem:
Here's a bit about the compact framework, but it's the same in the
grown-ups framework:
The .NET Compact Framework supports automatic marshaling of structures
and classes that contain simple types. All fields are laid out
sequentially in memory in the same order as they appear in the
structure or class definition. Both classes and structures appear in
native code as pointers to C/C++ structs.
Objects in the managed heap can be moved around in memory at any time
by the garbage collector, so their physical addresses may change
without notice. P/Invoke automatically pins down managed objects
passed by reference for the duration of each method call. This means
pointers passed to unmanaged code will be valid for that one call.
Bear in mind that there is no guarantee that the object will not be
moved to a different memory address on subsequent calls.
http://msdn.microsoft.com/en-us/library/aa446538.aspx#netcfmarshallingtypes_topic6
This is major hurdle for a RegisterCallback( fcnPtr, dataPtr) function. The pointer passed in at registration time could change at any time the RegisterCallback() is not the current statement. The posting author summed it up this way
You don't need to do anything as the structures are pinned automatically for duration of the call.
implying, of course, not pinned down outside the call.
For this reason we decided on a design change to have the response structure built in, so to speak, the C/C++ world of the DLL, not in VB's space. That way it'll stay put. The actual callback function's signature will remain unchanged so the VB program can know where the DLL put the response. This also allows the responders in the DLL to allocate separate response structures for separate needs.
Once again my update is too large for a mere comment!
Update 18 Apr 2013:
Well, the attempt to use the code from Calling Managed Code from Unmanaged Code cited above was a bust. We ended up having to add /clr to the DLL make turning the DLL into managed code, which made it unusable from a C application.
We are now testing the example at Callback Sample which I was able to show made a DLL that worked with both VB and C++. You'd need to have the PinvokeLib.dll Source to make this work.
Here is the code for the C++ (C really) tester. Compiled as a MSVC project.
NOTE: Notice the __cdecl in this line:
typedef bool (__cdecl *FPtr)(BOOL_FP_INT fp, int i );
It was the secret I had to find. The DLL and this app are compiled with __cdecl linkage, not __stdcall. They are the default in VC++ and I just used the defaults. I tried changing everything to __stdcall but that didn't work. Has to be __cdecl.
// PinvokeTester.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
#include <cstdlib>
#include <string.h>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <Windows.h>
#define PINVOKELIB_API __declspec(dllimport)
HINSTANCE hLib; // Windows DLL handle
bool CALLBACK VBCallBack( int value );
bool AttachLibrary( void );
void * GetFuncAddress( HINSTANCE hLib, const char* procname );
int main(int argc, char* argv[])
{
if ( !AttachLibrary() )
{
printf( "Lib did not attach.\n" );
exit(1);
}
typedef bool (CALLBACK *BOOL_FP_INT)(int i );
typedef bool (__cdecl *FPtr)(BOOL_FP_INT fp, int i );
FPtr TestCallBack = (FPtr)GetFuncAddress( hLib, "TestCallBack" );
TestCallBack( (BOOL_FP_INT)VBCallBack, 255 );
return 0;
}
bool CALLBACK VBCallBack( int value )
{
printf( "\nCallback called with param: %d", value);
return true;
}
bool AttachLibrary( void )
{
// Get a var for the IPC-dll library.
std::string dllName;
/*--- First, link to the IPC-dll library or report failure to do so. ---*/
dllName = ".\\PinvokeLib";
if ( NULL == (hLib = LoadLibraryA( dllName.c_str() )) )
{
printf( "\nERROR: Library \"%s\" Not Found or Failed to Load. \n\n", dllName.c_str() );
printf( "\"%s\"\n", GetLastError() );
return false;
}
return true;
}
//=====================================================================
void * GetFuncAddress( HINSTANCE hLib, const char* procname )
{
void * procAddr = NULL;
procAddr = (void *)GetProcAddress( hLib, procname );
// If the symbol wasn't found, handle error ---------------------
if ( NULL == procAddr )
{
std::cout << "ERROR: Could not get an address for the \""
<< procname << "\" function. : "
<< GetLastError() << std::endl;
exit( 7 );
procAddr = (void*)NULL;
}
return procAddr;
}
I am attempting to schedule a task (to open an .exe at a specific time) using C++ win32. But at one specific point I am getting an error, I have searched & searched to try & find the definition of this error but I cannot find it?
Do you know what this error means: Hexadecimal: 80004003 Decimal: 2147500035
I wont post the whole function because its rather long (unless you may need it to determine the error context?).
The code I am using (that causes the error) is the following:
// QI for the executable task pointer.
hr = action -> QueryInterface( IID_IExecAction, (void**) execAction );
action -> Release();
if( FAILED(hr) )
{
printf("QueryInterface call failed for IExecAction: %x %X %u \n", hr, hr, hr );
rootFolder -> Release();
task -> Release();
CoUninitialize();
return false;
}
The output is: QueryInterface call failed for IExecAction: 80004003 80004003 2147500035
0x80004003 is an "invalid pointer" error, a.k.a. E_POINTER.
I assume the declaration of execAction is something like:
IExecAction* execAction = NULL;
But, QueryInterface expects a pointer to an interface pointer. In other words, you pass a storage location in which to place an IUnknown*... or, in this specific case, a IExecAction*.
So, you need to pass the address of execAction so QueryInterface can return the interface pointer to you. As in:
hr = action -> QueryInterface( IID_IExecAction, (void**) &execAction );
I assume this is what's happening since initializing pointer values to NULL is a common coding practice, and QueryInterface is documented to return E_POINTER when the second argument is NULL. If not, please update your question with the declaration of execAction.