C# FormsAuthentication的用法

[codesyntax lang=”csharp”]

using System;
using System.Web;
using System.Web.Security;

namespace AuthTest
{
    public class Authentication
    {
        /// <summary>
        /// 设置用户登陆成功凭据(Cookie存储)
        /// </summary>
        /// <param name="UserName">用户名</param>
        /// <param name="PassWord">密码</param>
        /// <param name="Rights">权限</param>
        public static void SetCookie(string UserName,string PassWord,string Rights)
        {
            //
            //String PassWord="test";
            //
            String UserData = UserName + "#" + PassWord+"#"+Rights;
            if (true)
            {
                //数据放入ticket
                FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, UserName, DateTime.Now, DateTime.Now.AddMinutes(60), false, UserData);
                //数据加密
                string enyTicket = FormsAuthentication.Encrypt(ticket);
                HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, enyTicket);
                HttpContext.Current.Response.Cookies.Add(cookie);
            }
        }
        /// <summary>
        /// 判断用户是否登陆
        /// </summary>
        /// <returns>True,Fales</returns>
        public static bool isLogin()
        {
            return HttpContext.Current.User.Identity.IsAuthenticated;
        }
        /// <summary>
        /// 注销登陆
        /// </summary>
        public static void logOut()
        {
            FormsAuthentication.SignOut();
        }
        /// <summary>
        /// 获取凭据中的用户名
        /// </summary>
        /// <returns>用户名</returns>
        public static string getUserName()
        {
            if (isLogin())
            {
                string strUserData = ((FormsIdentity)(HttpContext.Current.User.Identity)).Ticket.UserData;
                string[] UserData = strUserData.Split('#');
                if (UserData.Length != 0)
                {
                    return UserData[0].ToString();
                }
                else
                {
                    return "";
                }
            }
            else
            {
                return "";
            }
        }
        /// <summary>
        /// 获取凭据中的密码
        /// </summary>
        /// <returns>密码</returns>
        public static string getPassWord()
        {
            if (isLogin())
            {
                string strUserData = ((FormsIdentity)(HttpContext.Current.User.Identity)).Ticket.UserData;
                string[] UserData = strUserData.Split('#');
                if (UserData.Length!=0)
                {
                    return UserData[1].ToString();
                }
                else
                {
                    return "";
                }
            }
            else
            {
                return "";
            }
        }
        /// <summary>
        /// 获取凭据中的用户权限
        /// </summary>
        /// <returns>用户权限</returns>
        public static string getRights()
        {
            if (isLogin())
            {
                string strUserData = ((FormsIdentity)(HttpContext.Current.User.Identity)).Ticket.UserData;
                string[] UserData = strUserData.Split('#');
                if (UserData.Length!=0)
                {
                    return UserData[2].ToString();
                }
                else
                {
                    return "";
                }
            }
            else
            {
                return "";
            }
        }
    }
}

[/codesyntax]

点击下载:Authentication.cs

uTorrent绿化辅助工具

不知道有多少用uTorrent做种混上传站的朋友,大家可能面临这样一个问题,就是重装了系统之后,就得重新一个个种子导入重新上传,很是麻烦,受到CCF论坛某朋友的提示,得知将%systemdata%/utorrent下的文件拷贝到你的utorrent目录下,即可完成绿化。于是,就有了我这样的一个小工具。原理非常简单,只是为了方便懒人吧 :) 嘿嘿,按照惯例,提供源代码与编译好的程序。

点此下载:uTorrent_Backup_2011_02_26

点此下载:uTorrent_Backup_Src_2011_02_26(源代码)

'swap' : none of 2 overload have a best conversion 解决办法

今天用C++做模板的一个实验,写了一个Swap(T &a,T &b)的模板函数,结果编译竟然出错,提示“’swap’ : none of 2 overload have a best conversion”。经过查找资料,发现C++内置了这个swap函数,如果再次重写会与系统自带的冲突,所以解决办法也很简单咯,改个名就好咯~~do_swap(T &a,T &b)

