存档

‘日常’ 分类的存档

c#创建大于屏幕尺寸的窗体

2014年11月16日 没有评论

最近的一个星期,衣服自己洗一直在折腾一件事情,最终才得以解决,现在拿出来和大家分享。

问题是这样的,如何生成一个winform 窗体,使得它的尺寸要比当前屏幕还要大。

我是在 c# 中碰到的,但是对于其它语言应该也是一样的。开始的时候我也为是MDI的限制,后来发现这个限制对一般窗体都适用,网上资料也显示,对于窗体的尺寸设置,无论是 Size 还是单独的宽度、高度,如果超过了屏幕的尺寸,系统会自动给截断。

例如,对于1366*768 分辨率、100%的DPI,如果你创建了一个窗体,并设置其尺寸为 1400*900,那么最终的窗体尺寸会是 1478*780,多余的就不显示了,当然也不会崩溃。系统对于宽度和高度会允许多添加 12像素。如果是 125%的DPI,那么这个值是 16像素。但是不会允许更多。

由于对于windows桌面应用程序驾驭能力的不足,只好请教他人。对于这个问题,大家集中表现为两种情况,一种是表示从来没有接触过MDI表示不会,毕竟是从MDI程序发现的;另外的尝试一把发现确实不太好解决劝我放弃。只好自己一个人坚持下去寻找原因。

我相信这个需求一定是可以实现,并且很简单,只是我暂时没有找到方法而已。

后来看到一个Delphi的程序实现了我想要的效果,我通过spy++比较程序间的差异,并辗转和人家交流才明白,原来是要去掉一个样式并重新设置大小。但是我这边一直没有效果。后来才发现是常量声明错误,我给设置成负值了。汗~

首先,获取窗体的当前样式,然后去掉WS_THICKFRAME样式,之后再重新设置窗体的位置和尺寸即可。如我开始所想,确实很简单,只是想到这里不太容易。如果是 c++ 之类的语言,可以在窗体(包括MDI窗体)构造的时候设置就可以了,c# 给封装起来了,所以只好放后面设置。

申明如下:

[DllImport(“user32.dll”, SetLastError = true, CharSet = CharSet.Auto)]
public static extern int SetWindowLong(IntPtr hwnd, int nIndex, int newLong);

[DllImport(“user32.dll”, SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetWindowLong(IntPtr hwnd, int nIndex);

[DllImport(“user32.dll”)]
public static extern int SetWindowPos(IntPtr hwnd, int hwndInsertAfter, int x, int y, int width, int height, int flags);

[DllImport(“shell32.dll”)]
public static extern IntPtr ShellExecute(IntPtr hwnd,string lpOperation,string lpFile,string lpParameters,string lpDirectory,int nShowCmd);

public static int GWL_STYLE = (-16);
public static int WS_THICKFRAME = 262144;
public static int HWND_TOP = 0;
public static int SWP_SHOWWINDOW = 64;
public static int SW_SHOW = 5;

封装起来,这样调用会比较方便,
public void SetNewSize(int width, int height)
{
int style = GetWindowLong(this.Handle, GWL_STYLE);

SetWindowLong(this.Handle, GWL_STYLE, style & ~WS_THICKFRAME);
SetWindowPos(this.Handle, HWND_TOP, 0, 0, width, height, SWP_SHOWWINDOW);
}

最后说几个小细节作为结尾吧,对于c#而言,这个调用不能放在构造函数里,因为会被后面系统自动设置给覆盖掉,应该在 frmChild.Show()之后才有效。衣服自己洗这里也是坑了很久。另外大家可以看代码是如何去掉WS_THICKFRAME样式的,还可以思考下为什么要先获取窗体样式而不直接设置。

这下算是解决了心里的一个疙瘩,不知道做技术的是不是都这样。

分类: 日常 标签: , , ,

代理网络使用远程桌面

2014年10月12日 没有评论

衣服自己洗在阿里云弄了一个主机, 放随便搞的一些东西。

经过一段时间的观察,发现经常有人在扫描远程桌面和SQL Server,尝试登录。阿里云的云盾似乎没有很好的过滤掉。看着每天的攻击很是担心,虽然服务器上几乎没有跑任何程序,我承认我的服务器就是个装饰。

为了安全起见,同时又可以方便使用,衣服自己洗修改了远程桌面和SQL Server的默认端口,把3389 修改为8888,过了几天再去检查服务器,发现攻击记录就少了很多了。

有一天在单位有事情需要远程访问服务器,远程桌面打开失败,突然想起来单位是使用的代理上网,服务器远程桌面使用的8888端口被代理给屏蔽了,但是系统的远程桌面又不支持代理设置,那一刻很是抓狂。

老实说,公司的代理网络有时候很不够好。

事情当时就这么过去了,可是衣服自己洗很是不甘心。凭什么呀?于是在网络上各种搜索,想找到解决方案。

要求是这样的:打开生效退出后也不对系统造成影响,功能尽量简单,满足要求即可。

过了好几个月后,终于找到了方法,就是 CCProxy + Proxifier。这2个软件网上都有单独的介绍,我也分别尝试了,都失败了,后来看到一个帖子后才有的思路,重新尝试,果然有效果。

我猜测原理是酱紫的,CCProxy提供Socket到http的转换,而Proxifier则是为不支持代理的软件提供代理的支持。网上很多失败的情况,都是单独使用了其中的一个。

首先安装2个软件,软件的安装没有先后顺序。接下来来配置CCProxy,在设置界面里勾选Socket/MMS,记住端口号 1080,下方会显示局域网地址192.168.30.1,也需要记下来后面需要使用的。然后再点击高级,切换到二级代理选项卡,选择启用二级代理,并输入办公网络上网代理的地址。然后确定即可。

对于Proxifier,先选择菜单栏的配置文件/代理服务器,然后点击添加,输入上面CCProxy里局域网地址192.168.30.1,和端口号1080。当然各位同学的IP地址可能不是这个,只要保证2个软件的IP是一样的即可。勾选Socket 5 协议,点击确定。

还差一步,选择菜单栏的配置文件/代理规则,然后点击添加,在新窗口里输入你想代理的程序,我们是要使用远程桌面,所以这里就属于远程桌面程序名称mstsc.exe,下方的动作就选择刚才设置的代理。效果如下图所示:

proxifier

点击确定,并勾选生效。界面看起来就应该是下面的样子:

mstsc_rule

到这里就配置完毕,大家可以放心使用拉。允许远程桌面,真的是可以访问了,反正衣服自己洗感觉很爽。

上面最后一步是设置需要代理访问的程序,不仅仅是远程桌面,衣服自己洗还设置了MongoVUE也访问代理,这样做是为了尽量减少干扰,毕竟办公网络其它程序例如QQ、浏览器还是可以上网的,所以这个步骤大家灵活处理好了。

iOS使用keychain存储数据

2014年9月23日 没有评论

在某个周六的时候,我跑去听了一个淘宝举办的无线交流会,对于安全来说还是蛮有收获的。回来后在网上找相关资料,看到一个关于使用 keychain 来存储数据的方案,思路比较不错。

使用keychain,有2点好处。

1、数据相对使用NSUserDefaults,更安全一点。

2、可以用来进行应用间的数据共享。

下面给出通用类代码,首先是头文件

KeychainManager.h

 

#import <Foundation/Foundation.h>

@interface KeychainManager : NSObject

+ (void)save:(NSString *)key withValue:(id)value;

+ (id)get:(NSString *)key;

+ (void)deleteData;

@end

接下来,是具体的实现代码

KeychainManager.m

#import “KeychainManager.h”

@implementation KeychainManager

static NSString * const KEY_IN_KEYCHAIN = @”com.5danyuan.app”;

+ (void)save:(NSString *)key withValue:(id)value{

    NSMutableDictionary *dic = [NSMutableDictionary dictionary];

    

    [dic setObject:value forKey:key];

    

    NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:

                                  (__bridge_transfer id)kSecClassGenericPassword,

                                  (__bridge_transfer id)kSecClass,

                                  KEY_IN_KEYCHAIN,(__bridge_transfer id)kSecAttrService,

                                  KEY_IN_KEYCHAIN,(__bridge_transfer id)kSecAttrAccount,

                                  (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,

                                  (__bridge_transfer id)kSecAttrAccessible,

                                  nil];

    //删除旧数据

    SecItemDelete((__bridge_retained CFDictionaryRef)query);

    [query setObject:[NSKeyedArchiver archivedDataWithRootObject:dic] forKey: (__bridge_transfer id)kSecValueData];

    SecItemAdd((__bridge_retained CFDictionaryRef)query, NULL);

}

+ (id)get:(NSString *)key{

    NSMutableDictionary *dic = nil;

    NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:

                                  (__bridge_transfer id)kSecClassGenericPassword,

                                  (__bridge_transfer id)kSecClass,

                                  KEY_IN_KEYCHAIN,(__bridge_transfer id)kSecAttrService,

                                  KEY_IN_KEYCHAIN,(__bridge_transfer id)kSecAttrAccount,

                                  (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,

                                  (__bridge_transfer id)kSecAttrAccessible,

                                  nil];

    [query setObject: (id)kCFBooleanTrue forKey: (__bridge_transfer id)kSecReturnData];

    [query setObject: (__bridge_transfer id)kSecMatchLimitOne forKey: (__bridge_transfer id)kSecMatchLimit];

    CFDataRef keyData = NULL;

    if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)query, (CFTypeRef *)&keyData) == noErr) {

        @try {

            dic = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithData: (__bridge_transfer NSData *)keyData];

        }

        @catch (NSException *exception) {

            NSLog(@”Unarchive of %@ failed:%@”,KEY_IN_KEYCHAIN,exception);

        }

        @finally {

            

        }

    }

    

    if(dic != nil){

        return [dic objectForKey:key];

    }

    

    return nil;

}

