I am making an application for xbox 360 that will import functions which were exported from a system dll and call them when needed. I thought I did everything right as far as exporting then importing the functions, but it crashes on a single line of code.
I started by defining the functions inside of the system dll as follows:
void (__cdecl *SV_GameSendServerCommand)(int Client, int Type, char *Command) = (void(__cdecl * )(int, int, char * ))0x82254940;
bool (__cdecl *Dvar_GetBool)(char *Dvar) = (bool(__cdecl * )(char * ))0x8229EF58;
I created a .def file to export the functions while assigning their ordinals:
LIBRARY testdll
EXPORTS
SV_GameSendServerCommand #1
Dvar_GetBool #2
I built the system dll and placed the resulting testdll.lib in the folder where my application's source code was. I then placed the following in stdafx.h of that application:
#pragma comment(lib, "testdll.lib")
I prototyped the functions to be imported and used a function called resolveFunct to get the addresses of the imported functions.
void (__cdecl *SV_GameSendServerCommand)(int Client, int Type, char *Command);
bool (__cdecl *Dvar_GetBool)(char *Dvar);
UINT32 resolveFunct(char* modname, UINT32 ord)
{
UINT32 ret=0, ptr2=0;
HANDLE ptr32 = 0;
ret = XexGetModuleHandle(modname, &ptr32);
if(ret == 0)
{
ret = XexGetProcedureAddress(ptr32, ord, &ptr2);
if(ptr2 != 0)
return ptr2;
}
return 0; // function not found
}
When I tried printing the address of the function, it was successful and read 0x91F8BF54. I did this twice, and it printed both times. The proceeding line of code caused my application to crash.
DWORD WINAPI Start(LPVOID)
{
for(;;)
{
if(!LoadedUp)
{
printf("0x%p\n", resolveFunct("testdll.xex",2));
if(Dvar_GetBool == NULL)
{
printf("0x%p\n", resolveFunct("testdll.xex",2));
Dvar_GetBool = (bool(__cdecl*)(char*))resolveFunct("testdll.xex",2);
I don't understand why this line of code causes my program to crash, though. Any answers/suggestions are appreciated. Thanks!
Related
C# code:
class Hello{
public void helloWorld(char[] chars){
//do something
}
}
C++ code to call C#:
MyCSDLL::Hello* hello;
//init hello, some calls are ok.
char* myCharPtr;
//init with message
HRESULT result = hello->helloWorld(safeArray, (MyCSDLL::_MyRetVal) _retValPtr);
Adapting from How to create and initialize SAFEARRAY of doubles in C++ to pass to C#
void createSafeArray(SAFEARRAY** saData, char* charPtr)
{
char* iterator = charPtr;
SAFEARRAYBOUND Bound;
Bound.lLbound = 0;
Bound.cElements = 10;
*saData = SafeArrayCreate(VT_R8, 1, &Bound);
char HUGEP *pdFreq;
HRESULT hr = SafeArrayAccessData(*saData, (void HUGEP* FAR*)&pdFreq);
if (SUCCEEDED(hr))
{
do {
*pdFreq++ = *iterator;
} while (*iterator++);
}
}
How to call hello->helloWorld()? it is expecting SAFEARRAY*. The current code gives 80131538 error. How to fix it?
C++ Project is not CLR.
Let's suppose the C# code is this:
namespace ClassLibrary1
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Hello
{
public void helloWorld(char[] chars)
{
...
}
}
}
Then, you can call it with this C/C++ code, for example:
#import "C:\mycode\ClassLibrary1\bin\Debug\classlibrary1.tlb" raw_interfaces_only
using namespace ClassLibrary1;
HRESULT CallHello(wchar_t* charPtr, int count)
{
CComPtr<_Hello> p;
HRESULT hr = p.CoCreateInstance(__uuidof(Hello));
if (FAILED(hr))
return hr;
SAFEARRAY* psa = SafeArrayCreateVector(VT_UI2, 0, count);
if (!psa)
return E_OUTOFMEMORY;
LPVOID pdata;
hr = SafeArrayAccessData(psa, &pdata);
if (SUCCEEDED(hr))
{
CopyMemory(pdata, charPtr, count * 2); // count is the number of chars
SafeArrayUnaccessData(psa);
hr = p->helloWorld(psa);
}
SafeArrayDestroy(psa);
return hr;
}
.NET's char type is unicode, so the binary size is two bytes, the C equivalent is wchar_t (or unsigned short, etc...). So the safearray element type must match that, that's why I used VT_UI2 (VT_R8 that you used is Real of size 8 bytes, so it's equivalent to .NET's double type).
If you really want to use C's char, then you must do some kind of conversion to a 2-byte character.
Also, you can use the SafeArrayCreateVector function which directly allocates a 1-dimension safe array. Don't forget to call cleanup methods.
I have some 15-year-old C++ code that I am trying to bring up to more modern times. At this stage, I'm trying to get code that compiled with Visual C++ 6.0 to now compile with VS 2003 (Microsoft Visual C++ .NET 69462-335-0000007-18915). If we can get this to compile cleanly & run properly, then we can take another step to get it into a more recent version of VS. But I'm having a number of problems...
Here is a snippet of the (simplified) code:
class toS
{
public:
toS() { buff[0] ='\0'; }
operator LPCTSTR() { return buff; }
protected:
void Append (TCHAR c)
{
LPTSTR p = buff + _tcslen(buff);
*p++ = c;
*p = '\0';
}
TCHAR buff[40];
};
class LtoS : public toS
{
public:
LtoS(LONG n, TCHAR c = '\0')
{
_ltot(n, buff, 10);
Append(c);
}
};
void WriteBool(const CString& Section, const CString& Key, bool Value);
CString Section;
int nLine = 0;
std::vector<bool> *BoolVect;
std::vector<bool>::iterator vi;
...
for (vi = BoolVect->begin(); vi != BoolVect->end(); vi++)
WriteBool(Section, "LineVis " + LtoS(nLine++), *vi);
...
From this I get the following error message:
error C2677: binary '+' : no global operator found which takes type 'LtoS' (or there is no acceptable conversion)
Any idea how this code ever worked? If I can find out what it did in the past, I can begin to define the overloaded operator+ to match the functionality.
Compiler error goes away when I make class tos inherit from CString with:
class tos : public CString { ... }
Hopefully this will not only compile, but will execute correctly...
Deriving from several of the comments, try adding a public conversion operator to class toS as follows:
operator LPCTSTR() const { return &buff[0]; }
You may need to explicitly construct the string in the for loop as well, e.g.:
WriteBool(Section, CString("LineVis ") + static_cast<LPCTSTR>(LtoS(nLine++)), *vi);
(Side note: As you probably know since you just extracted code for an example, there's a problem here:
std::vector<bool> BoolVect;
...
for (vi = BoolVect->begin(); vi != BoolVect->end(); vi++)
The notation you're using to access the BoolVect implies that it is a pointer, but it's not being declared as such in your example.)
I try to create a managed C++ assembly in VS 2010 to interface with WinAPI and use it in my other C# assemblies. I've read all posts, even searched in code in GitHub, with no success.
Maybe its about the __clrcall in the error message, should not it be __stdcall? Any ideas?
The exact error message is:
error C2440: '=' : cannot convert from 'LRESULT (__clrcall xxx::Win32Demo::* )(HWND,UINT,WPARAM,LPARAM)' to 'WNDPROC'
The source code:
#pragma once
using namespace System;
using namespace System::Drawing;
#include "stdafx.h"
#include "windows.h"
namespace xxx
{
ref class Win32Demo
{
private: HWND__ * handle;
private: static Char * windowClass;
public:
Win32Demo(void)
{
}
static Win32Demo()
{
tagWNDCLASSEXW w;
windowClass = (wchar_t*) L"Hello";
w.cbSize = sizeof(tagWNDCLASSEXW);
w.style = 0x803;
w.lpfnWndProc = WindowProc; // Error
w.cbClsExtra = 0;
w.cbWndExtra = 0;
w.hInstance = 0;
w.hIcon = 0;
w.hCursor = 0;
w.hbrBackground = CreateSolidBrush(0);
w.lpszMenuName = NULL;
w.lpszClassName = windowClass;
w.hIconSm = 0;
}
public :
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return 0;
}
};
}
This goes wrong because your WndProc() function is being compiled to IL, not machine code. Which happened because you compile it with /clr in effect. It is not just a compile time error, it also cannot work at runtime. Windows doesn't know how to call a managed method, not without the kind of help you get from Marshal::GetFunctionPointerForDelegate().
It is better to just not go there. Either move this code in a separate .cpp file that you compile without the /clr option. Or use #pragma managed(push, off) before this code so that it gets compiled to machine code instead of IL.
And consider the managed class wrappers that give you the same kind of functionality. Like the classes in the System.Windows.Forms namespace. Or if you want to keep this code then derive your own class from the NativeWindow class to attach the window handle, allowing you to override WndProc() with managed code.
Apparently the __stdcall calling convention is not supported for methods of managed classes. So you'll need to put WindowProc inside an unmanaged class:
class WindowProcCallback
{
public:
static LRESULT __stdcall WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
...
}
};
ref class Win32Demo
{
...
};
One suggestion: turn on warnings so that you get warnings about stuff like this. With warnings you would have gotten the following warning:
warning C4441: calling convention of '__stdcall ' ignored; '__clrcall ' used instead
//Block.h
#pragma once
class Block
{
public:
CRect pos;
int num;
public:
Block(void);
~Block(void);
};
//view class
public:
Block currentState[5]; // stores the current state of the blocks
void CpuzzleView::OnDraw(CDC* pDC)
{
CpuzzleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
//draw the 4 blocks and put text into them
for(int i=0;i<4;i++)
{
pDC->Rectangle(currentState[i].pos);
// i'm getting an error for this line:
pDC->TextOut(currentState[i].pos.CenterPoint(), currentState[i].num);
}
pDC->TextOut(currentState[i].pos.CenterPoint(), currentState[i].num);
The error says that no instance of overloaded function CDC::TextOutW() matches the argument list . But the prototype for the function is:
CDC::TextOutW(int x, int y, const CString &str )
all i've done is that instead of the 2 points i've directly given the point object returned by CenterPoint() ... shouldn't it work?
That's because you didn't supplied arguments list correctly. Please read compiler error message carefully, it's usually helps to solve the problem.
TextOut(currentState[i].pos.CenterPoint(), currentState[i].num);
In this call you passed CPoint object and int. This is not correct, you need to pass int, int and CString (or const char* and int length).
To fix this you shall do something like this:
CString strState;
strState.Format("%d", currentState[i].num); // Or use atoi()/wtoi() functions
TextOut(currentState[i].pos.CenterPoint().x, currentState[i].pos.CenterPoint().x, strState);
I am learning myself to load DLL files at run time and call functions from there.
For a start, I decided to pick mathematical cosf function. After some searching I learned that all mathematical functions can be found in msvcr100.dll. So here is code that I have written:
#include <stdio.h>
#include <Windows.h>
FARPROC getEntry(HMODULE &m, const char* name) {
FARPROC p=GetProcAddress(m, name);
if (!p) {
printf("Error: Entry %s not found\n", name);
printf("Error code: %d\n",GetLastError());
exit(1);
} else
printf("Entry %s loaded\n", name);
return p;
}
int main() {
HMODULE msvcr = LoadLibraryA("msvcr100.dll");
if (!msvcr)
printf("File msvcr100.dll not found\n");
else
printf("msvcr100.dll loaded\n");
FARPROC fun = getEntry(msvcr, "cos");
FARPROC fun2 = getEntry(msvcr, "cosf");
FreeLibrary(msvcr);
return 0;
}
If I run it, I get the following output:
msvcr100.dll loaded
Entry cos loaded
Error: Entry cosf not found
Error code: 127
Why?
Error code 127 stand for ERROR_PROC_NOT_FOUND -- The specified procedure could not be found.
According to Dependency Walker, there is a cosf function inside MSVCR100.DLL. Ordinal number 1349, Entry Point 0xC2750.
The function name does not seem to be mangled.
Both 'cos' and 'cosf' are listed in the run-time library function reference: http://msdn.microsoft.com/en-us/library/ydcbat90.aspx
What am I missing?
If I should use a different dll for cosf -- which one is it?
cos takes doubles, I need a function which takes floats.
Thank you!
From the <math.h> header file:
inline float cosf(_In_ float _X)
{return ((float)cos((double)_X)); }
Or in other words, it is an inline function that actually uses cos(). And thus isn't exported from the DLL.