专利在线申请之入门到精通再到放弃

    xiaoxiao2025-04-08  42

    开通专利申请的在线模式是一种巨大的进步,虽然仅仅只是创新工作上的一小步。经通周末两天两夜的"研发",终于把专利在线申请流程和软件搞明白了。此文适合于懂.NET C#、证书、控件等技术的人员阅读,也适合不懂这些技术的人员阅读。

    "研发"专利申请软件的使用技术是一种非常辛苦的工作,所以我觉得有必要记录下来,以后每年清明节可以来此瞻仰和扫墓。我对CPC软件的评价也是中肯的:它不是一堆屎,因为不仅仅是一堆屎!

    一、环境搭建

    专利申请软件简称CPC客户端,无需登录即可使用,签名的时候指定证书即可,所以CPC实际上就是一个专利案卷编辑器,经过测试发现,CPC在XP下运行状况相对比较良好(仅此而已),按以下配置部署软件环境:

    操作系统:WindowsXP

    public static bool IsUnsupported => ((!IsWindowsXP && !IsWindows2003) && !IsWindows7);

    .Net框架版本:最高3.5

    IE版本:7、8、9(注:XP下无法安装IE9)

    证书控件:http://interactive.cponline.cnipa.gov.cn/txnDownloadTl01.do?select-key:filename=OCX.zip

    CPC客户端:http://cponline.sipo.gov.cn/nas/nas03/web/content/attachment/201202/14130914kpjg.rar

    CPC更新程序:http://cponline.sipo.gov.cn/nas/nas03/web/content/attachment/201905/18095452b7az.zip

    Office版本:2003或2007,高了不行

    IE选项设置:给cponline.sipo.gov.cn和interactive.cponline.cnipa.gov.cn任何想要的权限,不得讲条件,包括但不限于允许未认证的控件下载或运行、加入信任站点、将安全等级能调多低就调多低。

    你会问,没有XP怎么办?这个问题问得好,下载安装Oracle VM VirtualBox,虚拟一个XP。

    二、安装软件及操作

    安装CPC软件后根据自带说明安装更新程序,运行软件:

    在网站http://cponline.sipo.gov.cn/注册一个个人或企业的账号,申请证书,整个流程网上申请网站的流程图是准确的。

    由于IE下操作可能出现的问题多,对控件要求、安全要求也多,所以不在线上编译申请文件,全部在线下完成,但是证书也是要在网上下载的,必须。另外,要完整提交申请,线上必须用证书登录,但是一直没有办法使用证书登录,如下图:

    不知道为什么检索不到证书,我查看源代码,它是用控件检索证书:

    <object id="ctl" type="application/x-causn" width="0" height="0"> <param name="onload" value="pluginLoaded" /> <param name="onAddfile" value="onAddfile" /> </object> //初始化数据 jq(function() { pageSetup_RegSet(); //获取登录地址 func_getDwfwUri(); //初始化设置账号登录验证码 func_setDefaultCode(1); //控件初始化 ctl.onInit(); plugin = ctl; //初始化证书列表 certs = plugin_GetCertificates(ctl); if (certs == null || certs.length == 0) { jq("#certificate").append("<option value='-1'>未检测到证书</option>"); } else { for (var i = 0; i < certs.length; i++) { var cert = certs[i]; var strCertNumber = cert.SerialNumber; var strCertCn = cert.CommonName + ""; jq("#certificate").append( "<option value='"+strCertNumber+"'>" + strCertCn + "</option>"); } } checkKeyType(jq('#certificate')[0]); });

    查了一下,application/x-causn是指控件

    就是“C:\Program Files (x86)\kairende\CA证书控件x86”下的那堆东西!

    要是检索不到证书,分析代码就无能为力了,我保证,证书是安装了的。

    由此可见,当时是用pfx文件安装的,它包含了私钥。可恨的是,当时安装证书的时候没有允许导出私钥,pfx文件找不到了,只能导出cer证书,这种证书没有带私钥,在别的电脑上后,也会检测不到证书

    回过头来,登录网站,下载证书!再啰嗦一下,切记保存pfx到硬盘,并且按照他的指示,保存到证书安装目录。

    下载一次后,就不再允许下载了,这个坑让我废了两个证件号。如果你说没有废,请教我怎么重新下载证书!?我本以为作废证书以后就可以重新申请证书,然并卵!

    三、制作专利申请文件

    打开CPC客户端,设置网络服务器

    选择一个能通的服务器。

    经过测试,如果你勾选https,可能无法连接服务器。

    证书管理,选择一个证书。

    现在可以开始制作专利申请文件了,申请什么类型专利可以根据自己的需要选择。

    进入案卷文件编辑器。

    有两个钉子问题,需要单独拿出来说:

    1.上传图片格式和尺寸问题

    上CPC源代码先,怎么解决就不用多说了:

    string str6 = Path.GetExtension(str3).Replace(".", ""); if (str5 != str6) { this.dtdErr = string.Concat(new object[] { "Validation", wj.WENJIANMC, "第", i + 1, "幅图片", innerText, "的文件类型与list.xml文件中的描述不一致!请重新编辑图片后再签名打包。", Environment.NewLine, this.dtdErr }); } else if ((((str5.ToLower() != "jpg") && (str5.ToLower() != "jpeg")) && (str5.ToLower() != "tiff")) && (str5.ToLower() != "tif")) { if ((wj.BEIZHU.ToUpper() != "PDF") || (str5.ToUpper() != "PDF")) { this.dtdErr = string.Concat(new object[] { "Validation", wj.WENJIANMC, "第", i + 1, "幅图片", innerText, "是", str5, "格式!请插入jpg、jpeg、tiff或tif格式后再签名打包。", Environment.NewLine, this.dtdErr }); } } else { box.Load(str3); image = box.Image; num2 = ((float.Parse(image.Width.ToString()) * 2.54) * 10.0) / ((double) image.HorizontalResolution); num = ((float.Parse(image.Height.ToString()) * 2.54) * 10.0) / ((double) image.VerticalResolution); if ((image.HorizontalResolution > 300f) || (image.VerticalResolution > 300f)) { this.dtdErr = string.Concat(new object[] { "Validation", wj.WENJIANMC, "第", i + 1, "幅图片", innerText, " DPI大于300,请修改后再签名打包。", Environment.NewLine, this.dtdErr }); str2 = "error"; } else { if (str3.IndexOf("130001") >= 0) { if ((num2 > 150.0) || (num > 220.0)) { this.dtdErr = string.Concat(new object[] { "Validation", wj.WENJIANMC, "第", i + 1, "幅图片", innerText, "超出150mm x 220mm!请验证后再签名打包。", Environment.NewLine, this.dtdErr }); str2 = "error"; continue; } } else if ((num2 > 165.0) || (num > 245.0)) { this.dtdErr = string.Concat(new object[] { "Validation", wj.WENJIANMC, "第", i + 1, "幅图片", innerText, "超出165mm x 245mm!请验证后再签名打包。", Environment.NewLine, this.dtdErr }); str2 = "error"; continue; } if (((str5 == "tif") || (str5 == "tiff")) && !clsImageHandle.IsCCITT4Image(str3)) { this.dtdErr = string.Concat(new object[] { "Validation", wj.WENJIANMC, "第", i + 1, "幅图片", innerText, " 不是Group 4 压缩方式的TIF文件!请修改验证后再签名打包。", Environment.NewLine, this.dtdErr }); str2 = "error"; } } }

    所以制作附图的时候,图片全部用灰度,不要用RGB模式,假如是300分辨率,图片宽<1948px,高小于3000px就行了, 至于其它分辨率,自己再根据上图公式去算一下吧。另外,如果你上传TIFF图片,要用Group 4压缩,用ACDSee10免费版就很好压缩。

    2.签名失败问题

    private bool Sign() { StreamWriter writer; AnJuan aJ = this.SQLF.AJ; string path = Program.TEMP_ROOT_PATH + this.ZippedPath + @"zip\" + aJ.ANJUANBH.ToString() + ".zip"; if (Settings.Default.IsRemPassword) { string str2 = this.sign.SignFile(path); if (string.IsNullOrEmpty(str2)) { return false; } writer = new StreamWriter(Program.TEMP_ROOT_PATH + this.ZippedPath + @"zip\" + aJ.ANJUANBH.ToString() + "_ca.txt", true); writer.WriteLine(str2); writer.Close(); if (!this.sign.VerifyFile(path, str2)) { return false; } return true; } string str4 = Program.TOOLS_ROOT_PATH + "testsign.exe"; SignFileReturnClass class2 = this.sign.SignFile(path, str4, pub.GetIssuerDn()); if (class2.ReturnCode != "00") { return false; } writer = new StreamWriter(Program.TEMP_ROOT_PATH + this.ZippedPath + @"zip\" + aJ.ANJUANBH.ToString() + "_ca.txt", true); writer.WriteLine(class2.ReturnString); writer.Close(); if (!this.sign.VerifyFile(path, class2.ReturnString)) { return false; } return true; }

    看到没,知道为什么签名错误了吧!?为此我写了一个小工具,验证一下签名看有什么问题,以下是代码片断:

    public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { } private void button1_Click(object sender, EventArgs e) { openFileDialog1.Title = "请选择有效的案卷文件(zip)"; openFileDialog1.Filter = "案卷文件|*.zip"; openFileDialog1.FileName = ""; DialogResult dr = openFileDialog1.ShowDialog(this); if (dr == DialogResult.OK) { bool rs = Sign(openFileDialog1.FileName); if (rs) { label1.Text = "签名结果:" + rs.ToString(); } } } private bool Sign(string path) { try { FileInfo file = new FileInfo(path); string aj = file.Name.Substring(0, file.Name.Length - 4); StreamWriter writer; listBox1.Items.Add("开始准备签名..."); listBox1.Items.Add("Path..." + path); SignClass sign = new SignClass(GetIssuerDn()); bool s1 = sign.SetCurrentCert(0); listBox1.Items.Add("证书数..." + sign.GetCertsCount()); listBox1.Items.Add("设置当前证书..." + s1.ToString()); string str2 = sign.SignFile(path); listBox1.Items.Add("签名值长度..." + str2.Length); if (string.IsNullOrEmpty(str2)) { listBox1.Items.Add("签名错误代码:" + sign.cur_cert.GetLastErr()); return false; } writer = new StreamWriter(file.DirectoryName + "\\" + aj + "_ca.txt", true); writer.WriteLine(str2); writer.Close(); if (!sign.VerifyFile(path, str2)) { listBox1.Items.Add("验证签名...失败!"); return false; } return true; } catch (Exception ex) { listBox1.Items.Add("签名异常..." + ex.ToString()); return false; } } private string GetIssuerDn() { return "CN=国家知识产权局CA证书, OU=国家知识产权局, O=国家知识产权局, L=BeiJing, S=BeiJing, C=CN"; } private string GetIssuerDn_CN() { return "国家知识产权局CA证书"; } }

    我可以再完善一下,使用  testsign.exe 再测试一下,这货应该能够返回为什么不能签名成功,懒得试了,谁有空谁试!

    过了五分钟,强迫症发作了。。。

    你们不用试了,代码跟SignClass一样,也不知道是谁抄谁!

    using DS20SignLib; using SignTest.Utility; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; public class SignClass { private IDS20SignCtl sign = new DS20SignCtlClass(); private Certificates certs; public Certificate cur_cert; public SignClass(string strIssuerDn) { DS20SignLib.Filter filter = this.sign.Filter; filter.Clear(); filter.Issuer = strIssuerDn; this.certs = this.sign.Certificates; } public int GetCertsCount() => this.certs.Count; public string[] GetCommandNameList() { int count = this.certs.Count; if (count <= 0) { return null; } string[] strArray = new string[count]; for (int i = 0; i < count; i++) { strArray[i] = ((Certificate)this.certs[i]).CommonName; } return strArray; } public Dictionary<string, string> GetCurCertInfo() { if (this.cur_cert == null) { throw new Exception("没有指定证书"); } return new Dictionary<string, string> { { "CommonName", this.cur_cert.CommonName }, { "Subject", this.cur_cert.Subject }, { "Issuer", this.cur_cert.Issuer }, { "SerialNumber", this.cur_cert.SerialNumber }, { "ValidFrom", this.cur_cert.ValidFrom.ToString("yyyy年MM月dd日") }, { "ValidTo", this.cur_cert.ValidTo.ToString("yyyy年MM月dd日") } }; } public string GetCurCertName() { if (this.cur_cert == null) { throw new Exception("没有指定证书"); } foreach (string str2 in this.cur_cert.Subject.Split(new char[] { ',' })) { string str3 = str2.Substring(0, str2.IndexOf("=")); string str4 = str2.Substring(str2.IndexOf("=") + 1); if (((str3.Trim().ToLower() == "ou") && (str4.Trim().ToLower() != "zljca")) && (str4.Trim().ToLower() != "国家知识产权局")) { return str4; } } return ""; } public bool IsVaild() { if (this.cur_cert == null) { throw new Exception("没有指定证书"); } return (this.cur_cert.ValidTo >= DateTime.Now); } public bool SetCurrentCert(int index) { if (this.certs.Count <= 0) { throw new Exception("没有找到证书"); } if (this.certs[index] == null) { throw new Exception("指定证书越界"); } this.cur_cert = (Certificate)this.certs[index]; return (this.cur_cert != null); } public bool SetCurrentCert(string commonname) { if (this.certs.Count <= 0) { throw new Exception("没有找到证书"); } for (int i = 0; i < this.certs.Count; i++) { Certificate certificate = (Certificate)this.certs[i]; if (certificate.CommonName == commonname) { this.cur_cert = certificate; break; } } return (this.cur_cert != null); } public string SignFile(string path) { if (this.cur_cert == null) { throw new Exception("没有指定证书"); } return this.cur_cert.EnvSignFile(path, 0); } public SignFileReturnClass SignFile(string path, string sign_exe_path, string IssuerDn) { SignFileReturnClass class2; if (this.cur_cert == null) { throw new Exception("没有指定证书"); } if (!File.Exists(sign_exe_path)) { throw new Exception("签名验证程序文件不存在"); } string fileName = "\"" + sign_exe_path + "\""; string arguments = "\"" + this.cur_cert.CommonName + "\" \"" + IssuerDn + "\" \"" + path + "\""; ProcessStartInfo startInfo = new ProcessStartInfo(fileName, arguments) { RedirectStandardOutput = true, RedirectStandardInput = true, CreateNoWindow = true, UseShellExecute = false }; string str3 = ""; try { Process process = Process.Start(startInfo); str3 = process.StandardOutput.ReadToEnd(); process.WaitForExit(); if (string.IsNullOrEmpty(str3.Trim())) { throw new Exception("没有获取到返回值"); } string returncode = str3.Substring(0, 2); string returnstring = str3.Substring(3); class2 = new SignFileReturnClass(returncode, returnstring); } catch (Exception exception) { throw exception; } return class2; } public string SignString(string strChars) { if (this.cur_cert == null) { throw new Exception("没有指定证书"); } return this.cur_cert.Sign(strChars); } public bool VerifyFile(string path, string encryptString) => (this.sign.VerifyEnvFile(encryptString, 0, path) != null); } namespace Utility { public class SignFileReturnClass { private string returncode; private string returnstring; public SignFileReturnClass(string returncode, string returnstring) { this.returncode = returncode; this.returnstring = returnstring; } public string ReturnCode { get => this.returncode; set => returncode = value; } public string ReturnString { get => this.returnstring; set => returnstring = value; } } }

     需要引用CPC目录下的 Ds20Sign.dll 文件,这个不是.net链接库,直接添加引用就好了。

    用自己的代码签名看看:

    真的签名失败,而这个错误码是 Ds20Sign.dll 里报出来的,没办法,只能认为是证书的问题了,这个签名只是本地签名,似乎没有与CPC服务器通讯,暂且认为是本地证书的问题吧!签名测试我使用了真实的案卷文件,在Temp/Upload/zip目录下,签名成功的话会生成一个签名文件,这是CPC的逻辑,我只是照搬下来!

    理论上找http://www.kairende.com/可以解决返回10001的错误原因,从这公司的网站可以看得出来,没有技术支持费用估计人家不会提供文档或是理你!专利局开发CPC那帮人购买了他们的CA产品?

    假设你都已经编辑完成了,现在可以签名提交了。

    如果证书没有问题,签名通过之后就是打包上传了,上传成功,恭喜你,完成专利申请的递交了,等待受理!

    四,想对专利局那帮程序员说点什么~!

    1.重写代码,并使用.net 4.6以上版本开发,明年.Net 5都快出来了;

    2.别用DevExpress了吧,有花钱买吗?

    3.可以多用开源的组件,如NOPI,这样可以不用依赖MS Office,现在电脑我都不安装Office家庭了,用WPS足够能够应付日常工作。

    4.网站功能重写,兼容IE\Firefox\Safari\Chrome等。为什么登录总是检测不到证书?为什么IE问题验证码错误?放弃Ds20Sign.dll换个别的方案吧!?证书签名的方案很多的啊!最好是有开源的!

    5.招一个月薪超过5000的程序员开发!

    6.再招个产品经理,规划一下软件功能!

    7.招一个技术总监,将系统重新架构一下!

    祝你们好运!别再开发出一堆屎,影响国家形象!

    对了,你会问我后来是怎么申请发明专利的。我放弃软件递交了,因为签名错误是一个不可逾越的问题,再加上我也没有办法重新下载证书,还能怎么办!?经过两天熬夜到4点,最后还是打印申请文件,邮递到代办点了!~

    我不打算找中介,没钱!

     

    最新回复(0)