+ (void)deleteData{

    NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:

                                  (__bridge_transfer id)kSecClassGenericPassword,

                                  (__bridge_transfer id)kSecClass,

                                  KEY_IN_KEYCHAIN,(__bridge_transfer id)kSecAttrService,

                                  KEY_IN_KEYCHAIN,(__bridge_transfer id)kSecAttrAccount,

                                  (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,

                                  (__bridge_transfer id)kSecAttrAccessible,

                                  nil];

    

    SecItemDelete((__bridge_retained CFDictionaryRef)query);

}

@end

 对于通用类而言,提供了3个方法,添加、删除、保存。其中,为了安全起见,防止被恶意分析,获取的get方法的返回值是 id 类型的。对于合法的使用者,自然是知道应该转换为什么样的数据类型的。

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

c# winform添加防火墙规则支持

2014年9月23日 没有评论

在最近的一个项目中,程序需要依赖第三方应用。所以在程序启动的时候,如果第三方应用没有运行,则主动调用起来。对于网络应用程序,或者一些需要用到自定义端口的程序,在启动的时候,可能会被系统防火墙给拦截,询问用户是否需要给与权限。

有的时候,这会让人很抓狂,特别是对于某xx程序,呵呵,我真的不是在黑360。

如果一个已经被用户授权获得管理员权限的应用,如果可以顺手把防火墙规则给加上去,至少看起来不用那么纠结了。

多的不说,下面是具体的静态类。

