Author Topic: MSVC runtime problem  (Read 16402 times)

0 Members and 1 Guest are viewing this topic.

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
MSVC runtime problem
« on: June 30, 2008 »
Hi all,

I've been working through the tutorials at directxtutorial.com along with the book "Introduction to 3d Game Programming with DirectX 9.0c" by Frank Luna, in order to get my first spinny cube working.  Well I managed it, and managed to get uFMOD working for some music at the same time.

The problem I've come across is trying to distribute it.  When I try to run a release executable (compiled in VS2008) on my other PC, I get the error, "This application has failed to start because the application configuration is incorrect".  Some googling indicates that this is a problem with the VC runtime files and can be solved by either A) installing the VC redistributable on the target machine, B) distributing the runtime files and a manifest along with my program, or C) statically linking the runtime libraries.  I don't want to do A or B and doing C causes my compiled exe to grow considerably (and it still didn't work; the target machine then complained that d3dx9_37.dll couldn't be found - it has directx9.0c installed though?).

Can anyone shed any light on how I can overcome this?  Is there a way that I can remove the dependency on the VC runtime libraries?

Let me know if seeing the code would help and I'll post it for you. :)

Edit: ok, I fixed the missing d3d dll issue when statically linking, it was due to me using a newer SDK version than the redistributable version on my other PC.  Installing the June 2008 redistributable fixed it.  Should I be using an older SDK version to try and avoid that issue?  Anyway, that only resolved the missing dll issue, now it just crashes and asks if I want to send the dump to microsoft.  That aside, I still don't want to be statically linking those libraries, so I'm no further forward.  :-\
« Last Edit: June 30, 2008 by Naptha »

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: MSVC runtime problem
« Reply #1 on: June 30, 2008 »
If you link statically, all the required functions from the runtime-dlls are included into your binary; size grows - significantly.
you can either:
- link dynamically and advise the user to install the corresponding vc-redist
- implement small versions of the functions yourself (usually just some math/malloc/entrypoint-stuff is required)
- link with msvcrt.lib from vs2003 (those dlls are already included with winxp)

with every update of the dx-sdk (every few month), the d3dx9-dlls get updated, too.
you can either:
- expect the user to update, too
- deliver the required version of the dll with your binary
- don't use d3dx (and implement the required things yourself)
- use opengl instead ;)
Challenge Trophies Won:

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: MSVC runtime problem
« Reply #2 on: June 30, 2008 »
If you link statically, all the required functions from the runtime-dlls are included into your binary; size grows - significantly.
you can either:
- link dynamically and advise the user to install the corresponding vc-redist
- implement small versions of the functions yourself (usually just some math/malloc/entrypoint-stuff is required)
- link with msvcrt.lib from vs2003 (those dlls are already included with winxp)

with every update of the dx-sdk (every few month), the d3dx9-dlls get updated, too.
you can either:
- expect the user to update, too
- deliver the required version of the dll with your binary
- don't use d3dx (and implement the required things yourself)
- use opengl instead ;)


Thanks Hellfire, that sheds some light on it for me.  I'd suspected that writing my own version of the required functions might be one solution, but I'm not too sure how to go about that.  I'll try linking with msvcrt.lib first.  Anyone have other tips on how they've resolved this issue?

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: MSVC runtime problem
« Reply #3 on: June 30, 2008 »
Quote
writing my own functions [...] but I'm not too sure how to go
First of all tell your linker to ignore all libs.
Go through the errors and remove all calls you don't need and/or embed them in #defines for debug/release.
What is left are a couple of functions you need to implement (you can eg find some of the math-stuff on chaos' website) and some internal stuff (entry-point & setup) which is compiler/linker-specific (I'm still using VS2003/2005, not idea what's new/broken in 2008)...
However, implementing yourself also means more code-size, it'll be smaller to refer to the dlls - and it's even smaller not to call at all ;)
Challenge Trophies Won:

Offline AnimalMother

  • btst #6,$bfe001
  • Atari ST
  • ***
  • Posts: 113
  • Karma: 7
    • View Profile
Re: MSVC runtime problem
« Reply #4 on: June 30, 2008 »
I have the same problem with those bloated exe´s. I googled a bit and found a replacement for Visual C runtime library. -> http://wcrt.sourceforge.net/
The price for size is that not all c functions are supported, so refer to the manual.
But I would give it a try. I haven´t tested it yet but it sounds promissing.

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: MSVC runtime problem
« Reply #5 on: June 30, 2008 »
I've got C++ working without any CRT in VS2008, but when I crinkle it breaks the segment ordering required for the static initialisers to work.  Not sure whether it's even possible to fix that.

Jim
Challenge Trophies Won:

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: MSVC runtime problem
« Reply #6 on: July 06, 2008 »
Thanks for all the help so far! By ignoring default libs, removing some function calls and adding a custom WinMainCRTStartup() I have just one unresolved symbol remaining:

Code: [Select]
main.obj : error LNK2001: unresolved external symbol __fltused
I gather this is added whenever any floating point operations are carried out.  Without removing these operations, could anyone enlighten me as to how to resolve this?  I read somewhere that

Code: [Select]
int _fltused;
would resolve the linker problem, but it doesn't appear to have any effect.

EDIT: The following stopped the linker error:

Code: [Select]
extern "C"
{
int _fltused;
}

But then when it runs it reports unhandled exceptions at:

Code: [Select]
d3ddev->CreateVertexBuffer(24*sizeof(CUSTOMVERTEX), 0, CUSTOMFVF, D3DPOOL_MANAGED, &t_buffer, NULL);
« Last Edit: July 06, 2008 by Naptha »

Offline rain_storm

  • Here comes the Rain
  • DBF Aficionado
  • ******
  • Posts: 3088
  • Karma: 182
  • Rain never hurt nobody
    • View Profile
    • org_100h
Re: MSVC runtime problem
« Reply #7 on: July 06, 2008 »
something in your code wants to use floats? without the c runtime you no longer have math functions so you need to provide your own implementations this can be achieved with inline asm.

Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: MSVC runtime problem
« Reply #8 on: July 06, 2008 »
Your solution for __fltused is correct - just create an int of that name.
I don't think it's related to the CreateVertexBuffer.
Have you done something with the __chkstk and other C++ things yet?

Jim
Challenge Trophies Won:

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: MSVC runtime problem
« Reply #9 on: July 07, 2008 »
Great help again guys - now able to compile and run successfully with /NODEFAULTLIB.  :||  Still to test it on my other PC though - suspect I may still some directx version issues to iron out.

After some googling I realised the exceptions were being caused by two missing calls to ZeroMemory.  I replaced them with calls to the following function which I added:
Code: [Select]
__forceinline void _MEMSET_( void *_dst, int _val, size_t _sz )
{
   while ( _sz ) ((BYTE *)_dst)[--_sz] = _val;
}

Jim: don't recall seeing any unresolved symbol __chkstk, unless that was one of the RTCs.  I eliminated them by turning off runtime checks.

rain_storm: I thought that might be an issue, and I googled around and found some useful info which could help in future.  In this instance I don't actually do any floating point math in my code so there were no unresolved symbols except for __fltused, which from what I gather is generated if you even declare a float.

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: MSVC runtime problem
« Reply #10 on: July 07, 2008 »
The __chkstk stuff I see is in VS2008, C++ code, where it's needed to hit the stack pages which need to be allocated.  I remember understanding this stuff once, but I've forgotten the details...

There are a number of other artifacts you need for VS2008 C++, which I am happy to share details about.  I also have a party complete tiny C runtime library which I am more than happy to post here, it uses Windows API for file and memory handling, and little custom routines for many other useful things.

With crinkler I am able to get my DBF competition demos which were 60 or 70Kb down to 10-12Kb, even though I didn't write them with size coding in mind at all - no optimisation.  The only thing missing is the static initialisers.  That's just because crinkler doesn't order/merge segments the same way as Microsoft's linker.  It's not a big problem since I can initialise the thing manually, I was just trying to automate it all :)
The problem is .CRT$XIA is supposed to come before .CRT$XIZ and any initializers are meant to be alphabetically ordered, segment name-wise, in between them, so my one ends up in .CRT$XIU.
With kkrunkchy I can only get to 25Kb.

crt.zip attached - it's very green and sloppy, I hardly expect any of it to work right, but it's enough to support 6 out of 10 of my demos.  Cut and paste what you need.  The atof and float to string have come from the web - if you use them you need to credit.

Jim
Challenge Trophies Won:

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: MSVC runtime problem
« Reply #11 on: July 07, 2008 »
Thanks Jim, that should be very useful. :)

I tried out Crinkler but couldn't link successfully using it.  It says it can't load MAIN.OBJ, although the file is created right where it should be.  ???

Edit: Disregard that, I remembered that I came across that last night and found it was down to whole program optimisation being turned on.  Now I get:
Quote
: fatal error: LNK   0: import 'HeapAlloc' from 'kernel32' uses forwarded RVA. This feature is not supported by crinkler (yet)

It's mentioned in the Crinkler docs:
Quote
The import code does not support forwarded RVA imports, which means that some functions, such as HeapAlloc, cannot be used. This makes Crinkler unable to link with libc. What a loss.

But I'm unsure exactly how to prevent it trying to link kernel32.lib.  ???

I wanted to give Crinkler a go to see if the /REPLACEDLL option could be used to resolve D3DX version issues as the docs suggest.
« Last Edit: July 07, 2008 by Naptha »

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: MSVC runtime problem
« Reply #12 on: July 07, 2008 »
Go to Project->Properties->Configuration Properties->Linker->Input
and add the library file names in to the Additional Dependencies box.

