存档

文章标签 ‘C#’

c# 控制台程序支持更长的字符输入长度

2014年9月12日 没有评论

对于c#的命令行程序,我们很多时候是使用 Console.ReadLine()来获取用户的输入,但是在默认情况下,有一个限制就是长度不能超过256,如果超出了就无法再输入了。

最近工作上的一个加密小工具,为了简单省事,使用了命令行的方式。结果在大家使用了半年后发现个别不能加密的情况,原因就是长度超过了256。

解决方法比较简单。

using System.IO;

Stream input = Console.OpenStandardInput(10240);       //长度限制由 256 修改为10240

Console.SetIn(new StreamReader(input));

string text = Console.ReadLine();

分类: 一句话 标签: , ,

c#应用程序获取管理员权限

2014年8月12日 没有评论

从vista开始,微软对操作系统的安全性下足了功夫,对于敏感操作例如C盘文件、注册表打开等,都会弹出对话框让用户确认选择。

在这样的机制下,一些恶意程序就得到了抑制,不会再像XP那样,后台偷偷运行用户都不知道。今天衣服自己洗,要和大家分享的是,如何获取管理员权限。

对于敏感操作,如果没有管理员权限,那么操作会失败。为了避免这样的情况,有的时候主动要求管理员权限,对于正常的应用程序来说,是一个比较好的事情。

c#获取管理员权限,大致有2中方式:

1、代码方式。在应用程序的入口函数里添加下面的代码,思路是这样的,启动的时候,获取当前用户的身份,如果已经是管理员了,那么就直接运行对应的窗体。如果不是,那么通过新开进程的方式。代码很简单,就不加注释说明了,加粗的那行代码就是最关键的。

System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(identity);

if (principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator))
{
Application.Run(new frmMain());
}
else
{
ProcessStartInfo info = new ProcessStartInfo();
info.UseShellExecute = true;
info.WorkingDirectory = Environment.CurrentDirectory;
info.FileName = Application.ExecutablePath;
info.Verb = “runas”;

Process.Start(info);
}

如果当前用户是普通用户,调试程序获取管理员权限,并不需要VS开发环境是管理员权限运行的,不需要退出VS再以管理员权限打开,是不是很方便呀?在这样的情况下,是无法断点调试的。衣服自己洗就碰到了这样的情况,如果想要断点调试,那么就要选择附加到进程的方式才可以。

对于C++其它语言来说,获取管理员权限,思路和这个差不多,所以这个方法算是大众思路了。

2、配置文件方式

.Net framework给予我们另外一种方式,通过添加manifest文件来实现获取管理员权限的需求。在项目中,添加一个manifest文件,menifest文件也叫做“应用程序清单文件”。

默认创建的清单文件里,requestedExecutionLevel节点即描述了程序运行需要的权限。修改为下面的内容即可:

<requestedExecutionLevel level=”requireAdministrator” uiAccess=”false” />

其实在里面的注释里也有,从注释里拷贝一下也是可以的。

分类: 日常 标签: , ,

winform 调整 ListViewItem高度

2014年8月8日 没有评论

这几天在写一个小工具,里面用到了ListView控件,在添加项的时候,需要设置每个项的高度,因为默认的高度感觉比较小。

我本以为这样的需要来进行重绘,那样感觉很麻烦。后来网上搜索了一把,有一个好方法,衣服自己洗赶紧地给收录进来。

每个LiveView 是可以设置 SmallImageList 和 LargeImageList的,该属性对应一个 ImageList,我们从这个上面着手就可以了。通过设置ImageList的尺寸可以实现修改 ListViewItem 的高度。

imageList.ImageSize = new Size(32, 32);

当然,最好里面对应的图片也是这个尺寸,以避免图片的缩放。

解决好这个问题后,我发现了一个新的问题,就是ListViewItem里的图标显示失真,可是图标都是我的从系统里提取出来的,按说是没有问题的。在解决上面高度的问题的时候,偶然找到了原因,对于 ImageList ,需要设置下图片的颜色深度,就像下面的样子:

imageList.ColorDepth = ColorDepth.Depth32Bit;

 

现在就妥妥的了。

分类: 一句话 标签: , ,

.Net程序实现多语言