public class FirewallHelper
{
/// <summary>
/// 添加端口号到防火墙
/// </summary>
/// <param name=”name”></param>
/// <param name=”port”>端口号</param>
/// <param name=”protocol”>TCP/UDP/ANY</param>
public static void addPort(string name, int port, string protocol)
{
//创建防火墙管理类实例
INetFwMgr manager = (INetFwMgr)Activator.CreateInstance(Type.GetTypeFromProgID(“HNetCfg.FwMgr”));
//或者使用Type.GetTypeFromCLSID(new GUID(” {304CE942-6E39-40D8-943A-B913C40C9CD4}”)),
//其中, {304CE942-6E39-40D8-943A-B913C40C9CD4} 是防火墙的CLSID

INetFwOpenPort fwPort = (INetFwOpenPort)Activator.CreateInstance(Type.GetTypeFromProgID(“HNetCfg.FwOpenPort”));

fwPort.Name = name;
fwPort.Port = port;
if (protocol.ToUpper() == “TCP”)
{
fwPort.Protocol = NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP;
}
else if (protocol.ToUpper() == “ANY”)
{
fwPort.Protocol = NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_ANY;
}
else
{
fwPort.Protocol = NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_UDP;
}
fwPort.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
fwPort.Enabled = true;

bool exist = false;
//加入到防火墙的管理策略
foreach (INetFwOpenPort item in manager.LocalPolicy.CurrentProfile.GloballyOpenPorts)
{
if (fwPort == item)
{
exist = true;
break;
}
}
if (!exist) {
//不存在则添加
manager.LocalPolicy.CurrentProfile.GloballyOpenPorts.Add(fwPort);
}
}

/// <summary>
/// 添加应用程序到防火墙
/// </summary>
/// <param name=”name”></param>
/// <param name=”path”>应用程序的完整绝对路径,包含文件名</param>
public static void addApp(string name, string path)
{
INetFwMgr manager = (INetFwMgr)Activator.CreateInstance(Type.GetTypeFromProgID(“HNetCfg.FwMgr”));
INetFwAuthorizedApplication app = (INetFwAuthorizedApplication)Activator.CreateInstance(Type.GetTypeFromProgID(“HNetCfg.FwAuthorizedApplication”));

app.Name = name;
app.ProcessImageFileName = path;
app.Enabled = true;

bool exist = false;
foreach (INetFwAuthorizedApplication item in manager.LocalPolicy.CurrentProfile.AuthorizedApplications)
{
if (name == item.Name)
{
exist = true;
break;
}
}

if (!exist)
{
manager.LocalPolicy.CurrentProfile.AuthorizedApplications.Add(app);
}
}

/// <summary>
/// 从防火墙中删除端口号
/// </summary>
/// <param name=”port”></param>
/// <param name=”protocol”>TCP/UDP/ANY</param>
public static void delPort(int port, string protocol)
{
INetFwMgr manager = (INetFwMgr)Activator.CreateInstance(Type.GetTypeFromProgID(“HNetCfg.FwMgr”));

if (protocol.ToUpper() == “TCP”)
{
manager.LocalPolicy.CurrentProfile.GloballyOpenPorts.Remove(port, NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP);
}
else if (protocol.ToUpper() == “ANY”)
{
manager.LocalPolicy.CurrentProfile.GloballyOpenPorts.Remove(port, NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_ANY);
}
else
{
manager.LocalPolicy.CurrentProfile.GloballyOpenPorts.Remove(port, NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_UDP);
}
}

/// <summary>
/// 从防火墙中移除应用程序
/// </summary>
/// <param name=”path”>应用程序的完整绝对路径,包含文件名</param>
public static void delApp(string path)
{
INetFwMgr manager = (INetFwMgr)Activator.CreateInstance(Type.GetTypeFromProgID(“HNetCfg.FwMgr”));

manager.LocalPolicy.CurrentProfile.AuthorizedApplications.Remove(path);
}
}

 

因为都是静态类,要使用的时候,直接调用就可以了。

分类: 日常 标签: , ,

香蕉派远程桌面连接

2014年8月14日 没有评论