I found some code on the web that used HeapAlloc but as you say, crinkler doesn't like that, so I went back to old school Win32.
Code: [Select]
void *malloc(size_t size)
{
//return HeapAlloc(GetProcessHeap(), 0, size);
return GlobalAlloc(GMEM_FIXED, size);
}

void free(void *memblock)
{
//HeapFree(GetProcessHeap(), 0, memblock);
GlobalFree(memblock);
}

Jim
Challenge Trophies Won:

Offline Rbz

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 2757
  • Karma: 493
    • View Profile
    • https://www.rbraz.com/
Re: MSVC runtime problem
« Reply #13 on: July 08, 2008 »
@Naptha: Check out this dx9 framework that I did sometime ago, maybe it can help you...

http://www.rbraz.com/source/1K_DX9_FrameWork_VC2005.zip
Challenge Trophies Won:

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: MSVC runtime problem
« Reply #14 on: July 08, 2008 »
@Naptha: Check out this dx9 framework that I did sometime ago, maybe it can help you...

http://www.rbraz.com/source/1K_DX9_FrameWork_VC2005.zip

That is very nice indeed, gave me plenty of pointers on where I can tidy things up.  ;D

So the problem I was left with, after removing dependency on the VC runtimes and getting the correct version of DirectX installed on the target, was inexplicable crashes.  A bit of thinking lead me to the conclusion that since I have no compatability code in there, I probably shouldn't be arbitrarily setting hardware vertex processing, pure devices, or multisampling.  :-[  Changing those settings got it working fine.  Thanks for all the help.  :cheers:

I'd still like to try Crinkler, but I'm still a little confused about the HeapAlloc error - as far as I can see, I don't have any calls to HeapAlloc.  ???

Anyway, since it's now working at least, here's the code I've pieced together so far:

Code: [Select]
extern "C"
{
int _fltused;
}

#include <d3d9.h>
#include <d3dx9.h>
#include <mmsystem.h>
#include "ufmod.h"

#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)

LPDIRECT3D9 g_pD3D;
LPDIRECT3DDEVICE9 g_pD3DDev;
LPDIRECT3DVERTEXBUFFER9 g_pVBuffer = NULL;   
HWAVEOUT* g_pHWave = NULL;

void initD3D(HWND hWnd);
void renderFrame(void);
void initGraphics(void);

struct CUSTOMVERTEX {FLOAT X, Y, Z; DWORD COLOR;};

__forceinline void _MEMSET_( void *_dst, int _val, size_t _sz )
{
   while ( _sz ) ((BYTE *)_dst)[--_sz] = _val;
}

void WinMainCRTStartup()
{
    HWND  hWnd = ( CreateWindowEx(WS_EX_TOPMOST, "edit",0,0,0,0,0,0,0,0,0,0) );

    initD3D(hWnd);

g_pHWave = uFMOD_PlaySong("song.xm", 0, XM_FILE);

ShowCursor(FALSE);

while (!KEY_DOWN(VK_ESCAPE))
{
renderFrame();
}

uFMOD_StopSong();

ExitProcess(0);
}

void initD3D(HWND hWnd)
{
    g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);

    D3DPRESENT_PARAMETERS d3dpp;

    _MEMSET_(&d3dpp, 0, sizeof(d3dpp));
    d3dpp.Windowed = FALSE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
    d3dpp.BackBufferHeight = SCREEN_HEIGHT;
d3dpp.MultiSampleType = D3DMULTISAMPLE_2_SAMPLES;
d3dpp.MultiSampleQuality = 0;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

    g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,
                      D3DDEVTYPE_HAL,
                      hWnd,
                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                      &d3dpp,
                      &g_pD3DDev);

initGraphics();

g_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE);
g_pD3DDev->SetRenderState(D3DRS_ZENABLE, TRUE);

    return;
}

void initGraphics(void)
{

CUSTOMVERTEX t_vert[] =
{
// side 1
{ -3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 255), },

// side 2
{ -3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 255), },

// side 3
{ -3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 255), },

// side 4
{ -3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 255), },

// side 5
{ 3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 255), },

// side 6
{ -3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ -3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 255), },
};

g_pD3DDev->CreateVertexBuffer(24*sizeof(CUSTOMVERTEX),
   0,
   CUSTOMFVF,
   D3DPOOL_MANAGED,
   &g_pVBuffer,
   NULL);

    VOID* pVoid;

    g_pVBuffer->Lock(0, 0, (void**)&pVoid, 0);
    memcpy(pVoid, t_vert, sizeof(t_vert));
    g_pVBuffer->Unlock();

    return;
}