人人网日志导出(备份)工具 (2012-2-9更新)

之前的时候Kaisir有练手写过一个小的人人网的日志导出工具,也是一直开源放在那里的。不过近期有童鞋在我部落格留言说之前的那个失效了,而且他自己尝试修改却总是报错。好吧,Kaisir还是比较喜欢助人为乐的,拿出一些时间,又看了看曾经写的这个小东西,顺便再次分析下人人网的结构~~

最近人人网的结构可以说较我之前研究的时候做了很多修改,主要修改如下:

1)全站使用Ajax技术,很多地方都是进行了异步刷新。这样的好处是只刷新需要的地方,增强用户体验的同时减少了带宽的消耗。

2)请求页面的时候对来路(Referer)进行了判断,请求页面时,先通过请求ajaxproxy.htm这个文件来设置Referer,如果不包含这个Referer则转回首页。

3)大部分连接增加异步请求参数。这个很奇怪,我使用FireBug对数据包进行分析抓取的时候没有抓到这个参数,以至于我多次提交系统都给我返回了错误的页面,后来使用Wireshark抓包做协议分析才看到这个参数~~郁闷啊郁闷~~这里浪费了很多时间~~

既然知道了这些改变,那修改我的程序就简单多鸟~~不过这次还是重写了下HttpHelper这个类,上次写的那个冗余太多了,代码不漂亮~这下尽可能的封装,然后再使用函数的重构把它给分开了~~

大家普遍反映,20120209版出现不能备份的bug,请大家先下载之前的版本 :)

2012年2月9日更新:

1)提高日志备份的稳定性,出现错误可以自动跳过。
点此下载:RenRen20120209

源代码:RenRen_src

2011年4月7日更新:
这次变动的地方比较多,主要变动如下:
1)改变文章获取方式,由以前获取全部列表后再获取文章转变为获取一页列表保存一页文章。
2)增加断点续备功能,如果中途备份出错,下次备份开始时会接着上次进度继续,如果不想这样做,可以手动删除位于D:Kaisir下面的savepoint.dat
3)增加导入的文章导出功能,以前导入校内的日志备份出来全是空白。
4)修正“通过手机发布的日志”保存空白的情况。
下载地址:
http://code.google.com/p/renren-backup-tool/

2011年3月13日更新:

我把这个小项目在Google Code托管了,详情可见:

http://code.google.com/p/renren-backup-tool/

希望参与这个项目维护的可以联系我 :)

2011年3月12日更新:

增加随机间隔,模拟真实用户访问,防止保存过程中被人人网强制中断连接。

按照惯例,依然提供源代码,与编译好的程序。

人人网日志备份工具:点此下载

人人网日志备份工具(源代码):点此下载

2010年11月17日更新:

增加图片下载功能(感谢ALsite增加此功能)

好吧 这回依然提供源代码可直接运行的程序

PS:

1)页面默认保存在D盘Kaisir文件夹下。

2)如果文章显示为乱码,请手动指定文件编码为UTF-8

 

Windows 7下解除VS 2008 90天试用的方法

今天才发现我的VS2008装了SP1以后还没有激活,变成了试用版。想用以前的办法在添加删除程序里输入序列号的方法竟然失效,在Win7该显示序列号输入框的地方竟然什么东西都没有~~查了半天资料,甚至在微软的MSDN讨论区中查了半天,得到的结果竟然是需要修改文件,然后重装VS2008。汗……这么费时费力的事情Kaisir是坚决不会做的。又是一阵搜索,终于找到了一个补丁~~使用方法也很简单:

1)打开“控制面板”–“添加删除功能”–找到Visual Studio2008–点击修改删除。

2)在出现“Microsoft Visual Studio 2008 安装程序 -维护页”这个窗口时,以管理员身份运行我给的补丁。

3)点击右上角的“Bug 微软”按钮。回到“维护页” 下方就会出来一个可供输入序列号的输入框。输入正式版序列号。

