Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

This morning I found out that CodeAse, sells a tool, CodeAse 2.0, which is just LLBLGen 1.x but with different screencolors. LLBLGen 1.x is BSD licensed, but that doesn't mean you can simply rebadge it and sell it as if you wrote it! The BSD license clearly states you have to mention the original author of the work you use in your software in the About box and documentation. This didn't happen.

This apparently is the downside of releasing software under the BSD license: there are always lazy people around which just grab your hard work and act as if they spend 3 months of programming the stuff, because they didn't.

To all the people who want to purchase CodeAse 2.0: you can better get the free LLBLGen, it's the same code and it doesn't cost you a dime: http://www.sd.nl/software. To all the people who have already purchased CodeAse 2.0: you bought a product which violated the license of the code it contains. I'm not sure what that means for your situation, but if I look at SCO, I'd drop CodeAse on the spot.

Published Sunday, February 29, 2004 11:14 AM by FransBouma
Filed under:

Comments

# Frans Bouma is getting ripped off.

Sunday, February 29, 2004 3:35 AM by TrackBack

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Sunday, February 29, 2004 5:42 AM by matthew
this is exactly the problem with the licence you chose. Don't forget that Microsoft uses BSD code in Windows with only very minor notification, and basically unless you choose a different licence, there's nothing you can do about this. In fact I think the BSD licence no longer contains the advertising clause....

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Sunday, February 29, 2004 5:50 AM by Frans Bouma
This is the license I used:

COPYRIGHTS:
Copyright (c)2002 Solutions Design. All rights reserved.
http://www.sd.nl

Released under the following license: (BSD2)
-------------------------------------------
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

(disclaimer)
-------
This is not met. Nowhere can I find who wrote their software (namely: me).

It's ok for me that they sell it, that's indeed the disadvantage of the BSD license and I knew that upfront, as you said, MS uses BSD licensed code too (but says so), however the stuff still needs to meet the license of the code it contains, which in this case it doesn't. :(

Now it appears as if they had a great idea, they wrote some nice tool and their customers think they actually did. The license is in every codefile they have used in the tool, they couldn't have missed it.

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Sunday, February 29, 2004 5:58 AM by matthew
more stuff from the same guys:

http://www.invenmanager.com/products/DesktopDefault.aspx

is this ripped off as well?

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Sunday, February 29, 2004 6:08 AM by Frans Bouma
That Export .NET sounds like McLaws' GenX control.

I'll mail him about this. Thanks for the tip.

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Sunday, February 29, 2004 6:12 AM by Frans Bouma
It can also be SeriousFish.com's eXport.NET... but that's commercial too... A bit too much work perhaps to create your own tool with that.

I'm not aware of an open source excel exporter tool for .NET, if there is, it's a likely candidate...

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Sunday, February 29, 2004 6:26 AM by matthew
this company is also called orilogic. The exporter is not real Excel, it just seems (from reflector) to emit HTML, which Excel can parse.....

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Sunday, February 29, 2004 9:31 AM by Brad More
Just spread the word folks. If this isn't outright theft, it's certainly in the gray area. Word of mouth might be sufficient to at least partially nullify their ill gotten gain.

# Karim Hyatt is also getting ripped off it appears

Sunday, February 29, 2004 6:43 PM by Martin Liversage
Look at this: http://www.codease.com/web/DesktopDefault.aspx?tabid=81

Then compare to this: http://www.microsoft.com/belux/nl/msdn/community/columns/hyatt/ntier1.mspx

I wish that Codease will be hit by the MS legal department... hard. Now, think that I should ever wish that...

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Sunday, February 29, 2004 10:13 PM by Darrell
Sheesh. There are always slackers ripping off the hard work of others.

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Monday, March 01, 2004 12:33 PM by Karim Hyatt
Well, well,

Thanks Martin for letting me know. Theft is theft, I guess that for some people, nothing is sacred!

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Monday, March 01, 2004 2:10 PM by FG
Frans,
how do you deal with the situation?

Are you going to let them know, that they have stolen your source ?

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Monday, March 01, 2004 4:00 PM by Frans Bouma
I've mailed them, they mailed me back that they disagreed... The license is very clear, very small and they didn't meet any of the points. Their product is for over 90% my code, still they claim copyright.

They're in singapore, I'm in The Netherlands, I'm not really sure what to do, besides spreading the word. I hope enough people will know that they are just trying to make a quick buck by deliberately not obeying a license.

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Tuesday, March 02, 2004 6:12 AM by m7
that pisses me off. frans puts in a shitload of hard work, someone else rips it off and charges for it.

how sure are you that they've copied your code, frans? have u seen their source code? i would imagine there's a fine line between "similar in design" and "copying your code".

if you're certain that they've copied it, then under the terms of the license, you should be able to sue them regardless of where they trade from. if they are making money from your product illegally you should be able to sue them for exactly that amount.

but for now, if you're sure about this, spread the word. a LOT of people read asp.net/forums, so i'd consider letting people over there know.

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Tuesday, March 02, 2004 6:22 AM by Frans Bouma
Well, I'm not offended by them selling my code, because that's related to the license I used: BSD2, and I used that license on purpose: because I believe in total freedom of sourcecode. The thing is: the license is not restrictive but does have a few rules. One of them is that you have to state who really made the code. This is not done. In other words: no customer of them knows I made the code (more than 90% of the code in their app is mine), they all think CodeAse made the code, which is not the case.

Example:
Decompiled from their CodeAse.Tables.dll: (clsTable.GetFields(), they didn't even change the names)
-------
public void GetFields()
{ SqlDataAdapter adapter1;
SqlCommand command1;
DataTable table1;
string text1;
int num1;
DataRow row1;
int num2;
string text2;
Exception exception1;
table1 = new DataTable();
text1 = "SELECT INFORMATION_SCHEMA.COLUMNS.*,(SELECT COLUMNPROPERTY(OBJECT_ID(@sTableName), INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME, 'IsComputed')) AS IsComputed,(SELECT COL_LENGTH(@sTableName, INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME)) AS ColumnLength,(SELECT COLUMNPROPERTY(OBJECT_ID(@sTableName), INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME, 'IsIdentity')) AS IsIdentity,(SELECT COLUMNPROPERTY(OBJECT_ID(@sTableName), INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME, 'IsRowGuidCol')) AS IsRowGuidColumn,(ISNULL((SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo' AND COLUMN_NAME=INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME AND EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo' AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND CONSTRAINT_NAME=INFORMATION_SCHEMA.KEY_COLUMN_USAGE.CONSTRAINT_NAME)), 0)) AS IsPrimaryKey,(ISNULL((SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo'AND COLUMN_NAME=INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME AND EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo' AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME=INFORMATION_SCHEMA.KEY_COLUMN_USAGE.CONSTRAINT_NAME)), 0)) AS IsForeignKey, (ISNULL((SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo'AND COLUMN_NAME=INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME AND EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo' AND CONSTRAINT_TYPE = 'UNIQUE' AND CONSTRAINT_NAME=INFORMATION_SCHEMA.KEY_COLUMN_USAGE.CONSTRAINT_NAME)), 0)) AS HasUniqueConstraint FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @sTableName AND TABLE_SCHEMA='dbo'";
command1 = new SqlCommand(text1, this.m_scoActiveConnection);
adapter1 = new SqlDataAdapter(command1);
try
{
command1.Parameters.Add(new SqlParameter("@sTableName", 22, 250, 1, 0, 0, 0, "", 1024, this.m_sTableName));
adapter1.Fill(table1);
this.m_arrfFields = new clsField[((uint) table1.Rows.Count)];
for (num1 = 0; (num1 < this.m_arrfFields.Length); num1 = (num1 + 1))
{
row1 = table1.Rows[num1];
this.m_arrfFields[num1] = new clsField(row1["COLUMN_NAME"].ToString());
this.m_arrfFields[num1].bIsComputed = (Convert.ToInt32(row1["IsComputed"]) == 1);
this.m_arrfFields[num1].bIsForeignKey = (Convert.ToInt32(row1["IsForeignKey"]) == 1);
this.m_arrfFields[num1].bIsPrimaryKey = (Convert.ToInt32(row1["IsPrimaryKey"]) == 1);
this.m_arrfFields[num1].bIsIdentity = (Convert.ToInt32(row1["IsIdentity"]) == 1);
this.m_arrfFields[num1].bIsRowGUIDColumn = (Convert.ToInt32(row1["IsRowGuidColumn"]) == 1);
this.m_arrfFields[num1].bHasUniqueConstraint = (Convert.ToInt32(row1["HasUniqueConstraint"]) == 1);
this.m_arrfFields[num1].sDataType = row1["DATA_TYPE"].ToString();
this.m_arrfFields[num1].iLength = Convert.ToInt32(row1["ColumnLength"]);
if (row1["CHARACTER_MAXIMUM_LENGTH"].ToString().Length > 0)
{
num2 = Convert.ToInt32(row1["CHARACTER_MAXIMUM_LENGTH"]);
if ((this.m_arrfFields[num1].sDataType.ToLower(CultureInfo.InvariantCulture) == "nvarchar") || (this.m_arrfFields[num1].sDataType.ToLower(CultureInfo.InvariantCulture) == "nchar"))
{
this.m_arrfFields[num1].iLength = num2;

}

}
this.m_arrfFields[num1].iOrdinalPosition = Convert.ToInt32(row1["ORDINAL_POSITION"]);
if (row1["NUMERIC_PRECISION"].ToString().Length > 0)
{
this.m_arrfFields[num1].iPrecision = Convert.ToInt32(row1["NUMERIC_PRECISION"]);

}
if (row1["NUMERIC_SCALE"].ToString().Length > 0)
{
this.m_arrfFields[num1].iScale = Convert.ToInt32(row1["NUMERIC_SCALE"]);

}
this.m_arrfFields[num1].slTypeToPrefix = this.m_slTypeToPrefix;
this.m_arrfFields[num1].slTypeToNETType = this.m_slTypeToNETType;
this.m_arrfFields[num1].slTypeToVBCastType = this.m_slTypeToVBCastType;
this.m_arrfFields[num1].slTypeToSqlType = this.m_slTypeToSqlType;
this.m_arrfFields[num1].slTypeToCSCastType = this.m_slTypeToCSCastType;
this.m_arrfFields[num1].bIsNullable = (row1["IS_NULLABLE"].ToString().ToLower(CultureInfo.InvariantCulture) == "yes");
this.m_arrfFields[num1].sDefaultValue = row1["COLUMN_DEFAULT"].ToString();
if (this.m_arrfFields[num1].bIsPrimaryKey)
{
this.m_iAmountPrimaryKeyFields = (this.m_iAmountPrimaryKeyFields + 1);

}
text2 = string.Concat(this.m_sTableName.ToLower(CultureInfo.InvariantCulture), ".", this.m_arrfFields[num1].sFieldName.ToLower(CultureInfo.InvariantCulture));
this.m_arrfFields[num1].bIsExcluded = !(this.m_alExcludedFields.IndexOf(text2) < 0);

}

}
catch (Exception exception2)
{
exception1 = exception2;
throw new Exception(string.Concat("clsTable::GetFields:Error occured: ", exception1.Message), exception1);

}
finally
{
adapter1.Dispose();
adapter1 = null;

}

}
-----

Source from LLBLGen 1.x: clsTable.GetFields():
public void GetFields()
{
SqlDataAdapter sdaFieldRetrieval;
SqlCommand scmFieldRetrieval;
DataTable dtFields = new DataTable();

// we'll retrieve ALL fieldinformation with 1 single query. this query is quite long, but
// doesn't use any systemspecific tables at all.
string sSQL = "SELECT INFORMATION_SCHEMA.COLUMNS.*,(SELECT COLUMNPROPERTY(OBJECT_ID(@sTableName), INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME, 'IsComputed')" +
") AS IsComputed,(SELECT COL_LENGTH(@sTableName, INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME)) AS ColumnLength,(SELECT " +
"COLUMNPROPERTY(OBJECT_ID(@sTableName), INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME, 'IsIdentity')) AS IsIdentity,(SELECT " +
"COLUMNPROPERTY(OBJECT_ID(@sTableName), INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME, 'IsRowGuidCol')) AS IsRowGuidColumn,(ISNULL(" +
"(SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo' AND COLUMN_NAME=" +
"INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME AND EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME=@sTableName " +
"AND TABLE_SCHEMA='dbo' AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND CONSTRAINT_NAME=INFORMATION_SCHEMA.KEY_COLUMN_USAGE.CONSTRAINT_NAME)" +
"), 0)) AS IsPrimaryKey,(ISNULL((SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo'" +
"AND COLUMN_NAME=INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME AND EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME=" +
"@sTableName AND TABLE_SCHEMA='dbo' AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME=INFORMATION_SCHEMA.KEY_COLUMN_USAGE.CONSTRAINT_NAME)" +
"), 0)) AS IsForeignKey, (ISNULL((SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo'" +
"AND COLUMN_NAME=INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME AND EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE " +
"TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo' AND CONSTRAINT_TYPE = 'UNIQUE' AND CONSTRAINT_NAME=INFORMATION_SCHEMA.KEY_COLUMN_USAGE.CONSTRAINT_NAME)" +
"), 0)) AS HasUniqueConstraint FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @sTableName AND TABLE_SCHEMA='dbo'";
scmFieldRetrieval = new SqlCommand(sSQL,m_scoActiveConnection);
sdaFieldRetrieval = new SqlDataAdapter(scmFieldRetrieval);
try
{
scmFieldRetrieval.Parameters.Add(new SqlParameter("@sTableName", SqlDbType.VarChar, 250, ParameterDirection.Input, false, 0, 0, "", DataRowVersion.Proposed, m_sTableName));

// Fill the datatable
sdaFieldRetrieval.Fill(dtFields);

// Create field objects
m_arrfFields = new clsField[dtFields.Rows.Count];

// for each row, add a clsField object to the array.
for(int i = 0;i < m_arrfFields.Length;i++)
{
DataRow drCurrent = dtFields.Rows[i];

m_arrfFields[i] = new clsField(drCurrent["COLUMN_NAME"].ToString());
// fill properties.
m_arrfFields[i].bIsComputed = (Convert.ToInt32(drCurrent["IsComputed"]) == 1);
m_arrfFields[i].bIsForeignKey = (Convert.ToInt32(drCurrent["IsForeignKey"]) == 1);
m_arrfFields[i].bIsPrimaryKey = (Convert.ToInt32(drCurrent["IsPrimaryKey"]) == 1);
m_arrfFields[i].bIsIdentity = (Convert.ToInt32(drCurrent["IsIdentity"]) == 1);
m_arrfFields[i].bIsRowGUIDColumn = (Convert.ToInt32(drCurrent["IsRowGuidColumn"]) == 1);
m_arrfFields[i].bHasUniqueConstraint = (Convert.ToInt32(drCurrent["HasUniqueConstraint"]) == 1);
m_arrfFields[i].sDataType = drCurrent["DATA_TYPE"].ToString();
m_arrfFields[i].iLength = Convert.ToInt32(drCurrent["ColumnLength"]);
if(drCurrent["CHARACTER_MAXIMUM_LENGTH"].ToString().Length > 0)
{
// has a value
int iCharacterMaxLength = Convert.ToInt32(drCurrent["CHARACTER_MAXIMUM_LENGTH"]);

if((m_arrfFields[i].sDataType.ToLower(CultureInfo.InvariantCulture) == "nvarchar") ||
(m_arrfFields[i].sDataType.ToLower(CultureInfo.InvariantCulture) == "nchar"))
{
// set length to length mentioned in CHARACTER_MAXIMUM_LENGTH
m_arrfFields[i].iLength = iCharacterMaxLength;
}
}
m_arrfFields[i].iOrdinalPosition = Convert.ToInt32(drCurrent["ORDINAL_POSITION"]);
if(drCurrent["NUMERIC_PRECISION"].ToString().Length > 0)
{
m_arrfFields[i].iPrecision = Convert.ToInt32(drCurrent["NUMERIC_PRECISION"]);
}
if(drCurrent["NUMERIC_SCALE"].ToString().Length > 0)
{
m_arrfFields[i].iScale = Convert.ToInt32(drCurrent["NUMERIC_SCALE"]);
}
m_arrfFields[i].slTypeToPrefix = m_slTypeToPrefix;
m_arrfFields[i].slTypeToNETType = m_slTypeToNETType;
m_arrfFields[i].slTypeToVBCastType = m_slTypeToVBCastType;
m_arrfFields[i].slTypeToSqlType = m_slTypeToSqlType;
m_arrfFields[i].slTypeToCSCastType = m_slTypeToCSCastType;
m_arrfFields[i].bIsNullable = (drCurrent["IS_NULLABLE"].ToString().ToLower(CultureInfo.InvariantCulture) == "yes");
m_arrfFields[i].sDefaultValue = drCurrent["COLUMN_DEFAULT"].ToString();
if(m_arrfFields[i].bIsPrimaryKey)
{
m_iAmountPrimaryKeyFields++;
}

// check if this field is excluded (i.e., in the list of excluded fields)
m_arrfFields[i].bIsExcluded = (m_alExcludedFields.IndexOf(m_arrfFields[i].sFieldName.ToLower(CultureInfo.InvariantCulture)) >= 0);
}
}
catch(Exception ex)
{
// bubble error.
throw new Exception("clsTable::GetFields:Error occured: " + ex.Message, ex);
}
finally
{
sdaFieldRetrieval.Dispose();
sdaFieldRetrieval = null;
}
}

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Tuesday, March 02, 2004 6:34 AM by Frans Bouma
Some small differences are most likely due to optimization of the compiler. oh wait, I can check compiled versions of LLBLGen 1.x with their dll :D

Compiled LLBLGen 1.x clsTables.GetFields()
------
public void GetFields()
{ SqlDataAdapter adapter1;
SqlCommand command1;
DataTable table1;
string text1;
int num1;
DataRow row1;
int num2;
Exception exception1;
table1 = new DataTable();
text1 = "SELECT INFORMATION_SCHEMA.COLUMNS.*,(SELECT COLUMNPROPERTY(OBJECT_ID(@sTableName), INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME, 'IsComputed')) AS IsComputed,(SELECT COL_LENGTH(@sTableName, INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME)) AS ColumnLength,(SELECT COLUMNPROPERTY(OBJECT_ID(@sTableName), INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME, 'IsIdentity')) AS IsIdentity,(SELECT COLUMNPROPERTY(OBJECT_ID(@sTableName), INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME, 'IsRowGuidCol')) AS IsRowGuidColumn,(ISNULL((SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo' AND COLUMN_NAME=INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME AND EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo' AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND CONSTRAINT_NAME=INFORMATION_SCHEMA.KEY_COLUMN_USAGE.CONSTRAINT_NAME)), 0)) AS IsPrimaryKey,(ISNULL((SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo'AND COLUMN_NAME=INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME AND EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo' AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME=INFORMATION_SCHEMA.KEY_COLUMN_USAGE.CONSTRAINT_NAME)), 0)) AS IsForeignKey, (ISNULL((SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo'AND COLUMN_NAME=INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME AND EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME=@sTableName AND TABLE_SCHEMA='dbo' AND CONSTRAINT_TYPE = 'UNIQUE' AND CONSTRAINT_NAME=INFORMATION_SCHEMA.KEY_COLUMN_USAGE.CONSTRAINT_NAME)), 0)) AS HasUniqueConstraint FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @sTableName AND TABLE_SCHEMA='dbo'";
command1 = new SqlCommand(text1, this.m_scoActiveConnection);
adapter1 = new SqlDataAdapter(command1);
try
{
command1.Parameters.Add(new SqlParameter("@sTableName", 22, 250, 1, 0, 0, 0, "", 1024, this.m_sTableName));
adapter1.Fill(table1);
this.m_arrfFields = new clsField[table1.Rows.Count];
for (num1 = 0; (num1 < this.m_arrfFields.Length); num1 = (num1 + 1))
{
row1 = table1.Rows[num1];
this.m_arrfFields[num1] = new clsField(row1["COLUMN_NAME"].ToString());
this.m_arrfFields[num1].bIsComputed = (Convert.ToInt32(row1["IsComputed"]) == 1);
this.m_arrfFields[num1].bIsForeignKey = (Convert.ToInt32(row1["IsForeignKey"]) == 1);
this.m_arrfFields[num1].bIsPrimaryKey = (Convert.ToInt32(row1["IsPrimaryKey"]) == 1);
this.m_arrfFields[num1].bIsIdentity = (Convert.ToInt32(row1["IsIdentity"]) == 1);
this.m_arrfFields[num1].bIsRowGUIDColumn = (Convert.ToInt32(row1["IsRowGuidColumn"]) == 1);
this.m_arrfFields[num1].bHasUniqueConstraint = (Convert.ToInt32(row1["HasUniqueConstraint"]) == 1);
this.m_arrfFields[num1].sDataType = row1["DATA_TYPE"].ToString();
this.m_arrfFields[num1].iLength = Convert.ToInt32(row1["ColumnLength"]);
if (row1["CHARACTER_MAXIMUM_LENGTH"].ToString().Length > 0)
{
num2 = Convert.ToInt32(row1["CHARACTER_MAXIMUM_LENGTH"]);
if ((this.m_arrfFields[num1].sDataType.ToLower(CultureInfo.InvariantCulture) == "nvarchar") || (this.m_arrfFields[num1].sDataType.ToLower(CultureInfo.InvariantCulture) == "nchar"))
{
this.m_arrfFields[num1].iLength = num2;

}

}
this.m_arrfFields[num1].iOrdinalPosition = Convert.ToInt32(row1["ORDINAL_POSITION"]);
if (row1["NUMERIC_PRECISION"].ToString().Length > 0)
{
this.m_arrfFields[num1].iPrecision = Convert.ToInt32(row1["NUMERIC_PRECISION"]);

}
if (row1["NUMERIC_SCALE"].ToString().Length > 0)
{
this.m_arrfFields[num1].iScale = Convert.ToInt32(row1["NUMERIC_SCALE"]);

}
this.m_arrfFields[num1].slTypeToPrefix = this.m_slTypeToPrefix;
this.m_arrfFields[num1].slTypeToNETType = this.m_slTypeToNETType;
this.m_arrfFields[num1].slTypeToVBCastType = this.m_slTypeToVBCastType;
this.m_arrfFields[num1].slTypeToSqlType = this.m_slTypeToSqlType;
this.m_arrfFields[num1].slTypeToCSCastType = this.m_slTypeToCSCastType;
this.m_arrfFields[num1].bIsNullable = (row1["IS_NULLABLE"].ToString().ToLower(CultureInfo.InvariantCulture) == "yes");
this.m_arrfFields[num1].sDefaultValue = row1["COLUMN_DEFAULT"].ToString();
if (this.m_arrfFields[num1].bIsPrimaryKey)
{
this.m_iAmountPrimaryKeyFields = (this.m_iAmountPrimaryKeyFields + 1);

}
this.m_arrfFields[num1].bIsExcluded = !(this.m_alExcludedFields.IndexOf(this.m_arrfFields[num1].sFieldName.ToLower(CultureInfo.InvariantCulture)) < 0);

}

}
catch (Exception exception2)
{
exception1 = exception2;
throw new Exception(string.Concat("clsTable::GetFields:Error occured: ", exception1.Message), exception1);

}
finally
{
adapter1.Dispose();
adapter1 = null;

}

}

i.o.w.: exactly the same. And it is exactly the same, over and over and over. They moved around some classes into dll's, but that doesn't alter the code one bit.

The irony was that when I wanted to test it, it asked for a 'license' and because I didn't have one I could not test it... just use Northwind.

The generated code is changed a little, it now uses some central methods, however the vast majority of it is the same. All SQL proc code for example is exactly the same.

These central methods are very different in coding style. (commenting for example, no XML comments).

It seems like a quick sunday afternoon hack in existing code (i.e. add some lines, slap your name on it and you have a product).

This issue has changed my view on open source licenses though. Every piece of open source I'll release in the future will be GPL-ed, if they then violate it, I can mail Slashdot and the FSF and it will be solved :)

The suggestion of the forums is ok, but it will give them extra exposure as well, and I don't want that too. Decisions...

Thanks for the support, all!

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Tuesday, March 02, 2004 12:02 PM by Shannon J Hager
what makes it so bad is that all they have to do to comply with the license is say that the code is based on LLBLGen and then point out the things they added. They did add a few things and the price is low enough, there really is no excuse for this at all.

But don't let a thief and liar change your view on licensing, it doesn't matter what license your code was under (GPL or non-open), a thief is a thief and they don't care which rule they break. Their answer is "we didn't use your code" so that wouldn't change just because your licensing terms changed.

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Tuesday, March 02, 2004 12:22 PM by Frans Bouma
Shannon: Yeah, they had to do so little, it's absurd they didn't do it.

Well, one advantage of the GPL any other license will never have: it has a big group of followers which are very active. Spreading the word of a GPL violation on for example /. will mobilize these groups instantly and it's a bit of power towards the violator you miss when you use another type of license, unfortunately :/

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Tuesday, March 02, 2004 11:05 PM by Shannon J Hager
I'm sure you could do the same with the BSD license, but the fact (sometimes) sad fact is that the physical distance and political differences between you and the thiefs means that the chance of anything ever happening is slim-to-none.

I notice they did remove the blatently stolen article from their site, so they do have some sense, maybe there is hope.

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Wednesday, March 03, 2004 6:11 AM by Frans Bouma
As a last resort I yesterday asked them why they didn't simply obey the license terms and suddenly they were willing to do so. I've mailed what I wanted them to do (adding a single line to the about box, as stated in the license) however haven't heared since. I'll try mailing them later today again.

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Thursday, March 04, 2004 1:03 AM by jf
hey, the news is out in Singapore, btw - take a look at this... - http://www.lugs.org.sg/cgi-bin/ezmlm-browse?command=threadindex&list=SlugNet&threadid=aldgkglmacchddmpfjoh

This is the Singapore Linux User Group mailing list, btw.

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Thursday, March 04, 2004 4:20 AM by Frans Bouma
THanks JF, it's also on slashdot now (not the FP, in the ask /. section).

I've mailed them again, see if they respond...

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Thursday, March 04, 2004 7:40 AM by Brian Schkerke
Honestly I don't think it'd matter if the code was GPL or BSD - companies like this would take the code anyway.

*spits*

s'ok Frans, LLBLGen Pro beats the snot out of 1.2. ;)

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Thursday, March 04, 2004 8:28 AM by Frans Bouma
Brian :)

Yeah, I don't think the license itself will stop them. It's however the crowd of followers who can stop them...

# BSD2 license violation solved

Thursday, March 04, 2004 10:13 PM by TrackBack

# re: Code theft: Codease uses my LLBLGen 1.x sourcecode as if it is theirs!

Friday, March 05, 2004 4:13 AM by Frans Bouma
It has been solved. They 've updated the application and documentation. :)

# Interesting stuff I missed this week

Friday, March 05, 2004 12:27 PM by TrackBack

# Interesting stuff I missed this week

Friday, March 05, 2004 1:40 PM by TrackBack