2014年5月8日 没有评论

最近工作中要用到一个小工具,出于快速开发的目的,使用c#作为开发语言,放弃了c++,功能简单,当然是怎么方便怎么来。其它的功能这里就不说了,衣服自己洗这里要分享的就是其中的一个功能,对全球化多语言的支持。

.Net中要实现全球化,是把不同的语言放在不同的字典中,然后运行时动态选择。具体实现来说,可以有2种方式:

1、系统自带的Resources.resx文件

Resources.resx 是.Net提供的一个资源文件,可以提供对字符串,图片、二进制数据的存储,Resources.resx 本质上是一个xml 文件。比如,我们通过 VS 在文件中添加一个字符串,键为 Name,值为 唠叨下。

接下来,是考虑如何在程序中调用,非常简单,我们可以这样写 string name = Properties.Resources.Name;

注意这里的Name即为我们在Resources.resx里定义的键。之所以可以这么来调用,是由于VS自动帮助我们在 Resources.Designer.cs文件中定义了相关的方法。如果细心点,你会发现还可以使用Resources.ResourceManager 的GetString()方法和GetObject()方法,也可以达到相同的目的。拿到了值后,我们就可以做对应的显示了。

上面是第一步,接着我们来进行第二步。我们直接复制Resources.resx文件,并粘贴后改名,例如Resources.en-US.resx。这里需要说2点,一个是文件名格式,en-US是语言。另外一个是重命名后,Resources.en-US.Designer.cs里的内容给清空了,这个是没有关系的。事实上如果不清空,编译会报错。

这个时候,编译我们的工程,会发现在bin目录下生成一个en-US目录,里面有一个dll文件。默认的Resources.resx不会生存额外的文件夹,会直接编译到主程序中。

最后,我们需要添加显示,不然程序运行始终显示的是里的字符串。在程序的入口添加下面的代码,表示以当前系统的显示语言作为程序的语言。
Thread.CurrentThread.CurrentUICulture = new CultureInfo(System.Globalization.CultureInfo.CurrentUICulture.Name);

有的软件可能想要提供一个菜单,供用户主动选择语言,那么在初始化的时候,可以传入语言参数,例如 new CultureInfo(“zh-CN”)等等。

经过上面的处理,程序在运行的时候,就会得到我们需要的语言。

2、自定义的方式

上面的方式在编译后,会根据不同的语言生成对应的文件夹。例如我要做的小工具,就要生成28个国家的文件夹。看起来是不是很猥琐?我这里做过尝试,把所有的语言文件夹移动同目录下的一个新文件夹中,例如 Language 是不可行的。

还比如说,多语言的翻译和开发是同步进行的,希望以后再不重新编译版本的情况下新增别的语言等等各种需求,我们可以自定义。

不想要那么多文件夹,可以把所有的多语言翻译都放在Resources.resx文件里,并添加语言前缀,例如zh-cn_Name等等,利用Resources.resx会被编译到主程序的原理,就解决了过多的文件夹的问题。

对于想要动态新增语言,就只好将多语言放到数据库或者xml配置文件里,按语言取名,程序读取的时候来解析数据库或者xml。好处是只要新增了xml,程序不需要编译就支持了。缺点是由于可以修改,如果用户手动修改的话,可能会导致一些意外产生,不过额外做一些加密操作应该可以过滤掉大部分误操作。

衣服自己洗在上面介绍了2种方式,各位同学可以根据实际情况灵活采用不同的方式。满足了老板的需求,剩下的就是喝啤酒泡妹子去了。

分类: 日常 标签: ,

c++程序窗口不在任务栏上显示

2014年4月18日 没有评论

一般说来,程序在运行的时候,会在任务栏上显示图标,当然XP系统还是会一起显示程序的标题。虽然加班是不变的,而需求是一定变化的。出于某些需要,要实现程序在运行时不显示窗体。对于c#程序而言,只用设置 ShowInTaskbar = false 即可。而对于c++程序,还不能这么简单的使用。

今天衣服自己洗分享的是使用 ITaskbarList 接口来实现c++程序窗口不在任务栏上显示的目的。

从IE4开始,window提供了ITaskbarList 接口,我们可以简单地调用即可。