4)Done.

点此下载:CrackVS2008ForWindows7

当然,出于版权的原因,序列号我就不提供了,大家各显神通好了啦~~嘿嘿。

(本文软件,图片来源自:真有意思–三脚猫的部落格)

很有趣的一道C语言题

题目要求不允许改变main()函数,只能通过在test()函数中写代码来改变yy的值~~

[codesyntax lang=”c”]

void test(void)
{

//在这写代码

}

void main()

{
	int yy=1;
	test();
	printf("%d",yy);
}

[/codesyntax]

哈哈 当时看了这个题就觉得特别好玩 看了大家的回答更发现自己了解的知识还真是还有很大的欠缺哈 高人太多啦 哈哈哈哈~~~突然又很有奋斗的动力~~为成为计算机很NB的人而努力奋斗哈哈~~

附上几个参考答案,VC++ 6 编译通过。

答案一:

[codesyntax lang=”c”]

void test(void)
{
	int *p;
	p=(int *)&p;
	while (*p!=1)

	{
		p++;
	}
	*p=88888888;
}

[/codesyntax]

(PS:这是出题者自己公布的答案)

答案二:

[codesyntax lang=”c”]

void test(void)
{
	#define yy 9999
	#define int /##/##int
}

[/codesyntax]

(PS:这个很赖皮的说~~哈哈)

答案三:

[codesyntax lang=”c”]

void test(void)
{
	_asm
	{
		push ebp
		mov ebp,[ebp]
		mov dword ptr[ebp-4],0x00000003 //这个0x00000003就是覆盖了y的值
		pop ebp
	}
}

[/codesyntax]

(PS:我认为这是很标准的一个答案。)

黑客帝国数字雨 VC6源代码

很不错的效果 这个在Win7 X64 VC6编译通过~~

代码原作者不详。

[codesyntax lang=”c”]

#include <windows.h>

#define ID_TIMER    1
#define STRMAXLEN  25 //一个显示列的最大长度
#define STRMINLEN  8  //一个显示列的最小长度

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
typedef struct tagCharChain //整个当作屏幕的一个显示列,这是个双向列表
{
        struct tagCharChain *prev; //链表的前个元素
        TCHAR  ch;                  //一个显示列中的一个字符
        struct tagCharChain *next; //链表的后个元素
}CharChain, *pCharChain;

typedef struct tagCharColumn
{
        CharChain *head, *current, *point;
        int x, y, iStrLen; //显示列的开始显示的x,y坐标,iStrLen是这个列的长度
        int iStopTimes, iMustStopTimes; //已经停滞的次数和必须停滞的次数,必须停滞的次数是随机的
}CharColumn, *pCharColumn;

int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
        static TCHAR szAppName[] = TEXT ("matrix") ;
        HWND            hwnd ;
        MSG            msg ;
        WNDCLASS    wndclass ;

        wndclass.style                = CS_HREDRAW | CS_VREDRAW ;
        wndclass.lpfnWndProc        = WndProc ;
        wndclass.cbClsExtra        = 0 ;
        wndclass.cbWndExtra        = 0 ;
        wndclass.hInstance        = hInstance ;

wndclass.hIcon                = LoadIcon (NULL, IDI_APPLICATION) ;
        wndclass.hCursor        = LoadCursor (NULL, IDC_ARROW) ;
        wndclass.hbrBackground        = (HBRUSH) GetStockObject (BLACK_BRUSH) ;
        wndclass.lpszMenuName        = NULL ;
        wndclass.lpszClassName        = szAppName ;

        if(!RegisterClass (&wndclass))
        {
            MessageBox (NULL, TEXT ("此程序必须运行在NT下!"), szAppName, MB_ICONERROR) ;
            return 0;
        }

        hwnd = CreateWindow (szAppName, NULL,
                            WS_DLGFRAME | WS_THICKFRAME | WS_POPUP,
                            0, 0,
                            GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
                            NULL, NULL, hInstance,
                            NULL) ;

        ShowWindow (hwnd, SW_SHOWMAXIMIZED) ; //最大化显示
        UpdateWindow (hwnd) ;
        ShowCursor(FALSE); //隐藏鼠标光标

        srand ((int) GetCurrentTime ()) ; //初始化随机数发生器
        while (GetMessage (&msg, NULL, 0, 0))

