按日归档: 2007/04/05

用BCB在windows桌面创建快捷方式

API提供了一个叫做IShellLink的COM接口允许我们创建快捷方式。为在桌面创建快捷方式,我们创建一个IShellLink对象,设置它的属性,然后把这个link保存到desktop目录。
下面的例子代码演示了怎样创建一个快捷方式。在这个例子里,这个快捷方式保存在C:Drive目录下。
//———————————————————————-
include <shlobj.h>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if(OpenDialog1->Execute())
CreateShortCut(OpenDialog1->FileName);
}
//———————————————————————-
void TForm1::CreateShortCut(const AnsiString &file)
{
IShellLink* pLink;
IPersistFile* pPersistFile;
if(SUCCEEDED(CoInitialize(NULL)))
{
if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink, (void **) &pLink)))
{
pLink->SetPath(file.c_str());
pLink->SetDescription(“Woo hoo, look at Homer“s shortcut“);
pLink->SetShowCmd(SW_SHOW);
if(SUCCEEDED(pLink->QueryInterface(IID_IPersistFile,
(void **)&pPersistFile)))
{
WideString strShortCutLocation(“C:\bcbshortcut.lnk“);
pPersistFile->Save(strShortCutLocation.c_bstr(), TRUE);
pPersistFile->Release();
}
pLink->Release();
}
CoUninitialize();
}
}
//———————————————————————-
上面的例子只是把快捷方式文件保存到了c:drive目录下,但没保存到desktop目录下。
要让快捷方式出现在桌面上,只须把快捷方式文件保存到desktop目录下。首先我们要找到windows的desktop目录,请参阅判断 windows的Desktop及相关目录这一节。一旦我们知道了desktop所在的目录,我们就能将快捷方式文件保存到desktop目录下。然后 windows就能将快捷方式图标显示到桌面上。下面是经过改进了的例子:
//———————————————————————-
void TForm1::CreateShortCut(const AnsiString &file)
{
IShellLink* pLink;
IPersistFile* pPersistFile;
LPMALLOC ShellMalloc;
LPITEMIDLIST DesktopPidl;
char DesktopDir[MAX_PATH];
if(FAILED(SHGetMalloc(&ShellMalloc)))
return;
if(FAILED(SHGetSpecialFolderLocation(NULL,
CSIDL_DESKTOPDIRECTORY,
&DesktopPidl)))
return;
if(!SHGetPathFromIDList(DesktopPidl, DesktopDir))
{
ShellMalloc->Free(DesktopPidl);
ShellMalloc->Release();
return;
}
ShellMalloc->Free(DesktopPidl);
ShellMalloc->Release();
if(SUCCEEDED(CoInitialize(NULL)))
{
if(SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink, (void **) &pLink)))
{
pLink->SetPath(file.c_str());
pLink->SetDescription(“Woo hoo, look at Homer“s shortcut“);
pLink->SetShowCmd(SW_SHOW);
if(SUCCEEDED(pLink->QueryInterface(IID_IPersistFile,
(void **)&pPersistFile)))
{
WideString strShortCutLocation(DesktopDir);
strShortCutLocation += “\bcbshortcut.lnk“;
pPersistFile->Save(strShortCutLocation.c_bstr(), TRUE);
pPersistFile->Release();
}
pLink->Release();
}
CoUninitialize();
}
}
//———————————————————————-
不要陷于COM的泥沼之中
创建快捷方式包括一些对COM的使用。不要让你陷入到COM的复杂之中。COM只是创建和使用对象的一种方法。在这个例子里我们可以考虑不使用COM而是用等价的C++技术。
COM code C++ psuedo-equivalent
IShellLink* pLink; TShellLink *Link;
IPersistFile* pPersistFile; TPersistFile *PersistFile;
CoInitialize();

CoCreateInstance(CLSID_ShellLink, Link = new TShellLink;
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink,
(void **) &pLink)

pLink->SetPath(file.c_str()); Link->SetPath(file.c_str());
pLink->SetShowCmd(SW_SHOW); Link->SetShowCmd(SW_SHOW);

pLink->QueryInterface(IID_IPersistFile PersistFile =
(void **)&pPersistFile))) dynamic_cast<TPersistFile*>(Link);
pPersistFile->Save(“C:\“, TRUE); PersistFile->Save(“C:\“);

pPersistFile->Release(); delete PersistFile
pLink->Release(); delete Link;
CoUninitialize();

Read: 696

堆和栈的区别

作者: 芊珑发布日期: 2006-2-10 查看数: 125 出自: http://www.cnitexam.com
一、预备知识—程序的内存分配
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 – 程序结束后有系统释放
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。

二、例子程序
这是一个前辈写的,非常详细
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}
二、堆和栈的理论知识
2.1申请方式
stack:
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
heap:
需要程序员自己申请,并指明大小,在c中malloc函数
如p1 = (char *)malloc(10);
在C++中用new运算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在栈中的。
2.2
申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统, 会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等 于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
2.3申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因 此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
2.4申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活
2.5堆和栈中的存储内容
栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。
2.6存取效率的比较

char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:
#include
void main()
{
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}
对应的汇编代码
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。
?

2.7小结:
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

堆和栈的区别主要分:
操作系统方面的堆和栈,如上面说的那些,不多说了。
还有就是数据结构方面的堆和栈,这些都是不同的概念。这里的堆实际上指的就是(满足堆性质的)优先队列的一种数据结构,第1个元素有最高的优先权;栈实际上就是满足先进后出的性质的数学或数据结构。
虽然堆栈,堆栈的说法是连起来叫,但是他们还是有很大区别的,连着叫只是由于历史的原因。

Read: 750

联高软件:BCB编程经验几则