首先我们需要添加头文件的引用    #include “ShObjIdl.h”

然后,我们在代码里添加这样一个方法:
void ShowInTaskbar(HWND hWnd, BOOL bshow){
HRESULT hr;
ITaskbarList *pList;
hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER,
IID_ITaskbarList, (void **)&pList);

pList->HrInit();

if (bshow){
pList->AddTab(hWnd);
}
else{
pList->DeleteTab(hWnd);
}

pList->Release();
}

最后一步,在窗口初始化的时候,调用这个方法即可。两个参数分别为窗体的句柄,是否显示。

分类: 日常 标签: , ,

c# 调用 c++ dll 问题的解决

2012年12月3日 没有评论

上一个星期,都在解决一个问题,c# 调用 c++ 的 dll 。

问题出现在字符串上,在 win8 64位+vs2012 环境下,64位的c#去调用64位的 c++ dll。在调试的时候,总是自动退出调试,没有进入异常,也没有什么输出。dll 方法是接收2个参数,并返回一个字符串。c# 通过调用获得返回的字符串。

一开始的时候,我以为是由于 c# 和 c++ 之间不同的类型转换时,我给设置错了类型导致,然后又仔细拿网上的好几篇文章做对比,发现这块没有问题。dll 文件并不是我们这边提供的,没有源码所以也不好联调。我就给 dll 那边发邮件,描述情况,并期待他们的反馈。

对方那边就只会c++,我提供的c#代码他们看不太懂,再加上对方没有64位环境,同时也不愿意提供dll的源码给我这边调试,进度比较慢。白天就是邮件来邮件去,晚上的时候我就各种安装系统,发现这问题只在64 位系统上出现,在 32 位系统上是可以正确调用的。

后来突然想到,如果我这边新建一个 c++ 项目的话,能不能够复现呢?果然,问题复现了,现在抛开对方的 dll 文件,也可以进行调试了。经过跟踪,发现 c++ 代码完全成功执行了,但是在 c# 调用这边就崩溃了。这么看起来,似乎和 c++ 代码方面的关系不大。于是又仔细检查了 c++ 的导出函数设置,没有问题。我以为是我c#项目的问题,删掉重建了个简单的,还是不行。

接下来,我又怀疑是不是 vs 本身的问题,因为是用的 2012 的版本,恰好这个时候,vs2012 sp1补丁包出来了,果断地升级。升级后发现还是崩溃了。

到这里似乎没有进展了,最后我请教了 c++ 方面的救兵。雪飞同学果然很是强悍,不多会就给出了我一个解决方法。在 c# 这边的函数申明这里设置返回类型为 IntPtr 类型,然后使用 Marshal.PtrToStringAuto 方法进行转换为托管字符串。问题就解决了。

我们一起还讨论这个问题出现的原因,一个可能的原因是在64位平台上,c++ 返回的是一个64位的指针,但是c#在调用的时候,并没有作为64位指针来获取,或者说拿了一个错误的指针,导致字符串获取失败。有可能在 c# 64位平台上字符串的初始化的时候,从非托管代码到托管代码的构造函数里存在缺陷。当然这个问题,是不是这样的,我们就不清楚了。获取给 vs 的开发team发个邮件可以得到更详细的信息。

在今天的时候,我越想越愤懑,为什么别的语言可以,c# 就非得这样,在32位和64位平台上还要做区分代码编写。碰巧下午我测试时先申明了字符串,然后再调用,发现问题居然解决了。似乎验证了和雪飞同学一起讨论的结果。

可是,最好的一个解决方法居然是这样的。这一刻,我觉得太蛋疼了。真的。

string s=””;s=GetInfo(); 的写法和 string s=GetInfo(); 之间对于托管代码和非托管代码居然有这样的区别。

 

还有另外一个问题,就是结构体转换成字节时,进入了异常。也是字符串的问题,后来根据 google 上面的搜索解决了。如果结构体里包含字符数组,在转换成字节时,需要先定义长度,不然会转换失败。具体来说就是在结构体里字符数组前面添加属性定义。例如

[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 6)]             public char[] device ;  //这里的 device 为 “iphone”,长度为6,所以 SizeConst=6

 

分类: 日常 标签: , , , , ,