I suspect you might be right that it can be done in a single statement, but for myself, I seldom get too fancy if there is a conceptually simpler 'brute force' way to do it, so I always first do a SELECT count(*) type statement to see if the return is zero or non-zero, then follow that with an if depending on the prior outcome.
Frederick2 189 Posting Whiz
Looks like we cross posted. But yes, do your own thing for sure. I am only posting this code to give you some new ideas. I know its a lot to absorb.
One thing you might not be aware of is that Windows has a date/time entity - SYSTEMTIME I believe, which stores both time and date in one struct.
Also, I'm not sure I'd use a text file for this. But since you first mentioned that was what you were using and the problems you were having with it, that's why I decided to show how it might be done that way.
If binary data was used then it wouldn't be necessary to read the entire file into memory. You could just move through the file looking for what you need. But a whole binary (random access flat file) file could be read into memory like a text file. In that case you would'nt need a multi-dimensional array, but a single dimension array of a class/struct type, i.e.,
struct MyAppointments
{
double dblDateTime;
char szDescription[56];
};
Or whatever, and you would make an array of those...
MyAppointments* pMyAppointments = new [] MyAppointments[iNumber];
Or something like that. And others have mentioned relational databases. So there's lots of ways of attacking it.
Frederick2 189 Posting Whiz
One last thing. In the includes you at the top of the main program I just posted is CArray.h. That is simply the CArray Class I posted twice today. You can copy that to a seperate text file and name it CArray.h, or just put that code in the main source code file Main.cpp.
I tried copying my mangled code out of a post into Notepad and it came out OK, so the dog's breakfast this forum software makes of my code can be rectified apparently.
Frederick2 189 Posting Whiz
// Main.cpp
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#include <windows.h>
#include <cstdio>
#include <new>
#include "Strings.h"
#include "Carray.h"
size_t iGetRecordCount(FILE* fp) // This function simply returns
{ // the number of lines found in
wchar_t szBuffer[128]; // a text file. Need to pass in
size_t iCtr=0; // valid cstdio FILE* object.
while(!feof(fp))
{
fgetws(szBuffer,128,fp);
iCtr++;
}
return iCtr;
}
template <typename t1> void PrintData(CArray<t1>& strAr) // This function shows how to pass templated objects
{ // through parameter list. Note here it is passing
for(int i=0; i<=strAr.UBound(1); i++) // a CArray object By Reference, which is our two
{ // dimensional array of my String Class objects. It
strAr(i,0).Print(false); // simply outputs these to console. Note its using
strAr(i,1).Print((wchar_t*)L"\t\t",false); // overloaded String Class Print() methods.
strAr(i,2).Print((wchar_t*)L"\t",true);
}
}
int main()
{
size_t iParseCount=0; // For obtaining the number of semicolon delimited fields in a text file line
wchar_t szBuffer[128]; // To hold line reada text file. in from text file through C Runtime getws()
size_t iRecCt=0; // For holding the number of lines of data in the data file
String strLine; // An object of my String Class type. szBuffer contents to be reassigned to this
FILE* fp=NULL; // C Std. Lib. FILE object (in cstdio.h)
fp=fopen("Data.dat","r"); // Open data file containing 5 lines
if(fp) // If successfully opened, find out how many records/lines are in it
{ // Then output to console that number. Then rewind() to set file
iRecCt=iGetRecordCount(fp); // pointer to beginning …
Frederick2 189 Posting Whiz
// Strings.cpp
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#define NEW_GCC
#include <windows.h>
#include <stdlib.h>
#include <cstdio>
#include <tchar.h>
#include <math.h>
#include <string.h>
#include "Strings.h"
#ifdef MyDebug
extern FILE* fp;
#endif
String operator+(TCHAR* lhs, String& rhs) //global function
{
String sr=lhs;
sr=sr+rhs;
return sr;
}
String Str(double dblNum)
{
return dblNum;
}
#ifdef x64
String Str(int iNum)
{
return iNum;
}
String Str(unsigned int iNum)
{
return iNum;
}
String Str(SSIZE_T iNum)
{
return iNum;
}
String Str(size_t iNum)
{
return iNum;
}
#else
String Str(int iNum)
{
return iNum;
}
String Str(unsigned int iNum)
{
return iNum;
}
#endif
String::String()
{
lpBuffer=new TCHAR[MINIMUM_ALLOCATION];
lpBuffer[0]=_T('\0');
this->iCapacity=MINIMUM_ALLOCATION-1;
this->iLen=0;
}
String::String(const TCHAR ch) //Constructor: Initializes
{ //with TCHAR
this->iLen=1;
int iNewSize=MINIMUM_ALLOCATION;
this->lpBuffer=new TCHAR[iNewSize];
this->iCapacity=iNewSize-1;
this->lpBuffer[0]=ch, this->lpBuffer[1]=_T('\0');
}
String::String(const TCHAR* pStr) //Constructor: Initializes
{ //with TCHAR*
this->iLen=(int)_tcslen(pStr);
int iNewSize=(this->iLen/16+1)*16;
this->lpBuffer=new TCHAR[iNewSize];
this->iCapacity=iNewSize-1;
_tcscpy(lpBuffer,pStr);
}
String::String(const String& s) //Constructor Initializes With
{ //Another String, i.e., Copy Constructor
int iNewSize=(s.iLen/16+1)*16;
this->iLen=s.iLen;
this->lpBuffer=new TCHAR[iNewSize];
this->iCapacity=iNewSize-1;
_tcscpy(this->lpBuffer,s.lpBuffer);
}
String::String(const int iSize, bool blnFillNulls) //Constructor Creates String With Custom Sized
{ //Buffer (rounded up to paragraph boundary)
int iNewSize=(iSize/16+1)*16;
this->lpBuffer=new TCHAR[iNewSize];
this->iCapacity=iNewSize-1;
this->iLen=0;
this->lpBuffer[0]=_T('\0');
if(blnFillNulls)
{
for(size_t i=0; i<this->iCapacity; i++)
this->lpBuffer[i]=0;
}
}
String::String(int iCount, const TCHAR ch)
{
int iNewSize=(iCount/16+1)*16;
this->lpBuffer=new TCHAR[iNewSize];
this->iCapacity=iNewSize-1;
for(int i=0; i<iCount; i++)
this->lpBuffer[i]=ch;
this->lpBuffer[iCount]=_T('\0');
this->iLen=iCount;
}
String::String(int iNum)
{
this->lpBuffer=new TCHAR[16];
this->iCapacity=15;
this->iLen=_stprintf(this->lpBuffer,_T("%d"),iNum);
}
#ifdef x64
String::String(size_t iNum)
{
this->lpBuffer=new TCHAR[32];
this->iCapacity=31;
this->iLen=_stprintf(this->lpBuffer,_T("%llu"),iNum);
}
String::String(SSIZE_T iNum)
{
this->lpBuffer=new TCHAR[32];
this->iCapacity=31;
this->iLen=_stprintf(this->lpBuffer,_T("%lld"),iNum);
}
#endif
String::String(unsigned int iNum)
{
this->lpBuffer=new …
Frederick2 189 Posting Whiz
//Strings.h
#ifndef Strings_h
#define Strings_h
#define EXPANSION_FACTOR 2
#define MINIMUM_ALLOCATION 16
#define x64
class String
{
public:
String(); //Uninitialized Constructor
String(const TCHAR); //Constructor Initializes With A TCHAR.
String(const TCHAR*); //Constructor Initializes String With TCHAR*
String(const String&); //Constructor Initializes String With Another String (Copy Constructor)
String(const int, bool); //Constructor Creates String With User Specified Capacity and optionally nulls out
String(const int, const TCHAR); //Constructor initializes String with int # of TCHARs
String(int); //Constructor initializes String with int converted to String
#ifdef x64
String(size_t); //Constructor initializes String with size_t object converted to String
String(SSIZE_T);
#endif
String(unsigned int); //Constructor initializes String with unsigned int converted to String
String(double); //Constructor initializes String with double converted to String
String& operator=(const TCHAR); //Assign A TCHAR To A String
String& operator=(const TCHAR*); //Assign A Null Terminated TCHARacter Array To A String
String& operator=(const String&); //Assigns Another String To this One
String& operator=(int iNum); //Assigns an unsigned int to a String
#ifdef x64
String& operator=(size_t iNum); //Assigns a size_t integral object to a String
String& operator=(SSIZE_T iNum); //Assigns a SSIZE_T integral object to a String
#endif
String& operator=(unsigned int iNum); //Assigns an unsigned int to a String
String& operator=(double dblNum); //Assign a double to a String
String operator+(const TCHAR); //For adding TCHAR to String
String operator+(const TCHAR*); //Adds a TCHAR* to this
String operator+(String&); //Adds another String to this
String& operator+=(const TCHAR ch); //Add TCHAR to this
String& operator+=(const String&); //Adds a String to this and assigns it to left of equal sign
String& operator+=(const TCHAR*); //Adds …
Frederick2 189 Posting Whiz
Hello again CuriousGeorge. In this, my last major code post, is a complete example of starting with a data file such as this ...
9:00 AM; 1/15/2015; Dentist Appointment at 9:00 AM|
7:00 PM; 1/21/2015; Date with Cindy|
8:00 PM; 2/12/2015; Concert at Tom T Hall|
3:00 PM; 6/1/2015; Graduate From College|
9:00 AM; 6/2/2015; Start Six Figure coding job|
...named Data.dat, and parsing it into a 5 x 3 dynamic String array giving (iRow, iCol) access to the individual array elements. So to use this example copy that data to a text file and save it to your working directory as "Data.dat".
Now, here's the ringer. I don't use anything whatsoever from the C++ Standard Library. I wrote that off over a decade ago. I have my own classes for everything I do from database access to String Classes and everything in between. So those Parse(), ParseCount(), Trim(), etc., functions I previously posted were simply altered forms of code in C form from my String Class, which I'll attempt to post in its entirety.
What might have been better for me to do would be to just use the string class <string> from the C++ Std. Lib. with that Parse() code and CArray code I posted, but I'd have to work at that a bit and I have this code ready.
Here are some issues to keep in mind about this code. There is a #define in Strings.h at top named #define x64. That needs …
Frederick2 189 Posting Whiz
Haven't posted here for about 4 years, so I'm trying to catch up! :)
In terms of the way you set out to solve your appointment app CuriousGeorge, i.e., parsing a delimited text file, you'll almost inevitably need to read the entirety of that text file into memory and operate upon it there during the time your app is running. In such an app, if the user has the option of editing records, adding new ones, etc., then upon closing the app the possibly edited data in memory would be written back to storage.
Now, since there likely will be more than one line in the underlying data file, and each line may be comprised of several colon, comma, etc., delimited fields, this data model suggests a two dimensional array. If there are 5 records, and each record contains three fields, then a 5 X 3 array would be efficient. But the thing is, the bare C and C++ languages without the Standard Libraries are pretty miserable at arrays. You would like your program to be able to handle an underlying data file with a variable number of lines in it. But you can't know the number of lines until the program is run. In Microsoft's C/C++ compiler multi-dimensional arrays have to have constant sizes, i.e., you can't specify variables in the array declaration. The GCC C/C++ compiler allows this, but there are other significant issues involved.
So lets see about solving this in an efficient C like manner. Once …
Frederick2 189 Posting Whiz
"I think I will give it another shot!"
That's what I was hoping. Its a program you should be able to do. But wait 'till I give you some array code. That's the final missing ingredient.
In terms of wchar_t, that's a typedef of an unsigned short int, which is something of an ideal construct for storing a wide character, i.e., what we usually think of as a UNICODE character. I mostly work in wide characters nowadays, and while I don't know I suspect a lot of others do to.
In terms of size_t, that's an operating system defined type that is 32 bits for x86 systems and 64 bits for x64 systems. Things being what they are right now, i.e., transitioning from x86 to x64 code, I test compile on x86 and x64 systems. I suspect there may be reasons not to use the size_t type as I do, but its something of a struggle for me to learn all the subtle nuances of the various variable types.
Yes, to a computer, the characters that we read are just numbers.
Frederick2 189 Posting Whiz
If you are still interested in this topic CuriousGeorge I’ll present some code that I believe might solve some of the specific issues you mentioned.
Here only about a month ago I removed a String::Parse method, as well as a couple others, out of my String Class, so that code could be used in a C like manner in cases where I didn’t want to compile the entirety of my String Class into my executable. Making my executables and dlls really small is something I glory in, and I’ll wear myself to a frazzle at times to accomplish it.
Anyway, taking your specific case, assume we have a text string comprised of three semicolon delimited fields such as this…
wchar_t szString[]=L"9:00 AM; 6/1/2015; Dentist Appointment";
Here is an example program showing how to separate those three fields out using only C isms and no high powered C++ stuff…
#include <cstdlib>
#include <cstdio>
#include <string.h>
size_t iParseCount(const wchar_t* pString, wchar_t cDelimiter)
{
int iCtr=0; //reflects # of strings delimited
const wchar_t* p; //by delimiter.
p=pString;
while(*p)
{
if(*p==cDelimiter)
iCtr++;
p++;
}
return ++iCtr;
}
void Parse(wchar_t** pStrings, const wchar_t* pDelimitedString, wchar_t cDelimiter)
{
wchar_t* pBuffer=NULL;
const wchar_t* c;
wchar_t* p;
size_t i=0;
pBuffer=(wchar_t*)malloc(wcslen(pDelimitedString)*sizeof(wchar_t)+sizeof(wchar_t));
if(pBuffer)
{
pBuffer[0]=0;
p=pBuffer;
c=pDelimitedString;
while(*c)
{
if(*c==cDelimiter)
{
pStrings[i]=(wchar_t*)malloc(wcslen(pBuffer)*sizeof(wchar_t)+sizeof(wchar_t));
wcscpy(pStrings[i],pBuffer);
p=pBuffer;
i++;
pBuffer[0]=0;
}
else
{
*p=*c, p++;
*p=0;
}
c++;
}
pStrings[i]=(wchar_t*)malloc(wcslen(pBuffer)*sizeof(wchar_t)+sizeof(wchar_t));
wcscpy(pStrings[i],pBuffer);
free(pBuffer);
}
}
void LTrim(wchar_t* pStr)
{
size_t iCt=0, iLen=0;
iLen=wcslen(pStr);
for(size_t i=0; i<iLen; i++)
{
if(pStr[i]==32 || pStr[i]==9)
iCt++; …
Frederick2 189 Posting Whiz
[QUOTE]
Do you have any Windows graphic library function calls ...
anything like this ...
move_to(int x, int y);
move_to(double x, double y);
draw_to(int x, int y);
draw_to(double x, double y);
etc... ?
[\QUOTE]
No, I infrequently need graphic calls in my apps, and while GDI is deprecated, I still use it directly on those rare occasions I do need to do any drawing.
Basically, I need relatively easy database access in my apps, and had always used ODBC directly going back to my C days in the 90s. At that time I had built my own wrappers around the ODBC function calls. Sometime after I taught myself C++ I converted that wrapper code to an ODBC class, and that works well for me.
In terms of dynamic multi-dimensional arrays, which are critical to my work (I need up to four dimensions), I created a templated class for that which operates after the basic model, where I’ve overloaded the ‘(‘ and ‘)’ operators so as to give me access like so …
Ar(2,4,6)
Instead of this C/C++ ism…
Ar[2][4][6].
I also like the way the basic family of languages handle strings, so I wrote my own string class which I use in place of the one in the C++ Standard Library. Its mosly wrappers around the C Standard Library string primitives, i.e., wcscpy(), wcscat(), wcslen(), etc. A lot of useful functions for dealing with apps such as the OP described I put in my string …
Frederick2 189 Posting Whiz
The other posters hit on all this,but I'd like to emphasize you need decent libraries to build business or technical applications reasonably easy in C++. This was a problem I faced early on in my C++ work (like 15 years ago), and my solution was to completely ditch the C++ Standard Library and write my own.
Arrays in C++ are pathetic compared to the capabilities offered by other languages. The same can be said of string management. And a lot of other things too.
If you would care to provide further details of the file structure you've come up with and a few more details of the app you are trying to build, I'd take a look at it and see if any of my library code (which I'd be happy to share) would help.
Basically, I do line of business and technical apps in C++ (for Windows using its Api) and put up with some of the downfalls of the language because the benifits outweigh the downfalls. For example, its not a language that will go away if any company fails. This has been an issue with some of the work I do. Also, it is fast and can be efficient if coded properly.
Frederick2 189 Posting Whiz
I'll help, but you've got to learn how to use code tags first. Not too many folks want to look at unformatted code.
Frederick2 189 Posting Whiz
No need to reply. I just figured it out!
Public Class StrTests01
Dim s1 As New String("")
Private Sub StrTests01_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
s1 = "Here Is A String I Want To Draw!"
Me.Invalidate()
End Sub
Private Sub StrTests01_Paint(ByVal sender As Object, ByVal pea As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
If s1.Length = 0 Then
pea.Graphics.DrawString("Hello, World!", Me.Font, New SolidBrush(SystemColors.WindowText), 0, 0)
Else
pea.Graphics.DrawString(s1, Me.Font, New SolidBrush(SystemColors.WindowText), 0, 0)
End If
End Sub
End Class
Frederick2 189 Posting Whiz
I'm still struggling. Can't anyone help with this simple question? Here's what I have so far, but nothing's working...
Public Class StrTests01
Private Sub StrTests01_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
Dim ps As Graphics = Me.CreateGraphics()
'RaiseEvent StrTests01_Paint(sender, ps)
'RaiseEvent OnPaint(sender, ps)
StrTests01_Paint(sender, ps)
End Sub
Private Sub StrTests01_Paint(ByVal sender As Object, ByVal pea As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
pea.Graphics.DrawString("Hello, World!", Me.Font, New SolidBrush(SystemColors.WindowText), 0, 0)
End Sub
End Class
Frederick2 189 Posting Whiz
How can I cause the Paint event to fire from a Form_Click() event? This is what I'm trying to do...
Public Class StrTests01
Private Sub StrTests01_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
Dim ps As Graphics = Me.CreateGraphics()
'RaiseEvent StrTests01_Paint(sender, ps)
End Sub
Private Sub StrTests01_Paint(ByVal sender As Object, ByVal pea As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
pea.Graphics.DrawString("Hello, World!", Me.Font, New SolidBrush(SystemColors.WindowText), 0, 0)
End Sub
End Class
Frederick2 189 Posting Whiz
For what operating system???
Frederick2 189 Posting Whiz
Search for Code::Blocks. Also, Microsoft's Visual C++ Compiler comes in a free 'Express' edition.
Also I heard windows 8 will allow us to code in javascript and HTML5 so this is another small question, what is actually the use of c++ if thing can be done using javascript and HTML5?
Based on the contents of your post and the above quote, it sounds to me like some other language would be better suited to your needs than C++. Possible .NET. C++ is more for system software development and high performance software, IMHO, of course.
Frederick2 189 Posting Whiz
Although the short answer is TextOut(). But, having said that, since you were unsure how to represent an integral value within a character string buffer and output it with MessageBox, it likely wouldn't hurt you to examine the link above.
Frederick2 189 Posting Whiz
Thanks. Also, how would I print some text and a variable?
Check out my first GUI tutorial here...
http://www.jose.it-berater.org/smfforum/index.php?topic=3389.0
Everything you need to know!
Frederick2 189 Posting Whiz
case WM_CREATE:
CreateWindow(
TEXT("button"), TEXT("Click"),
WS_VISIBLE | WS_CHILD | WS_BORDER,
10, 30, 55, 20,
hwnd, (HMENU) 1, NULL, NULL
);
break;
case WM_COMMAND:
if(LOWORD(wParam) == 1)
{
TCHAR szBuffer[16];
money--; //this has already been declared at 50.
_stprintf(szBuffer,_T("%d"),money);
MessageBox(hwnd, szBuffer, _T("New money value"), MB_OK); //also tried money.toString() but that doesn't work either.
}
break;
.ToString is .NET stuff. Won't work in Win32.
I like to start control ids at 1500, so they don't interfere too badly with MS defined values. Also, use equates...
#define IDC_BUTTON1 1500
Also, for that to compile you should include....
#include <windows.h>
#include <tchar.h>
#include <cstdio>
Let me know if it doesn't work. Maybe I missed something else...
Frederick2 189 Posting Whiz
I fixed a few more of your multitudinous errors
#include <windows.h>
#include <windowsx.h>
//WinProc Function prototype
LRESULT CALLBACK WindowProc (HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam);
//entry point for any windows program
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
wchar_t szClassName[]=L"WindowsClass1";
//window handle
HWND hWnd;
//holds informaintion for windows class
WNDCLASSEXW wc;
//clear windows were using
ZeroMemory(&wc, sizeof(WNDCLASSEXW));
//WC structure data
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = szClassName; //You can't assign a char array with = sign!
RegisterClassExW(&wc); //you forgot to register the window class
//generate the window
hWnd = CreateWindowExW(0, L"WindowsClass1", L"Windows Form Frame 1", WS_OVERLAPPEDWINDOW, 300, 300, 500, 400, NULL, (HMENU)NULL, hInstance, 0);
//Show generated Window
ShowWindow(hWnd, nCmdShow);
MSG msg;
// wait for the next message in the queue, store the result in 'msg'
while(GetMessageW(&msg, NULL, 0, 0))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessageW(&msg);
}
// return this part of the WM_QUIT message to Windows
return msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch(message)
{
// this message is read when the window is closed
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
} break;
}
// Handle any messages the switch statement didn't
return DefWindowProcW (hWnd, message, wParam, lParam); …
Frederick2 189 Posting Whiz
I've fixed your program so that it will at least compile and run AltXError. You made a lot of serious errors. I consider this to be a very poor attempt at something that is rather exacting. I'd encourage you to study harder and be more careful. Here is your somewhat repaired program. It still isn't exactly right, but its closer.
#include <windows.h>
#include <windowsx.h>
//WinProc Function prototype
LRESULT CALLBACK WindowProc (HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam);
//entry point for any windows program
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
wchar_t szClassName[]=L"WindowsClass1";
//window handle
HWND hWnd;
//holds informaintion for windows class
WNDCLASSEXW wc;
//clear windows were using
ZeroMemory(&wc, sizeof(WNDCLASSEX));
//WC structure data
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = szClassName;
RegisterClassExW(&wc);
//generate the window
hWnd = CreateWindowExW(0, L"WindowsClass1", L"Windows Form Frame 1", WS_OVERLAPPEDWINDOW, 300, 300, 500, 400, NULL, (HMENU)NULL, hInstance, 0);
//Show generated Window
ShowWindow(hWnd, nCmdShow);
MSG msg;
// wait for the next message in the queue, store the result in 'msg'
while(GetMessage(&msg, NULL, 0, 0))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
}
// return this part of the WM_QUIT message to Windows
return msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch(message)
{
// this message …
Frederick2 189 Posting Whiz
Here is a tutorial that might help...
http://www.jose.it-berater.org/smfforum/index.php?topic=3389.0
The first problem I saw in your code is that you foreward declare WinProc, but you named your actual Window Procedure 'WindowProc', and so when you used the term ...
wc.lpfnWndProc = WindowProc;
...it was unrecognized by the compiler (it wasn't foreward declared.
Also, the 10th parameter of the CreateWindowEx() call should have a cast like so...
...,(HMENU)NULL,...
Just spotted your first error about the int. You didn't put a semicolon after this declare...
LRESULT CALLBACK WinProc (HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
...so it gave an error on the next line. So you've a lot of problems here.
Frederick2 189 Posting Whiz
Here is a tutorial that might help...
http://www.jose.it-berater.org/smfforum/index.php?topic=3389.0
The first problem I saw in your code is that you foreward declare WinProc, but you named your actual Window Procedure 'WindowProc', and so when you used the term ...
wc.lpfnWndProc = WindowProc;
...it was unrecognized by the compiler (it wasn't foreward declared.
Also, the 10th parameter of the CreateWindowEx() call should have a cast like so...
...,(HMENU)NULL,...
Frederick2 189 Posting Whiz
Say, Mike, I'm getting a bunch of linker errors on that in CodeBlocks related to your inclusion of <map>. I'm not very familiar with STL, and was wondering what I need to link against to get it to work. Here are the errors I'm getting...
||=== FrmWrk34, Release ===|
C:\Code\CodeBlks\ClassFrameworks\FrmWrk34\.objs\main.o:main.cpp|| undefined reference to `CWindow::m_hWnd_CWnd_map'|
C:\Code\CodeBlks\ClassFrameworks\FrmWrk34\.objs\main.o:main.cpp|| undefined reference to `CWindow::m_hWnd_CWnd_map'|
C:\Code\CodeBlks\ClassFrameworks\FrmWrk34\.objs\main.o:main.cpp|| undefined reference to `CWindow::m_hWnd_CWnd_map'|
C:\Code\CodeBlks\ClassFrameworks\FrmWrk34\.objs\main.o:main.cpp|| undefined reference to `CWindow::m_hWnd_CWnd_map'|
C:\Code\CodeBlks\ClassFrameworks\FrmWrk34\.objs\main.o:main.cpp|| undefined reference to `CWindow::m_hWnd_CWnd_map'|
C:\Code\CodeBlks\ClassFrameworks\FrmWrk34\.objs\main.o:main.cpp|| more undefined references to `CWindow::m_hWnd_CWnd_map' follow|
||=== Build finished: 6 errors, 0 warnings ===|
At present I'm only linking against gdi32, user32 and kernel32. You know, maybe I ought to try with VC9 and not bother you. Maybe they link by default with more libs.
Frederick2 189 Posting Whiz
I really appreciate your taking the time to examine my rather difficult and long post Mike! I'm going to study what you just provided!
Fred
Frederick2 189 Posting Whiz
I'm passing a this pointer in my constructor initialization list for use by a base class and VC9 gives me this warning about it...
main.cpp(124) : warning C4355: 'this' : used in base member initializer list
The program runs perfectly as compiled by VC9 Pro or Code::Blocks 10.05. In Code::Blocks 10.05 using MinGW I get no warnings and a perfectly clean compile. I really think its OK but I wanted to run it by the experts here to see what others might think, and naturally, I might be missing something. If there is a problem I'd like to know about it.
Theoretically, the base address of any base class should be the same as the base address of a class from which it singly inherits. That's all I really need to ensure.
The context for what I'm doing is I put together a simple Windows Class Framework. I never use class frameworks myself, as I'm a pure Win32 Sdk coder, but I put one together for myself nonetheless to play with. Here is the code for the whole program. You can try it out and get the warning if you care to. Oh, I did do a search here on this problem first and found this...
http://www.daniweb.com/software-development/cpp/threads/100917
where MattEvans and Ancient Dragon had an exchange over this issue. But it doesn't look like they really resolved it. MattEvans rewrote his program just to get rid of the warning. Here is my code...
… Frederick2 189 Posting Whiz
Hello Muel12! I'm with Greywolf in that this is one big project you've chosen. My guess is you are looking at several years work.
I'm in a technical speciality field myself, that is, forestry. I write biometric applications. I use both C++ and PowerBASIC. I'd have to say that I would find PowerBASIC more suitable for the types of things you are interested in doing due to advanced support for multi-dimensional arrays of any order, i.e., 3, 4, etc. Also, there is very easy access to COM and Excel in particular. Naturally, since Excel uses VBA, it might be easier to directly utilize your existing code behind your cells in Excel.
However, C++ is good too. There is a more extensive user base and no doubt lots of library code you could use.
I wish you the best!
Frederick2 189 Posting Whiz
Your basic console mode "Hello, World!" program comes in around 6 K using stdio.h and printf and anywhere between 250 K - 500 K using iostream and std::cout. For these reasons I never use iostream. I do console output with printf. Anyway, iostream isn't particularly useful in GUI.
Wide character strings are pretty much necessary, and if I were you I'd give up on using both the char data type and the wchar_t data type in favor of the TCHAR data type and the tchar.h macros (if you are using Windows, that is!). If you are going to interoperate between null terminated character buffers and the std::string or std::wstring classes you are going to have to get used to declaring instances of both and moving strings between them.
Frederick2 189 Posting Whiz
I commend you for your interest in Win32 becool. Its how I like to code. You really do have to pay close attention to project setup issues using Visual Studio simply because its so complex and sophisticated. I prsonally prefer using simpler lighter weight tools, but that is simply a personal preference.
Like you were told, you need to set up a Win32 project with no framework support. Carefully check out all the options available when setting up a project. Investigate all the screens. Also, when you have it set up, check out all the options in the 'Project Properties' screens. I know there are a lot of them. I don't have VS 2010 but rather VS 2008 Pro, and with that I can tell Visual Studio to statically link with the C Runtime so that I don't need any other support files for my program to run. A basic Win32 Gui (Hello, World! type) should come in around 8 or 10 K or so, and it should run without any redistributable, as it will only be linking with user, gdi, and kernel. And you should be able to distribute that 'as is'. At least I can with exes produced by VS 2008.
Frederick2 189 Posting Whiz
Here is a link to a tutorial I wrote on using ODBC to connect to SQL Server Express, Microsoft Access, And Microsoft Excel....
http://www.jose.it-berater.org/smfforum/index.php?board=378.0
Frederick2 189 Posting Whiz
Which operating system are you working with?
Frederick2 189 Posting Whiz
Good one Narue! Except I'd say SetConsoleCursorPosition() is cutting edge avant guard bleeding edge state of the art console mode coding for Windows!
Frederick2 189 Posting Whiz
I'm someone who uses old software all the time, and it continually amazes me the way most folks rail at old software. I fully realize I'm in the minority in terms of personally having no problems whatsoever with old software, and I've just had to face that, mostly keep my mouth shut (I don't enjoy being flammed anymore than anyone else does), and go on. I've accepted the fact that folks regularly throw away or recycle perfectly functioning computers that are only a couple years old, and disgard old perfectly functioning software and replace it with buggy bloated newer software. While I don't understand any of it, I think about it just about every day. The only possible theory I can come up with to explain all this (I think about it a lot) is its just the software related manifestation of consummerism whereby planned and hopefully accelerated obsolescence is required to maintain corporeate profits, keep programmers employed, so on and so forth.
Sometime in the late 1990s I used QuickBasic 4.5 (my Mother bought it for me for a birthday present around 1985 or so) to write data collector programs for the dual boot DOS / Windows CE data recorders my organization (a large forestry organization) uses to collect timber data. At this time in 2011 those programs are still being used and form the mainstay of out field data collection. I would guess that so far 300 million dollars worth of timber sale data have been collected …
WaltP commented: My experience exactly. +16
Frederick2 189 Posting Whiz
Just for the heck of it, I translated my PowerBASIC code to C++. Here's the whole program (which contains the fnWndProc_OnPaint() handler which paints the screen red and prints "Hello, World!" in a gigantic font). Its a compilable program...
//WinTypes.h
#ifndef WINTYPES_H
#define WINTYPES_H
#define dim(x) (sizeof(x) / sizeof(x[0]))
typedef struct WindowsEventArguments
{
HWND hWnd;
WPARAM wParam;
LPARAM lParam;
HINSTANCE hIns;
}WndEventArgs, *lpWndEventArgs;
long fnWndProc_OnPaint (lpWndEventArgs Wea);
long fnWndProc_OnClose (lpWndEventArgs Wea);
struct EVENTHANDLER
{
unsigned int Code;
long (*fnPtr)(lpWndEventArgs);
};
const EVENTHANDLER EventHandler[]=
{
{WM_PAINT, fnWndProc_OnPaint},
{WM_CLOSE, fnWndProc_OnClose}
};
#endif
//Main.cpp
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <tchar.h>
#include "WinTypes.h"
long fnWndProc_OnPaint(lpWndEventArgs Wea)
{
TCHAR szBuffer[]=_T("Hello, World!");
HFONT hFont,hTmpFnt;
HBRUSH hBrush,hTmpBr;
PAINTSTRUCT ps;
RECT rc;
HDC hDC;
hDC=BeginPaint(Wea->hWnd,&ps);
hBrush=CreateSolidBrush(0x000000FF);
hTmpBr=(HBRUSH)SelectObject(hDC,hBrush);
GetClientRect(Wea->hWnd,&rc);
FillRect(hDC,&rc,hBrush);
DeleteObject(SelectObject(hDC,hTmpBr));
SetTextColor(hDC,0x00FFFFFF);
hFont=CreateFont(80,0,0,0,FW_BOLD,0,0,0,0,0,0,2,0,_T("SYSTEM_FIXED_FONT"));
hTmpFnt=(HFONT)SelectObject(hDC,hFont);
SetBkMode(hDC,TRANSPARENT);
DrawText(hDC,szBuffer,13,&rc,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
DeleteObject(SelectObject(hDC,hTmpFnt));
EndPaint(Wea->hWnd,&ps);
return 0;
}
long fnWndProc_OnClose(lpWndEventArgs Wea)
{
DestroyWindow(Wea->hWnd);
PostQuitMessage(0);
return 0;
}
LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
WndEventArgs Wea;
for(unsigned int i=0; i<dim(EventHandler); i++)
{
if(EventHandler[i].Code==msg)
{
Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
return (*EventHandler[i].fnPtr)(&Wea);
}
}
return (DefWindowProc(hwnd,msg,wParam,lParam));
}
int WINAPI WinMain(HINSTANCE hIns,HINSTANCE hPrevIns,LPSTR lpszArgument,int iShow)
{
TCHAR szClassName[]=_T("Hello");
WNDCLASSEX wc;
MSG messages;
HWND hWnd;
wc.lpszClassName=szClassName; wc.lpfnWndProc=fnWndProc;
wc.cbSize=sizeof (WNDCLASSEX); wc.style=CS_VREDRAW|CS_HREDRAW;
wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); wc.hInstance=hIns;
wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION); wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wc.cbWndExtra=12;
wc.lpszMenuName=NULL; wc.cbClsExtra=0;
RegisterClassEx(&wc);
hWnd=CreateWindow(szClassName,szClassName,WS_OVERLAPPEDWINDOW,150,150,500,450,HWND_DESKTOP,0,hIns,0);
ShowWindow(hWnd,iShow);
UpdateWindow(hWnd);
while(GetMessage(&messages,NULL,0,0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
Frederick2 189 Posting Whiz
That's not terribly hard. All you need to do is create a BRUSH of the color you want and select it into the device context in your WM_PAINT handler. I don't think I have a C/C++ example handy, but here is a PowerBASIC example of a WM_PAINT handler where I paint the whole window bright red, and draw "Hello, World!" in massive white text on it...
Function OnPaint(wea As WndEventArgs) As Long
Local hDC,hBrush,hTmp,hFont As Dword
Local lpPaint As PAINTSTRUCT
Local strText As String
Local rc As RECT
hDC = BeginPaint(wea.hWnd, lpPaint)
hBrush=CreateSolidBrush(&h000000FF)
hTmp=SelectObject(hDC,hBrush)
Call GetClientRect(wea.hWnd,rc)
Call FillRect(hDC,rc,hBrush)
Call DeleteObject(SelectObject(hdc,hTmp))
Call SetTextColor(hDC,&H00FFFFFF)
hFont=CreateFont(40,0,0,0,%FW_BOLD,0,0,0,0,0,0,2,0,"SYSTEM_FIXED_FONT")
hTmp=SelectObject(hDC,hFont)
Call SetBkMode(hDC,%TRANSPARENT)
strText = "Hello, World!"
Call TextOut(hDC,52,90,ByVal StrPtr(strText),Len(strText))
Call DeleteObject(SelectObject(hdc,hTmp))
Call EndPaint(wea.hWnd,lpPaint)
OnPaint=0
End Function
Frederick2 189 Posting Whiz
What you are asking is somewhat advanced. Data entry in the form of something like a spreadsheet is accomplished through 'grids', which are usually Windows custom controls, although if you are working with .NET there are ones available. Of course, we're talking GUIs here - not console programs. So I'm not sure what level you are at in your C++ endeavors.
If by chance you want something like that in a console mode setting - that is rather complivated also, by the way.
However, having created a GUI application and put a grid control on it and set the numbers of columns and rows you want, you could then enter data. Having done that your next step is to 'persist' the data in some form, i.e., simple flat files, a database, whatever. Have I answered your question?
Frederick2 189 Posting Whiz
Like tonyjv intimated, I don't think its terribly useful to invest time in DOS coding at this point.
Having said that however, its possible to create quite a lot of GUI like 'controls' in DOS using the extended asci characters. A lot of us old time DOS coders did that before Win32 took over. For example, when I was learning assembler and C many years ago I made my own 'Open File' dialog box with recursive directory searches, scroll bars and such - all mousable. Using the Int 33h mouse interrupts you can create mousable programs. The old DOS style menues where you have a number for a selection, i.e.,
1) Open File
2) Calculate Volumes
3) Print Report
.
etc
can be made mousable by highlighting each selection as the mouse is moved over it. So on and soi forth.
For myself, I can't really see ever going back to something like that.
Here's just another thought though. I don't want to cause any language flamewars here, but I happen to divide my coding pretty evenly between the C/C++ and PowerBASIC languages. PowerBASIC has a product called the 'Console Compiler' that takes old DOS BASIC code and compiles it into 32 bit Win executables. I'm mentioning this because it wouldn't surprise me to learn that some of your boss's old programs were in some version of BASIC such as QuickBasic, TurboBasic PDS 7.1 or something like that. The executables produced by this language are as …
Frederick2 189 Posting Whiz
Is the C++ created dll just a plain vanella Windows dll, or is it a COM component housed in a dll?
Frederick2 189 Posting Whiz
One last point though... DllTool has a number of flags such as the -k flag that mention about eliminating the @# symbols from the exports. I tried it but to no apparent effect. I also tried implementing that stuff about fixup errors, but that didn't work either - at least for me.
Frederick2 189 Posting Whiz
However, I had no luck repeating the above success with the __stdcall and def file additions. Here is the best I could do…
Step 1: Compile dllMain.cpp To Object File ( dllMain.o );
//dllMain.cpp
//g++ -c dllMain.cpp -o dllMain.o
#include <stdio.h>
extern "C" void __stdcall Print(char* pTxt)
{
printf("%s\n", pTxt);
}
C:\Code\CodeBlks\MkDll>g++ -c dllMain.cpp -o dllMain.o
C:\Code\CodeBlks\MkDll>dir
Volume in drive C is Main
Volume Serial Number is 0C18-9CF6
Directory of C:\Code\CodeBlks\MkDll
03/01/2011 12:23 PM <DIR> .
03/01/2011 12:23 PM <DIR> ..
02/28/2011 11:32 AM 5,759 CmdLnOutput.txt
03/01/2011 12:23 PM 112 dllMain.cpp
03/01/2011 12:23 PM 376 dllMain.o
02/28/2011 08:29 PM 216 Host.cpp
02/28/2011 10:07 AM 124 MkDll.bat
02/28/2011 10:19 AM 148 MkDll.def
02/28/2011 08:42 PM <DIR> sav1
03/01/2011 12:20 PM <DIR> sav2
6 File(s) 6,735 bytes
4 Dir(s) 36,252,532,736 bytes free
Step 2: Use DllTool To Read In MkDll.def File (Module Definition File), Create Export lib and Library File ( *.lib );
C:\Code\CodeBlks\MkDll>DllTool -v -d MkDll.def -e expMkDll.o -l libMkDll.lib dllMain.o
DllTool: Processing def file: MkDll.def
DllTool: LIBRARY: MkDll.dll base: ffffffff
DllTool: Processed def file
DllTool: Scanning object file dllMain.o
DllTool: Done reading dllMain.o
DllTool: Processing definitions
DllTool: Processed definitions
DllTool: Generating export file: expMkDll.o
DllTool: Opened temporary file: dclec.s
DllTool: run: as -o expMkDll.o dclec.s
DllTool: Generated exports file
DllTool: Creating library file: libMkDll.lib
DllTool: run: as -o dcleh.o dcleh.s
DllTool: run: as -o dclet.o dclet.s
DllTool: Created lib file
C:\Code\CodeBlks\MkDll>dir
Volume in drive C is Main
Volume Serial Number is 0C18-9CF6
Directory of C:\Code\CodeBlks\MkDll
03/01/2011 …
Frederick2 189 Posting Whiz
Because I was having such difficulties with this, I decided to see if I could satisfactorily create a working Dll that was simpler in that I wouldn’t be using a *.def file or the __stdcall stack setup. I was able to do that finally, and here is that code…
Step 1: Compile Dll Code To Object File ( *.o );
//dllMain.cpp
#include <stdio.h>
extern "C" void Print(char* pTxt)
{
printf("%s\n", pTxt);
}
C:\Code\CodeBlks\MkDll>g++ -c dllMain.cpp -o dllMain.o
C:\Code\CodeBlks\MkDll>dir
Volume in drive C is Main
Volume Serial Number is 0C18-9CF6
Directory of C:\Code\CodeBlks\MkDll
03/01/2011 11:48 AM <DIR> .
03/01/2011 11:48 AM <DIR> ..
02/28/2011 11:32 AM 5,759 CmdLnOutput.txt
02/28/2011 08:43 PM 87 dllMain.cpp
03/01/2011 11:48 AM 372 dllMain.o
03/01/2011 11:45 AM 196 Host.cpp
02/28/2011 10:07 AM 124 MkDll.bat
02/28/2011 10:19 AM 148 MkDll.def
02/28/2011 08:42 PM <DIR> sav1
6 File(s) 6,686 bytes
3 Dir(s) 36,252,704,768 bytes free
Step 2: Use DllTool.exe To Create Exports File And Lib file;
C:\Code\CodeBlks\MkDll>DllTool -e expMkDll.o -l MkDll.lib dllMain.o
C:\Code\CodeBlks\MkDll>dir
Volume in drive C is Main
Volume Serial Number is 0C18-9CF6
Directory of C:\Code\CodeBlks\MkDll
03/01/2011 11:50 AM <DIR> .
03/01/2011 11:50 AM <DIR> ..
02/28/2011 11:32 AM 5,759 CmdLnOutput.txt
02/28/2011 08:43 PM 87 dllMain.cpp
03/01/2011 11:48 AM 372 dllMain.o
03/01/2011 11:50 AM 288 expMkDll.o
03/01/2011 11:45 AM 196 Host.cpp
02/28/2011 10:07 AM 124 MkDll.bat
02/28/2011 10:19 AM 148 MkDll.def
03/01/2011 11:50 AM 1,494 MkDll.lib
02/28/2011 08:42 PM <DIR> sav1
8 File(s) 8,468 bytes
3 Dir(s) 36,252,700,672 bytes free
Step 3: Use g++ …
Frederick2 189 Posting Whiz
Hello Mike!
You’ve really been a trooper trying to help with this! Thanks!
Still doesn't work though. When my host is like so…
//without extern "C"
//g++ Host.cpp -l libMkDll -o Host.exe
#include <stdio.h>
void __stdcall Print(const char*);
int main()
{
const char* const pStr = "Hello, World!";
Print(pStr);
getchar();
return 0;
}
I get this…
C:\Code\CodeBlks\MkDll>g++ Host.cpp -l libMkDll -o Host.exe
C:\DOCUME~1\Fred\LOCALS~1\Temp\ccrTHitH.o:Host.cpp:(.text+0x25): undefined reference to `Print(char const*)@4'
collect2: ld returned 1 exit status
…and when like so….
//with extern "C"
//g++ Host.cpp –l libMkDll -o Host.exe
#include <stdio.h>
extern “C” void __stdcall Print(const char*);
int main()
{
const char* const pStr = "Hello, World!";
Print(pStr);
getchar();
return 0;
}
…I get instead this…
C:\Code\CodeBlks\MkDll>g++ Host.cpp -l libMkDll -o Host.exe
C:\DOCUME~1\Fred\LOCALS~1\Temp\ccK4JLHV.o:Host.cpp:(.text+0x25): undefined reference to `Print@4'
collect2: ld returned 1 exit status
Can’t win no-how! I’m beginning to dispair that this indeed can’t be done with GNU.
Frederick2 189 Posting Whiz
Aren't you supposed to write:
$ g++ Host.cpp -l libMkDll.lib -o Host.exe
You're right! I think I missed that. I have no explanation for the problem I'm getting now though. I think I deserve an A for effort though....
C:\Code\CodeBlks\MkDll>g++ Host.cpp -l libMkDll.lib -o Host.exe
c:/program files/codeblocks/mingw/bin/../lib/gcc/mingw32/4.4.1/../../../../mingw32/bin/ld.exe: cannot find -llibMkDll.lib
collect2: ld returned 1 exit status
C:\Code\CodeBlks\MkDll>g++ Host.cpp -llibMkDll.lib -o Host.exe
c:/program files/codeblocks/mingw/bin/../lib/gcc/mingw32/4.4.1/../../../../mingw32/bin/ld.exe: cannot find -llibMkDll.lib
collect2: ld returned 1 exit status
C:\Code\CodeBlks\MkDll>g++ Host.cpp -l C:\Code\CodeBlks\MkDll\libMkDll.lib -o Host.exe
c:/program files/codeblocks/mingw/bin/../lib/gcc/mingw32/4.4.1/../../../../mingw32/bin/ld.exe: cannot find -lC:\Code\CodeBlks\MkDll\libMkDll.lib
collect2: ld returned 1 exit status
C:\Code\CodeBlks\MkDll>g++ Host.cpp -l libMkDll.lib -o Host.exe
c:/program files/codeblocks/mingw/bin/../lib/gcc/mingw32/4.4.1/../../../../mingw32/bin/ld.exe: cannot find -llibMkDll.lib
collect2: ld returned 1 exit status
C:\Code\CodeBlks\MkDll>g++ Host.cpp L"C:\Code\CodeBlks\MkDll" -l libMkDll.lib -o Host.exe
g++: LC:\Code\CodeBlks\MkDll: Invalid argument
C:\Code\CodeBlks\MkDll>g++ Host.cpp -LC:\Code\CodeBlks\MkDll -l libMkDll.lib -o Host.exe
c:/program files/codeblocks/mingw/bin/../lib/gcc/mingw32/4.4.1/../../../../mingw32/bin/ld.exe: cannot find -llibMkDll.lib
collect2: ld returned 1 exit status
C:\Code\CodeBlks\MkDll>dir
Volume in drive C is Main
Volume Serial Number is 0C18-9CF6
Directory of C:\Code\CodeBlks\MkDll
02/28/2011 03:56 PM <DIR> .
02/28/2011 03:56 PM <DIR> ..
02/28/2011 11:32 AM 5,759 CmdLnOutput.txt
02/28/2011 02:36 PM 109 dllMain.cpp
02/28/2011 02:36 PM 376 dllMain.o
02/28/2011 02:37 PM 716 expMkDll.o
02/28/2011 02:43 PM 205 Host.cpp
02/28/2011 02:37 PM 1,510 libMkDll.lib
02/28/2011 10:07 AM 124 MkDll.bat
02/28/2011 10:19 AM 148 MkDll.def
02/28/2011 02:38 PM 22,421 MkDll.dll
9 File(s) 31,368 bytes
2 Dir(s) 36,253,954,048 bytes free
C:\Code\CodeBlks\MkDll>g++ Host.cpp -L./ -llibMkDll.lib -o Host.exe
c:/program files/codeblocks/mingw/bin/../lib/gcc/mingw32/4.4.1/../../../../mingw32/bin/ld.exe: cannot find -llibMkDll.lib
collect2: ld returned 1 exit status
C:\Code\CodeBlks\MkDll>g++ Host.cpp -l libMkDll.a -o Host.exe
c:/program files/codeblocks/mingw/bin/../lib/gcc/mingw32/4.4.1/../../../../mingw32/bin/ld.exe: cannot find -llibMkDll.a
collect2: ld returned 1 exit status
C:\Code\CodeBlks\MkDll>g++ …
Frederick2 189 Posting Whiz
Thanks for the input Mike! I'm getting closer! The extern “C” thing always confuses me. I find myself not always sure when/if to use it. Anyway, I added it to my Dll function, and that finally allowed for a successful compile/link…
#include <stdio.h>
extern "C" void __stdcall Print(const char* pTxt)
{
printf("%s\n", pTxt);
}
I did get these warnings, however…
Warning: resolving _Print by linking to _Print@4
Use --enable-stdcall-fixup to disable these warnings
Use --disable-stdcall-fixup to disable these fixups
But when I used Microsoft’s DumpBin.exe utility on the Dll, it looked like it exported the symbol ‘Print’ exactly the way I wanted it…
C:\Code\CodeBlks\MkDll>dumpbin /exports MkDll.dll
Microsoft (R) COFF Binary File Dumper Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
Dump of file MkDll.dll
File Type: DLL
Section contains the following exports for expMkDll.o.dll
0 characteristics
4D6BF1F7 time date stamp Mon Feb 28 14:05:27 2011
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 000011D8 Print
Summary
1000 .bss
1000 .data
1000 .debug_abbrev
1000 .debug_aranges
1000 .debug_frame
1000 .debug_info
1000 .debug_line
1000 .debug_loc
1000 .debug_pubnames
1000 .debug_ranges
1000 .edata
1000 .idata
1000 .rdata
1000 .reloc
1000 .text
In the above dump note the text Print. That is just how it should be. With high hopes next I decided to throw together a quick host to see if it works, so I made this…
//Host.cpp
//g++ Host.cpp libMkDll.lib -o Host.exe
#include <stdio.h>
void __stdcall Print(const …
Frederick2 189 Posting Whiz
Could someone familiar with command line compiling using GNU C/C++ Compiler Collection please help me with a Dll creation problem I have? What I would like to know is how to create a Windows Dll out of the following very simple test file that is essentially just a "Hello, World!" type thing...
//dllMain.cpp
#include <stdio.h>
void __stdcall Print(const char* pTxt)
{
printf("%s\n", pTxt);
}
As you can see there is just one function which just outputs a char* to the console. The main wrinkles that have so far foiled all my attempts at this are that the function is defined as __stdcall not __cdecl, and I wish to use a Windows Module Definition File, i.e., a *.def file to indicate the exports to the linker - not __declspec(dllexport) or anything like that. Here is the def file. Lets call the project MkDll so that the module definition file is MkDll.def....
; MkDll.def
LIBRARY "MkDll.dll"
DESCRIPTION 'SERVER Windows Dynamic Link Library'
EXPORTS
Print PRIVATE
Here is what I have accomplished so far. My project directory is C:\Code\CodeBlks\MkDll...
C:\Code\CodeBlks\MkDll>g++ -c dllMain.cpp -o dllMain.o
C:\Code\CodeBlks\MkDll>dir
Volume in drive C is Main
Volume Serial Number is 0C18-9CF6
Directory of C:\Code\CodeBlks\MkDll
02/28/2011 10:13 AM <DIR> .
02/28/2011 10:13 AM <DIR> ..
02/28/2011 10:10 AM 92 dllMain.cpp
02/28/2011 10:13 AM 391 dllMain.o
02/28/2011 10:07 AM 124 MkDll.bat
02/28/2011 10:10 AM 148 MkDll.def
4 File(s) 755 bytes
2 Dir(s) 36,273,405,952 bytes free
C:\Code\CodeBlks\MkDll>
As can be seen above I have successfully compiled dllMain.cpp into …
Frederick2 189 Posting Whiz
Thanks guys! Just what I was looking for!
Frederick2 189 Posting Whiz
I don't even know how anyone could ask such a question. The answer is of course not. Visual Basic 4-6 made heavy use of COM and COM components. These components are usable from C++, but the components are binary objects - not code.
Frederick2 189 Posting Whiz
The first is people who basically use C++ for the object-oriented features of it (grouping data and code, encapsulation, dynamic polymorphism, etc.) but basically stick to C when it comes to the implementation. This includes using (almost) only C constructs (like null-terminated strings and arrays) and mostly C functions (like atoi(), strcmp(), printf(), scanf(), fopen(), etc., etc.). I understand why people do this, basically, once you are familiar with a set of functions and your are effective at using them, mind as well do so instead of re-learning the basics. I used to do this. But, I would say, that most people grow out of this because as you get exposed to other peoples code that relies on C++ standard constructs and functions, you have to get to know them anyways, and when you do, you will most likely prefer them to their C-style counterparts (if they even exist, because the C++ standard library is far superior to the C libraries).
You've got me nailed Mike_2000_17!
I started to learn C++ over ten years ago; liked it at first because of neat stuff like classes, references, etc; then got badly turned off by virtually all the C++ libraries, which I simply have no taste for. I eventually gave up C++; used C and other languages.
About 4-5 years ago I did some rethinking on the matter, and decided that I had more or less 'thrown the baby out with the bath water'. C++ had features which were just …