{
            TranslateMessage (&msg) ;
            DispatchMessage (&msg) ;
        }
        ShowCursor(TRUE); //显示鼠标光标
        return msg.wParam ;
}

TCHAR randomChar() //随机字符产生函数
{
        return (TCHAR)(rand()%(126-33)+33); //33到126之间
}

int init(CharColumn *cc, int cyScreen, int x) //初始化
{
        int j;
        cc->iStrLen = rand()%(STRMAXLEN-STRMINLEN) + STRMINLEN; //显示列的长度
        cc->x = x+3 ;        //显示列的开始显示的x坐标
        cc->y =rand()%3?rand()%cyScreen:0; //显示列的开始显示的y坐标
        cc->iMustStopTimes = rand()%6 ;
        cc->iStopTimes    = 0 ;
        cc->head = cc->current =
                        (pCharChain)calloc(cc->iStrLen, sizeof(CharChain)); //生成显示列
        for(j=0; j<cc->iStrLen-1; j++)
        {
                cc->current->prev = cc->point; //cc->point一个显示列的前个元素
                cc->current->ch  = '';
                cc->current->next = cc->current+1; //cc->current+1一个显示列的后个元素
                cc->point          = cc->current++; //cc->point = cc->current; cc->current++;
        }
        cc->current->prev = cc->point; //最后一个节点
        cc->current->ch  = '';
        cc->current->next = cc->head;

cc->head->prev    = cc->current; //头节点的前一个为此链的最后一个元素

        cc->current = cc->point = cc->head; //free掉申请的内存要用current当参数
        cc->head->ch = randomChar(); // 对链表头的 元素填充
        return 0;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
      HDC          hdc ;
      //ctn 用来确定一个显示链是否 向下前进,如果等待次数超过必须等待的次数,ctn就代表要向下前进
      int i, j, temp, ctn; //j为一个显示链中除链表头外的在屏幕上显示的y坐标,temp绿色过度到黑色之用
      static  HDC hdcMem;
      HFONT    hFont;
      static  HBITMAP hBitmap;
      static  int cxScreen, cyScreen; //屏幕的宽度 高度.
      static  int iFontWidth=10, iFontHeight=15, iColumnCount; //字体的宽度 高度, 列数
      static  CharColumn *ccChain;

      switch (message)
      {
        case WM_CREATE:
            cxScreen = GetSystemMetrics(SM_CXSCREEN) ; //屏幕宽度
            cyScreen = GetSystemMetrics(SM_CYSCREEN) ;
            SetTimer (hwnd, ID_TIMER, 10, NULL) ;

            hdc = GetDC(hwnd);
            hdcMem = CreateCompatibleDC(hdc);
            hBitmap = CreateCompatibleBitmap(hdc, cxScreen, cyScreen);
            SelectObject(hdcMem, hBitmap);
            ReleaseDC(hwnd, hdc);
            //创建字体
            hFont = CreateFont(iFontHeight, iFontWidth-5, 0, 0, FW_BOLD, 0, 0, 0,

     DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
                                DRAFT_QUALITY, FIXED_PITCH | FF_SWISS, TEXT("Fixedsys"));
            SelectObject(hdcMem, hFont);
            DeleteObject (hFont) ;
            SetBkMode(hdcMem, TRANSPARENT); //设置背景模式为 透明
            iColumnCount = cxScreen/(iFontWidth*3/2); //屏幕所显示字母雨的列数

            ccChain = (pCharColumn)calloc(iColumnCount, sizeof(CharColumn));
            for(i=0; i<iColumnCount; i++)
            {
                init(ccChain+i, cyScreen, (iFontWidth*3/2)*i);
            }
            return 0 ;

        case WM_TIMER:
            hdc = GetDC(hwnd);
            PatBlt (hdcMem, 0, 0, cxScreen, cyScreen, BLACKNESS) ; //将内存设备映像刷成黑色
            for(i=0; i<iColumnCount; i++)
            {
                ctn = (ccChain+i)->iStopTimes++ > (ccChain+i)->iMustStopTimes;
                //
                (ccChain+i)->point = (ccChain+i)->head; //point用于遍历整个显示列

                //第一个字符显示为 白色
                SetTextColor(hdcMem, RGB(255, 255, 255));

TextOut(hdcMem, (ccChain+i)->x, (ccChain+i)->y, &((ccChain+i)->point->ch), 1);
                j = (ccChain+i)->y;
                (ccChain+i)->point = (ccChain+i)->point->next;
                //遍历整个显示列,将这个显示列里的字符从下往上显示
                temp = 0 ; //temp绿色过度到黑色之用
                while((ccChain+i)->point != (ccChain+i)->head && (ccChain+i)->point->ch)
                {
                        SetTextColor(hdcMem, RGB(0, 255-(255*(temp++)/(ccChain+i)->iStrLen), 0));
                        TextOut(hdcMem, (ccChain+i)->x, j-=iFontHeight, &((ccChain+i)->point->ch), 1);
                        (ccChain+i)->point = (ccChain+i)->point->next;
                }
                if(ctn)
                    (ccChain+i)->iStopTimes = 0 ;
                else continue;
                (ccChain+i)->y += iFontHeight; //下次开始显示的y坐标 为当前的y坐标加上 一个字符的高度
                //如果开始显示的y坐标减去 整个显示列的长度超过了屏幕的高度
                if( (ccChain+i)->y-(ccChain+i)->iStrLen*iFontHeight > cyScreen)
                {
                        free( (ccChain+i)->current );
    init(ccChain+i, cyScreen, (iFontWidth*3/2)*i);
                }
                //链表的头 为此链表的前个元素,因为下次开始显示的时候 就相当与在整个显示列的开头添加个元素,然后在开始往上显示
                (ccChain+i)->head = (ccChain+i)->head->prev;
                (ccChain+i)->head->ch = randomChar();
            }

            BitBlt(hdc, 0, 0, cxScreen, cyScreen, hdcMem, 0, 0, SRCCOPY);
            ReleaseDC(hwnd, hdc);
            return 0;

        case WM_RBUTTONDOWN:
            KillTimer (hwnd, ID_TIMER) ;
            return 0;

        case WM_RBUTTONUP:
            SetTimer (hwnd, ID_TIMER, 10, NULL) ;
            return 0;

        //处理善后工作
        case WM_KEYDOWN:
        case WM_LBUTTONDOWN:
        case WM_DESTROY:
            KillTimer (hwnd, ID_TIMER) ;
            DeleteObject(hBitmap);
            DeleteDC(hdcMem);
            for(i=0; i<iColumnCount; i++)
            {
                free( (ccChain+i)->current );
            }
            free(ccChain);
            PostQuitMessage (0) ;
            return 0 ;
        }
        return DefWindowProc (hwnd, message, wParam, lParam) ;
}