在前面的几篇文章里,衣服自己洗分享了香蕉派的一些设置,可是没有告诉各位同学,显示器是我从单位借用抱回家的,单位的网络有限制,对于软件安装什么的,都无法进行,只好带回家。大家能想象出在下班高峰的地铁上,一个抱着显示器的人是有多么艰难。

由于是借用公家的显示器,终归是要还的,所以支持远程桌面什么的,就是十分必需的了。在网上搜索了一把,基本上是2种方案,一个是使用vnc,考虑到windows上还需要安装软件,所以我给过滤掉了。第二个是直接使用windows自带的远程桌面,很多人推荐使用xrdp,估计是x remote desktop的意思吧。

sudo apt-get install xrdp

然后从家里路由器里拿到香蕉派的IP地址,接着就是远程桌面了。网上的帖子大致如此。

可是衣服自己洗远程桌面时,显示登录成功,可是始终是灰色的屏幕,没有任何东西,只有一个X鼠标。这不科学,你们知道吗!网上搜索了很久,基本上没有人遇到,只有2个人有同样的问题,可惜没有后文,我想应该是我的关键词有问题吧。

搞了很久,都没有答案,以至于衣服自己洗现在才把香蕉派的系列文章写下来。终于某一天在ubuntu的论坛里看到一个帖子。

妈蛋,原因竟然是ubuntu环境和xrdp的桌面环境冲突导致远程桌面灰屏。接下来就是各种找解决思路,功夫不负有心人,终于找到了,使用xfce4。

剩下的就简单了,xrdp 还是需要安装的,sudo apt-get install xfce4

然后呢就是 echo xfce4-session >~/.xsession,重启下xrdp的服务即可了。

这个问题虽然出现在香蕉派上,但是理论上也存在ubuntu无法远程桌面的问题。

香蕉派环境配置(二)之合并分区

2014年8月14日 1 条评论

经过一段时间的运行,香蕉派里磁盘空间很快就满了。使用 df -lh 命令,可以看到 /dev/root 占用率已经达到 100%。这个现象让我很是迷惑,当初买SD卡时我买的是8G大小,难道这么快就用光光了?对于 Linux 我不懂,顿时慌了手脚,于是就在考虑是买一个更大容量的SD卡,还是考虑采用移动硬盘的方式,还是把香蕉派扔掉的犹豫中渡过了几个不眠夜。

目前我的香蕉派里就安装了Nginx、PHP、Mysql,加上系统本身的空间,内容应该没有特别大。

在一次偶然的过程中,我打开了Disks程序,突然发现SD卡,里面还有大约4G的空白空间。我的第一反应是还好自己放在购物车里的订单还没有支付。既然有剩余空间就比较好处理了,用一些工具应该可以实现。可惜我不会,只好求助网络。

网上搜索有帖子说,对于Linux系统一旦安装好,那么分区就是固定的了,一个处理不好连系统无法启动。我这边看到有2个分区,第一个分区不到100M,应该是引导分区,第二个分区就是实际用的。剩余4.3G是剩余空间,还没有分区。

以root登录系统,使用 Disks 工具,选中那个4.3G的空白空间,然后格式化并添加。记得是快速格式化,磁盘格式选择和主分区一致的Ext4格式。

现在就该使用解决问题的命令fdisk了,命令格式:fdisk <存储设备名>  //如: fdisk /dev/sda
进入fdisk 后,使用单键命令
m 显示Help

p  列出所有分区
d  删除分区
n  新建分区
w 存盘退出
q 不存盘退出

对主设备进行fdisk,对于香蕉派,命令是:sudo fdisk  /dev/mmcblk0。

按 p 键 列出所有分区,可见有三个分区。第一个分区是 FAT32分区,是引导用的,第二个分区是Linux 主分区,第三个分区是刚添加的那个4.3G的空白分区。记下Linux 主分区的Start Sector号 ,我的是102400。

按 d 键 Partition Number (分区号) 选 2, 删除linux主分区(第2个区)。再按d键, Partition Number (分区号) 选 3,  删除4.3G的空白分区(第3个区)

