DirectX 8 Under Windows 2000 Problem!

Started by
5 comments, last by AndyTX 22 years, 8 months ago
I have created a program using the DirectX 8 SDK that uses DirectDraw (sorry), DirectSound, DirectInput and DirectMusic. It all works perfectly under Windows 98 for myself and others. However, when I try to run it under Windows 2000 (with DX8 installed), I right away get an error like: "Cannot find ordinal 21 in DDRAW.DLL". And the program quits. I should mention that I am using LIB files that I created with IMPLIB and compiling under Borland C++ Builder 5, but this has never posed a problem in the past. I''m completely stuck on this one as I don''t know much about DirectX under Windows 2000, and every other DirectX program seems to be compatible with both OSs... Do I have to re-IMPLIB the DirectX DLLs in Windows 2000? If so, does that mean I have to compile separate programs for each OS? Any help would be much appreciated. Thanks in advance.
Advertisement
Actually one more thing. To help get me to get on the right track (or any track), does anyone have any idea whatsoever what that error means? What is "ordinal 21" and why does it work under Win98?

Thanks all.
Ordinals are a now obsolete way of referring to functions you want to import from a DLL.

A DLL contains a set of "exported" functions, these are the ones available for external programs to use.

Stored in the DLL is a table of these exports which has one entry per exported function, the table has the ASCII name of the export (such as "DirectDrawCreateEx").
As well as the name it has a reference number for that function called an ordinal. Ordinals were from the Windows 3.1 days, but are still included in DLLs for backwards compatibility.

The problem with referring to an export by its ordinal is if a new function is added to a DLL after you build the dependent app, there is a chance the ordinal will have changed. For (hypothetical) example:

Version 1.01 of MyDLL.DLL:
"MyExportedFunction1", Ordinal = 30
"MyExportedFunction2", Ordinal = 31
"MyExportedFunction3", Ordinal = 32

Version 1.02 of MyDLL.DLL:
"MyExportedFunction1", Ordinal = 30
"SpecialPatchFunction",Ordinal = 31
"MyExportedFunction2", Ordinal = 32
"MyExportedFunction3", Ordinal = 33


If your application refers to MyExportedFunction2 using its ordinal, when a new function is added, its possible the ordinal changed... boom... broblems

An equal problem would be if a function were removed in a newer version of a DLL, say your import library referred to ordinal 33, then you tried to run the code on the old DLL, you''d get en error similar to the one you''re experiencing.

With a DirectX app, once its built, as long as a high enough version is on the target machine you only need one app for all versions of Windows (bar 3.1, WFW or Win32s but nobody uses them any more ;-)


Now for some ideas about what is going on:

1. Either you have an old version of IMPLIB which only handles ordinals, or maybe the parameters you''ve passed it specify you want to make an import library which uses ordinals instead of symbols. For modern Windows programming always use named exports, never use ordinals!.

2. DirectX 8 didn''t install properly on the Windows2000 machine - if it still had say DirectX 7 on, then the DLL your app might be referring to could be wrong.

3. Are you explicitly loading the DDRAW DLL with LoadLibrary or are you only using import libraries - if you are doing it manually, see the above - DON''T refer to exports with ordinal values.

4. Which entry points are you using for DDraw... It should be DirectDrawCreateEx, DirectDrawCreate and similar (ie. the ones in the SDK documentation). The DLL does export a lot of others but they''re for communication with other components of DirectX, don''t use them. (e.g. DdEntry1 etc).

5. If you IMPLIBed with and the resultant library creates ordinals, if you did it to a debug version of the DLL from the SDK, a retail version of the DLL on a target machine would be different (ie. have less ordinals etc).


HTH

--
Simon O''''Connor
Creative Asylum Ltd
www.creative-asylum.com

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

Wow! Lots of very helpful info. That you very very much! I owe you big time

Something you said to gives me an idea on something to check. It is remotely possible that it used the implib from Borland C++ 5.0 which I also had installed... I don''t know if this used ordinals, but I should re-IMPLIB it with the latest version.

Also, I do use import libraries and as far as I know, I don''t use ordinals, but maybe it is doing it behind my back. Also, I use DirectDrawCreateEx to create DDraw and I have never touched any Debug DLLS (they aren''t usually compatible with Borland). However, thanks a lot for the suggestions.

What I think I''ll do is re-IMPLIB the DLLS from Windows 2000, recompile the program under 2000 and hope everything works. If so, I''ll check if it works under 98 still.

Thanks so very much for all your help. That actually clears up some questions I had about DLLs too!
Something else to note, it''s generally a bad idea to use DirectDrawCreate or DirectDrawCreateEx due to version incompatibilities. (For example, if you link against these functions and try to load on an earlier version of directx, it''ll produce an error similar to what you''re seeing, but no custom error handling. Maybe EHable, but who knows?) It''s also possible on later libraries that these functions may be deprecated.

Might be better off (on the whole) using COM to instantiate directx. For example:

HRESULT hr = S_OK;
LPDIRECTDRAW7 pDD = NULL;


CoInitialize(NULL);
hr = CoCreateInstance(CLSID_DirectDraw7, NULL, CLSCTX_INPROC,
IID_IDirectDraw7, &pDD);

if(FAILED(hr))
{
// Error, etc
}
else
{
Assert(pDD != NULL); // etc.
}

You''re not going to find a version of windows without coinitialize or cocreateinstance (maybe 3.1?), so relying on that isn''t a bad thing.
Cool, thanks for the code. Actually, I may use that because it is kind of annoying to require people to get DirectX 8 to use my DirectDraw applications... heh.

On another note, I finished re-IMPLIBing the libraries and I used the ''-f'' option which states:
-f - Force imports by name (with hints)

And guess what? It compiles and works fine in Windows 2000 now! And also, it works in Windows 98 still! I''m not sure if the -f actually did anything, but it all works now. I''m so glad you guys helped me.

Thanks again for all your help and support
The code which GregoryHermann posts is one way to do it, although due to the IDirectDraw7 IID it still requires DirectX 7 to be installed on a machine to succeed. The advantage is you can present a much more meaningful message to the user, so instead of "Cannot find Ordinal 21" (which doesn''t even mean much to other programmers) you get a chance to pop up a "This application requires at least DirectX 7 to be installed" box.

An alternative to using the above COM interface solution is to load the DLL explicitly with LoadLibrary() and search for relevent entry points with GetProcAddress().

The CoCreateInstance does the same sort of thing - it searches the registry (HKEY_CLASSES_ROOT etc) for the matching IID (CLSID) which tells it which DLL to load, it then uses a special entry point which tells it how to instansiate a DDraw object.

When using either of these methods, you should make sure you remove the imported library from the build or the hardcoded dependency on the specific DLL will remain.


--
Simon O''''Connor
Creative Asylum Ltd
www.creative-asylum.com

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

This topic is closed to new replies.

Advertisement