问:怎么实现TRichEdit的自动滚行?象某些阅读器那样的功能。
答:用ScrollWindowEx或者ScrollWindowEx就可以了。
ScrollWindow(RichEdit1- >Handle, 0, -1, NULL, NULL); //向下滚1个像素
ScrollWindow(RichEdit1- >Handle, 0, 1, NULL, NULL); //向上滚1个像素

问:在下最近在自己编组件,按照BCB的帮助提示做好了图标,也按照它的提示建立了联系,
但就是看不到自己的图标,只有默认的!!!
答:用IMAGE EDITOR编辑DCR文件,记信图标名称必须和组件名称相同,我说的是图标名称,不是文件名称。生成DCU文件后,用BRCC32.EXE对该DCR文 件进行编译生成DCU文件,将DCU文件加入到BPK包中,编译、安装包应可以看到你自制组件的包了。

问:物理删除记录,用ADO压缩Access2000库的方法?
答:用ADO压缩Access2000库
#include "utilcls.h"
void CompactDatabase(String f1,String psw1, String f2,String psw2)
{
String Provider1="Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
+ f1 + ";Jet OLEDB:Database Password=" + psw1;
String Provider2="Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
+ f2 + ";Jet OLEDB:Database Password=" + psw2;
Variant Adoobj=Variant::CreateObject("JRO.JetEngine");
Adoobj.OleProcedure("CompactDatabase",Provider1,Provider2);
AdoObj.Clear();//释放ADO对象
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
String f1="yhecdagl1.mdb"; // 源库1
String psw1="yhecdagl"; // 密码1
String f2="yhecdagl2.mdb"; // 新目的库2
String psw2="yhecdagl2"; // 新密码2
String dir=ExtractFilePath(Application->ExeName);
if(FileExists(f2))
DeleteFile(f2);
CompactDatabase(dir+f1,psw1,dir+f2,psw2);
ShowMessage("Finished");
}

问:能否通过按钮使用SQL创建一个名为a.db的文件?
答:这儿一个db文件就是一个数据表,所以可以通过创建表的方式来创建。
通过SQL语句就可以了,通过SQL语句我们可以创建不仅仅是表,还有别的很多,如字段等
Query1->Close;
Query1->DatabaseName="c:temp";
Query1->SQL->Text="create table a.db (field1 varchar(10),field2 varchar(10))";
Query1->ExecSQL;

问:TMediaPlayer如何用MediaPlayer1播放mp3?
设备类型指定了好几种怎么都不行?MediaPlayer1->DeviceType 为dtCdAudio,
dtDAT,dtOther,dtSeqencer,dtWaveAudio,dtAutoSelect都不行!;应怎么做才行?
答:
1.我来说说。MediaPlayer本身是高用windows提供的dll来工作的,但是由于bcb不是ms的,所以。。。在win98下的话,你可以查找到win.ini,在win.ini里修改东东就行了。
[mci extensions]
mp3=MPEGVideo
2.你可以用SndPlaySound函数来播放
char *tStream=new char…;
可以先用TFileStream把文件读到内存中,Read到tStream中
SndPlaySound(tStream,SND_MEMORY);

问:[TRichedit]:如何带格式存储Richedit内容到Access?
答:用AnsiString!!!!
具体方法如下,设保存RichEdit的字段为RichField:
TStringStream *pms=new TStringStream(NULL);
TStringList *StrList=new TStringList();
RichEditContent->Lines->SaveToStream(pms);
pms->Position = 0;
StrList->LoadFromStream(pms);
RichField->AsString=StrList->Text;

问:请问有什么办法使得子form一直留在最前面?
答:主要是重载Form的虚拟函数CreateParams, 改变TCreateParams的成员WndParent就可以了
class TForm2 : public TForm
{
__published: // IDE-managed Components
private: // User declarations
protected:
virtual void __fastcall CreateParams(TCreateParams & Param);
public: // User declarations
__fastcall TForm2(TComponent* Owner);
};
void __fastcall TForm2::CreateParams(TCreateParams & Param)
{
//调用基类的函数
TForm::CreateParams(Param);
Param.ExStyle |= WS_EX_TOPMOST;
//这儿最关键的是只要Param.WndParent不是Application- >Handle就可以了,
//不一定非要用GetDesktopWindow(),用其它的窗口也可以。
Param.WndParent = GetDesktopWindow();
}

问:[TTabSheet]怎么改变TabSheet标题部分的小矩形颜色。
小弟这样做的:
//TabSheet1- >PageControl = PageControl1;
TabSheet1- >Brush- >Color = clBlue;
上面的小矩形仍然为灰色。
PageControl1- >Brush- >Color = clBlue;
整个pagecontrol都变蓝色了,就是那个小矩形还灰色。
答:OwnDraw=true;
void __fastcall TForm1::TabControl1DrawTab(TCustomTabControl *Control,
int TabIndex, const TRect &Rect, bool Active)
{
Control- >Canvas- >Brush- >Color=clRed;
Control- >Canvas- >Rectangle(Rect);
}
—————————————–
PageControl也差不多,如果要不同的TabSheet有不同的颜色,可以判断TabIndex
void __fastcall TForm1::PageControl1DrawTab(TCustomTabControl *Control,
int TabIndex, const TRect &Rect, bool Active)
{
Control- >Canvas- >Brush- >Color=clGreen;
Control- >Canvas- >Pen- >Color=clGreen;
Control- >Canvas- >Rectangle(Rect);
}

问:我想写一个互斥量,但是怕和系统中的互斥量同名,有不有办法便利系统中的互斥量?
答:看CreateMutex 的帮助,如果你创建时返回ERROR_ALREADY_EXISTS,表示已经存在了,你就再换一个名字创建啊。

Read: 722