[/codesyntax]

.Net 无限分类的实现 (二)

上次写了使用TreeView控件进行无限分类绑定的方法,这回再写个通用性更好的~~嘿嘿 绑定DropDownList~~思想跟上篇日志很接近,也是使用递归,当然,网络上还有很多人给数据库增加了一个“Depth(深度)”的字段,这样进行绑定的时候还可以更简单些哈~~当然,没有必要的就不加了,还是递归使用起来简单些哈~~不多说了,上代码哈:

[codesyntax lang=”csharp”]

        protected void bind_droplist(string ChildNode, string tmp)
        {
            DataTable dt = bil.GetByClassPre(ChildNode).Tables[0];

            foreach (DataRow dr in dt.Rows)
            {
                if (dr["ClassPre"].ToString()=="0")
                {
                    //如果是根节点
                    tmp = "";
                    DropDownList1.Items.Add(dr["ClassName"].ToString());
                    bind_droplist(dr["ClassId"].ToString(), tmp + " ");
                }
                else
                {
                    //不是根节点
                    DropDownList1.Items.Add( tmp+"|-" + dr["ClassName"].ToString());
                    bind_droplist(dr["ClassId"].ToString(), tmp + " ");
                }
            }
        }

[/codesyntax]

.Net 无限分类的实现