void renderFrame(void)
{

    g_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
g_pD3DDev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

    g_pD3DDev->BeginScene();

g_pD3DDev->SetFVF(CUSTOMFVF);

static float xIndex = 0.0f; xIndex += 0.02f;
static float yIndex = 0.0f; yIndex += 0.04f;
D3DXMATRIX matRotateY;
D3DXMATRIX matRotateX;
D3DXMatrixRotationY(&matRotateY, yIndex);
D3DXMatrixRotationX(&matRotateX, xIndex);
g_pD3DDev->SetTransform(D3DTS_WORLD, &(matRotateY * matRotateX));

D3DXMATRIX matView;
D3DXMatrixLookAtLH(&matView,
   &D3DXVECTOR3 (0.0f, 0.0f, 20.0f),    // the camera position
   &D3DXVECTOR3 (0.0f, 0.0f, 0.0f),    // the look-at position
   &D3DXVECTOR3 (0.0f, 1.0f, 0.0f));    // the up direction

g_pD3DDev->SetTransform(D3DTS_VIEW, &matView);

D3DXMATRIX matProjection;

D3DXMatrixPerspectiveFovLH(&matProjection,
   D3DXToRadian(45),    // the horizontal field of view
   (FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // aspect ratio
   1.0f,    // the near view-plane
   100.0f);    // the far view-plane

g_pD3DDev->SetTransform(D3DTS_PROJECTION, &matProjection);

g_pD3DDev->SetStreamSource(0, g_pVBuffer, 0, sizeof(CUSTOMVERTEX));
g_pD3DDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
g_pD3DDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2);
g_pD3DDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 8, 2);
g_pD3DDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 12, 2);
g_pD3DDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 16, 2);
g_pD3DDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 20, 2);

    g_pD3DDev->EndScene();

    g_pD3DDev->Present(NULL, NULL, NULL, NULL);

    return;
}

There are still a couple of things I want to add once I learn them, like using indices to clean up the vertex code.

Edit: I just noticed I still have a memcpy in there, I assume that works because it's an intrinsic?
« Last Edit: July 08, 2008 by Naptha »

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: MSVC runtime problem
« Reply #15 on: July 08, 2008 »
re: memcpy - Either that or it inlined it.
re: HeapAlloc - if ufmod is a static library it may well want HeapAlloc.

Jim
Challenge Trophies Won:

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: MSVC runtime problem
« Reply #16 on: July 08, 2008 »
re: HeapAlloc - if ufmod is a static library it may well want HeapAlloc.

And indeed it does:
Code: [Select]
; Dynamic memory allocation
alloc:
; EAX: how many bytes to allocate
push eax
push 9 ; HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE
push DWORD PTR [hHeap]
call HeapAlloc
test eax,eax
jnz alloc_R
pop edx ; EIP
pop ebx
leave
So my only option would then be to amend that (somehow  ???) and recompile uFMOD?

Sorry to be a pain, if I'm asking too many questions, just tell me to shut up.  :-[
« Last Edit: July 08, 2008 by Naptha »

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: MSVC runtime problem
« Reply #17 on: July 08, 2008 »
Nasty!  Ideally you grab the source for ufmod and replace the HeapAlloc with GlobalAlloc.  If that's not possible it may be possible to patch it, with some effort.  Or, find another player that has source or doesn't use HeapAlloc.
Please, keep asking questions!  It's a great way for us all to learn :)

Jim
Challenge Trophies Won:

Offline Naptha

  • C= 64
  • **
  • Posts: 53
  • Karma: 3
    • View Profile
Re: MSVC runtime problem
« Reply #18 on: July 08, 2008 »
Nasty!  Ideally you grab the source for ufmod and replace the HeapAlloc with GlobalAlloc.  If that's not possible it may be possible to patch it, with some effort.  Or, find another player that has source or doesn't use HeapAlloc.
Please, keep asking questions!  It's a great way for us all to learn :)

Jim


Ok! So, I guessed from your previous example that GlobalAlloc might be the way to go.  Fortunately ufmod does come with the assembler source, now all I need to do is learn enough assembly to figure out how the parameters for HeapAlloc are passed, and then change them to suit a call to GlobalAlloc.  Some more googling I think...

In the meantime, if anyone has a suggestion for another tracker lib I could try please let me know. ;)

Offline benny!

  • Senior Member
  • DBF Aficionado
  • ********
  • Posts: 4384
  • Karma: 228
  • in this place forever!
    • View Profile
    • bennyschuetz.com - mycroBlog
Re: MSVC runtime problem
« Reply #19 on: July 08, 2008 »
...

In the meantime, if anyone has a suggestion for another
tracker lib I could try please let me know. ;)

What about minifmod ?
[ mycroBLOG - POUET :: whatever keeps us longing - for another breath of air - is getting rare ]

Challenge Trophies Won: