2009年5月26日星期二

Microsoft机器翻译MSDN杂志

今天看2009年5月份的MSDN杂志时发现这样一段话:
"请注意: 从即日起,杂志的内容将由机器翻译为简体中文。得益于这一快速发展的新技术,我们将能够以更多的语言、更快的速度与全世界的读者分享内容。我们欢迎您评估这些页面的翻译质量并提出意见。"


这一段话中提到了“机器翻译”,让我想起还在学校的时候使用过的Google Translation服务,不过我记得当时的翻译结果是惨不忍睹的:)我仔细看了MSDN的翻译结果之后,感觉这次微软的机器翻译基本上也是这个情况。


Google的翻译工具有一个提供修改意见的地方,如果觉得翻译结果不满意,我们可以给出自己的翻译建议。毕竟在现阶段,人的理解能力是机器所无法达到的。这个可以为翻译工具提供建议的特性我在MDSN的翻译结果页面里找到了,请看下面这个图:

note:不过我始终无法正确提交翻译的建议,不知为何……

虽然翻译的质量不怎么样,但是微软已经打算要将机器翻译用作商用了,因为微软不在提供中文版的MSDN杂志,而是让用户阅读由机器翻译成的内容:
请注意,我们将不再提供简体中文版的 MSDN Magazine CHM 文件。然而,您仍可通过单击“HTML Help Format”按钮,以访问美国英语版的 CHM 文件。
看来微软是要逼我们为它的翻译机器做出贡献了,呵呵
此为机器翻译内容,社区成员可对其进行编辑。我们十分希望您能单击与以下任一句子关联的“编辑”链接,对翻译进行改进。

2009年5月21日星期四

S#arp Architecture for the ASP.NET MVC Framework

This is a solid architectural foundation for rapidly building maintainable web
applications leveraging the ASP.NET MVC framework with NHibernate. The primary
advantage to be sought in using any architectural framework is to decrease the
code one has to write while increasing the quality of the end product

S#arp Architecture adheres to the following key principles:
•Focused on Domain Driven Design
•Loosely Coupled
•Preconfigured Infrastructure
•Open Ended Presentation


Watch the introduction video on dimecasts.net: # 75 - Introdction to S#arp Architecture . It's an opensource project holded on google code.


2009年5月19日星期二

DataBinding无法绑定到public字段上

DataBind连接UI控件和后台数据源的技术,我们可以非常方便地将它用于DataGridView或ListBox这样的数据控件的数据显示。通过简单地设置一下数据源和所要显示的属性名就可以了:

listBox.DataSource = bindingSource;
listBox.DisplayMember = "propertyName";

上面代码中的DisplayMember就是设置将数据源中对象的哪个属性显示出来。这里需要注意,DisplayMember只能对应到对象的属性(Property)上,不能设置为对象的字段(Field),即使公共字段也不行。对于下面这个对象:

internal class TestBinding
{
public string publicField;

private string publicProperty;

public string PublicProperty
{
get { return publicProperty; }
set { publicProperty = value; }
}
}

如果我们设置绑定:

listSubsetHeaders.DisplayMember = "publicField"; //failed:bind to public field
listSubsetHeaders.DisplayMember = "PublicProperty"; //ok: bind to property

DataBind不允许绑定到公共字段上,必须绑定到属性才行:
One of the reasons why data-binding support is limited to properties happens to
be the fact that all of data-binding is built around PropertyDescriptors and not
on direct reflection.


这里有篇blog讨论了这个问题:Data-binding to public fields... yes or no?

2009年5月15日星期五

Assertion failed: _CrtIsValidHeapPointer(pUserData) in dbgheap.c.

今天将在vs2003中写的c++项目升级到vs2005,结果发现运行的时候报异常了。

Assertion failed: _CrtIsValidHeapPointer(pUserData) in dbgheap.c

对于托管的C++代码,当它们被编译成dll时,默认情况下是不能使用本地c/c++库(Native c/c++ lib)的,这些本地库包括C run-time(CRT)、ATL和MFC。有这个限制是因为在c++.net 的dll中默认不能使用任何的静态变量(除非是像整形这样非常简单的类型),而这些本地库通常都使用了静态变量。在c++.net项目的属性中默认使用/NOENTRY编译参数来实现这个限制。应用了/NOENTRY参数的DLL项目中不能使用CRT、ATL和MFC,否则就会产生异常。而我的C++ 项目中正好使用了MFC的窗体控件,而且是被编译成DLL的,所以报错了。
这个问题的解决办法有两个:
  1. 在编译时仍然使用/NOENTRY参数,但是禁用自动初始化,改为手动初始化所引用的静态变量 。自动初始化CRT、ATL和MFC有可能会产生死锁(DeadLock)。关于如何手动初始化,请参考Microsoft的技术支持文档“You receive linker warnings when you build Managed Extensions for C++ DLL projects”中的“Resolution”部分。
  2. 在编译时去掉/NOENTRY参数。 这是非官方的解决方案,非常简单。

我直接使用了第二种方案,问题解决了。如果你也遇到跟我一样的问题,不妨试试看。

2009年5月13日星期三

第一次遇到在多种语言同时出现在一个真实的项目中

换到新公司了,这里几乎都是用微软的技术,包括.net 2.0/3.5, vs2005/2008, sql server 2005/2008, windows 2003/2008。其中.net 3.5中WPF和WCF的使用非常频繁。以前都听说.net不适用与企业级项目,只能做中小型应用,现在看来情况好像不是这样的。不过微软的解决方案相较于Linux阵营的而言,从成本上好像确实好高出很多,据说我所知公司在开发和运行环境上的投入非常大,这包括微软的软件licence费用和微软的咨询服务收费。公司从开发流程,开发方式以及技术的使用上都是走微软的路子:)

记得在刚学习微软的.net时,书上就介绍说.net平台提供了各种语言之间的互操作性,同一个项目了可以使用各种不同的语言进行开发,只要这些语言是.net兼容的。之前一直以为没有人会这么做的,毕竟不同的语言在写法和思维方式上多少会有些差异,而且同一项目的人在阅读别人的代码会很困难,想象一下突然让你去读你不熟悉的语言,还要修改功能是个什么感觉?

我最近就遇到了这样的问题。在接手现在的项目之前,我只用C#,对于C++不怎么了解,更不用说用它来开发了。可是现在的项目在拿到源代码的时候就傻了,真的,不开玩笑,呵呵。你猜怎么地,混合编程啦,c++和c#语言各完成一部分工作,读起来那叫一个痛苦……

你也许觉得是我不怎么会C++的原因,其实不全是这样。同组的同事中有多年C++背景的,不过他们是纯C++的,不是微软的c++.net,看起来也很头大,基本上认同c++.net的行为比较奇怪,呵呵,看来还是不适应。

Anyway,硬着头皮继续看吧……

2009年4月29日星期三

LinqToSql异常:"you can't new an Entity in a query"

下面这段代码执行的时候就会抛出标题中提到的异常:

public Product GetProduct(int productId)
{
var product = (from p in dbContext.Products
where p.ProductID == productId
select new Product { Name = p.Name, ListPrice = p.ListPrice, ProductID = p.ProductID }
).Single();
return product;
}


原因在于我们在查询语句的最后执行了一个创建新的Product的方法,这就是异常中提到的new entity的意思。在query中我们并不是不能创建对象的实例,而是不能创建“实体”的实例,在linq to sql中实体指的就是与数据库表对应的那个对象,比如这里的Product

为了验证这一点,我们将Product换成别的类,比如ProductData:

public ProductData GetProduct(int productId)
{
var product = (from p in dbContext.Products
where p.ProductID == productId
select new ProductData {
Name = p.Name,
ListPrice = p.ListPrice,
ProductID = p.ProductID
}).Single();
return product;
}

这样就没问题了,query可以正常执行。ProductData类是我们自定义的类,用作DataContract,不是linq to sql的建模工具从数据库生成的。

[DataContract]
public class ProductData
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int ProductID { get; set; }
[DataMember]
public decimal ListPrice { get; set; }
}
所以,如果你得到这个异常,不妨检查看看你的query语句里是否包含了“实体”。

2007年4月27日星期五

save pictures from MS Word

作为word文档解析的一部分,图片的提取非常的重要。在google上搜索word图片提取找到的基本是VBA的方式,写一段脚本嵌入word中然后执行这样子,一来不熟悉,二来也不符合我对word文档处理的要求。我这里是需要从word文档外部来解析,也就是用一个程序打开word文件,读取其中的内容,这是一种从外部处理的方式,与VBA这种嵌入的方式有较大差别。其实升级到.net framework2.0之后,VSTO已经提供了很多方便操作office文件的方法,当然也包括word。这里就介绍一下借助VSTO和剪贴板来提取word图片的方法。
业务需求

有一个word文档,里面包含了一些构件描述信息和一些图片,要求找出图片另存到一个目录下,然后将该图片替换成一个指示出了图片位置的标签,比如

[img]img/PORT.doc/picture_2.Jpeg[img]

目的是为了在进一步解析构件信息,并存入数据库之后网站的表示层可以直接根据该标签找到图片并显示。
可行的解决方案


既然是要提取图片,那么首先就得在word中找到图片。图片(Picture)在word中会以两种形式存在——Shape和InlineShape——如果要取出所有的图片一定记住不要漏掉了任何一个。但是不是所有的Shape和InlineShape都是picture,我们需要先做判断:

Shape中有两种类型的picture:
MsoShapeType.msoPicture
MsoShapeType.msoLinkedPicture

InlineShape中有两种类型的picture: WdInlineShapeType.wdInlineShapePicture WdInlineShapeType.wdInlineShapeLinkedPicture

找到所有了的图片之后将它们拷贝到剪贴板,然后就可以保存了。基本步骤如下:

1. 首先打开文档。因为要替换图片,那么要求打开文档的时候是可以编辑的——ReadOnly设为false。
2. 读取所有的shape,包括Shape和InlineShape。
3. 读取一个shape判断是否为Picture,如果是则将其选中,并拷贝到剪贴板。
4. 将剪贴板的图片保存到指定目录下。
5. 找到图片在word中的位置,在其前面插入图片标记
6. 将图片从word中删除
7. 继续读取下一个shape

打开文档

oWordApp = new ApplicationClass();
object readOnly = True;

object o_fileName = fileName;
Document wordDoc;
wordDoc = oWordApp.Documents.Open(ref o_fileName,
ref missing, ref readOnly,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref isVisible,
ref missing, ref missing, ref missing, ref missing);
wordDoc.Activate();

读取所有的shape

IList shapes = new ArrayList();
foreach(Shape shape in doc.Shapes)
{
shapes.Add(shape);
}
foreach(InlineShape shape in doc.InlineShapes)
{
shapes.Add(shape);
}



判断是否为Picture


if (isCommonShape)
{
commonShape = (Shape) shape;
isPicture = (commonShape.Type == MsoShapeType.msoPicture ||
commonShape.Type == MsoShapeType.msoLinkedPicture);
}
else if(isInlineShape)
{
inlineShpae = (InlineShape) shape;
isPicture = (inlineShpae.Type == WdInlineShapeType.wdInlineShapePicture ||
inlineShpae.Type == WdInlineShapeType.wdInlineShapeLinkedPicture);
}
选中,并拷贝到剪贴板

if(isCommonShape)
{
commonShape.Select(ref missing);
}
else
{
inlineShpae.Select();
}

wordApp.Selection.CopyAsPicture();

图片保存到指定目录下

System.Windows.Forms.Clipboard.GetImage().Save(fileNameOfPict, ImageFormat.Jpeg);

插入图片标记

object start = oWordApp.Selection.Start; //Shape的起始位置
doc.Range(ref start, ref start).Text = string.Format("[img]{0}[img]", fileNameOfPict);

将图片从word中删除

commonShape.Delete();




完整的代码

public void ProcessAllPicturesOfDoc(Document doc)
{
IList shapes = new ArrayList();
foreach(Shape shape in doc.Shapes)
{
shapes.Add(shape);
}
foreach(InlineShape shape in doc.InlineShapes)
{
shapes.Add(shape);
}
ExtractShape(shapes,doc,oWordApp);
}
public void ExtractShape(IList shapes,Document doc,ApplicationClass wordApp)
{
object missing = Missing.Value;
string pictDirect = "img/" + doc.Name + "/";
int i = 0;

foreach (object shape in shapes)
{
bool isPicture;
bool isCommonShape = shape is Shape;
bool isInlineShape = shape is InlineShape;

Shape commonShape = null;
InlineShape inlineShpae = null;
//check if the shape is a picture
if (isCommonShape)
{
commonShape = (Shape) shape;
isPicture = (commonShape.Type == MsoShapeType.msoPicture ||
commonShape.Type == MsoShapeType.msoLinkedPicture);
}
else if(isInlineShape)
{
inlineShpae = (InlineShape) shape;
isPicture = (inlineShpae.Type == WdInlineShapeType.wdInlineShapePicture ||
inlineShpae.Type == WdInlineShapeType.wdInlineShapeLinkedPicture);
}
else
{
throw new Exception("unknown Shape");
}

if (isPicture)
{

i++;
//select the range of the shape
//Note: the difference between two methods of selection
if(isCommonShape)
{
commonShape.Select(ref missing);
}
else
{
inlineShpae.Select();
}
//compy the picture to clipboard
wordApp.Selection.CopyAsPicture();
if (System.Windows.Forms.Clipboard.ContainsImage())
{
if (!Directory.Exists(pictDirect))
Directory.CreateDirectory(pictDirect);
string fileNameOfPict = pictDirect + "picture_" + i.ToString() + ".Jpeg";
//save picture
System.Windows.Forms.Clipboard.GetImage().Save(fileNameOfPict, ImageFormat.Jpeg);
//insert the img tag just at the start position of the shape
object start = oWordApp.Selection.Start;
doc.Range(ref start, ref start).Text = string.Format("[img]{0}[img]", fileNameOfPict);
//delete the picture
if(isCommonShape)
{
commonShape.Delete();
}
else
{
inlineShpae.Delete();
}
}
else
{
throw new Exception("error occures when copying picture");
}
}
}
}

以上的代码在VS2005+Office2003+xp2下测试通过,