以前总想着搞这个无限分类,今天终于得空好好的看了下,发现实现的原理还是很简单的,数据结构上,用两列(分类编号,上级编号)就可以实现,可是为了联合查询的方便,一般都再增加一列(深度),在这个实例里,我只用了两列,剩下的无非就是递归着对TreeView进行数据绑定而已~~。

[codesyntax lang=”csharp”]

    public partial class _Default : System.Web.UI.Page
    {
        BIL bil = new BIL();
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                bind_tree("0",null);
            }
        }
        protected void bind_tree(string ChildNode,TreeNode tn)
        {
            DataTable dt = bil.GetByClassPre(ChildNode).Tables[0];

            foreach (DataRow dr in dt.Rows)
            {
                TreeNode Node = new TreeNode();
                if (tn==null)
                {
                    //根
                    Node.Text = dr["ClassName"].ToString();
                    this.TreeView1.Nodes.Add(Node);
                    bind_tree(dr["ClassId"].ToString(), Node);
                }
                else
                {
                    //当前节点的子节点
                    Node.Text = dr["ClassName"].ToString();
                    tn.ChildNodes.Add(Node);
                    bind_tree(dr["ClassId"].ToString(),Node);
                }
            }
        }
    }

[/codesyntax]

完整实例:点击下载(Vs2008+Access)

sql server express 启用sa及附加数据库的方法

最近一直在玩VS,因为VS自带的那个Sql Server Express没有企业管理器,所以感觉特别鸡肋,于是我在虚拟机里搞了一个Sql Server的服务器,可是今天这个Vmware又起不来了,于是我只好啃啃这块鸡肋~~

还好鸡肋也不是特别鸡肋,至少提供了可以执行sql语句的地方~我的思路很简单,附加数据库,然后用存储过程修改sa密码,之后再用sa链接数据库。思路很清晰,可是事实证明,思路永远跟显示存在着差距:

附加数据库的步骤很顺利,通过一个内置的存储过程  sp_attach_db ‘数据库名’,’数据库全路径’,’日志全路径’ 这样就把附加数据库搞定了~~修改sa密码同样也很easy,修改了master表,  ALTER LOGIN [sa] WITH PASSWORD=N’新密码’ 这样就搞定了修改密码。可是当我尝试用sa与新密码登陆时,却被告知sa登陆失败,上网查询了下下,发现express版默认登陆验证方式是windows方式,而常规的更改方法需要企业管理器,没办法只好用非常规的办法了,查了半天资料,终于在CSDN找到了有用的东西:

想要修改登陆模式,可以通过修改注册表的办法进行

2005:HKLMSOFTWAREMicrosoftMicrosoft SQL ServerMSSQL.1MSSQLServerLoginMode
2008:HKEY_LOCAL_MACHINESOFTWAREMicrosoftMicrosoft SQL ServerMSSQL10.MSSQLSERVERMSSQLServerLoginMode

1:windows身份验证
2:混合身份验证

这下就好了,我改了注册表,重启了Sql server服务,却出现了新的问题,提示 “sa已被禁用”汗……再接着搜索,发现还是修改master表可以解决这个问题:

USE [master]
GO
ALTER   LOGIN   sa   ENABLE   ;

至此,就可以使用sa跟密码进行登录咯~~

PS:最后附个SQL Server Management Studio Express 2005的下载链接吧:点此下载