按 p 键 列出所有分区,可见只剩第一个分区了

按 n 键,重新创建linux主分区
Partition Type(分类类型) 选 P (Primary)
Partition Number (分区号) 选 2

First Sector(起始Sector) 一定要输入刚才记下来的Start Sector号(我的是102400),默认直接回车也可以。Last Sector (终止Sector)用默认值,直接回车。

按 p 键 列出所有分区,可见有两个分区,linux主分区在第2个,起始位置是原位置。 按 w 键 存盘退出fdisk。

接下来,立即重启,不要做任何其它事情

sudo reboot

重启并登录后,立即用以下命令sudo resize2fs /dev/mmcblk0p2 ,该命令将把第二个分区扩展到新的空间中。现在查看一下硬盘使用情况,OK了。无论是用 Disks 程序还是 df -lh 命令,都可以看到主分区有7G多了。

上述操作的原理是:首先删除了linux主分区和空白,重建的主分区起始Sector位置与原主分区一致,再resize2fs,则原主分区数据完全没变,但改变了主分区的大小。

至此,香蕉派的分区合并就完成了,衣服自己洗很是高兴,希望对手头上有树莓派/香蕉派的同学有帮助。

香蕉派环境配置(一)之用户修改

2014年8月14日 没有评论

上一篇,衣服自己洗为大家分享了香蕉派的基本知识。这是第二篇,关于环境配置的一些细节。

按照官方的流程,先格式化SD卡,然后写入系统镜像,完成后插入SD卡,开机引导即可进入系统,很是简单。我使用的是 Ubuntu 的镜像。

官方的镜像里的帐号是 Lemaker/bananapi,root/bananapi。我们先通过 Lemaker 用户进入系统,屎黄色的桌面背景很是醒目哟。

对于用户而言,第一个要做的就是添加自己喜欢的用户名,修改 Lemaker 貌似会出问题,可能是镜像的原因吧。开始菜单,设置,用户和群组,添加用户,设置自己喜欢的用户名和密码,设置类型为 Administrator,我有注意到官方的用户类型的 Customer,不太清楚这个区别有多大。

然后注销,以刚创建的用户名登录,进入到系统后,删除 默认的Lemaker用户。接下来就是修改主机名了,修改 /etc/hostname 文件,例如Lubuntu,保存退出,然后重启。

这个时候,我们在使用需要 sudo 权限的命令时,界面上会每次都显示 sudo:unable to resolve host Lubuntu,出现这个的原因在于系统对于主机名的解析不识别。解决方法也很简单,修改 /etc/hosts 文件,添加对本地的映射,内容如下:

127.0.0.1    localhost  Lubuntu

保存退出即可。

 

分类: 日常 标签: , , ,

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” />

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

分类: 日常 标签: , ,

一种mysql 无法登陆的解决办法

2014年7月8日 没有评论

由于工作需要,在内网里假设论坛,本来是打算使用windows系统的,可是下载数据库,很久都没有下载回来,只好放弃而改用linux服务器。

服务器居然是Redhat 的系统,一路各种安装,但是在安装mysql时出错了。

安装mysql后,使用命令登录mysql居然报错了,Mysql ERROR 1045 (28000): Access denied for user ‘root’@’localhost'(using password: NO),这个错误搞得很郁闷,可能是密码在配置mysql的时候异常,所以导致我们没有正确的密码,知道问题后,立即想到解决办法了,那就是重新设置一个密码,方法如下

1.先关闭mysql并设置密码
1.#sudo /etc/init.d/mysql stop
2.#sudo mysqld_safe –user=mysql –skip-grant-tables –skip-networking &
3.#sudo mysql -u root mysql
4.mysql> UPDATE user SET Password=PASSWORD(‘pas’) where USER=’root’;
5.mysql> FLUSH PRIVILEGES;
6.mysql> quit

2.重启mysql并尝试登录
1.#sudo /etc/init.d/mysql restart
2.#sudo mysql -u root -p
3.Enter password:
4.#输入密码,出现下面这个就表示登录正常了
5.mysql>

Mysql ERROR 1045 (28000): Access denied for user ‘root’@’localhost'(using password: NO)这个错误在使用phpmyadmin登录的时候只提示(28000),同时phpmyadmin也会提示密码出错,按以上方法设置之后就可以用新密码登录phpmyadmin了。

登陆成功,剩下的就是拷贝文件,然后进行论坛的初始化操作了,这里就不提了。

分类: 日常 标签: ,

inno setup初探

2014年6月10日 没有评论

由于工作的原因,需要对应用程序制作安装包。在以前的项目中,都是使用的 InstallShield  来做的安装包,最近的一个项目是从一个日本开发团队的项目中新建的一个分支,他们原本的安装包都是使用 Inno Setup 来创建的,结合项目背景和安装包的复杂度,我们就踏上了inno setup的路。

inno setup 相对于 InstallShield 轻量了很多,也是使用了 iss 作为安装脚本文件的后缀。常量的定义也大大方便了开发人员。

下面描述下常见的常量

AppId 应用程序唯一ID
AppName 应用程序名称
AppVersion 应用程序版本号
AppPublisher 应用程序制造商
AppSupportURL 应用程序厂商的URL

DefaultDirName 默认的安装路径
OutputDir exe安装包的输出路径
UninstallDisplayIcon 卸载程序的图标

上面的几个变量中,第一部分的信息会显示在添加删除程序中,尤其以AppId最为重要,操作系统以此来区分不同的应用程序。如果是同一个应用程序不同的版本,请保证该变量始终是相同的。inno setup可以帮助生成GUID格式的AppId。

而[Files]段是描述了拷贝文件的路径和方式,例如下面的

Source : “{#SourcePath}\WinGather.exe”; DestDir: “{app}”; Flags: ignoreversion

意思就是把 SourcePath 定义的目录下的 WinGather.exe 程序拷贝到程序的安装目录下。{app} 是一个系统变量,表示程序在用户机器上的安装目录。ignoreversion 是在拷贝的过程中忽略版本的不同。

如果一个应用中有很多个文件需要拷贝,有的还包括子目录,都这样写就会很琐碎。于是就有这样的版本:

Source: “{#SourcePath}\ccprompt\*”; DestDir: “{app}\ccprompt”; Flags:ignoreversion recursesubdirs

从这里我们可以看到通配符*的使用,这样就会方便很多哟。此外,recursesubdirs 参数表示如果包含子目录的话,那么连同子目录也一起拷贝。这样 [Files] 就会少很多,尽管有通配符的支持,但是实际应用中要看情况而定,目的是为了避免安装包拷贝时的准确性,如果安装不对劲,也方便查找定位原因。

[run]段的作用是描述在安装的最后一步所要做的操作,多用于启动服务或者清理等操作,例如下面的:

Filename:”net.exe”; Parameters:”stop ccsdk”; Flags:waituntilterminated runhidden runascurrentuser;

这个例子就是调用 net 来停止一个叫做 ccsdk 的服务,同时有3个额外的选项,分别表示等这个操作完成后再进行后续的安装,不显示界面,以当前用户即管理员权限运行。如果运行一个命令行或者批处理,如果不使用 runhidden,那么在界面上就会看到有一个窗口一闪而过,体验不是很好。

[uninstallDelete]段的作用是描述在卸载的时候,要删除的文件,多用于程序在运行期间产生的文件例如日志、临时文件等,例如:

Type:filesanddirs; Name:”{app}\log.txt”

上面就是简单的描述了一下,inno setup其实非常简单,环境本身也提供了安装想到和帮助文档,文档里写的是非常的详细。所以我这里几乎没有什么内容可写。对于E文不懂的同学,可以在网上下一个中文版的帮助手册。最后说一下,inno setup的安装脚本是不区分大小写的。

分类: 日常 标签: , ,