Add a simple license key: I take the CRC of the license info, plus
some magic numbers. This would be trivial to break, but still more difficult than patching the binary to skip the check... [git-p4: depot-paths = "//depot/solvespace/": change = 1853]solver
parent
5a2803617b
commit
0c10efdab6
2
Makefile
2
Makefile
|
@ -39,7 +39,7 @@ SSOBJS = $(OBJDIR)\solvespace.obj \
|
|||
RES = $(OBJDIR)\resource.res
|
||||
|
||||
|
||||
LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib opengl32.lib glu32.lib \
|
||||
LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib shell32.lib opengl32.lib glu32.lib \
|
||||
extlib\libpng.lib extlib\zlib.lib
|
||||
|
||||
all: $(OBJDIR)/solvespace.exe
|
||||
|
|
|
@ -1304,7 +1304,7 @@ for new users; to learn about this program, see the video tutorials.
|
|||
<h2>Licensing</h2>
|
||||
|
||||
As downloaded, MechSketch does not include a license key. This means
|
||||
that it cannot create files with more than seven groups. Larger files
|
||||
that it cannot create files with more than six groups. Larger files
|
||||
may be opened, but not modified. This light version of MechSketch
|
||||
is intended for evaluation, but non-commercial / personal use is
|
||||
also permitted.
|
||||
|
|
112
export.cpp
112
export.cpp
|
@ -117,46 +117,46 @@ havepoly:
|
|||
|
||||
// Some software, like Adobe Illustrator, insists on a header.
|
||||
fprintf(f,
|
||||
" 999\n"
|
||||
"file created by SolveSpace\n"
|
||||
" 0\n"
|
||||
"SECTION\n"
|
||||
" 2\n"
|
||||
"HEADER\n"
|
||||
" 9\n"
|
||||
"$ACADVER\n"
|
||||
" 1\n"
|
||||
"AC1006\n"
|
||||
" 9\n"
|
||||
"$INSBASE\n"
|
||||
" 10\n"
|
||||
"0.0\n"
|
||||
" 20\n"
|
||||
"0.0\n"
|
||||
" 30\n"
|
||||
"0.0\n"
|
||||
" 9\n"
|
||||
"$EXTMIN\n"
|
||||
" 10\n"
|
||||
"0.0\n"
|
||||
" 20\n"
|
||||
"0.0\n"
|
||||
" 9\n"
|
||||
"$EXTMAX\n"
|
||||
" 10\n"
|
||||
"10000.0\n"
|
||||
" 20\n"
|
||||
"10000.0\n"
|
||||
" 0\n"
|
||||
"ENDSEC\n");
|
||||
" 999\r\n"
|
||||
"file created by SolveSpace\r\n"
|
||||
" 0\r\n"
|
||||
"SECTION\r\n"
|
||||
" 2\r\n"
|
||||
"HEADER\r\n"
|
||||
" 9\r\n"
|
||||
"$ACADVER\r\n"
|
||||
" 1\r\n"
|
||||
"AC1006\r\n"
|
||||
" 9\r\n"
|
||||
"$INSBASE\r\n"
|
||||
" 10\r\n"
|
||||
"0.0\r\n"
|
||||
" 20\r\n"
|
||||
"0.0\r\n"
|
||||
" 30\r\n"
|
||||
"0.0\r\n"
|
||||
" 9\r\n"
|
||||
"$EXTMIN\r\n"
|
||||
" 10\r\n"
|
||||
"0.0\r\n"
|
||||
" 20\r\n"
|
||||
"0.0\r\n"
|
||||
" 9\r\n"
|
||||
"$EXTMAX\r\n"
|
||||
" 10\r\n"
|
||||
"10000.0\r\n"
|
||||
" 20\r\n"
|
||||
"10000.0\r\n"
|
||||
" 0\r\n"
|
||||
"ENDSEC\r\n");
|
||||
|
||||
// Now begin the entities, which are just line segments reproduced from
|
||||
// our piecewise linear curves.
|
||||
fprintf(f,
|
||||
" 0\n"
|
||||
"SECTION\n"
|
||||
" 2\n"
|
||||
"ENTITIES\n");
|
||||
" 0\r\n"
|
||||
"SECTION\r\n"
|
||||
" 2\r\n"
|
||||
"ENTITIES\r\n");
|
||||
|
||||
int i, j;
|
||||
for(i = 0; i < sp->l.n; i++) {
|
||||
|
@ -172,22 +172,22 @@ havepoly:
|
|||
double s = SS.exportScale;
|
||||
|
||||
fprintf(f,
|
||||
" 0\n"
|
||||
"LINE\n"
|
||||
" 8\n" // Layer code
|
||||
"%d\n"
|
||||
" 10\n" // xA
|
||||
"%.6f\n"
|
||||
" 20\n" // yA
|
||||
"%.6f\n"
|
||||
" 30\n" // zA
|
||||
"%.6f\n"
|
||||
" 11\n" // xB
|
||||
"%.6f\n"
|
||||
" 21\n" // yB
|
||||
"%.6f\n"
|
||||
" 31\n" // zB
|
||||
"%.6f\n",
|
||||
" 0\r\n"
|
||||
"LINE\r\n"
|
||||
" 8\r\n" // Layer code
|
||||
"%d\r\n"
|
||||
" 10\r\n" // xA
|
||||
"%.6f\r\n"
|
||||
" 20\r\n" // yA
|
||||
"%.6f\r\n"
|
||||
" 30\r\n" // zA
|
||||
"%.6f\r\n"
|
||||
" 11\r\n" // xB
|
||||
"%.6f\r\n"
|
||||
" 21\r\n" // yB
|
||||
"%.6f\r\n"
|
||||
" 31\r\n" // zB
|
||||
"%.6f\r\n",
|
||||
0,
|
||||
e0.x/s, e0.y/s, 0.0,
|
||||
e1.x/s, e1.y/s, 0.0);
|
||||
|
@ -195,10 +195,10 @@ havepoly:
|
|||
}
|
||||
|
||||
fprintf(f,
|
||||
" 0\n"
|
||||
"ENDSEC\n"
|
||||
" 0\n"
|
||||
"EOF\n" );
|
||||
" 0\r\n"
|
||||
"ENDSEC\r\n"
|
||||
" 0\r\n"
|
||||
"EOF\r\n" );
|
||||
|
||||
spa.Clear();
|
||||
fclose(f);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define mFile (&SolveSpace::MenuFile)
|
||||
#define mGrp (&Group::MenuGroup)
|
||||
#define mAna (&SolveSpace::MenuAnalyze)
|
||||
#define mHelp (&SolveSpace::MenuHelp)
|
||||
#define S 0x100
|
||||
#define C 0x200
|
||||
const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
||||
|
@ -101,11 +102,11 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||
{ 1, "&Stop Tracing...\tCtrl+Shift+S", MNU_STOP_TRACING, 'S'|S|C,mAna },
|
||||
{ 1, "Step &Dimension...\tCtrl+Shift+D", MNU_STEP_DIM, 'D'|S|C,mAna },
|
||||
|
||||
{ 0, "&Help", 0, NULL },
|
||||
{ 1, "&Load License...", 0, NULL },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "&Website / Manual", 0, NULL },
|
||||
{ 1, "&About", 0, NULL },
|
||||
{ 0, "&Help", 0, 0, NULL },
|
||||
{ 1, "&Load License...", MNU_LICENSE, 0, mHelp },
|
||||
{ 1, NULL, 0, 0, NULL },
|
||||
{ 1, "&Website / Manual", MNU_WEBSITE, 0, mHelp },
|
||||
{ 1, "&About", MNU_ABOUT, 0, mHelp },
|
||||
{ -1 },
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,14 @@ void Group::AddParam(IdList<Param,hParam> *param, hParam hp, double v) {
|
|||
}
|
||||
|
||||
void Group::MenuGroup(int id) {
|
||||
if(!SS.license.licensed && SS.group.n >= 7) {
|
||||
Error("The free version of this software does not support more "
|
||||
"than six groups.\r\n\r\n"
|
||||
"To remove this restriction, please choose Help -> "
|
||||
"Website / Manual, and purchase a license.");
|
||||
return;
|
||||
}
|
||||
|
||||
Group g;
|
||||
ZERO(&g);
|
||||
g.visible = true;
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
$POLY = 0xedb88320;
|
||||
|
||||
sub ProcessBit {
|
||||
my ($bit) = @_;
|
||||
|
||||
my $topWasSet = ($shiftReg & (1 << 31));
|
||||
|
||||
$shiftReg <<= 1;
|
||||
if($bit) {
|
||||
$shiftReg |= 1;
|
||||
}
|
||||
|
||||
if($topWasSet) {
|
||||
$shiftReg ^= $POLY;
|
||||
}
|
||||
}
|
||||
|
||||
sub ProcessByte {
|
||||
my ($v) = @_;
|
||||
for(0..7) {
|
||||
ProcessBit($v & (1 << $_));
|
||||
}
|
||||
}
|
||||
|
||||
sub ProcessString {
|
||||
my ($str) = @_;
|
||||
for (split //, $str) {
|
||||
if($_ ne "\n" and $_ ne "\r") {
|
||||
ProcessByte(ord($_));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub LicenseKey {
|
||||
my @MAGIC = ( 203, 244, 134, 225, 45, 250, 70, 65,
|
||||
224, 189, 35, 3, 228, 51, 77, 169, );
|
||||
my $magic = join('', map { chr($_) } @MAGIC);
|
||||
|
||||
my ($line1, $line2, $users) = @_;
|
||||
|
||||
$shiftReg = 0;
|
||||
ProcessString($line1);
|
||||
ProcessString($line2);
|
||||
ProcessString($users);
|
||||
ProcessString($magic);
|
||||
|
||||
my $key = '±²³MechSketchLicense' . "\n";
|
||||
$key .= $line1 . "\n";
|
||||
$key .= $line2 . "\n";
|
||||
$key .= $users . "\n";
|
||||
$key .= sprintf("%08x\n", $shiftReg);
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
|
||||
$line1 = "Jonathan Westhues";
|
||||
$line2 = "";
|
||||
$users = "single-user license";
|
||||
|
||||
print LicenseKey($line1, $line2, $users);
|
||||
|
141
solvespace.cpp
141
solvespace.cpp
|
@ -2,7 +2,21 @@
|
|||
|
||||
SolveSpace SS;
|
||||
|
||||
void SolveSpace::CheckLicenseFromRegistry(void) {
|
||||
// First, let's see if we're running licensed or free
|
||||
CnfThawString(license.line1, sizeof(license.line1), "LicenseLine1");
|
||||
CnfThawString(license.line2, sizeof(license.line2), "LicenseLine2");
|
||||
CnfThawString(license.users, sizeof(license.users), "LicenseUsers");
|
||||
license.key = CnfThawDWORD(0, "LicenseKey");
|
||||
|
||||
license.licensed =
|
||||
LicenseValid(license.line1, license.line2, license.users, license.key);
|
||||
}
|
||||
|
||||
void SolveSpace::Init(char *cmdLine) {
|
||||
CheckLicenseFromRegistry();
|
||||
|
||||
// Then, load the registry settings.
|
||||
int i;
|
||||
// Default list of colors for the model material
|
||||
modelColor[0] = CnfThawDWORD(RGB(150, 150, 150), "ModelColor_0");
|
||||
|
@ -431,14 +445,14 @@ void SolveSpace::MenuAnalyze(int id) {
|
|||
case GraphicsWindow::MNU_STOP_TRACING: {
|
||||
char exportFile[MAX_PATH] = "";
|
||||
if(GetSaveFile(exportFile, CSV_EXT, CSV_PATTERN)) {
|
||||
FILE *f = fopen(exportFile, "w");
|
||||
FILE *f = fopen(exportFile, "wb");
|
||||
if(f) {
|
||||
int i;
|
||||
SContour *sc = &(SS.traced.path);
|
||||
for(i = 0; i < sc->l.n; i++) {
|
||||
Vector p = sc->l.elem[i].p;
|
||||
double s = SS.exportScale;
|
||||
fprintf(f, "%.10f, %.10f, %.10f\n",
|
||||
fprintf(f, "%.10f, %.10f, %.10f\r\n",
|
||||
p.x/s, p.y/s, p.z/s);
|
||||
}
|
||||
fclose(f);
|
||||
|
@ -457,3 +471,126 @@ void SolveSpace::MenuAnalyze(int id) {
|
|||
}
|
||||
}
|
||||
|
||||
void SolveSpace::Crc::ProcessBit(int bit) {
|
||||
bool topWasSet = ((shiftReg & (1 << 31)) != 0);
|
||||
|
||||
shiftReg <<= 1;
|
||||
if(bit) {
|
||||
shiftReg |= 1;
|
||||
}
|
||||
|
||||
if(topWasSet) {
|
||||
shiftReg ^= POLY;
|
||||
}
|
||||
}
|
||||
|
||||
void SolveSpace::Crc::ProcessByte(BYTE b) {
|
||||
int i;
|
||||
for(i = 0; i < 8; i++) {
|
||||
ProcessBit(b & (1 << i));
|
||||
}
|
||||
}
|
||||
|
||||
void SolveSpace::Crc::ProcessString(char *s) {
|
||||
for(; *s; s++) {
|
||||
if(*s != '\n' && *s != '\r') {
|
||||
ProcessByte((BYTE)*s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SolveSpace::LicenseValid(char *line1, char *line2, char *users, DWORD key)
|
||||
{
|
||||
BYTE magic[17] = {
|
||||
203, 244, 134, 225, 45, 250, 70, 65,
|
||||
224, 189, 35, 3, 228, 51, 77, 169,
|
||||
0
|
||||
};
|
||||
|
||||
crc.shiftReg = 0;
|
||||
crc.ProcessString(line1);
|
||||
crc.ProcessString(line2);
|
||||
crc.ProcessString(users);
|
||||
crc.ProcessString((char *)magic);
|
||||
|
||||
return (key == crc.shiftReg);
|
||||
}
|
||||
|
||||
void SolveSpace::CleanEol(char *in) {
|
||||
char *s;
|
||||
s = strchr(in, '\r');
|
||||
if(s) *s = '\0';
|
||||
s = strchr(in, '\n');
|
||||
if(s) *s = '\0';
|
||||
}
|
||||
|
||||
void SolveSpace::LoadLicenseFile(char *filename) {
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if(!f) {
|
||||
Error("Couldn't open file '%s'", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[100];
|
||||
fgets(buf, sizeof(buf), f);
|
||||
char *str = "±²³MechSketchLicense";
|
||||
if(memcmp(buf, str, strlen(str)) != 0) {
|
||||
fclose(f);
|
||||
Error("This is not a license file,");
|
||||
return;
|
||||
}
|
||||
|
||||
char line1[512], line2[512], users[512];
|
||||
fgets(line1, sizeof(line1), f);
|
||||
CleanEol(line1);
|
||||
fgets(line2, sizeof(line2), f);
|
||||
CleanEol(line2);
|
||||
fgets(users, sizeof(users), f);
|
||||
CleanEol(users);
|
||||
|
||||
fgets(buf, sizeof(buf), f);
|
||||
DWORD key = 0;
|
||||
sscanf(buf, "%x", &key);
|
||||
|
||||
if(LicenseValid(line1, line2, users, key)) {
|
||||
// Install the new key
|
||||
CnfFreezeString(line1, "LicenseLine1");
|
||||
CnfFreezeString(line2, "LicenseLine2");
|
||||
CnfFreezeString(users, "LicenseUsers");
|
||||
CnfFreezeDWORD(key, "LicenseKey");
|
||||
Message("License key successfully installed.");
|
||||
|
||||
// This updates our display in the text window to show that we're
|
||||
// licensed now.
|
||||
CheckLicenseFromRegistry();
|
||||
SS.later.showTW = true;
|
||||
} else {
|
||||
Error("License key invalid.");
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void SolveSpace::MenuHelp(int id) {
|
||||
switch(id) {
|
||||
case GraphicsWindow::MNU_WEBSITE:
|
||||
OpenWebsite("http://www.mechsketch.com/helpmenu");
|
||||
break;
|
||||
|
||||
case GraphicsWindow::MNU_ABOUT:
|
||||
Message("This is MechSketch version 0.1.\r\n\r\n"
|
||||
"For more information, see http://www.mechsketch.com/\r\n\r\n"
|
||||
"Built " __TIME__ " " __DATE__ ".\r\n\r\n"
|
||||
"Copyright 2008 Jonathan Westhues, All Rights Reserved.");
|
||||
break;
|
||||
|
||||
case GraphicsWindow::MNU_LICENSE: {
|
||||
char licenseFile[MAX_PATH] = "";
|
||||
if(GetOpenFile(licenseFile, LICENSE_EXT, LICENSE_PATTERN)) {
|
||||
SS.LoadLicenseFile(licenseFile);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: oops();
|
||||
}
|
||||
}
|
||||
|
|
30
solvespace.h
30
solvespace.h
|
@ -64,11 +64,16 @@ int SaveFileYesNoCancel(void);
|
|||
#define DXF_EXT "dxf"
|
||||
#define CSV_PATTERN "CSV File (*.csv)\0*.csv\0All Files (*)\0*\0\0"
|
||||
#define CSV_EXT "csv"
|
||||
#define LICENSE_PATTERN \
|
||||
"License File (*.license)\0*.license\0All Files (*)\0*\0\0"
|
||||
#define LICENSE_EXT "license"
|
||||
BOOL GetSaveFile(char *file, char *defExtension, char *selPattern);
|
||||
BOOL GetOpenFile(char *file, char *defExtension, char *selPattern);
|
||||
void GetAbsoluteFilename(char *file);
|
||||
void LoadAllFontFiles(void);
|
||||
|
||||
void OpenWebsite(char *url);
|
||||
|
||||
void CheckMenuById(int id, BOOL checked);
|
||||
void EnableMenuById(int id, BOOL checked);
|
||||
|
||||
|
@ -92,6 +97,7 @@ void dbp(char *str, ...);
|
|||
CO((tri).a), CO((tri).b), CO((tri).c))
|
||||
|
||||
void SetWindowTitle(char *str);
|
||||
void Message(char *str, ...);
|
||||
void Error(char *str, ...);
|
||||
void ExitNow(void);
|
||||
|
||||
|
@ -376,6 +382,7 @@ public:
|
|||
|
||||
// The platform-dependent code calls this before entering the msg loop
|
||||
void Init(char *cmdLine);
|
||||
void CheckLicenseFromRegistry(void);
|
||||
void Exit(void);
|
||||
|
||||
// File load/save routines, including the additional files that get
|
||||
|
@ -464,6 +471,29 @@ public:
|
|||
bool generateAll;
|
||||
} later;
|
||||
void DoLater(void);
|
||||
|
||||
// For the licensing
|
||||
class Crc {
|
||||
public:
|
||||
static const DWORD POLY = 0xedb88320;
|
||||
DWORD shiftReg;
|
||||
|
||||
void ProcessBit(int bit);
|
||||
void ProcessByte(BYTE b);
|
||||
void ProcessString(char *s);
|
||||
};
|
||||
Crc crc;
|
||||
struct {
|
||||
bool licensed;
|
||||
char line1[512];
|
||||
char line2[512];
|
||||
char users[512];
|
||||
DWORD key;
|
||||
} license;
|
||||
static void MenuHelp(int id);
|
||||
void CleanEol(char *s);
|
||||
void LoadLicenseFile(char *filename);
|
||||
bool LicenseValid(char *line1, char *line2, char *users, DWORD key);
|
||||
};
|
||||
|
||||
extern SolveSpace SS;
|
||||
|
|
|
@ -98,6 +98,9 @@ void TextWindow::ScreenHowGroupSolved(int link, DWORD v) {
|
|||
void TextWindow::ScreenShowConfiguration(int link, DWORD v) {
|
||||
SS.TW.GoToScreen(SCREEN_CONFIGURATION);
|
||||
}
|
||||
void TextWindow::ScreenGoToWebsite(int link, DWORD v) {
|
||||
OpenWebsite("http://www.mechsketch.com/txtlink");
|
||||
}
|
||||
void TextWindow::ShowListOfGroups(void) {
|
||||
Printf(true, "%Ftactv show ok group-name%E");
|
||||
int i;
|
||||
|
@ -140,6 +143,22 @@ void TextWindow::ShowListOfGroups(void) {
|
|||
&(TextWindow::ScreenShowGroupsSpecial));
|
||||
Printf(false, " %Fl%Ls%fconfiguration%E",
|
||||
&(TextWindow::ScreenShowConfiguration));
|
||||
|
||||
// Show license info
|
||||
Printf(false, "");
|
||||
if(SS.license.licensed) {
|
||||
Printf(false, "%FtLicensed to:");
|
||||
Printf(false, "%Fg %s", SS.license.line1);
|
||||
if(strlen(SS.license.line2)) {
|
||||
Printf(false, "%Fg %s", SS.license.line2);
|
||||
}
|
||||
Printf(false, "%Fg %s", SS.license.users);
|
||||
} else {
|
||||
Printf(false, "%Fx*** THIS SOFTWARE IS NOT LICENSED ***");
|
||||
Printf(false, "%Fx eval / non-commercial use only");
|
||||
Printf(false, "%Fx buy at %Fl%f%Llhttp://www.mechsketch.com/%E",
|
||||
&ScreenGoToWebsite);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ const TextWindow::Color TextWindow::fgColors[] = {
|
|||
{ 'r', RGB( 0, 0, 0) },
|
||||
{ 'x', RGB(255, 20, 20) },
|
||||
{ 'i', RGB( 0, 255, 255) },
|
||||
{ 'g', RGB(160, 160, 160) },
|
||||
{ 0, 0 },
|
||||
};
|
||||
const TextWindow::Color TextWindow::bgColors[] = {
|
||||
|
|
5
ui.h
5
ui.h
|
@ -130,6 +130,7 @@ public:
|
|||
static void ScreenColor(int link, DWORD v);
|
||||
|
||||
static void ScreenShowConfiguration(int link, DWORD v);
|
||||
static void ScreenGoToWebsite(int link, DWORD v);
|
||||
|
||||
static void ScreenStepDimSteps(int link, DWORD v);
|
||||
static void ScreenStepDimFinish(int link, DWORD v);
|
||||
|
@ -224,6 +225,10 @@ public:
|
|||
MNU_TRACE_PT,
|
||||
MNU_STOP_TRACING,
|
||||
MNU_STEP_DIM,
|
||||
// Help,
|
||||
MNU_LICENSE,
|
||||
MNU_WEBSITE,
|
||||
MNU_ABOUT,
|
||||
} MenuId;
|
||||
typedef void MenuHandler(int id);
|
||||
typedef struct {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <commctrl.h>
|
||||
#include <commdlg.h>
|
||||
#include <gl/gl.h>
|
||||
|
@ -55,25 +56,50 @@ void dbp(char *str, ...)
|
|||
va_end(f);
|
||||
}
|
||||
|
||||
void Error(char *str, ...)
|
||||
|
||||
static void DoMessageBox(char *str, va_list f, BOOL error)
|
||||
{
|
||||
va_list f;
|
||||
char buf[1024];
|
||||
va_start(f, str);
|
||||
char buf[1024*50];
|
||||
vsprintf(buf, str, f);
|
||||
va_end(f);
|
||||
|
||||
EnableWindow(GraphicsWnd, FALSE);
|
||||
EnableWindow(TextWnd, FALSE);
|
||||
|
||||
int flags;
|
||||
if(error) {
|
||||
flags = MB_OK | MB_ICONERROR;
|
||||
} else {
|
||||
flags = MB_OK | MB_ICONINFORMATION;
|
||||
}
|
||||
HWND h = GetForegroundWindow();
|
||||
MessageBox(h, buf, "SolveSpace Error", MB_OK | MB_ICONERROR);
|
||||
MessageBox(h, buf, "SolveSpace", flags);
|
||||
|
||||
EnableWindow(TextWnd, TRUE);
|
||||
EnableWindow(GraphicsWnd, TRUE);
|
||||
SetForegroundWindow(GraphicsWnd);
|
||||
}
|
||||
|
||||
void Error(char *str, ...)
|
||||
{
|
||||
va_list f;
|
||||
va_start(f, str);
|
||||
DoMessageBox(str, f, TRUE);
|
||||
va_end(f);
|
||||
}
|
||||
|
||||
void Message(char *str, ...)
|
||||
{
|
||||
va_list f;
|
||||
va_start(f, str);
|
||||
DoMessageBox(str, f, FALSE);
|
||||
va_end(f);
|
||||
}
|
||||
|
||||
|
||||
void OpenWebsite(char *url) {
|
||||
ShellExecute(GraphicsWnd, "open", url, NULL, NULL, SW_SHOWNORMAL);
|
||||
}
|
||||
|
||||
void ExitNow(void) {
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue